diff --git a/index.html b/index.html index dfbf132..95d0522 100644 --- a/index.html +++ b/index.html @@ -19,8 +19,8 @@ - -
加载中...
+ +
加载中...
- + + + @@ -137,7 +139,5 @@ - - diff --git a/pages/appendix_tools.md b/pages/appendix_tools.md index 70e9acb..3d1ea8b 100644 --- a/pages/appendix_tools.md +++ b/pages/appendix_tools.md @@ -20,4 +20,25 @@ g 1 1 5 4 #0ff{ }; +--- + +
+ --- \ No newline at end of file diff --git a/script/View.js b/script/View.js new file mode 100644 index 0000000..ebf2918 --- /dev/null +++ b/script/View.js @@ -0,0 +1,1027 @@ +// AssetManager.ts +var Point = class _Point { + x = 0; + y = 0; + constructor(x, y) { + if (x !== void 0 && y !== void 0) { + this.x = x; + this.y = y; + return; + } + } + clone() { + return new _Point(this.x, this.y); + } +}; +var Size = class { + width = 0; + height = 0; + constructor(width, height) { + if (width !== void 0 && height !== void 0) { + this.width = width; + this.height = height; + return; + } + } + clone() { + return new Point(this.width, this.height); + } +}; +var Rect = class _Rect { + left = 0; + top = 0; + right = 0; + bottom = 0; + get x() { + return this.left; + } + set x(value) { + const diff = value - this.left; + this.left += diff; + this.right += diff; + } + get y() { + return this.top; + } + set y(value) { + const diff = value - this.top; + this.top += diff; + this.bottom += diff; + } + get width() { + return this.right - this.left; + } + set width(value) { + this.right = this.left + value; + } + get height() { + return this.bottom - this.top; + } + set height(value) { + this.bottom = this.top + value; + } + get centerX() { + return (this.left + this.right) / 2; + } + get centerY() { + return (this.top + this.bottom) / 2; + } + get location() { + let point = new Point(); + point.x = this.centerX; + point.y = this.centerY; + return point; + } + set location(point) { + let w = this.width; + let h = this.height; + this.left = point.x; + this.right = this.left + w; + this.top = point.y; + this.bottom = this.top + h; + } + get size() { + let size = new Size(); + size.width = this.width; + size.height = this.height; + return size; + } + set size(size) { + this.width = size.width; + this.height = size.height; + } + get isEmpty() { + return this.width <= 0 || this.height <= 0; + } + constructor(arg0, arg1, arg2, arg3) { + if (typeof arg0 === "number" && typeof arg1 === "number") { + if (typeof arg2 === "number" && typeof arg3 === "number") { + this.left = arg0; + this.top = arg1; + this.right = arg0 + arg2; + this.bottom = arg1 + arg3; + return; + } + this.right = arg0; + this.bottom = arg1; + return; + } else if (arg0 instanceof Point && arg1 instanceof Size) { + this.left = arg0.x; + this.top = arg0.y; + this.right = arg0.x + arg1.width; + this.bottom = arg0.y + arg1.height; + return; + } else if (arg0 instanceof Size) { + this.right = arg0.width; + this.bottom = arg0.height; + return; + } + } + inflate(dx, dy) { + this.left -= dx; + this.right += dx; + this.top -= dy; + this.bottom += dy; + } + clone() { + return new _Rect(this.left, this.top, this.width, this.height); + } + union(rect) { + const left = Math.min(this.left, rect.left); + const top = Math.min(this.top, rect.top); + const right = Math.max(this.right, rect.right); + const bottom = Math.max(this.bottom, rect.bottom); + return new _Rect(left, top, right - left, bottom - top); + } +}; +var Color = class _Color { + argb = 0; + constructor(a, r, g, b) { + if (typeof a === "string") { + let s = a; + if (s.startsWith("#")) { + s = s.substring(1); + } + s = s.trim(); + switch (s.length) { + case 3: + s = "ff" + s.split("").map((c) => c + c).join(""); + break; + case 4: + s = s.split("").map((c) => c + c).join(""); + break; + case 6: + s = "ff" + s; + break; + case 8: + break; + default: + s = "ffffffff"; + } + const u = parseInt(s, 16); + this.argb = u; + return; + } + if (a !== void 0 && r === void 0 && g === void 0 && b === void 0) { + this.argb = a; + return; + } + if (a === void 0 && r !== void 0 && g !== void 0 && b !== void 0) { + const u = 255 << 24 | (r & 255) << 16 | (g & 255) << 8 | b & 255; + this.argb = u; + return; + } + if (a !== void 0 && r !== void 0 && g !== void 0 && b !== void 0) { + const u = a << 24 | (r & 255) << 16 | (g & 255) << 8 | b & 255; + this.argb = u; + return; + } + this.argb = 0; + } + get a() { + return this.argb >>> 24 & 255; + } + set a(value) { + const v = value & 255; + this.argb = v << 24 | this.argb & 16777215; + } + get r() { + return this.argb >>> 16 & 255; + } + set r(value) { + const v = value & 255; + this.argb = this.argb & 4278255615 | v << 16; + } + get g() { + return this.argb >>> 8 & 255; + } + set g(value) { + const v = value & 255; + this.argb = this.argb & 4294902015 | v << 8; + } + get b() { + return this.argb & 255; + } + set b(value) { + const v = value & 255; + this.argb = this.argb & 4294967040 | v; + } + toUint32() { + return this.argb; + } + clone() { + return new _Color(this.argb); + } + static FromRgba(r, g, b, a) { + return new _Color(a, r, g, b); + } + toRgbaString() { + return `rgba(${this.r}, ${this.g}, ${this.b}, ${this.a / 255})`; + } + toHexString(includeAlpha = true) { + if (includeAlpha) { + return `#${this.argb.toString(16).padStart(8, "0")}`; + } else { + const rgb = this.argb & 16777215; + return `#${rgb.toString(16).padStart(6, "0")}`; + } + } + equals(other) { + return this.argb === other.argb; + } + static get Transparent() { + return new _Color(0, 0, 0, 0); + } + static get Black() { + return new _Color(255, 0, 0, 0); + } + static get White() { + return new _Color(255, 255, 255, 255); + } + withAlpha(alpha) { + return new _Color(alpha, this.r, this.g, this.b); + } + withRed(red) { + return new _Color(this.a, red, this.g, this.b); + } + withGreen(green) { + return new _Color(this.a, this.r, green, this.b); + } + withBlue(blue) { + return new _Color(this.a, this.r, this.g, blue); + } +}; +var SliceInfo = class { + bounds = new Rect(); + center = new Rect(); + pivot = new Point(); + scale = 1; + blobUrl = ""; + get isNinePatch() { + return !this.center.isEmpty; + } +}; +var assetFilePath = "assets.png"; +var slicesFilePath = "assets.bin"; +var directoryPath = "./script"; +async function loadAssetFile() { + const pngPath = directoryPath + "/" + assetFilePath; + return await new Promise((resolve, reject) => { + const img = new Image(); + img.onload = () => resolve(img); + img.onerror = (e) => reject(new Error(`Failed to load asset file: ${pngPath}`)); + img.src = pngPath; + }); +} +async function readFromStream(stream) { + const canvas = new OffscreenCanvas(1, 1); + let offset = 0; + const count = stream.getUint8(0); + offset += 1; + const sliceInfos = /* @__PURE__ */ new Map(); + for (let i = 0; i < count; i++) { + const sliceInfo = new SliceInfo(); + const keyLength = stream.getUint8(offset); + offset += 1; + const key = new TextDecoder().decode(new Uint8Array(stream.buffer, offset, keyLength)); + offset += keyLength; + const left = stream.getUint8(offset); + offset += 1; + const top = stream.getUint8(offset); + offset += 1; + const wh = stream.getUint16(offset, true); + offset += 2; + const width = wh & 31; + const height = wh >> 5 & 63; + sliceInfo.bounds = new Rect(left, top, width, height); + const hasCenter = (wh & 32768) !== 0; + const hasPivot = (wh & 16384) !== 0; + if (hasCenter) { + const centerByte = stream.getUint8(offset); + offset += 1; + const centerLeft = centerByte & 3; + const centerTop = centerByte >> 2 & 3; + const centerWidth = centerByte >> 4 & 3; + const centerHeight = centerByte >> 6 & 3; + sliceInfo.center = new Rect(centerLeft, centerTop, centerWidth, centerHeight); + } + if (hasPivot) { + const pivotByte = stream.getUint8(offset); + offset += 1; + let pivotLeft = pivotByte & 7; + let pivotTop = pivotByte >> 3 & 7; + if ((pivotByte & 128) !== 0) { + pivotLeft *= -1; + } + if ((pivotByte & 64) !== 0) { + pivotTop *= -1; + } + sliceInfo.pivot = new Point(pivotLeft, pivotTop); + } + canvas.width = width; + canvas.height = height; + const ctx = canvas.getContext("2d"); + if (ctx === null) { + throw new Error("Failed to get 2D context"); + } + ctx.clearRect(0, 0, width, height); + ctx.drawImage(assetFile, sliceInfo.bounds.left, sliceInfo.bounds.top, width, height, 0, 0, width, height); + const blob = await canvas.convertToBlob({ + type: "image/png" + }); + sliceInfo.blobUrl = URL.createObjectURL(blob); + sliceInfos.set(key, sliceInfo); + } + return sliceInfos; +} +var assetLoaded = false; +var assetFile = await loadAssetFile(); +var slices = await readFromStream(new DataView(await (await fetch(directoryPath + "/" + slicesFilePath)).arrayBuffer())).finally(() => { + assetLoaded = true; +}); + +// Consts.ts +var Tab = /* @__PURE__ */ function(Tab2) { + Tab2["Sounds"] = "sounds"; + Tab2["Rows"] = "rows"; + Tab2["Actions"] = "actions"; + Tab2["Decorations"] = "decorations"; + Tab2["Rooms"] = "rooms"; + Tab2["Windows"] = "windows"; + Tab2["Unknown"] = "unknown"; + return Tab2; +}({}); +var EventType = /* @__PURE__ */ function(EventType2) { + EventType2["AddClassicBeat"] = "AddClassicBeat"; + EventType2["AddFreeTimeBeat"] = "AddFreeTimeBeat"; + EventType2["AddOneshotBeat"] = "AddOneshotBeat"; + EventType2["AdvanceText"] = "AdvanceText"; + EventType2["BassDrop"] = "BassDrop"; + EventType2["Blend"] = "Blend"; + EventType2["CallCustomMethod"] = "CallCustomMethod"; + EventType2["ChangeCharacter"] = "ChangeCharacter"; + EventType2["ChangePlayersRows"] = "ChangePlayersRows"; + EventType2["Comment"] = "Comment"; + EventType2["CustomFlash"] = "CustomFlash"; + EventType2["DesktopColor"] = "DesktopColor"; + EventType2["FadeRoom"] = "FadeRoom"; + EventType2["FinishLevel"] = "FinishLevel"; + EventType2["Flash"] = "Flash"; + EventType2["FlipScreen"] = "FlipScreen"; + EventType2["FloatingText"] = "FloatingText"; + EventType2["ForwardDecorationEvent"] = "ForwardDecorationEvent"; + EventType2["ForwardEvent"] = "ForwardEvent"; + EventType2["ForwardRowEvent"] = "ForwardRowEvent"; + EventType2["HideRow"] = "HideRow"; + EventType2["HideWindow"] = "HideWindow"; + EventType2["InvertColors"] = "InvertColors"; + EventType2["MacroEvent"] = "MacroEvent"; + EventType2["MaskRoom"] = "MaskRoom"; + EventType2["Move"] = "Move"; + EventType2["MoveCamera"] = "MoveCamera"; + EventType2["MoveRoom"] = "MoveRoom"; + EventType2["MoveRow"] = "MoveRow"; + EventType2["NarrateRowInfo"] = "NarrateRowInfo"; + EventType2["NewWindowDance"] = "NewWindowDance"; + EventType2["PaintHands"] = "PaintHands"; + EventType2["PlayAnimation"] = "PlayAnimation"; + EventType2["PlayExpression"] = "PlayExpression"; + EventType2["PlaySong"] = "PlaySong"; + EventType2["PlaySound"] = "PlaySound"; + EventType2["PulseCamera"] = "PulseCamera"; + EventType2["PulseFreeTimeBeat"] = "PulseFreeTimeBeat"; + EventType2["ReadNarration"] = "ReadNarration"; + EventType2["RenameWindow"] = "RenameWindow"; + EventType2["ReorderRooms"] = "ReorderRooms"; + EventType2["ReorderRow"] = "ReorderRow"; + EventType2["ReorderSprite"] = "ReorderSprite"; + EventType2["ReorderWindows"] = "ReorderWindows"; + EventType2["SayReadyGetSetGo"] = "SayReadyGetSetGo"; + EventType2["SetBackgroundColor"] = "SetBackgroundColor"; + EventType2["SetBeatSound"] = "SetBeatSound"; + EventType2["SetBeatsPerMinute"] = "SetBeatsPerMinute"; + EventType2["SetClapSounds"] = "SetClapSounds"; + EventType2["SetCountingSound"] = "SetCountingSound"; + EventType2["SetCrotchetsPerBar"] = "SetCrotchetsPerBar"; + EventType2["SetForeground"] = "SetForeground"; + EventType2["SetGameSound"] = "SetGameSound"; + EventType2["SetHandOwner"] = "SetHandOwner"; + EventType2["SetHeartExplodeInterval"] = "SetHeartExplodeInterval"; + EventType2["SetHeartExplodeVolume"] = "SetHeartExplodeVolume"; + EventType2["SetMainWindow"] = "SetMainWindow"; + EventType2["SetOneshotWave"] = "SetOneshotWave"; + EventType2["SetPlayStyle"] = "SetPlayStyle"; + EventType2["SetRoomContentMode"] = "SetRoomContentMode"; + EventType2["SetRoomPerspective"] = "SetRoomPerspective"; + EventType2["SetRowXs"] = "SetRowXs"; + EventType2["SetSpeed"] = "SetSpeed"; + EventType2["SetTheme"] = "SetTheme"; + EventType2["SetVFXPreset"] = "SetVFXPreset"; + EventType2["SetVisible"] = "SetVisible"; + EventType2["SetWindowContent"] = "SetWindowContent"; + EventType2["ShakeScreen"] = "ShakeScreen"; + EventType2["ShakeScreenCustom"] = "ShakeScreenCustom"; + EventType2["ShowDialogue"] = "ShowDialogue"; + EventType2["ShowHands"] = "ShowHands"; + EventType2["ShowRooms"] = "ShowRooms"; + EventType2["ShowStatusSign"] = "ShowStatusSign"; + EventType2["ShowSubdivisionsRows"] = "ShowSubdivisionsRows"; + EventType2["SpinningRows"] = "SpinningRows"; + EventType2["Stutter"] = "Stutter"; + EventType2["TagAction"] = "TagAction"; + EventType2["TextExplosion"] = "TextExplosion"; + EventType2["Tile"] = "Tile"; + EventType2["Tint"] = "Tint"; + EventType2["TintRows"] = "TintRows"; + EventType2["WindowResize"] = "WindowResize"; + return EventType2; +}({}); +var EventAttriblte = /* @__PURE__ */ function(EventAttriblte2) { + EventAttriblte2[EventAttriblte2["None"] = 0] = "None"; + EventAttriblte2[EventAttriblte2["DurationEvent"] = 1] = "DurationEvent"; + EventAttriblte2[EventAttriblte2["RoomEvent"] = 2] = "RoomEvent"; + return EventAttriblte2; +}({}); +var EventInfo = class { + defaultTab; + durationKey = "duration"; + attr; + get isDurationEvent() { + return (this.attr & EventAttriblte.DurationEvent) !== 0; + } + get isRoomEvent() { + return (this.attr & EventAttriblte.RoomEvent) !== 0; + } + constructor(tab, enumAttriblte, durationKey) { + this.defaultTab = tab; + this.attr = enumAttriblte ?? EventAttriblte.None; + if (durationKey !== void 0) { + this.durationKey = durationKey; + } + } +}; +var WordInfo = class { + phrase; + length; + constructor(phrase, length) { + this.phrase = phrase; + this.length = length; + } +}; +var WordInfos = { + SayReaDyGetSetGoNew: new WordInfo("Rea, Dy, Get, Set, Go!", 4), + SayReaDyGetSetOne: new WordInfo("Rea, Dy, Get, Set, One!", 4), + SayGetSetGo: new WordInfo("Get, Set, Go!", 2), + SayGetSetOne: new WordInfo("Get, Set, One!", 2), + JustSayRea: new WordInfo("Rea", 0), + JustSayDy: new WordInfo("Dy", 0), + JustSayGet: new WordInfo("Get", 0), + JustSaySet: new WordInfo("Set", 0), + JustSayAnd: new WordInfo("And", 0), + JustSayGo: new WordInfo("Go!", 0), + JustSayStop: new WordInfo("Stop", 0), + JustSayAndStop: new WordInfo("And Stop!", 0), + SaySwitch: new WordInfo("Switch", 0), + SayWatch: new WordInfo("Watch", 0), + SayListen: new WordInfo("Listen", 0), + Count1: new WordInfo("1", 0), + Count2: new WordInfo("2", 0), + Count3: new WordInfo("3", 0), + Count4: new WordInfo("4", 0), + Count5: new WordInfo("5", 0), + Count6: new WordInfo("6", 0), + Count7: new WordInfo("7", 0), + Count8: new WordInfo("8", 0), + Count9: new WordInfo("9", 0), + Count10: new WordInfo("10", 0), + SayReadyGetSetGo: new WordInfo("Ready, Get, Set, Go!", 4), + JustSayReady: new WordInfo("Ready", 0) +}; +var EventInfos = { + AddClassicBeat: new EventInfo(Tab.Rows), + AddFreeTimeBeat: new EventInfo(Tab.Rows), + AddOneshotBeat: new EventInfo(Tab.Rows), + AdvanceText: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + BassDrop: new EventInfo(Tab.Actions), + Blend: new EventInfo(Tab.Decorations), + CallCustomMethod: new EventInfo(Tab.Actions), + ChangeCharacter: new EventInfo(Tab.Actions), + ChangePlayersRows: new EventInfo(Tab.Actions), + Comment: new EventInfo(Tab.Unknown), + CustomFlash: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + DesktopColor: new EventInfo(Tab.Windows, EventAttriblte.DurationEvent), + FadeRoom: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent), + FinishLevel: new EventInfo(Tab.Actions), + Flash: new EventInfo(Tab.Actions), + FlipScreen: new EventInfo(Tab.Actions), + FloatingText: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + ForwardDecorationEvent: new EventInfo(Tab.Decorations), + ForwardEvent: new EventInfo(Tab.Unknown), + ForwardRowEvent: new EventInfo(Tab.Rows), + HideRow: new EventInfo(Tab.Actions), + HideWindow: new EventInfo(Tab.Windows), + InvertColors: new EventInfo(Tab.Actions), + MacroEvent: new EventInfo(Tab.Unknown), + MaskRoom: new EventInfo(Tab.Rooms), + Move: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent), + MoveCamera: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + MoveRoom: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent), + MoveRow: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + NarrateRowInfo: new EventInfo(Tab.Sounds), + NewWindowDance: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + PaintHands: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + PlayAnimation: new EventInfo(Tab.Decorations), + PlayExpression: new EventInfo(Tab.Actions), + PlaySong: new EventInfo(Tab.Sounds), + PlaySound: new EventInfo(Tab.Sounds), + PulseCamera: new EventInfo(Tab.Actions), + PulseFreeTimeBeat: new EventInfo(Tab.Rows), + ReadNarration: new EventInfo(Tab.Sounds), + RenameWindow: new EventInfo(Tab.Windows), + ReorderRooms: new EventInfo(Tab.Rooms), + ReorderRow: new EventInfo(Tab.Rows), + ReorderSprite: new EventInfo(Tab.Decorations), + ReorderWindows: new EventInfo(Tab.Windows), + SayReadyGetSetGo: new EventInfo(Tab.Sounds), + SetBackgroundColor: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + SetBeatSound: new EventInfo(Tab.Sounds), + SetBeatsPerMinute: new EventInfo(Tab.Sounds), + SetClapSounds: new EventInfo(Tab.Sounds), + SetCountingSound: new EventInfo(Tab.Sounds), + SetCrotchetsPerBar: new EventInfo(Tab.Sounds), + SetForeground: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + SetGameSound: new EventInfo(Tab.Sounds), + SetHandOwner: new EventInfo(Tab.Actions), + SetHeartExplodeInterval: new EventInfo(Tab.Sounds), + SetHeartExplodeVolume: new EventInfo(Tab.Sounds), + SetMainWindow: new EventInfo(Tab.Windows), + SetOneshotWave: new EventInfo(Tab.Rows), + SetPlayStyle: new EventInfo(Tab.Actions), + SetRoomContentMode: new EventInfo(Tab.Rooms), + SetRoomPerspective: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent), + SetRowXs: new EventInfo(Tab.Rows), + SetSpeed: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + SetTheme: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + SetVFXPreset: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + SetVisible: new EventInfo(Tab.Decorations), + SetWindowContent: new EventInfo(Tab.Windows, EventAttriblte.DurationEvent), + ShakeScreen: new EventInfo(Tab.Actions), + ShakeScreenCustom: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + ShowDialogue: new EventInfo(Tab.Actions), + ShowHands: new EventInfo(Tab.Actions), + ShowRooms: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent), + ShowStatusSign: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + ShowSubdivisionsRows: new EventInfo(Tab.Actions), + SpinningRows: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + Stutter: new EventInfo(Tab.Actions), + TagAction: new EventInfo(Tab.Actions), + TextExplosion: new EventInfo(Tab.Actions), + Tile: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent), + Tint: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent), + TintRows: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), + WindowResize: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent) +}; + +// View.ts +var lineHeight = 6; +var charHeight = 8; +var iconSize = 14; +var IconStyle = class { + enabled = true; + active = false; + hover = false; + scale = 1; + showDuration = false; +}; +function withState(color, active, enabled) { + return (enabled ? color : new Color(4286874756)).withAlpha(active ? 192 : 91); +} +function createLayer(key, bound, color, style) { + const layer = document.createElement("div"); + const info = slices.get(key); + layer.style.position = "absolute"; + layer.style.boxSizing = "content-box"; + if (info.isNinePatch) { + const center = info.center; + const width = bound?.width ?? info.bounds.width; + const height = bound?.height ?? info.bounds.height; + layer.style.left = `${(bound?.left ?? bound?.x ?? 0) * style.scale}px`; + layer.style.top = `${(bound?.top ?? bound?.y ?? 0) * style.scale}px`; + layer.style.borderStyle = "solid"; + layer.style.borderWidth = `${center.top * style.scale}px ${(info.bounds.width - center.right) * style.scale}px ${(info.bounds.height - center.bottom) * style.scale}px ${center.left * style.scale}px`; + layer.style.borderImageSource = `url(${info.blobUrl})`; + layer.style.borderImageSlice = `${center.top} ${info.bounds.width - center.right} ${info.bounds.height - center.bottom} ${center.left} fill`; + layer.style.borderImageWidth = `1`; + layer.style.borderImageOutset = `0`; + layer.style.borderImageRepeat = `repeat`; + layer.style.width = `${(width - center.left - (info.bounds.width - center.right)) * style.scale}px`; + layer.style.height = `${(height - center.top - (info.bounds.height - center.bottom)) * style.scale}px`; + } else { + layer.style.left = `${((bound?.left ?? bound?.x ?? 0) - info.pivot.x) * style.scale}px`; + layer.style.top = `${((bound?.top ?? bound?.y ?? 0) - info.pivot.y) * style.scale}px`; + layer.style.width = `${(bound?.width ?? info.bounds.width) * style.scale}px`; + layer.style.height = `${(bound?.height ?? info.bounds.height) * style.scale}px`; + layer.style.backgroundImage = `url(${info.blobUrl})`; + layer.style.backgroundSize = `${bound?.width ?? info.bounds.width * style.scale}px ${bound?.height ?? info.bounds.height * style.scale}px`; + } + if (color && Color.White.equals(color) === false) { + const filterId = getColorMatrixId(color); + layer.style.filter = `url(#${filterId})`; + layer.onColorChange = (color2) => { + if (!color2) { + return; + } + const newFilterId = getColorMatrixId(color2); + layer.style.filter = `url(#${newFilterId})`; + }; + } else { + } + return layer; +} +var colorMatrixIds = /* @__PURE__ */ new Map(); +var colorMatrixCache = document.createElement("div"); +document.body.appendChild(colorMatrixCache); +function getColorMatrixId(rgba) { + if (colorMatrixIds.has(rgba.toUint32())) { + return colorMatrixIds.get(rgba.toUint32()); + } + const feColorMatrix = document.createElementNS("http://www.w3.org/2000/svg", "feColorMatrix"); + feColorMatrix.setAttribute("type", "matrix"); + const r = rgba.r / 255; + const g = rgba.g / 255; + const b = rgba.b / 255; + const a = rgba.a / 255; + feColorMatrix.setAttribute("values", `${r} 0 0 0 0 0 ${g} 0 0 0 0 0 ${b} 0 0 0 0 0 ${a} 0`); + const filter = document.createElementNS("http://www.w3.org/2000/svg", "filter"); + filter.setAttribute("id", `filter_${rgba.toHexString()}`); + filter.appendChild(feColorMatrix); + const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + svg.setAttribute("width", "0"); + svg.setAttribute("height", "0"); + svg.appendChild(filter); + colorMatrixCache.appendChild(svg); + colorMatrixIds.set(rgba.toUint32(), filter.getAttribute("id")); + return filter.getAttribute("id"); +} +function createRDFontLayer(text, style) { + const lineHead = new Point(0, -charHeight); + const start = lineHead.clone(); + const layer = document.createElement("div"); + layer.style.position = "absolute"; + for (let i = 0; i < text.length; i++) { + const char = text.charAt(i); + if (char === "\n") { + start.x = lineHead.x; + start.y += lineHeight * style.scale; + } else { + const charCode = char.charCodeAt(0); + const charKey = `char_${charCode.toString(16).padStart(4, "0")}`; + const charInfo = slices.get(charKey); + const charLayer = createLayer(charKey, new Point(start.x, start.y), null, style); + start.x += (charInfo?.bounds.width ?? charHeight) * style.scale; + layer.appendChild(charLayer); + } + } + return layer; +} +function createBackLayer(size, color, style) { + const outline = "event_outline"; + const back = "event_back"; + const backLayer = createLayer(back, new Rect(1, 1, (size?.width ?? iconSize) - 2, (size?.height ?? iconSize) - 2), withState(color, style.active, style.enabled), style); + const outlineLayer = createLayer(outline, size ? new Rect(size) : null, new Color(style.active ? 4294967295 : 4289243304), style); + if (backLayer.onColorChange) { + backLayer.onStateChange = (style2) => backLayer.onColorChange(withState(color, style2.active, style2.enabled)); + } + if (outlineLayer.onColorChange) { + outlineLayer.onStateChange = (style2) => outlineLayer.onColorChange(new Color(style2.active ? 4294967295 : 4289243304)); + } + return [ + backLayer, + outlineLayer + ]; +} +function colorOf(tab) { + switch (tab) { + case Tab.Sounds: + return new Color("d92433"); + case Tab.Rows: + return new Color("2c4fdb"); + case Tab.Actions: + return new Color("c544b3"); + case Tab.Rooms: + return new Color("d8b811"); + case Tab.Decorations: + return new Color("00c459"); + case Tab.Windows: + return new Color("50b5d7"); + default: + return new Color("7d7d7d"); + } +} +function layerHoverInit(layer) { + layer.onStateChange = (style) => { + if (style.hover) { + layer.style.opacity = "1.0"; + } else { + layer.style.opacity = "0"; + } + }; +} +function createElementEvent(obj, style) { + console.log(style); + style = { + ...new IconStyle(), + ...style + }; + const evttype = obj.type; + let key0 = `event_${obj.type}`; + if (!slices.has(key0)) { + console.warn(`Slice for event type ${evttype} not found, using Unknown.`); + if (!slices.has("event_Unknown")) { + return null; + } + key0 = "event_Unknown"; + } + const info = slices.get(key0); + if (!info) { + console.warn(`Slice info for event type ${evttype} not found.`); + return null; + } + const evttypeEnum = EventType[evttype]; + const evinfo = EventInfos[evttypeEnum]; + const key = "event_" + evttype; + const pulse = "event_beat_pulse"; + const hit = "event_beat_hit"; + const hitf = "event_beat_hit_freeze"; + const hitb = "event_beat_hit_burn"; + const beatcross = "event_beat_cross"; + const beatx = "event_beat_x"; + const beatsynco = "event_beat_synco"; + const beatline = "event_beat_line"; + const evtag = "event_tag"; + const evbarea = "event_beat_area"; + const beatColor = new Color(4284539717); + const element = document.createElement("div"); + const internalLayers = []; + function addLayers(layers) { + for (const layer of layers) { + if (layer) { + element.appendChild(layer); + internalLayers.push(layer); + } + } + } + element.style.imageRendering = "pixelated"; + switch (evttype) { + case EventType.AddClassicBeat: + { + const tick = obj.tick ?? 1; + const swing = (obj.swing ?? 0) || 1; + const hold = obj.hold ?? 0; + const syncoSwing = obj.syncoSwing ?? 0; + const prexs = obj.preXs ?? { + syncoBeat: -1, + syncoSwing: 0 + }; + const length = obj.length ?? 7; + const iconWidth = iconSize * (tick * (length - 1 - prexs.syncoSwing)); + const holdBar = hold > 0 ? createLayer(evbarea, new Rect(iconWidth, 0, iconSize * hold, iconSize), new Color(style.active ? 4291839731 : 4286462352), style) : null; + if (holdBar) { + holdBar.style.pointerEvents = "none"; + } + const backLayers2 = createBackLayer(new Size(iconWidth, iconSize), colorOf(obj.tab ?? evinfo.defaultTab), style); + const pulses = []; + for (let i = 0; i < length - 1; i++) { + const pulseLayer = createLayer(pulse, new Point(iconSize * (tick * (i + i % 2 * (1 - swing) - (i <= prexs.syncoBeat ? 0 : prexs.syncoSwing))), 0), null, style); + layerHoverInit(pulseLayer); + pulses.push(pulseLayer); + } + const hitLayer = createLayer(hit, new Point(iconSize * (tick * (length - 1 - (prexs.syncoSwing ?? 0))) - 1, 0), null, style); + addLayers([ + holdBar, + ...backLayers2, + ...pulses, + hitLayer + ]); + } + break; + case EventType.AddOneshotBeat: + { + const tick = obj.tick ?? 1; + const interval = obj.interval ?? 2; + const loop = obj.loops ?? 0; + const subdiv = obj.subdivisions ?? 1; + const hold = obj.hold ?? false; + const mode = obj.freezeBurnMode ?? null; + const delay = obj.freezeBurnMode === "Freezeshot" ? obj.delay ?? 0 : 0; + const subdivWidth = iconSize * (subdiv - 1) / subdiv * tick; + const eventWidth = iconSize * (interval * loop + tick + delay); + const off = interval - tick; + const backLayers2 = createBackLayer(new Size(eventWidth, iconSize), colorOf(obj.tab ?? evinfo.defaultTab), style); + const holdWidth = iconSize * (interval - tick - delay); + const holdLayer = hold && holdWidth - subdivWidth > 0 ? createLayer(evbarea, new Rect(eventWidth + subdivWidth, 0, holdWidth - subdivWidth, iconSize), new Color(style.enabled ? 4291839731 : 4285493103), style) : null; + const subdivLayer = subdiv > 1 ? createLayer(evbarea, new Rect(eventWidth, 0, subdivWidth, iconSize), new Color(style.enabled ? 4279480353 : 4285493103), style) : null; + const skipshotLayer = obj.skipshot ?? false ? createLayer(evbarea, new Rect(eventWidth + Math.max(subdivWidth, holdWidth), 0, iconSize * interval - Math.max(subdivWidth, holdWidth), iconSize), new Color(style.enabled ? 4291115835 : 4285493103), style) : null; + if (holdLayer) holdLayer.style.pointerEvents = "none"; + if (subdivLayer) subdivLayer.style.pointerEvents = "none"; + if (skipshotLayer) skipshotLayer.style.pointerEvents = "none"; + const pulses = []; + const crossLayers = []; + const posx = -off * iconSize; + const hittype = mode === "Freezeshot" ? hitf : hitb; + for (let l = 0; l <= loop; l++) { + for (let i = 0; i < subdiv; i++) { + const pulseLayer = createLayer(pulse, new Point(iconSize * (l * interval + i * tick / subdiv), 0), null, style); + layerHoverInit(pulseLayer); + pulses.push(pulseLayer); + } + for (let i = 0; i < subdiv; i++) { + const hitLayer2 = createLayer(hit, new Point(iconSize * (l * interval + delay + tick + i * tick / subdiv) - 1, 0), null, style); + pulses.push(hitLayer2); + } + const crossLayer1 = mode || hold ? createLayer(beatcross, new Point(iconSize * l * interval + posx - 1, 0), null, style) : null; + const crossLayer2 = mode ? createLayer(beatcross, new Point(iconSize * (l - (mode === "Freezeshot" ? 0 : 1)) * interval - 1, 0), null, style) : null; + const hitLayer = createLayer(hittype, new Point(iconSize * (l * interval + tick) - 1, 0), null, style); + if (crossLayer1) { + layerHoverInit(crossLayer1); + crossLayers.push(crossLayer1); + } + if (crossLayer2) { + layerHoverInit(crossLayer2); + crossLayers.push(crossLayer2); + } + pulses.push(hitLayer); + } + const loopLayer = createLayer("event_beat_loop", new Point(eventWidth, 0), null, style); + loopLayer.style.opacity = "0"; + loopLayer.onStateChange = (style2) => { + if (style2.hover) { + loopLayer.style.opacity = "1.0"; + } else { + loopLayer.style.opacity = "0"; + } + }; + addLayers([ + ...backLayers2, + holdLayer, + subdivLayer, + skipshotLayer, + ...pulses, + loopLayer, + ...crossLayers + ]); + } + break; + case EventType.Comment: + { + const backLayers2 = createBackLayer(info.bounds.size, new Color(obj.color ?? "7d7d7d"), style); + const iconLayer = createLayer(key, null, null, style); + addLayers([ + ...backLayers2, + iconLayer + ]); + } + break; + case EventType.AddFreeTimeBeat: + { + const hold = obj.hold ?? 0; + const holdLayer = hold > 0 ? createLayer(evbarea, new Rect(info.bounds.width, 0, iconSize * hold - info.bounds.width, iconSize), new Color(style.active ? 4291839731 : 4286462352), style) : null; + if (holdLayer) { + holdLayer.style.pointerEvents = "none"; + } + const backLayers2 = createBackLayer(new Size(info.bounds.width, iconSize), beatColor, style); + const hitLayer = obj.pulse === 6 ? createLayer(hit, new Point(0, 0), null, style) : null; + const textLayer = createRDFontLayer(((obj.pulse ?? 0) + 1).toString(), style); + textLayer.style.left = `${1.5 * style.scale}px`; + textLayer.style.top = `${10 * style.scale}px`; + addLayers([ + holdLayer, + ...backLayers2, + hitLayer, + textLayer + ]); + } + break; + case EventType.DesktopColor: + { + const duration = obj.duration ?? 0; + const backLayers2 = createBackLayer(new Size(info.bounds.width, info.bounds.height * 4), colorOf(obj.tab ?? evinfo.defaultTab), style); + const iconLayer = createLayer(`${key}_0`, new Point(0, info.bounds.height), null, style); + const iconColorLayer = createLayer(key, new Point(0, info.bounds.height), null, style); + const durationLayer = obj.duration > 1 ? createLayer(evbarea, new Rect(iconSize, 0, (duration - 1) * iconSize, info.bounds.height * 4), new Color(4283471790), style) : null; + addLayers([ + ...backLayers2, + durationLayer, + iconLayer, + iconColorLayer + ]); + } + break; + case EventType.PulseFreeTimeBeat: + { + const hold = obj.hold ?? 0; + const holdLayer = hold > 0 ? createLayer(evbarea, new Rect(info.bounds.width, 0, iconSize * hold - info.bounds.width, info.bounds.height), new Color(style.active ? 4291839731 : 4286462352), style) : null; + if (holdLayer) { + holdLayer.style.pointerEvents = "none"; + } + const backLayers2 = createBackLayer(new Size(info.bounds.width, info.bounds.height), beatColor, style); + const hitLayer = obj.pulse === 6 ? createLayer(hit, new Point(0, 0), null, style) : null; + let text = ""; + switch (obj.action) { + case "Custom": + text = ((obj.customPulse ?? 0) + 1).toString(); + break; + case "Increment": + text = ">"; + break; + case "Decrement": + text = "<"; + break; + case "Remove": + text = "x"; + break; + } + const textLayer = createRDFontLayer(text, style); + textLayer.style.left = `${1.5 * style.scale}px`; + textLayer.style.top = `${10 * style.scale}px`; + addLayers([ + holdLayer, + ...backLayers2, + hitLayer, + textLayer + ]); + } + break; + case EventType.ReorderRooms: + case EventType.ReorderWindows: + { + const backLayers2 = createBackLayer(info.bounds.size, colorOf(obj.tab ?? evinfo.defaultTab), style); + const orderLayers = []; + const order = obj.order ?? [ + 0, + 1, + 2, + 3 + ]; + for (let i = 0; i < order.length; i++) { + { + const orderLayer = createLayer(`${key}_${order[i]}`, new Point(0, i * iconSize), null, style); + orderLayers.push(orderLayer); + } + } + addLayers([ + ...backLayers2, + ...orderLayers + ]); + } + break; + default: + const backLayers = createBackLayer(info.bounds.size, colorOf(obj.tab ?? evinfo.defaultTab), style); + addLayers(backLayers); + switch (evttype) { + case EventType.CustomFlash: + addLayers([ + createLayer(`${key}_0`, null, new Color(obj.startColor ?? "000000"), style), + createLayer(`${key}_1`, null, new Color(obj.endColor ?? "000000"), style) + ]); + break; + case EventType.FlipScreen: + const flip = (obj.flipX ? 1 : 0) | (obj.flipY ? 1 : 0); + if (flip === 0) { + addLayers([ + createLayer(key, null, null, style) + ]); + } else { + addLayers([ + createLayer(`${key}_${flip - 1}`, null, null, style) + ]); + } + default: + const layer = document.createElement("div"); + layer.style.position = "absolute"; + layer.style.left = "0"; + layer.style.top = "0"; + layer.style.width = `${info.bounds.width * style.scale}px`; + layer.style.height = `${info.bounds.height * style.scale}px`; + layer.style.backgroundSize = `${info.bounds.width * style.scale}px ${info.bounds.height * style.scale}px`; + layer.style.backgroundImage = `url(${info.blobUrl})`; + element.appendChild(layer); + break; + } + break; + } + element.onStateChange = (style2) => { + style2 = { + ...style2 + }; + internalLayers.forEach((layer) => { + if (layer.onStateChange) { + layer.onStateChange(style2); + } + }); + }; + return element; +} +export { + createElementEvent +}; diff --git a/script/assets.bin b/script/assets.bin new file mode 100644 index 0000000..92ef748 Binary files /dev/null and b/script/assets.bin differ diff --git a/script/assets.png b/script/assets.png new file mode 100644 index 0000000..e4d0538 Binary files /dev/null and b/script/assets.png differ diff --git a/script/special.js b/script/special.js index 930c5cf..5e8373a 100644 --- a/script/special.js +++ b/script/special.js @@ -1,3 +1,5 @@ +import { createElementEvent } from "./View.js"; + let curx = 0; let cury = 0; let rowx; @@ -198,10 +200,133 @@ function rdview() { textarea.addEventListener('input', initCanvas); } +function rdview2() { + let rdview = document.getElementsByClassName("rdview2")[0]; + if (!rdview) return; + let rdcanvas = rdview.querySelector(".canvas"); + let textarea = rdview.querySelector("textarea.area"); + let number = rdview.querySelector(".number"); + const textareaStyles = window.getComputedStyle(textarea); + [ + 'fontFamily', 'fontSize', 'fontWeight', + 'letterSpacing', 'lineHeight', 'padding', + ].forEach(property => { + number.style[property] = textareaStyles[property]; + }); + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + const font = `${textareaStyles.fontSize} ${textareaStyles.fontFamily}`; + context.font = font; + function calcStringLines(sentence, width) { + if (!width) return 0; + const words = sentence.split(''); + let lineCount = 0; + + let currentLine = ''; + for (let i = 0; i < words.length; i++) { + const wordWidth = context.measureText(words[i]).width; + const lineWidth = context.measureText(currentLine).width; + if (lineWidth + wordWidth > width) { + lineCount++; + currentLine = words[i]; + } else { + currentLine += words[i]; + } + } + if (currentLine.trim() !== '') lineCount++; + return lineCount; + } + function calcLines() { + const lines = textarea.value.split('\n'); + const textareaWidth = textarea.getBoundingClientRect().width; + const textareaScrollWidth = textareaWidth - textarea.clientWidth; + const parseNumber = (v) => v.endsWith('px') ? parseInt(v.slice(0, -2), 10) : 0; + const textareaPaddingLeft = parseNumber(textareaStyles.paddingLeft); + const textareaPaddingRight = parseNumber(textareaStyles.paddingRight); + const textareaContentWidth = textareaWidth - textareaPaddingLeft - textareaPaddingRight - textareaScrollWidth; + const numLines = lines.map(lineString => calcStringLines(lineString, textareaContentWidth)); + let lineNumbers = []; + let i = 1; + while (numLines.length > 0) { + const numLinesOfSentence = numLines.shift(); + lineNumbers.push(i); + if (numLinesOfSentence > 1) { + Array(numLinesOfSentence - 1) + .fill('') + .forEach((_) => lineNumbers.push('')); + } + i++; + } + return lineNumbers; + } + function initLineNumbers() { + const lines = calcLines(); + const lineDoms = Array.from({ + length: lines.length, + }, (_, i) => `
${lines[i] || ' '}
`); + number.innerHTML = lineDoms.join(''); + } + function initCanvas() { + // const lang = textarea.value.split('\n')[0] + // const code = textarea.value.split('\n').slice(1).join('\n') + // rdcanvas.innerHTML = RDViewRender(lang, code) + const objs = JSON.parse(`[${textarea.value}]`); + const eventStyle = {"scale": 2.0, "showDuration": false }; + let maxy = 0; + for (let obj of objs) { + const style = {... eventStyle, enabled: obj.active ?? true }; + const elem = createElementEvent(obj, style); + elem.eventStyle = style; + elem.style.position = "absolute"; + elem.style.left = `${((((obj.bar ?? 1) - 1) * 8) + (obj.beat ?? 1) - 1) * 14 * eventStyle.scale}px`; + elem.style.top = `${(obj.y ?? obj.row ?? 0) * 14 * eventStyle.scale}px`; + if (((obj.y ?? obj.row ?? 0) * 14 * eventStyle.scale) + elem.offsetHeight > maxy) { + maxy = ((obj.y ?? obj.row ?? 0) * 14 * eventStyle.scale) + elem.offsetHeight; + } + elem.addEventListener("mousedown", (event) => { + const eStyle = elem.eventStyle; + eStyle.active = true; + elem.onStateChange(eStyle); + }); + elem.addEventListener("mouseover", (event) => { + const eStyle = elem.eventStyle; + eStyle.hover = true; + elem.onStateChange(eStyle); + }); + elem.addEventListener("mouseout", (event) => { + const eStyle = elem.eventStyle; + eStyle.hover = false; + eStyle.active = false; + elem.onStateChange(eStyle); + }); + elem.addEventListener("mouseup", (event) => { + const eStyle = elem.eventStyle; + eStyle.active = false; + elem.onStateChange(eStyle); + }); + rdcanvas.style.position = "relative"; + rdcanvas.style.height = `${maxy + 4 * 14 * eventStyle.scale}px`; + if (elem) { + rdcanvas.appendChild(elem); + } + } + //rdcanvas.innerHTML = RDView2Render(json); + } + initCanvas() + initLineNumbers() + textarea.addEventListener('input', initLineNumbers); + textarea.addEventListener('input', initCanvas); +} + window.$docsify.plugins = [].concat(window.$docsify.plugins, function (hook) { hook.doneEach(function () { themePosition(); rdview(); + rdview2(); document.documentElement.scrollTop = document.body.scrollTop = 0; }); }); + +import("./docsify.min.js").then(() => { + +}); \ No newline at end of file diff --git a/style/special.css b/style/special.css index a5db117..7ca8cae 100644 --- a/style/special.css +++ b/style/special.css @@ -162,7 +162,7 @@ div.theme-positions>.infobox { .markdown-section:has(div.rdview) {} -div.rdview { +div.rdview, div.rdview2 { & div.canvas { width: 100%; }