From 12844bbd7f042d8af09967caf9f5f98d46efa5b2 Mon Sep 17 00:00:00 2001 From: goyuken Date: Sun, 18 Nov 2012 17:02:55 +0000 Subject: [PATCH] GB: gbc color change infrastructure. not hooked up to UI yet --- BizHawk.Emulation/BizHawk.Emulation.csproj | 1 + .../Consoles/Nintendo/Gameboy/GBColors.cs | 100 ++++++++++++++++++ .../Consoles/Nintendo/Gameboy/Gambatte.cs | 18 +++- .../Consoles/Nintendo/Gameboy/LibGambatte.cs | 8 ++ .../output/dll/libgambatte.dll | Bin 177664 -> 177664 bytes libgambatte/include/gambatte.h | 2 + libgambatte/src/cinterface.cpp | 6 ++ libgambatte/src/cinterface.h | 2 + libgambatte/src/cpu.h | 4 + libgambatte/src/gambatte.cpp | 4 + libgambatte/src/memory.cpp | 4 + libgambatte/src/memory.h | 1 + libgambatte/src/video.cpp | 12 ++- libgambatte/src/video.h | 5 + 14 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 BizHawk.Emulation/Consoles/Nintendo/Gameboy/GBColors.cs diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj index 0c716e1f10..b02eb1a1b9 100644 --- a/BizHawk.Emulation/BizHawk.Emulation.csproj +++ b/BizHawk.Emulation/BizHawk.Emulation.csproj @@ -212,6 +212,7 @@ + diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/GBColors.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/GBColors.cs new file mode 100644 index 0000000000..be05f3e920 --- /dev/null +++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/GBColors.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Consoles.GB +{ + public class GBColors + { + /* + * The GBC uses a RGB555 color space, but it most definately does not resemble sRGB at all. + * To make matters worse, because of the reflective screen, the visible colors depend greatly + * on the viewing environment. + * + * All of these algorithms convert from GBC RGB555 to sRGB RGB888 + */ + public struct Triple + { + public int r; + public int g; + public int b; + public Triple(int r, int g, int b) + { + this.r = r; + this.g = g; + this.b = b; + } + + public Triple Bit5to8Bad() + { + Triple ret; + ret.r = r * 8; + ret.g = g * 8; + ret.b = b * 8; + return ret; + } + + public Triple Bit5to8Good() + { + Triple ret; + ret.r = (r * 255 + 15) / 31; + ret.g = (g * 255 + 15) / 31; + ret.b = (b * 255 + 15) / 31; + return ret; + } + + public int ToARGB32() + { + return b | g << 8 | r << 16 | 255 << 24; + } + } + + // the version of gambatte in bizhawk + public static Triple GambatteColor(Triple c) + { + Triple ret; + ret.r = (c.r * 13 + c.g * 2 + c.b) >> 1; + ret.g = (c.g * 3 + c.b) << 1; + ret.b = (c.r * 3 + c.g * 2 + c.b * 11) >> 1; + return ret; + } + + // vba's default mode + public static Triple VividColor(Triple c) + { + return c.Bit5to8Bad(); + } + + // "gameboy colors" mode on older versions of VBA + static int gbGetValue(int min, int max, int v) + { + return (int)(min + (float)(max - min) * (2.0 * (v / 31.0) - (v / 31.0) * (v / 31.0))); + } + public static Triple OldVBAColor(Triple c) + { + Triple ret; + ret.r = gbGetValue(gbGetValue(4, 14, c.g), + gbGetValue(24, 29, c.g), c.r) - 4; + ret.g = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, c.r), + 14 + gbGetValue(0, 3, c.r), c.b), + gbGetValue(24 + gbGetValue(0, 3, c.r), + 29 + gbGetValue(0, 1, c.r), c.b), c.g) - 4; + ret.b = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, c.r), + 14 + gbGetValue(0, 3, c.r), c.g), + gbGetValue(24 + gbGetValue(0, 3, c.r), + 29 + gbGetValue(0, 1, c.r), c.g), c.b) - 4; + return ret.Bit5to8Bad(); + } + + // "gameboy colors" mode on newer versions of VBA + public static Triple NewVBAColor(Triple c) + { + Triple ret; + ret.r = (c.r * 13 + c.g * 2 + c.b * 1 + 8) >> 4; + ret.g = (c.r * 1 + c.g * 12 + c.b * 3 + 8) >> 4; + ret.b = (c.r * 2 + c.g * 2 + c.b * 12 + 8) >> 4; + return ret.Bit5to8Bad(); + } + } +} diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs index 82f6a940e1..6856a50ffb 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -50,7 +50,8 @@ namespace BizHawk.Emulation.Consoles.GB // set real default colors (before anyone mucks with them at all) ChangeDMGColors(new int[] { 10798341, 8956165, 1922333, 337157, 10798341, 8956165, 1922333, 337157, 10798341, 8956165, 1922333, 337157 }); - + SetCGBColors(); + InitSound(); Frame = 0; @@ -706,6 +707,21 @@ namespace BizHawk.Emulation.Consoles.GB LibGambatte.gambatte_setdmgpalettecolor(GambatteState, (LibGambatte.PalType)(i / 4), (uint)i % 4, (uint)colors[i]); } + void SetCGBColors() + { + int[] lut = new int[32768]; + int i = 0; + for (int b = 0; b < 32; b++) + for (int g = 0; g < 32; g++) + for (int r = 0; r < 32; r++) + lut[i++] = GBColors.GambatteColor(new GBColors.Triple(r, g, b)).ToARGB32(); + unsafe + { + fixed (int* p = &lut[0]) + LibGambatte.gambatte_setcgbpalette(GambatteState, (IntPtr)p); + } + } + #endregion #region ISoundProvider diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs index 3877502c0d..73b17e0085 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs @@ -98,6 +98,14 @@ namespace BizHawk.Emulation.Consoles.GB [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_setdmgpalettecolor(IntPtr core, PalType palnum, uint colornum, uint rgb32); + /// + /// set cgb palette lookup + /// + /// opaque state pointer + /// uint32[32768], input color (r,g,b) is at lut[r | g << 5 | b << 10] + [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void gambatte_setcgbpalette(IntPtr core, IntPtr lut); + /// /// combination of button flags used by the input callback /// diff --git a/BizHawk.MultiClient/output/dll/libgambatte.dll b/BizHawk.MultiClient/output/dll/libgambatte.dll index 43f431c686b5a53cde7095974de75ec4ee788714..b1c05386050683412cec6a88b495bd49ea4dac13 100644 GIT binary patch delta 36298 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

O z-(edbjiyX?9)3_ectJ6I-rI2UJNhZ2RXdgB&pWcWmCVn_u~o|M&pS7d{GC+uCN3=& z=5iI7&MUut9v1;m`*Z*#&Rs=X7-I;$BbWK-($%UdR5**6Jedm1q3{u3BqE}?GJy~K zxPZO8)MM z^4}w?noj+S7RjKM3o!e0_K@a>ezljiPz;r!k316yTd&N*XYP#!L916#wIoNn$Q9K_ zlZ*%j&^7!cunXAWQcN{IanCO`P#Xkf=W)!t?H6lmv_yC9S=5}90-eW}pIZ*xgR2qc zl(m)V>`UcLWzUA?d+?b2g3|P8NW0$<+MUach|Iodq!?0=8kpbTPn)I;IvQ$kxfhr= z+Ws9uC*vrnr3H$)wfwUxuy*BsS5u=0tw1Sf-)0yFqiG8gxBnh2RJj$*Hn3R`IJR&f zuloN8X6SGEksR=GEC|$2_~Xn;a9GeZXWvf&k{w)D9YJ&M^gvsEeixJL@C(rSZJX|MY{oXedG^%(@`a;#4aL`+k#7oa7^GReFT@$@7*KsbdMhU5#c0^oO*<>^+TV_ zKc}HPCIxCgVI%1A9IAK(wv&b-v5%lHI1rwbzd9T)w(`{CrcU)wg7)(*Tt|hP%G}TG z#O}FTb_*JFHzH-OspX3(D?IWo1TT!Ia2+?~oV$l(hbxb+CG==8n+Q__%Uun^eeN8} zU)>ENS$!5ZI><}DFzYrlYhbM;K`W`^8JIqFbh&A;w=SOth1-*A2meehAJ5?5BR-zN_rH7a7`y#}T0+m@pCm$ZpPmrfwFi4M zK5;tM_8hd5D)j~LOLVIjgQ#%ZG$P$T45J?tn4i%^JCEZQj|)&m5ZfhBufFbKQ?GEL z_t9^y3%%k^PZf9P+k~c_$6NBWbA;{Un}39AD3|SM!};TA-yI=Z8v<6CFB#LVM_w7{u7zpL}!o?ZpaJgDnm% zmqE`B2ygGoIIKK&f=+qYoS+lTS5FKKY%XQ@(D#JXl^Z8I$gh5;v^g0zaP*fX(Q5p3 zhSX&>oHh5C#Q_ItNtxiwMMd-lyp%SBK55w1QYSutxZXY?Y^Ht-fYw`i`eaC-<y88Bnp6Ssb=2WvW5uRslxri_SM8i~_~a0~N}yCY5nt2IB z7*>BrV;FM~;{L9D^j$~xy>jNeX#CnAME(#Kr%OgNIv<`9P>x3zdc^b0UGNC6&ac}x z!^ts?rycc*#d_Oz?>4u_R&HS2f;oqi^VNk)`l*)qnab2tVU`TE2bFBg zM~Bc{?oYOn?tby~=6?(Z%Esm(kKhHBWfvRC$D%58&e@_W^EW6XPPKx&?Ku@@JqzW4 zOTj(47(84EUY|<=38R=!N6SaQQl_6CZf|-7-_;yL6C{6qLYR;D00&DOPfNy9q)(Be zevpiVkftHMfK-O`3sScqC1WWvIM1dRib=UQk+$7?Lq6y^7G=cvgGHz$v-3D-T8Sz{4;|>Z{7}YiO9>x z=Scn=rOv$VC04dB%KxYNV^0!i_t_i_7_9_Ba;f5X97|qNT`K_uIN@EMtzHy}9a_!r%7|%uobPW|}Z-LSmO6u8A+3=e( zo4&yc=Hx`ZSY#eZ29Kjm4~Rylcg0&Ay4pGysR|LvNZSvV4KDcyGEo@?pD zb|{;E-V=QJ56Rf$ie!8UX#uuU8CgUU?o}G#JVUawXX7S?Vr6kR^HHF*?ys;^7iFmzej@gpD0z1 zT@MGIr*yv5P0qTZq+OcAa+J3(_30D_#8owPbTcq?@{~z*N?G&Ob@YZ5 zdqXm&-casbdWaP&nU{OW&$dMeEtKt-yW>>o@a3U6rEK-&-Lf@92;F6?Dx!WEcQS#)Kd+@is*OILnltZ3Kwf5zYdPzkygCV$sL ziM-aa71 zx_Mv2nSicp1Ok~U6K~yzU#wkuE5FGJ12g`C)Xt9?B|zDWHn^ctdzomDdW;z(;BL;`m*Elng*p$H((89maeXB#QL*o>Y+v~ zq3em}%t$G%1vCDom)oOEiP}V2?P_52<^DeE3kKFb=8zBAOFk!O8kW##Z+Wc7xD^__OQB{LQd3UL@JQhdYOFyn#3^k9b(m7>;E z8PuLbjJ%TGjzhM$;*ho+QVse8*a+YcM3fyUMAP#~uOYpURIYCEV+pMq;UGNv>rpdv zMly;2z}~2I*UPec$&WqXY8;&01Eb9VU{{&?f-eU+2JSg~Pk$PtI}$H!tnfitS?TMCtL?%wJ}EOV752vDs5<^Y-jf zR;Dg%&rZps8cDb*)aDVams0eaZ)r>?7TQ4V+=0cabr>=2t1I(ipYc#0IJF#<6y4Q4~AohaXcWj_DjQ zRXq}owk*-M-5WVD7JxDVsMe8(#G%bNmNQ5hOPo{H$Ku&9%`?&V@;7hGM#nPx1!(Xu zDxH?Ve3_wGU{|SGX4cj&jpMW?WDviB>*2mw>{8EHq@F+dxD2se=>j3gjnL17P$dwy z3xsMnLPrmROCT7>3k@OTT}U2;>c{Q8j~szf>Bcyd;uhkDU{Ng)QXbG*eC$Dx=5P*~ zfMASe0-=#>3lMf0#6S!JrAnZrOkl?RN!6|;oQ0i6YSeiELOgVY2R(hX(HRJM%7cP| z#RCu1=>Z^m9p2sp@21lWc*;aUf76CR+PSJtIs-t6fsSyB5I8(RXCUBVlLUi39(am? zrvL!@9Ar>*BiHjDgh2vfyFjRNBRpwSS6Nt)pEQ{hnkK7TEUdL5T~u?_y%yHSuwB$D z)zcQ%)~{OB!ltNq2$(X3Q)a0htf&=0v=nXG(&8w}7VufWC`$xZ;7Aak$-8DG-d)bS=;GU>p)0On`txmKy=PO}&ds zflwq6Dg{CVm&t>0QXo_d1k-fhMMGDR2cgO?Fwy}c4Iv{f{EqV&F$$M}7Ylf`;LyNz z#Dh>R5R5Z~8j}cv@d|BC-hECeW?>st5(xd^D}0NPO{Xw1k4iE zV)dE6m|m5lW}K`0ML)A!WnT!DnE)Z9A|so1^1#0l@FD@P*5R@Tep*-gJkdKcqCc15 z=6{~x_EcAvK&aFa_InU63kKB!ZkjI`yySuZDd6bei2i90e5rtE33#OrpUmNWKd@3D zR0{;t62TzZ!(feorvm^1i*dssi40T>sG;L0XG3a14PDk^aBv=LPL$v<)xYj%BiJ|U;6cdHNLh@kQ3lMx$kwY4$_A+4QTC_WeF(B0>XVd> zRzE`~`<_+X4P{TV!Rq><>N^bCqiQx~f2rq(v26B<`al}96C27<8!l>;p*BL) zC_^nBqD@mjKqmX1QrnGWlc~p%qDN%1@AqoEQEWJSUww2GT7gSh3)L?J85m@+r)0nH z)NeD`9JWavFdA}nSKl8E?rqhWG2jkSDbv(HDRZc!$3jL7XDm>ljd5tqR$r$KOvfWb zPm}?LGN|DJWY7&|P#9&Pn}7^-l!5L+WT2xAbd-T^A~MiX20F?>HwhW&CM)Icy*5IighC<6gy=ysYwp$y$l2PSw< z7bsK%&l#veh#7+CBZ7c35X?jd6v}`yljSf)9r7r9nre@t5pvD~9fY6^wa3ti9w>tl zltGBu$bdo_cs>qHpgb;6sD>Wqpa!0EPy@jef`Bp*WFZ4e7GU5>8ESI{0cGfR9y0Kx z3@DU=%Y0_vHF+fvseHrZFs!tuvac0~TMP;Ik}jgkurOJ^@* z=bJVPo`WOH6Hk_Oyi$3@#)(7BlyZH)2|m3Fwl8WbmeNLc72w0@Dr~E z4AK|s@MqZ){F8-IxNUVLKacmA_Yn2+#8imizb7tYrZT**SxfRdGf-dA7xluAF_H}m z3&ou(=TNj_I|Hl@G|FpvCdiQ!v@%__C~QDCF#Em>n2j;ye24>S94`Ag*V1jWzL$LH z@=+dCCb=p?)YlZ&wKs~^4#3U}1`{)fIr44*qkUP5BTphJR_d*{pz50n>x1_tE<4ez zCH3n3nuMw;>scC3r(F|a3EWG=;MC{Wvxmu6^hLUBG+fp1ITnJi{JMO?z#z?#^W;P+ z+XC#)=-#C1&qdM>FS*G z#L>SieDQ-}H8tr@-{<0jUz3eBmCm){fZ>X+Wi1WZv6d85JM8s**v`BGKyqxL!Jm4L zjj*GCTmba+ub)ik?6zS5QufS@u^+Fwe!FH|VLtg)M0MegaI`}oPqLtrw&nPj4mX!y z;CC(e?xwqzg)N#Kz38wO0ikbD$pa~OW8{|0j=e=WU;^CSCV!{Q+lBW`_--Wipr)y8 z5R=snDjS3BvdYr!wg1cv=R9Mb)wmER4>a(DgFH*HBt^w3k;77@VVgb1&jdmgoxu*Jk$| zvfzn)+*T8q3k+kO^IAAZ8OM%F7ZSO0;BvX282Nt&6IcgRah!e^W`yKA7~+M>gx$JR4E;@3?60-7<38aH=O1``9n>0+VEhOB$7I4^bNRf=&W^Y~u27-r zQMiX3-m&0TMK1Xz{kbe*xKdhExQpBjHNCeE1XU~i8<8uM;rAvxY8uHwI!#; z|DcoAaWAk;n#A+a7n_HY%=NLPz!1y zJuG{XrQ>#;J7lRRUSxy8q2o(z5wcA$vFSr_=TG6Qkuw9m=PPuX7Z?AaX=MBJofOma zbLm!Z&K|;(7PP&VOVE^TqfqV#B!lbVuj-(eSzmk!MR$Sk;Tq0{X5ES0G5jvqQa^Z^ zb#4Z!e?T1bGQaxU%WMFx2Ngy#Jr~HiEO4Z&H7)@<4;AhqeIr^zTd7THdO#*Ma|c#q zc+?ISi>!JF>rUUO$hxFh5Qm0ACV*V2HqnVD&&Is zoZo+5W%g!o;zB0gcK5X$njZ=ugc8*Lud(jn^Z0A*K4j0m#v+iFzsCB}o_8mkN4+X8 zb;(Yah}*=j(R6`ynIZRrA^Q=0uLKM}+sW{nR_*dSn@(d73amT!&95{1sW)du#C{5W z5l1YC7B-^GvxhH{2*Nl{TB)NC>-F5T#^}R9$>+^ZXCQ!_&eysBQn1IOxwN5(F4yb$ zfrn`P8V|McsU$@lEDW?+$`>}wSA1Z3)%*tj+oh~dd;{nCvbx|67LG3rr9>RJR073G zUV(2-jYP(^roIn!44B@@=HQB#GaffP3b-aOzQKC3gKFzH@t!F3XZ80tSqvD4zs0iU z0oCgBZ?OW*#)uV|hHAvytVeTMGA>wlZ3PW6CA(|E3ex(_w;67|t83q8Y5ia!4%}&2 zkQ7w9A`J1+SwNH6=g_Ka3xaYr-@+B-A(Qzxyq4ct2OnL~sL(g3a9CdfQbXQhZP2OD zf2dRII}HEyPaXdbOM>DZtKI&(S^`h!8a{0u>nI#JS5HHeWq;7h`{4LNC2A-1ZBc1+ z7PJb3$0ak0mCn`O(2{$jQPAodY$Gzp;zsMRz06p!nzS9>Ci*k0F=&0c2ndD4{FqBR zM?cH6F0&Kh`RfP^HQI>i7p(=Vj|$7GaqqIwX>gnY+OxbwPe65gr_G`;;TFe>EX?gR7$#eDZJ>ySYbttRKg zeowimawE96Y>)Z>f{jA272z3i=2Gw>!8ucMF z?m#++8R$>{v5-=hvlK zpRkj1hq0B+*dNJ+6oTZBbp0!4JdgDCSEVy5*jyiZ<9DUs9cEK}Lhc+#&qxQ6-auN5 zG!JPklBIOa5jL=kPgV_6w_auQ#?{=xTd*2t3_xm%)EX%S=`lTZM&2E%4^k|W1*tER z8-72^X-FAJ4tzN`(?RL1Nrsl z>eWW_O!@u5(n$sx-!^`|dFc~=@)gFqmrf0kzn10kbJVyd@*H{4_0m_H$e0_>$J7Hs za;K2iP4CnkK%8tqH!`%pP@@XnXVU_ksj^Y-#CED(jPjIr8*kqR>@EB>5NkeM?YdN>otwuRszR#$hFv`7}wER zi#k9vUtu|UfbUUVmf)J2ncF+4JDbUi z9SMWte^rfZ%kDP(_M?ER@sFGh;EzPLzvL z4!h2bYf#Sm86BWph;rr`@VSaQm8-x9^Yc9dh> z?WmXG7Ev`4wYwGx{O!2%vmIA{%8;aM_=XsS1hk2kGs_*Co3#2e)>%Qv%=y zB&Cie+{B>{ijY(LPQ88mP05&Z3vHCpe)&l;%A!za+>SDhvKnO?vn3u(%qd0i*QbCs)FFG5h z*UL(uc}V`;$9QDH;^!ZGQy#El%;{fV->|K$boO*PCSdaG*cEigk4&c{Wg%@uDnqJ5 zGT^^2nUE$T{Rc_LKBWuNG^Bi_y+{nl6^TfTk;;*z5LrqNT{pFty_XIihJwdqFk?IgyQ1C!tx+X|EP6fL@B*t0l}s!GM1`5u zmJ8*Gkj!8)%$a(gg}hS(r7hM6$*Oi-D2KM(jwTXzrw*dwFXkZsY8`YVSp9IJ+@rAx zF_x%Fh$@cKIMb^sPfeJ`YR>>~M{#`ckV0FHZB zd^x&3fRwsDBTMU%B(zI-WHceAK)Ot%N<6|_Vn!R>81A7a;98TARGMcvdLg-W9ndvFbyz0Wm*(j5V<$<)5u4nevR4}eK7iR zbaiy&*om=oVwc8liQNLGm*6y)m@CY`m@k|C6GIZaBt|4U64k`>iNh_=ShriRBz=?|V4G-@!k{9G{4-38 zO{!^&snm4X^sVV9Q`gAY$Z?SiBUeQ}8~I7(FOk5NZj?fTXBuzBjO|DXU4x8zdOENLSlj~VMxO4gqIV3 zP6#%4GB32Owj^3-ShKC0te;p*{hyN$``X9arrV@4*a^a9o1aX4Gx>CKRr2{{SMufL z>f}F@ZzSJJmMSG_0N{^At&Vyvsv_z_)REYJap`fR_3(Qm_*&PU&lZW}W?W^PPg%!@H4F+axq9CInAMQoec;MlO(@Yrs#J!4I=>h|a4 zf%fyUmtqs*tZ|d#r@^&$#ve6y^oKX7?T+@EoNrS?3k>W z?3gVvj@aj7Uy6Mgf7*CYPz_{0P?p**3LxvSY~ z&M-e}{?XhQU;B{4nA8nfv&b%yDUo9%=fYV>#XSet^XqW=*$_wH8>{S)a3hW&PIbm((Pw zMN(8!LQ+!Fpro{Vt*4mTSCml-qGU-@SOeMGlW#5xF|DFtQ@@%Saa0Fv=bn)g#Ij6&sZjl^Qhy zvpz3sO;lObr%|6rHHZ#?Uk!*J5U+beki9Q^CC)y{*FQ$LY;Fx7G zD`N6vUX6Jx=DnD`G37A_V~)k#jA5}+u?Yxe*|D$0?u)I6JsNv5_Dt-R*uP?>xaM)~ z;yT8~#989{#f`CJK0h3{Fm74gO4xF1+$(Xr4TP87Ig4#kY^|6yH7G z65lU=aQuVuQ{x|vUlP9}-Vy&o{7dn#$M1>XAOBhW>G+@GFUH@F_e}^$2uTP}h)76E z7?3bDVRFKB1SESxUP58QHh93>31tZt2}csnCb$xQPms-aKeN#s3U}*e?q?osPB%Yn zo@JhE&NUa9pMgibVSdkiz1m0!BwB`9GAt7;vn}&2Pg&Mj6wC9Lw=BEt zmJcmoTE4NIvixTGpXHV%$lA&pV(nv%vnIiP##tv@v#g7(Pg^Oby1fhPOyDa? ze$J?ZzjvO z7Pj`bPPSN^)z;rO);7sD&9>0C%(fD7V2f>st;F^b-0-;V2itkuRomYPZBjauc3?Nb zOsx>v!cB3eBsk?*(`0cBI<_Q=;FKZq=Y*M1jS6?q}@uShAXQB=FAj#1sBEK&WiTuqF6 zIBHhZvZ$3&&ZwKN9JU!!hEHH!|39u++SuDmdMCEWO%=+n^`qpwEW zV`8i^Lt-*wosR>1xVBN8?zypgagVP8U^xt+PQxsQ3id5PI! zR?V-N-!We`-!%IrwuTS&PMn{(#LidiSFjRYO}v@tXK8KeV(ASRSz>V@sJvo%$8yzj z)8c1sZS7+1ZJlpjVs%(m>nqlGtbbZ>S^blmCyh>;m^3SCKGv|kNrw?fS|*1icTb+4 z{CM({$^T9MDEYJG2DZkwwpf!U*&emMVtX5r{k(GqN#Y00uIwH&k@v7EMCwA`>T>p<&p>qP4;>tgG2 zYXt)F57u9--I7d6)}*|owMq8PNpE11lw$*6Ob$+-kvu1PX>vjG#^e{VA*sezWT0(0 zwokKci*3to6C?_p2aBYO5IE*lhu@u^?I|(WvVvaG7XAMkDM6!YUDfE+#QZQ z8F@Cc8{(@KadmCf=BPKKc1M**8KRBR!9s8LdWsu_rE_A;&X{5ZQ$wr~3--L&oLE{o ze~JAK+b;jOHVB@N#61C5%tM?!5_dZ8V%&{5h81o&bT=!0as2Z5L-Cb}h}{xQ3D$)C zgd#YkE1^2!R>B|zxQXUh;f8w=)J~eun(g-`_DM`aEXzX#+no4D;_k$9U6nH|bD+us z%l}nj_Mur-aU8!l^Z~(%4u>n2hD=y1?=b@v>MBVb+NTu@f25CcYJ?#dR?x9*TU(a~Y_4 zz5llVo_`E;l^OEy`6K=#KOZUZEVOEZSA$eg71YD~e?XHi2i9IY2dh{3KGEXW2GhcV zaC6uIz@CVX#L&@dTk(Ng0mY@$wu*2o56jT03YkK;s%5QA%WKl=v8`e}YeGrG;<2bg z8QF}V#VQEduWqS}aa*#sRfd~QrjSn3MJj34zx??fMyDH|)=RI_a?FU}_XQ1_p@r7q zVDKLgpAC-c6S~Nh!j7$*|GaCFlZL|Q3q6xR&X7PvBC>Y z5^AY1D^0aoYu++-P|a4;h_u*lc475DH_e!UR^&#z=`fvun68ZJHa&lybJHdj;FId*~FVB>6tH_L1A zKJ<2CpV8(W_Rav3M=4J4W zEz5u#H{~3J%Uac-ep4eVp-Z%@m*|v!9l?^(P5KM8w*wJ#8WD3zA1`TtVj%Btc@SCQ delta 36443 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, colornum, rgb32); } +__declspec(dllexport) void gambatte_setcgbpalette(void *core, unsigned *lut) +{ + GB *g = (GB *) core; + g->setCgbPalette(lut); +} + class CInputGetter: public InputGetter { public: diff --git a/libgambatte/src/cinterface.h b/libgambatte/src/cinterface.h index 810347fc53..2c3a24d5a6 100644 --- a/libgambatte/src/cinterface.h +++ b/libgambatte/src/cinterface.h @@ -16,6 +16,8 @@ extern "C" __declspec(dllexport) void gambatte_setdmgpalettecolor(void *core, unsigned palnum, unsigned colornum, unsigned rgb32); + __declspec(dllexport) void gambatte_setcgbpalette(void *core, unsigned *lut); + __declspec(dllexport) void gambatte_setinputgetter(void *core, unsigned (*getinput)(void)); __declspec(dllexport) void gambatte_setreadcallback(void *core, void (*callback)(unsigned)); diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h index 13711eef00..2bba796af1 100644 --- a/libgambatte/src/cpu.h +++ b/libgambatte/src/cpu.h @@ -110,6 +110,10 @@ public: void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) { memory.setDmgPaletteColor(palNum, colorNum, rgb32); } + + void setCgbPalette(unsigned *lut) { + memory.setCgbPalette(lut); + } void setGameGenie(const std::string &codes) { memory.setGameGenie(codes); } void setGameShark(const std::string &codes) { memory.setGameShark(codes); } diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp index 5c295fbd98..f6dad17c48 100644 --- a/libgambatte/src/gambatte.cpp +++ b/libgambatte/src/gambatte.cpp @@ -182,6 +182,10 @@ void GB::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) p_->cpu.setDmgPaletteColor(palNum, colorNum, rgb32); } +void GB::setCgbPalette(unsigned *lut) { + p_->cpu.setCgbPalette(lut); +} + bool GB::loadState(std::istream &file) { if (p_->cpu.loaded()) { // p_->cpu.saveSavedata(); diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp index 4aaa934cf7..e32d0de4bb 100644 --- a/libgambatte/src/memory.cpp +++ b/libgambatte/src/memory.cpp @@ -1031,6 +1031,10 @@ void Memory::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned lon display.setDmgPaletteColor(palNum, colorNum, rgb32); } +void Memory::setCgbPalette(unsigned *lut) { + display.setCgbPalette(lut); +} + bool Memory::getMemoryArea(int which, unsigned char **data, int *length) { if (!data || !length) return false; diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h index 9b01cbf8b9..43a5cba486 100644 --- a/libgambatte/src/memory.h +++ b/libgambatte/src/memory.h @@ -173,6 +173,7 @@ public: } void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32); + void setCgbPalette(unsigned *lut); void setGameGenie(const std::string &codes) { cart.setGameGenie(codes); } void setGameShark(const std::string &codes) { interrupter.setGameShark(codes); } }; diff --git a/libgambatte/src/video.cpp b/libgambatte/src/video.cpp index d581304c57..f5fe80d8ad 100644 --- a/libgambatte/src/video.cpp +++ b/libgambatte/src/video.cpp @@ -30,12 +30,20 @@ void LCD::setDmgPalette(unsigned long *const palette, const unsigned long *const palette[3] = dmgColors[data >> 6 & 3]; } -static unsigned long gbcToRgb32(const unsigned bgr15) { +void LCD::setCgbPalette(unsigned *lut) { + for (int i = 0; i < 32768; i++) + cgbColorsRgb32[i] = lut[i]; +} + +unsigned long LCD::gbcToRgb32(const unsigned bgr15) { + /* const unsigned long r = bgr15 & 0x1F; const unsigned long g = bgr15 >> 5 & 0x1F; const unsigned long b = bgr15 >> 10 & 0x1F; return ((r * 13 + g * 2 + b) >> 1) << 16 | (g * 3 + b) << 9 | (r * 3 + g * 2 + b * 11) >> 1; + */ + return cgbColorsRgb32[bgr15 & 0x7FFF]; } /*static unsigned long gbcToRgb16(const unsigned bgr15) { @@ -357,7 +365,7 @@ bool LCD::cgbpAccessible(const unsigned long cycleCounter) { || cycleCounter >= m0TimeOfCurrentLine(cycleCounter) + 3 - isDoubleSpeed(); } -static void doCgbColorChange(unsigned char *const pdata, +void LCD::doCgbColorChange(unsigned char *const pdata, unsigned long *const palette, unsigned index, const unsigned data) { pdata[index] = data; index >>= 1; diff --git a/libgambatte/src/video.h b/libgambatte/src/video.h index b0cfca8560..897c172281 100644 --- a/libgambatte/src/video.h +++ b/libgambatte/src/video.h @@ -120,6 +120,7 @@ class LCD { PPU ppu; unsigned long dmgColorsRgb32[3 * 4]; + unsigned long cgbColorsRgb32[32768]; unsigned char bgpData[8 * 8]; unsigned char objpData[8 * 8]; @@ -137,6 +138,9 @@ class LCD { static void setDmgPalette(unsigned long *palette, const unsigned long *dmgColors, unsigned data); void setDmgPaletteColor(unsigned index, unsigned long rgb32); + unsigned long gbcToRgb32(const unsigned bgr15); + void doCgbColorChange(unsigned char *const pdata, unsigned long *const palette, unsigned index, const unsigned data); + void refreshPalettes(); void setDBuffer(); @@ -160,6 +164,7 @@ public: void saveState(SaveState &state) const; void loadState(const SaveState &state, const unsigned char *oamram); void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32); + void setCgbPalette(unsigned *lut); void setVideoBuffer(uint_least32_t *videoBuf, int pitch); void setOsdElement(std::auto_ptr osdElement) { this->osdElement = osdElement; }