From fabcfb162c5548e3834aaa6c42470f60e37545f3 Mon Sep 17 00:00:00 2001 From: Mentfent <167481805+mentusfentus@users.noreply.github.com> Date: Mon, 5 Aug 2024 21:18:47 -0300 Subject: [PATCH] DS Classic Menu: Improve clock hands and add outer shadow to the clock & calendar (#2450) * Fix recent sort... again * DS Classic Menu: Replace line renderer algorithm for a better one * DS Classic Menu: Added an outer shadow to clock and calendar --- quickmenu/arm9/source/graphics/graphics.cpp | 115 ++++++++++++------ .../nitrofiles/graphics/calendar/calendar.png | Bin 393 -> 835 bytes .../graphics/calendar/calendarbig.png | Bin 399 -> 877 bytes quickmenu/nitrofiles/graphics/clock.png | Bin 472 -> 1275 bytes 4 files changed, 81 insertions(+), 34 deletions(-) diff --git a/quickmenu/arm9/source/graphics/graphics.cpp b/quickmenu/arm9/source/graphics/graphics.cpp index 968b3d482f..7f00e64c14 100644 --- a/quickmenu/arm9/source/graphics/graphics.cpp +++ b/quickmenu/arm9/source/graphics/graphics.cpp @@ -99,10 +99,10 @@ int iconYpos[7] = {25, 73, 73, 121, 175, 170, 175}; bool showdialogbox = false; int dialogboxHeight = 0; -constexpr int calendarXPos = 127; +constexpr int calendarXPos = 125; constexpr int calendarYPos = 31; -constexpr int clockXPos = 15; -constexpr int clockYPos = 47; +constexpr int clockXPos = 13; +constexpr int clockYPos = 45; constexpr int batteryXPos = 242; constexpr int batteryYPos = 4; @@ -125,14 +125,14 @@ u16 bmpImageBuffer[256*192] = {0}; u16 topImageBuffer[256*192] = {0}; u16* colorTable = nullptr; -u16 calendarImageBuffer[113*113] = {0}; -u16 calendarBigImageBuffer[113*129] = {0}; +u16 calendarImageBuffer[117*115] = {0}; +u16 calendarBigImageBuffer[117*131] = {0}; u16 markerImageBuffer[13*13] = {0}; u16 batteryFullImageBuffer[12*7] = {0}; u16 batteryLowImageBuffer[12*7] = {0}; -u16 clockImageBuffer[97*97] = {0}; +u16 clockImageBuffer[101*101] = {0}; u16 clockNeedleColor; u16 clockPinColor; u16 clockUserColor; @@ -714,29 +714,45 @@ static void clockNeedleDraw(int angle, u32 length, u16 color) { constexpr float PI = 3.1415926535897f; + // Find coords from angle & length + int x0 = clockXPos + 50; + int y0 = clockYPos + 50; + float radians = (float)(angle%360) * (PI / 180.0f); + int x1 = x0 + std::cos(radians) * length; + int y1 = y0 - std::sin(radians) * length; - // used for the calculations - float x = clockXPos + 48.0f; - float y = clockYPos + 48.0f; - - // used for drawing - int xx, yy; + // Draw line using Bresenham's line algorithm + int dx = abs(x1 - x0); + int dy = -abs(y1 - y0); + + int stepX = x0 < x1 ? 1 : -1; + int stepY = y0 < y1 ? 1 : -1; - float cos = std::cos(radians); - float sin = std::sin(radians); + int error = (dx + dy); + int error2; - for (u32 i = 0; i < length; i++) { - x += cos; - y -= sin; + while (true) { + BG_GFX_SUB[y0*256+x0] = color; + BG_GFX_SUB[(y0+1)*256+x0] = color; + BG_GFX_SUB[y0*256+(x0-1)] = color; + BG_GFX_SUB[(y0+1)*256+(x0-1)] = color; - xx = x; - yy = y; + if (x0 == x1 && y0 == y1) break; - BG_GFX_SUB[yy*256+xx] = color; - BG_GFX_SUB[(yy+1)*256+xx] = color; - BG_GFX_SUB[yy*256+(xx-1)] = color; - BG_GFX_SUB[(yy+1)*256+(xx-1)] = color; + error2 = error * 2; + + if (error2 >= dy) { + if (x0 == x1) break; + error += dy; + x0 += stepX; + } + + if (error2 <= dx) { + if (y0 == y1) break; + error += dx; + y0 += stepY; + } } } @@ -785,7 +801,7 @@ static void calendarTextDraw(const Datetime& now) { // Draw marker { int myPos = (startWeekday + now.getDay() - 1) / 7; - markerDraw(calendarXPos+now.getWeekDay()*16+2, calendarYPos+myPos*16+34); + markerDraw(calendarXPos+now.getWeekDay()*16+4, calendarYPos+myPos*14+36); } // Draw dates @@ -804,13 +820,13 @@ static void calendarTextDraw(const Datetime& now) { } // Copy to background - updateTopTextArea(calendarXPos, calendarYPos, 113, 129); + updateTopTextArea(calendarXPos, calendarYPos, 113, 131); } void calendarDraw() { if (ms().macroMode) return; - int calendarHeight = 113; + int calendarHeight = 115; u16* src = calendarImageBuffer; Datetime datetime = Datetime::now(); @@ -818,15 +834,15 @@ void calendarDraw() { // If the dates exceed the small calendar then use the big calendar if (firstDay.getWeekDay() + firstDay.getMonthDays() > 7*5) { - calendarHeight = 129; + calendarHeight = 131; src = calendarBigImageBuffer; } int xDst = calendarXPos; int yDst = calendarYPos; - for (int yy = 0; yy < 129; yy++) { + for (int yy = 0; yy < 131; yy++) { xDst = calendarXPos; - for (int xx = 0; xx < 113; xx++) { + for (int xx = 0; xx < 117; xx++) { if (yy < calendarHeight) BG_GFX_SUB[yDst*256+xDst] = *(src++); else @@ -846,6 +862,8 @@ void calendarLoad(void) { markerLoad(); // Small calendar + int calendarX = calendarXPos; + int calendarY = calendarYPos; const char* filePath = "nitro:/graphics/calendar/calendar.png"; FILE* file = fopen(filePath, "rb"); @@ -860,12 +878,22 @@ void calendarLoad(void) { if (colorTable) { calendarImageBuffer[i] = colorTable[calendarImageBuffer[i]]; } + + calendarImageBuffer[i] = alphablend(calendarImageBuffer[i], topImageBuffer[(calendarY*256)+calendarX], image[(i*4)+3]); + + calendarX++; + if (calendarX >= calendarXPos + 117) { + calendarX = calendarXPos; + calendarY++; + } } } fclose(file); // Big calendar + calendarX = calendarXPos; + calendarY = calendarYPos; filePath = "nitro:/graphics/calendar/calendarbig.png"; file = fopen(filePath, "rb"); @@ -880,6 +908,14 @@ void calendarLoad(void) { if (colorTable) { calendarBigImageBuffer[i] = colorTable[calendarBigImageBuffer[i]]; } + + calendarBigImageBuffer[i] = alphablend(calendarBigImageBuffer[i], topImageBuffer[(calendarY*256)+calendarX], image[(i*4)+3]); + + calendarX++; + if (calendarX >= calendarXPos + 117) { + calendarX = calendarXPos; + calendarY++; + } } } @@ -894,6 +930,9 @@ void clockLoad(void) { const char* filePath = "nitro:/graphics/clock.png"; FILE* file = fopen(filePath, "rb"); + int clockX = clockXPos; + int clockY = clockYPos; + if (file) { // Start loading std::vector image; @@ -904,6 +943,14 @@ void clockLoad(void) { if (colorTable) { clockImageBuffer[i] = colorTable[clockImageBuffer[i]]; } + + clockImageBuffer[i] = alphablend(clockImageBuffer[i], topImageBuffer[(clockY*256)+clockX], image[(i*4)+3]); + + clockX++; + if (clockX >= clockXPos + 101) { + clockX = clockXPos; + clockY++; + } } clockDraw(); @@ -920,9 +967,9 @@ void clockDraw() { int dstX = clockXPos; int dstY = clockYPos; - for (int yy = 0; yy < 97; yy++) { + for (int yy = 0; yy < 101; yy++) { dstX = clockXPos; - for (int xx = 0; xx < 97; xx++) { + for (int xx = 0; xx < 101; xx++) { BG_GFX_SUB[dstY*256+dstX] = *(src++); dstX++; } @@ -932,12 +979,12 @@ void clockDraw() { float h = (float)time.getHour() + (float)time.getMinute() / 60.0f; clockNeedleDraw(90-(h * 30), 24, clockNeedleColor); // hour - clockNeedleDraw(90-(time.getMinute() * 6), 32, clockNeedleColor); // minute + clockNeedleDraw(90-(time.getMinute() * 6), 30, clockNeedleColor); // minute clockNeedleDraw(90-(time.getSecond() * 6), 36, clockUserColor); // second // draw clock pin - for (int yy = clockYPos+46; yy < clockYPos+46+5; yy++) { - for (int xx = clockXPos+46; xx < clockXPos+46+5; xx++) { + for (int yy = clockYPos+48; yy < clockYPos+48+5; yy++) { + for (int xx = clockXPos+48; xx < clockXPos+48+5; xx++) { BG_GFX_SUB[yy*256+xx] = clockPinColor; } } diff --git a/quickmenu/nitrofiles/graphics/calendar/calendar.png b/quickmenu/nitrofiles/graphics/calendar/calendar.png index 83d26c19292ba52a5c038f90809b839e9f1f3ef9..1340f9cb9fddd91fab0afa471029f59dcacccdb8 100644 GIT binary patch literal 835 zcmeAS@N?(olHy`uVBq!ia0vp^r9fQF!3HFk#riG;QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0XB4uCLY*0oMf1_q`Zo-U3d6>)EG85Z4gkZ?$xBw6Jpe^B#9 zrpBcw96Ot(`zAQ=Sm;05dWomwWV_bVmNQEV{U^Q z*55x9wfpY7^4%*tqt;*dJwJKH>Z_~nUcM3%Y8tIK-S_|U6c#f{ zik?{E;KphM6Iw7ibk@Q$5Jucwy);r;9O`VLYmt056=9?yqciV=%Wd0R&Tz{^#;&b_Z z^2Y_576fh{=yH&Pw82= z{Nt;0^$Y(fetvBC^Y5jP`kk9MOB>i1|336>-pZFtzt7t6->d4v=hsVqJN)-8yz}SA z&u^;FnaZ5!8^3tE{m2CQM_ZS$SM~hgW+!Oe`tI^?N6p?ZjxSZ?C+$u@U;Om5_mj`w z`;TXPq^EF6UW$}n+`nHf=V!K4?<`PYmVBBgWu9?q*7qxuSNuM||J7=v+sF0m0(KSs zd+hu3kH7rv{|kROcAi2BYmDG8+4RNinf;NV{one3#Q2}xId4^_f4EJK zzunh2LT7KNW>&|BS=+SqKCMs`J7el=&mX?|rhIqgGQm1-*$u#i&*16m=d#Wzp$Pz3 CXMKPG delta 372 zcmX@i*2%2c8Q|y6%O%Cdz`(%k>ERLtqzgfqg&9Z+1Oz^wsHjjc7vK}(die0+-@kuf zzI+)d0mPY^nGBAHe=mAHY0{*oRll>(CS3taa29w(7BevL9RguSQ4OyKpx_rz7srr@ z!*6f+avd@dV14k4mrd&WQDKo+_qRP@-SmQS*Gtiu-ItXsq9<3b{N}!brN!%huq4|j z!%PD`pGTV~?Wj+gGKG8c>)e=4OFDe!y*YPcpVP8e3myOYPh-lwb9%jiU&6Wwd`ff|NPN-Y;&aBm>E;IgH)#}+ryGxzT zEf#*-Tq5kUYwx@3a|7<4a0pXgdER_l=?u-4^{aE{pXOR}ZD9%X?U`QPKfWEkfBrG+ z&bIi@l~wf$Q>IM0f9kTXo=vpZsr%md{Jl>7^g<#}o!H;r^@p>tfBAtqaxCkCA;942 L>gTe~DWM4fK-H=O diff --git a/quickmenu/nitrofiles/graphics/calendar/calendarbig.png b/quickmenu/nitrofiles/graphics/calendar/calendarbig.png index c48b32b0d94c45ef56aeff440a50fbeb9971d3df..eade88a216e8d76078af6affc33cc2cad42fcbc6 100644 GIT binary patch literal 877 zcmeAS@N?(olHy`uVBq!ia0vp^r9j-w!3HEZpAXpqq!^2X+?^QKos)S9a~60+7BevL9RguSQ4OyK1_ov(PZ!6KinzD842y0#NH`=;lC1KQKdAX4 zQ{&PTj-AcYeG{B_EcBmjy~NXTvR!Lw%b6vG{u5t_N2Og%NYw39-n%D1&GFD0(a!<` z>+he5+I{z3`RHI3Gr?t6awSzRYXtqFmRJzOav3X7Q} zMNh17aAP%s2`!i$I_qfC#dn!qm$ZDls-pYb4=+=D6KlJwqbj)H!d1TRiulrLUw7=@ zZT&{%M&9=SfB)S49lJaH!EGx&z#15rcOrHORghj^G%b*yKO^WGXDxXu0K~=@wxmy z`Qrl3adn@Kw>^2|yRP!vv(M{($}KH+e)-2_`Ij5#ZHwpkNTsL0^v)MLf8ht?r}V5_ z{_)kh`h|ZKKR>qn`S;RC{m#vsr48(he;@ibZ{^FS-)C+3?^Si-^XnzQ9sc_k-uZLm z=Qq{oOl8jVjbA+7eq@6DqpeHWt9t%#vlBFKeRuh{qh{|H$Cs+{lXj<{FMj&j`^jhT z{l~LC(o?u3FGWf(?%%JL^E2D2cNQoxOFqq$GS9d)>-&|-D}JBf|7x|-?c@4&0lSL+ zJ@)GEw{%`$1V*JnUoVO~_7#1-Yiowyha~{{j zs#lWhmSy|t1m{-;IdZm;pW~{>$ffK^(l>+OQ&wE(4%Iz$E=RT>@YI(gf zeFtG@9=#O3W9{+7iNV5R-ua%c007ef0BLDy071k1qU(~9l7g!HYt3TR00009a7bBm000id000id z0mpBsWB>pF`bk7VR9M69*h>n+Fc1dd>J0`O*ToYQ>T6r@0$KC`-Si5s-RTj$t&^EV z`w%JtA=3X>83yt(X)rF#;(N;)1hx!WAVTUiN1P7rmZEF7bb)l0+BEwno6x)a;MTZQYGXy7A%Z$ zDvcE#av?%dE2fvqOm!5**H>-5w5ULnmEuID8>D zgeg3Ba7x`4;mcfc0@_3_+TcYDzVC<+e2+|Hw}*R~SKtG3`!7<6eoBcpIijrz9N2}{ z&($%i4BE##gIF!eU|!5sswgfzLQfToq>+d3o^|VrX53>IIb@lpl@9Zb1JMMwM&7Xf zsPx_Zyzwh*{lPj>bMxZepDotL#*d8MCE_)?W(;fk-7@;-jU*F-)}8L%FJ0{H{89Wk zx1)Rq;NJS^woaGV26}pW)=21MR#HM(Z-()dTC1HK0w%rC10J%#ZTdN38Ka{dpT|?U zDZaPH3vvQY17xgw3?|l3O60@7EGm1ocowr*NVBtnK|%R#hcOzB7MGzP9ZfJaqLN|X zeb6hEo%TTI&5tpeOl^Y|>zRC?FM|6Ax@Ob_Xj>nrf7mSJpND5jcn}i1*oIvaZ%flw zA7)J78!(lsC1ojykW98rZz$WhS=}O>OClPmZCh5MN5-OB9eKHJ|`JshBiNnnegaSNLHL*FRRELRP_{VLiJ%9kbH) z58<4Qqvn43wBaR!C|80^LgEA$SVw9jUV)XeGdDb2bwbHy8fCA(9Dg4{9)OOf`qPZ; z-dcu7+D3Ydw(1qogONhA&(fZLLOIWdkY}d~k>Qrg6usH;)}@f}%N)Uan0Q1X^?NbH zphT7}ZJq<9V1?!V?vkw+V7)F-MH>07`E&U_NZ~Xcb$;P$-4U&lr*NX4-_ zpWCz?ZLN(C29;(N(ymf=7)2$!!Q`0s)syMJ>TYO=!ZIBq1YzRpD1j2JKqwG;b%cV3Kc5t(Gojob|F9 z%^|b56gW$*H-wUEPJcnL3Mol=WcQy+fBWH=D+jm8fV@{+SPPx0#l|yFk>Cr^3%je= zhTW+ZoAUkG%4Q)<@iBWao zvF(3kH`KChTfd+#EX9!j9ju^Ix?4T|xqyJTu4*&d{PbmCY<*+h+J849;JOB70R+~& zOW%N<$GKI-B%QyqMHvU5+ifm&S`XKC^u= N9G4vtQX3qb^A}zIY$gBz delta 452 zcmV;#0XzQt3D^T6iBL{Q4GJ0x0000DNk~Le0001C0001C1Oos705mAlkdYxEe;80q zR7C&)0Q>v<)6>)Q^YgN@vUz!V`}6bTq*eJ0EUAWM8Uh68v6^}*}AQHB`C))JVC|4Wl4 z+n2Td>0op%LeLr+8Czzc4Kj|!f8e4JN(Gt`iM-m8kHJVsWXQ-7_gIxD&5$vw8EUnU zu`kaChFYD3(aM#LF-biJF@m_OL>z>O&9X4Ew6pHGhhg1u4?1H8{;)-0=$=gaQVV_J(OtmP@?4u$7t7s&X|io+&OB;`Fs=qdwxv%W=KEy zE{U2a95z?Hc_w1(;fIl5dveyxDDFKu8^SR8W0#2IL+Xb2$B);e>0y