From 434fed1cd6092c7c8cc24bc2cbd95d1d4a425494 Mon Sep 17 00:00:00 2001 From: yum Date: Mon, 20 Oct 2025 14:52:11 -0700 Subject: continue work on decoder, support auto tile size --- Scripts/DataDecoder.cs | 67 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 8 deletions(-) (limited to 'Scripts/DataDecoder.cs') diff --git a/Scripts/DataDecoder.cs b/Scripts/DataDecoder.cs index 810c46a..1128e2f 100644 --- a/Scripts/DataDecoder.cs +++ b/Scripts/DataDecoder.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using UdonSharp; using UnityEngine; using VRC.SDK3.Rendering; @@ -6,9 +7,12 @@ using VRC.Udon.Common.Interfaces; public class DataDecoder : UdonSharpBehaviour { public RenderTexture sourceTexture; - public int tileSize = 8; public int tileToCheck = 0; + private int tileSize = 8; + // Minimum size (in pixels) of a tile. This is shared with our tixl operator. + private const int kMinTileSize = 4; + private const int kMaxTileSize = 128; private Color32[] pixelData; private bool hasData = false; private int readWidth; @@ -18,9 +22,8 @@ public class DataDecoder : UdonSharpBehaviour void Update() { - if (sourceTexture == null || tileSize <= 0) return; + if (sourceTexture == null) return; - // TODO get more than one column int requestWidth = Mathf.Min(tileSize, sourceTexture.width); int requestHeight = sourceTexture.height; int pixelCount = requestWidth * requestHeight; @@ -62,21 +65,69 @@ public class DataDecoder : UdonSharpBehaviour private void ProcessTiles() { - if (pixelData == null || readWidth <= 0 || readHeight <= 0) return; + // Get the tile size. + { + int oldTileSize = tileSize; + tileSize = kMinTileSize; + tileSize = Parse24BitTile(0); + tileSize = Mathf.Clamp(tileSize, kMinTileSize, kMaxTileSize); + if (tileSize != oldTileSize) { + Debug.Log($"Tile size changed from {oldTileSize} to {tileSize}"); + } + } + + // Get the length. This is in units of subpixels. So we will need to access + // ceil(length/3) tiles. + int lengthSubpixels = Parse24BitTile(1); + int lengthTiles = (int) Mathf.Ceil(lengthSubpixels/3.0f); + + // Collect all nibbles into a flat array. Note that these are still + // encoded. + var nibbles = new List(lengthSubpixels); + for (int tile_i = 0; tile_i < lengthTiles; tile_i++) { + GetTileRGB(tile_i+2, out int r, out int g, out int b); + nibbles.Add(r); + if (nibbles.Count < nibbles.Capacity) { + nibbles.Add(g); + } + if (nibbles.Count < nibbles.Capacity) { + nibbles.Add(b); + } + } + + // Convert nibbles to bytes. + var bytes = nibbles; + for (int i = 0; i < nibbles.Count/2; i++) { + // See DataEncoder.cs. It puts the upper 4 bits before the lower 4 bits. + bytes[i] = (nibbles[2*i] & 0xF0) | ((nibbles[2*i+1] & 0xF0) >> 4); + } + // Remove second half of list. + bytes.RemoveRange(nibbles.Count/2, nibbles.Count/2); int tilesPerColumn = (int) Mathf.Floor(readHeight / tileSize); + } + + private int Parse24BitTile(int tileIdx) + { + GetTileRGB(tileIdx, out int r, out int g, out int b); + int data = 0; + data |= DecodeNibble(r); + data |= DecodeNibble(g) << 4; + data |= DecodeNibble(b) << 8; + return data; + } - GetTileRGB(tileToCheck, out int r, out int g, out int b); - Debug.Log($"Tile {tileToCheck}: R={r}, G={g}, B={b}"); + private int DecodeNibble(int subpixel) { + return (subpixel >> 4) & 0x0F; } - private void GetTileRGB(int tileIndex, out int r, out int g, out int b) + private void GetTileRGB(int tileIdx, out int r, out int g, out int b) { r = 0; g = 0; b = 0; - int tileY = tileIndex * tileSize; + int tileY = tileIdx * tileSize; int centerY = tileY + tileSize / 2; if (centerY >= readHeight) return; -- cgit v1.2.3