From 55e4b745ef433508ba3faa02b0d537d9890cf260 Mon Sep 17 00:00:00 2001 From: "nise.moe" Date: Wed, 6 Mar 2024 11:41:19 +0100 Subject: [PATCH] Basic error bar --- nise-replay-viewer/public/hit100.png | Bin 0 -> 3562 bytes nise-replay-viewer/public/hit300.png | Bin 0 -> 3562 bytes nise-replay-viewer/public/hit50.png | Bin 0 -> 3103 bytes .../public/hitcircleoverlay.png | Bin 22077 -> 8413 bytes nise-replay-viewer/public/hitmiss.png | Bin 0 -> 3569 bytes nise-replay-viewer/src/osu/Drawer.ts | 137 +++++++++++++++--- nise-replay-viewer/src/osu/OsuRenderer.ts | 33 +++-- 7 files changed, 142 insertions(+), 28 deletions(-) create mode 100644 nise-replay-viewer/public/hit100.png create mode 100644 nise-replay-viewer/public/hit300.png create mode 100644 nise-replay-viewer/public/hit50.png create mode 100644 nise-replay-viewer/public/hitmiss.png diff --git a/nise-replay-viewer/public/hit100.png b/nise-replay-viewer/public/hit100.png new file mode 100644 index 0000000000000000000000000000000000000000..26f7bbf36a2a6d7668be90472aa322030e8b0262 GIT binary patch literal 3562 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 XY7SLy-~;#mG=QD0y$$1v_r3oDfho(E literal 0 HcmV?d00001 diff --git a/nise-replay-viewer/public/hit300.png b/nise-replay-viewer/public/hit300.png new file mode 100644 index 0000000000000000000000000000000000000000..26f7bbf36a2a6d7668be90472aa322030e8b0262 GIT binary patch literal 3562 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 XY7SLy-~;#mG=QD0y$$1v_r3oDfho(E literal 0 HcmV?d00001 diff --git a/nise-replay-viewer/public/hit50.png b/nise-replay-viewer/public/hit50.png new file mode 100644 index 0000000000000000000000000000000000000000..d45dacc4dcad14b11cc0ea4d5f452d0e4feb3961 GIT binary patch literal 3103 zcmdUx`9BkmAIJ5nL~=}W6OzUpsX0EHD^qSZ9Sn2jnB_>AS*TF%A%>NFXd~LDFt@Gb zC})lja!l?d=GL5F-|v6%eLWtp*Yo}3`|*A}-jByC!OrF;|7pq7TwGlI=4Md%5$_#& zhll$p@1{=q9Dz5;%<F}@ z&m>XE!z|W>2!=^0#K1f->Q;$+$7mWun^QT8Mrk|uY3Leh`!ut_61IZtzfb$NRE zY3+=LU2pjBm(>q@^yfQstJze_%KpdM?#{exhTWL%y_!IsG#lSXt^Izh2pPeo8LP4u zYWaW<(YRsZjx%2moUQOa`J#UH6r$$NkX)nJKt!@y9R7L^@qwVdP1g$2-MO&SL$2fJ zNF!km71IJaf!gGDXh zMm*a{ELe@mAGv)y0DJitrOmy=jSPCMD+iMdJ2WmJhK2k<6A5c`}|5m*5MG zr*~u|D@(jC#3Cxv1G=yFN49d|M$*vQ z07T(*4}7(A)Z08$nJmXrwzv{>vmB`Pgi_M+D^q8=Ytix2U;L(NYeUWH%{i@T*^JL4 zdY@9t$g6wK;vSQT=ZL1)k6xFQh$z}jr8i2Un69$0_-9R4CwoQj`bWNR7UxA}7!iRD zGG3=hHFVr+q7QFI3hUgY>J3J=mqp>q)^mkMojAvO%9Q|XN9V_=y)K<-&bzEEa=$V; z4Srg4IXiD!S*AHItR{Skj)^*C;f4+@p$p%A^7S^`L55h=w*sN&mb_xjIAbz+=Tjb> zM?OxdZ+V&3O}1q2@^7{PKSNDme#h^(3x9nBALU(Lun_i$m>AaG9P5K`TT|DtLCa$a zhJapu1q&%De16naLjPS+$BA(1KtOL`NuVGqv0WAl79o-5FUsH?)&;E7;K=}hTI0b^ z&tV39go0TON^X0Q5Kl<(^%6z`HH+2*8&;E;84xW?vGZd}&O*Yc)1YZZ?^IiVuFbNM z%XI--WW_AQyGjZaq29IS0B2-Kq%v7O_WjP@`UEajV28r{qp@hkw6R&`G43W-jarsp zCprBs$=*W5bIESBwGoH=Zjv!0uc>5#+S036x8sRiZx+W>X$A*qg`J8Oi(2C}?&`su zPldERKFH!Ju^abryL@%nb;FVA-0^?k~wmN+u=-i7cnbw`wrLAH3LmI#Y4e zU#F#5ZJmT<4Aj-k(`UYzDW||KETNem(gM#C=4V6vMds~88G;ap0ue>g2j=1`O=BjV zrY^)L$mm4rbJeF`!CC;QjGN`mOT-_WFQ9luZ~wMZn!Iqv%hiyjhr8)Go~7*zHci48 z3isJC)S+D=?-gB0i?3`z$M`LgWuna0?rHK`4uqLNO{PiaoIBB! z11F?B?L73rF!-BFe}mUD%NQE6I#tb$ijzw)+Z4jfVN2yz1VXd4nu+@1V_J6P{2;7@ zAJj2-Ku8jQL4SXPn@Z^nOmTI(CQm9_2$4^jtMIW6DP!#PpFbOS>y;}v6Eicv%f#9J zsuME#IkmI%brPuik(gS!;0h|2&zoh=0##bNG>7jEDLo(k}7tMyKri0hm=R=D8Tx-|%-?@mT z_SEhn8rS!$*kzai-wVS|09SGIc#WKohtl(Jd$oC?o7%af$SB0@1dh~h9vcct$6sPLmVW*A4VeCiryGow8xLq&a$8=o!I^FHn9rm-VChWM&MQNA{IJ`fjsCpx%)aZd<6d6_ByK=ci@zG zPp5)~OaXH)x2Z3(X@o=^gOF7pGK=Bl17^!wp>^2=cYinE3l(>s%`Ht&A(6Q2;kIAw z8BPRH)!#U?0AJvg+THJe)?PG(M0Bx}mDtI#7+qOg|8sB7+?3oREAjMP%95vEY_Qdb zpn2H0IE_q^f-QOLE7wKIBC)aCTE-+W2!ER}chNI!C^jv&gq~FGxnn7L{!;Mw7 z^8)iH-)(IhE8*p+)(@vjcUXdLKNMX?8@=t%0eb=XZGRImvF0&rxEKqEQyuw#)0xk+ z+JDT_W6>DAT!oeUpb;S5AkQI%&<<*_NiDUVK&mj9HmhsrL!H|s<9zl0|(hpW49`kw??k@T}A&=X?e?Q zzkUY&@hmKoe^O%(rjF%fyD2}ej7PIzPA1`xL;<7*XL0rTIkiEN+oJ-4I|}}|+O`?p zK+1pw+92TE8*N=b_nvyMF;L=+CIZoA(yRy%RF9g%&8%!U*#!* zW{rg#l4`=TS@H$HjqCkn3qxrlzHq#EwdgGx+gL=lPw`<3gV z8q@PI5usRG;4u8sJFZ2~5B)rgr2t>rFO&MWmZ7QI(z4-LluUGYntrV(mZHTU(by`b zlTR0Ct?$7uNAb~M<2l|2>wC=as!ic6oQSWs?`+<$b8tkkZ1f)2Z)t8;drDZb%;RmT`V@)%$0mb9mLRFVIW)ERSljM5Ms UB3Q+k|L@x7rZ!O8b+@Pg0l?k22mk;8 literal 0 HcmV?d00001 diff --git a/nise-replay-viewer/public/hitcircleoverlay.png b/nise-replay-viewer/public/hitcircleoverlay.png index a79aad23fe3b6a54c406c4d3e803aea4abdac622..31341068907797728f9ce4d60a7572072f130e44 100644 GIT binary patch literal 8413 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 literal 22077 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 a8KWSaYJqQL{pb8$13c3<(kj<*LjMn0c+O)0 literal 0 HcmV?d00001 diff --git a/nise-replay-viewer/src/osu/Drawer.ts b/nise-replay-viewer/src/osu/Drawer.ts index c4277fd..ca45bbf 100644 --- a/nise-replay-viewer/src/osu/Drawer.ts +++ b/nise-replay-viewer/src/osu/Drawer.ts @@ -2,7 +2,7 @@ import { Vector2 } from "osu-classes"; import p5 from "p5"; import { loadImageAsync } from "@/utils"; import { Md5 } from "ts-md5"; -import {OsuRenderer} from "@/osu/OsuRenderer"; +import {Judgements, OsuRenderer} from "@/osu/OsuRenderer"; export class Drawer { @@ -27,6 +27,9 @@ export class Drawer { default7: undefined as any as p5.Image, default8: undefined as any as p5.Image, default9: undefined as any as p5.Image, + hitmiss: undefined as any as p5.Image, + hit50: undefined as any as p5.Image, + hit100: undefined as any as p5.Image }; private static p: p5; @@ -50,27 +53,127 @@ export class Drawer { this.p.drawingContext.globalAlpha = opacity; } - static drawCircleJudgement( + /** + * Draws the error bar for the given judgements. + * @param judgements + */ + static drawErrorBar(judgements: Judgements[]) { + let width = 512; + let height = 384; + + // TODO: Calculate real values + // @https://osu.ppy.sh/wiki/en/Beatmap/Overall_difficulty + let hitWindow300 = 50; + let hitWindow100 = 100; + let hitWindow50 = 150; + + let barWidth = 512 * 0.8; // Width of the error bar, 80% of canvas width + let barHeight = 20; // The height of the error bar + let barX = (width - barWidth) / 2; // Center the bar on the canvas + let barY = height + 52; + + // Draw the background for the 50's hit window (biggest) + Drawer.p.fill(217, 174, 71); + Drawer.p.rect(barX + barWidth / 2 - (hitWindow50), barY, hitWindow50 * 2, barHeight); + + // Draw the background for the 100's hit window (middle) + Drawer.p.fill(87, 225, 19); + Drawer.p.rect(barX + barWidth / 2 - (hitWindow100), barY, hitWindow100 * 2, barHeight); + + // Draw the background for the 300's hit window (smallest/closer to the center) + Drawer.p.fill(50, 188, 231); + Drawer.p.rect(barX + barWidth / 2 - (hitWindow300), barY, hitWindow300 * 2, barHeight); + + let tickDensity = new Array(Math.ceil(barWidth / 5)).fill(0); // Example: Each segment is 5 pixels wide + judgements.forEach(judgement => { + let judgementX = barX + barWidth / 2 + judgement.error / 2; + this.drawJudgementTick(judgementX, barY, barHeight, tickDensity); + }); + + // Draw a vertical bar in the exact center of the hit error bar + // Drawer.p.push(); + // Drawer.p.noFill(); + // Drawer.p.stroke(255); + // Drawer.p.strokeWeight(2); + // Drawer.p.line(barX + barWidth / 2, barY - 5, barX + barWidth / 2, barY + barHeight + 5); + + Drawer.p.pop(); + } + + //@ts-ignore + static drawJudgementTick(x, y, height, tickDensity) { + let barWidth = 512 * 0.8; + let barX = (512 - barWidth) / 2; // Center the bar on the canvas + + const segmentIndex = Math.floor((x - barX) / 5); // Assuming 5-pixel segments + tickDensity[segmentIndex]++; + + const opacity = this.calculateOpacity(tickDensity[segmentIndex]); + + Drawer.p.stroke(255, 255, 255, 255); + Drawer.p.strokeWeight(2); + Drawer.p.strokeCap(Drawer.p.SQUARE); // Slightly thicker ends for clarity + Drawer.p.colorMode(Drawer.p.RGB); + Drawer.p.stroke(Drawer.p.color(255, 255, 255, 255 * opacity)); // Apply opacity + Drawer.p.line(x, y, x, y + height); + } + + /** + * Calculate the opacity of the judgement tick. Lower opacity means less amount. + * + * @param count The amount of ticks + * @returns The opacity of the tick (0-1) + */ + static calculateOpacity(count: number): number { + const MIN_OPACITY = 0.55; // Minimum opacity enforced + const MAX_OPACITY = 1; // Maximum opacity + const MAX_DENSITY = 50; // Opacity reaches maximum at this tick count + + // Calculate linear opacity based on count + let opacity = (count / MAX_DENSITY) * (MAX_OPACITY - MIN_OPACITY) + MIN_OPACITY; + + // Ensure opacity is at least MIN_OPACITY and at most MAX_OPACITY + opacity = Math.max(opacity, MIN_OPACITY); + opacity = Math.min(opacity, MAX_OPACITY); + + return opacity; + } + + + static drawJudgement( position: Vector2, - radius: number, - judgement: string + judgement: string, + opacity: number ) { Drawer.p.push(); - Drawer.p.strokeWeight(2); - if (judgement === "OK") { - Drawer.p.stroke(`rgb(106, 176, 76)`); - Drawer.p.fill(`rgb(106, 176, 76)`); + //@ts-ignore + Drawer.p.drawingContext.globalAlpha = opacity; + if (judgement === "ONE_HUNDRED") { + Drawer.p.image( + this.images.hit100, + position.x, + position.y, + this.images.hit100.width, + this.images.hit100.height + ); } - if (judgement === "MEH") { - Drawer.p.stroke(`rgb(241, 196, 15)`); - Drawer.p.fill(`rgb(241, 196, 15)`); + if (judgement === "FIFTY") { + Drawer.p.image( + this.images.hit50, + position.x, + position.y, + this.images.hit50.width, + this.images.hit50.height + ); } if (judgement === "MISS") { - Drawer.p.stroke(`rgb(231, 76, 60)`); - Drawer.p.fill(`rgb(231, 76, 60)`); - } - if (judgement !== "GREAT") { - Drawer.p.circle(position.x, position.y, radius * 2); + Drawer.p.image( + this.images.hitmiss, + position.x, + position.y, + this.images.hitmiss.width, + this.images.hitmiss.height + ); } Drawer.p.pop(); } @@ -259,14 +362,12 @@ export class Drawer { let size = 4; if (lastFrame.button.mouseLeft1 || lastFrame.button.mouseLeft2) { Drawer.p.stroke("#BB6BD9"); - // TODO: Draw an X instead Drawer.p.line(lastFrame.position.x - size, lastFrame.position.y - size, lastFrame.position.x + size, lastFrame.position.y + size); Drawer.p.line(lastFrame.position.x + size, lastFrame.position.y - size, lastFrame.position.x - size, lastFrame.position.y + size); } if (lastFrame.button.mouseRight1 || lastFrame.button.mouseRight2) { Drawer.p.stroke("#F2994A"); - // TODO: Draw an X instead Drawer.p.line(lastFrame.position.x - size, lastFrame.position.y - size, lastFrame.position.x + size, lastFrame.position.y + size); Drawer.p.line(lastFrame.position.x + size, lastFrame.position.y - size, lastFrame.position.x - size, lastFrame.position.y + size); } diff --git a/nise-replay-viewer/src/osu/OsuRenderer.ts b/nise-replay-viewer/src/osu/OsuRenderer.ts index f4552c3..d2cc835 100644 --- a/nise-replay-viewer/src/osu/OsuRenderer.ts +++ b/nise-replay-viewer/src/osu/OsuRenderer.ts @@ -26,7 +26,7 @@ export enum OsuRendererEvents { SETTINGS = "SETTINGS", } -interface Judgements { +export interface Judgements { x: number; y: number; time: number; @@ -141,6 +141,8 @@ export class OsuRenderer { this.updateStatistics(); } + Drawer.drawErrorBar(this.judgements.filter(j => j.time < this.time && j.time - this.time > -10000)); + this.lastRender = Date.now(); this.renderPath(this.replay.replay!, Drawer.images.cursor); @@ -475,15 +477,16 @@ export class OsuRenderer { hitObject.currentComboIndex ); - // if (GameplayAnalyzer.renderJudgements[hitObject.startTime]) { - // Drawer.setDrawingOpacity(opacity / 2); - // - // Drawer.drawCircleJudgement( - // hitObject.stackedStartPosition, - // hitObject.radius, - // GameplayAnalyzer.renderJudgements[hitObject.startTime] - // ); - // } + let judgementsToShow = this.judgements.filter(j => j.time < this.time && j.time > hitObject.startTime); + if(judgementsToShow.length > 0) { + let judgement = judgementsToShow[0]; + Drawer.drawJudgement( + hitObject.stackedStartPosition, + judgement.type, + opacity + ); + } + Drawer.endDrawing(); return arScale; } @@ -531,6 +534,16 @@ export class OsuRenderer { Drawer.drawSliderFollowPoint(sliderPos, hitObject.radius); } + let judgementsToShow = this.judgements.filter(j => j.time < this.time && j.time > hitObject.startTime); + if(judgementsToShow.length > 0) { + let judgement = judgementsToShow[0]; + Drawer.drawJudgement( + hitObject.stackedStartPosition, + judgement.type, + opacity + ); + } + Drawer.endDrawing(); return arScale; }