grafx2_2.4+git20180105/0000775000000000000000000000000013223665350012737 5ustar rootrootgrafx2_2.4+git20180105/.gitlab-ci.yml0000664000000000000000000000044713223665306015401 0ustar rootrootbefore_script: - apt-get update -qq && apt-get install -y -qq libsdl1.2-dev libpng-dev libsdl-ttf2.0-dev libsdl-image1.2-dev liblua5.1-0-dev zip stages: - build job1: stage: build script: "cd src && make && make ziprelease" artifacts: paths: - "*.zip" grafx2_2.4+git20180105/share/0000775000000000000000000000000013223665306014042 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/0000775000000000000000000000000013223665306015233 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/gfx2.png0000664000000000000000000000263413223665306016614 0ustar rootrootPNG  IHDR00` PLTEapb~1  ]tRNS@ftEXtSoftwareGrafx2Sj/IDATHu E+D>h2ͥW*QD9-&Fu>h<0"aF̃Y> 03F{4=,zsnƩw'<<' :zbIF> $mVDwHr +׊&}`xNo}.Jg?TKZ%lW)JgeNƒ\ѹùr.?:?w<4=S)Z;F7Nĩ?iڸ hESoD )poXDVV ğ}_%ѷvi?k/U."}5_w5?N `qW?5 7 .W1A(3ho F緟N:G:Ð%PvУ=s:yxOhTqyD]HK~ UG]Nѓ~Q* P" [SljSfpa;Hv,z03\qhy ]!6`A1&bĚ2*$0eqp 20a溔%gB67%tPeTkQk|̼Kz*}CY`9NGHJUKvkn& Jja|W8py||q F+2>Dy1KM),D%to:wrR5QVh *27rX-ZG|sdӵLxM*`^[XS&*<LA`=ua}PQ@O"qh*2yfGـJ s#`J|R"@I2b3ZgR\/Ȁ>T>Yj[Vbܧow/ -hm9 {M۬zGf+Vf a@Vs٧vIVxn!dVep.,@MyG/@29Àt#`w:yh75fDTIENDB`grafx2_2.4+git20180105/share/grafx2/skins/font_Fairlight.png0000664000000000000000000000520513223665306022031 0ustar rootrootPNG  IHDR@ƒYPLTEmmm#tEXtSoftwareGrafx2Sj%IDATxY #13nMݙSCܙ̰㘵Xsي0 w-|n`+$K+ D8Wufן"bF`g 8#} 5=j 7olő>c%.([S(2F'" @P@2 q"5&8E hFA fquЃ&eDpOnd"j4Eѳ[/{BywX9GO%ztpr~=^UWFT;Eį}DV&x7OvŠ؛%oOM+ [-I g&^7HRʽ/UV3kVsJ2BuHr7 FS%X~qb ?<ũDî%"ecS=?=[ J lJ}q5Ǖw~Lѻz9C s*F*TWaPDXw5Dȃ`\ۙ }f! `#Q6PM/1!+2H)046s) 9*SwGBgdM$QxEVC!f{Mqc4 ew` 5b; p%$/ uI[!71i0 (N|hԏ@s' 8lo¾wNP#Qj=Ġ}6|SQ$%VHVIizϕ r Ԩ]hWI,[eE#!Bū/

+V"WrJFLJ$N]6e`پQqkm/^ +2FIq-]4PO'u|* @>sۤ@ NmE +3F W5 MLDKMm/h @iJv$Jy ~Q3Q50.XGZmZxR; 9ł΁CdڦP~ܧj74!Q!(g+@nZ>;1vgmY8ɍCbfݑ;rVO$~^RKОD8lUVX@{ЧbKdbzC}OgעS@;vSwSDGL8 08s^cրw` \wtH C*_yf޴~k!WݙαI\ o)߿)I *x9;ٱMDQ `$̼7sԢTfiQgg\,8 NIB<; x>-7 :pzsc6}Ƚ{T{f:MaHIENDB`grafx2_2.4+git20180105/share/grafx2/skins/skin_Clax2.gif0000664000000000000000000004763213223665306021062 0ustar rootrootGIF89aTTTTTTTTTTTTT̼|||lll\\\LLL<<<,,, |l\L<, ||ll\\LL<<,, |l\L<, ||ll\\LL<<,, |l\L<, ̼||ll\\LL<<,,  00@@TTddttxhTD4$ 00@@TTddttxhTD4$ 00@@TTddttxhTD4$<\|`@ <\|`@ <\|`@ 褈|Ԍp̀dtXhL\@P4D(|8p,`P@ ||||*||?||T||i||||||||"""fffmmm! CRNG1.0T /0?@OP_`op!, د~*"J pŋ3jȱǏ CIɓ(S\ɲ˗0crH` :(Qϟ@ JѣHh&N:!򤘴իXjuR~M>*g׳hӪ]˶m̯aB9ۻxW&ܦrKÈ8Đ#KL˘3k.ϠCMӨS^tIc˞M w NWFμCN]7uֱ3n[9a'^.OC%0B/4K~<}&N|F^~ʼn?@S!D v&HUX^|)SPl/ bB2V~8X\5vb>^vx ȡ8Е䱨``mrA4e6 fHBНM:Ybg-PC̙xjemC 汉vw#M}gEuM/EƧ8jjhbgnۃ㖴I$}UxV+*y|-&y#ީkĖԱ.VX$V[^n#DAI@'Vk ]JɂgP K+ip_Ոp jg J߆"^ nHaJ[h5^ `4L3woL`#{WF:6(M3۬8kZ{zK^Vy۲%fn(0B:k`!YgۍͮkXhgjgjs88# .a/5e)źûRsSMS_mg>$p$⦛ŽDqYY4+\u)U^`e~㘸Dl1A{h!Yv!$Gk|ԓƷ(0TL#lB!QYWtյCiO*sU ciJwd%"sҗb(w33L2'8njfeyK`̚|iz32 8Io0axH Djbx5RNQli9a3p*! Q8dzwx# ˿ [쉓'VӔc7EzUlvʗyҀw} h524$xׁw X~z ny.yeWO(.N=\GvxȂgaeP("cMUhyjgxYkp}mTVvvxz؇|z8nhXqcm"^78œ)؉Eu8mX5HR؊=Ȋ8Xx؋8XxȘʸ،xQxؘڸӘLBVH9xXV2>u]hҎeiV8>$T6T  iexi ()Pf8 O.SiB&b!&Eȑ =Dsc2E9 P7)TȎ/93)9rX')P1eHX*XYxNɕP1%X(I9s,KyY(GT`Tr3T4娕:6Uf>(eXt’ٕ:R(''阑EIlnS3E`H9}YՔ5"]RYffٗY,)޵d =UV)I LxqIq]v9i%ɚ Q6*I(i9fYiIks+)=YebeuvҟxDٗu_ɒ])`)9|9푓VTi?YCX*JUQIOIG ʘ8I$:`e٣eGlڏMi3`ٝ:9yJِG . 4*6!I7v'7Y)ZCtfaIybj ڥ[J#vڤ+ᩣexd=ɓѦ p:tJ26U:J`%G9 ɗiԩMy!" j 9*ў[Jp:FV {J*顪ڤiAJfa35^Jby2{,՜Łʨۥ_,"Թgz)q!ZSϪ맘 ɓZJ .L*j$$!u,',5Ӑ}W;]5ː)j:U Ԍ,æ7m[OK9mDF-f,U]u;6u`-v^]YfhmNM?=fpM3UkmXnqq#ܝͳE;Jʌհآ׍搊y˕I?)8׊œٞ&ٵ2ͼ튴̑W̜Wv\ڦmi=ܦL4kضi{X+ڣkMƔ]ݸ\̤ٓǽو]ؚ iq}LlL6]1w}y> miaLoLji];4}yk=ˆm>JM]ݦkُw9,yٻ=Jy\̗yS%ΟC]:6klTH.I^IƩ=@#ǂ /nuSc*FO&)@s]rArt]xJ4n׽욥D}Ɩ%~^nRBϗ͜,NWZH{])'nZf;Ɓ* ᭝ɩ>g&+h;*N*d~ X!; ,|Nn7n9{Dx^t|^\ݮ֙N*N%˸}޵K^~?L~. ә5x^  -n~82_46J<7Z-'[vHO0j;RD/y\^b?d_fhjlnpr?t_vx^7~P}Q|(0LiNv!)7#zR^!?BD/ՎO\".(Ԗӿ}Ia}OM$XA c؏Æ W_?+C'XI~%;ē1<^DuJI?L #ƙ?|8SO NZUYnWa^}xcÔL!.}y(D-lYÕOF J3iL1<'˚yhҥj8e̙5o3X83mңB=f囓~v͕qVhHTɕ/g9G #b?{Σj]/M;/9

;"8 DSTqE"pU-HĠ\{ c#lHH0Ȩ"q$bqJ*CM-&.PkAسP& ׃H(c1KP+sO>B𬶆q0roj)4԰4PSC%>;+7 T3IOTHMUMY5GSWTZkV\suW^{W`vXb5XdUvYfuYhvZjZlv[n[pw\r5\tU|u]vu]xw^z)]|zM O`5T:ԄAZXԆwb\hS0ԍ{O@yŽA֘-Nb2neav#ibRekzd~e!V:fΙ7Y(uz3j^sfEMiEvmqT&no8޻弑6Zmĩ ^~q񜝞)_9d|C蚻6\tw=[i8;kϼpO8כ铆zX{dzGy[w|7| w}ww}~P$` x@f B]Z`@A bBܠ3 ! G@ᢠRR0!k.0pz:)?" "\uHC)KY`(\>M"(YQtIIDg#]6qi蓧qb/>b )72,$Q*ro$)Y5/#K~2t$!(J<>2eH'.cLGrm,eiy1d̥%qK~1L{/8eL/9GW<#Ef$9%rR,1IiI`rR%!YM{“!r=-X3c"2IA63D(;)LZ2>,^F:Qhs[G$"iHR1FTiKYR4CRh›%)s`PFЧ;5RZlOSjUUfU[jWUUc%kYzVǪkek[ۚVcqot+椇=k^WXKؖ&`]lKX*z ؤaʬf%YhueMSZ~v@Ii90Riz\T[ܖ:jsJ6-ow\@rQhEF=,eik]B p3ٻn׶e{[~9WXSl[\*C&rd$'YKfrd(GYSr,gY[rp/YXͼ2YiVf1^\g;k^sf<9}t mC9p^tܕ?9]n'}K9zt+}O[4KSz̪sY TÙuVb[wՒuu:ε7kJ41},fľ /lM֞49mhԮ,l7C"rܝlh[^ż|{Lnpxd-4eǻ Œq*OW 1qDn}>s'>feϴ5.k2rL^s H/zϦϽ̒ ywqp3ɖOD_3gnc3h=uϻl>AC1AY:}n7EnxH;Ex9(kB[$Vws)}yz3qB=gfw\^@?8rދޏ<zs>/Ne|_N>O}{׹>~=VϽ ;.?O?.+?a@73?כ <+c?>S9;s:8#=2;@6!?3{? {˼ADH@A-9ã+:B:A?$=)$9:Cd+t\@wAԹ*446DƛC4DTRFLCRTSdTETtXDT;9L:_AE`ccE Cad|=_fD4bY|Z FeFfԵhܷH@R|k\FXGUtnDZaNa^ana~a{̼wm{^#V,#~RPש#>b&`M-()I+,.IbXv'1v0c4F9V#^㈭)cfdNfe&f etfkflfmfcn Ѐ giVXn>gtNgu^goxqgeVX Ȁ`g}g~gxgxpgNfՀ hfnh~hdhp&hqd6g^ ؀|hihg6fs fiP gcoHjf~@h ii` Ꟗf. Ȁhqa6g~ij빾kVhjkn΀~fГ N*xff~ kl k6f Pk6l`Vlހ h줞y&v귾k(m&Vޮ `I j `N*Ȁaܶ왖&jo~(kj nhpȎlq`슈lVo xokv.jjmwF> p pqƀ .o o6n pNkր^d l hqqo 6kjނfl!p (.q$lfrW4ionyf~mrs^VV Pu7Wt q6i g᐀h|sU>~ӾtEXf LMö ;Fh- r6Dh\gb^ k `v>mI΀~p 8ӎzwtv>x(|w}gvt'xf-.plm_Frl q'ww@?xj& gyh/niހp n׈dFoWo+?z.oZx]?/'~fWoyuomk騎 `xg{kh~ uxz7n`. /q'q˯uڞgtIj{Oai ` 𚮀vmSi.soV ig{ogzp~!|hf|'HHnrafxbghGtkvRxٯiq{'2uG xx~X~~3H(h0 С 'PH 6a G wݲ? ~iPEdfT}UdDuXb(W6#Y!LfSp0b奁L\p!{iRxZЀQJ9%U"$G8`UK!ZȅB8HdU~ Zm wL[h#$Y7D#|yh%z)XwbbJUuυrlכ:vOuVgz!3`^4Ba"ĞD)h+R{wTeU;.> \{^fzdJ+;/rpž *E`UFq:5Ҳd1ڑUddIged)Jbl1<3Q{ҒDt5&"KnqZLwAU;فa.&(NIiȔRKVq(1#t-D47߭"$[/'>4KZ }Nt`RcefV'InyQ(0pHWp6]zh*YoZ#s@?} ?a kV+*թ-JPP7Ѐ)G-htcho7X5 Pt!㛐yG<ЬC-z+ղ&{~ߥbctϼ ]-86* YE*l{2Jg%k39i/-`!$0!" V0qb~AWGUq!v: Ʃ>+l1]iO6d+,qb~FFIc18M9_F#;O+ɕy\-D)Bni ]AN w̅Y->V/+:nҒӨ53&:rl1U7 ?zd׾P4Tp ^H@U &-`"Loڙ6jo9mKԡVu:~Rq ®+d.0r{t_ѵ,o*0kH}hSƬ">#~PoqiMK+m8o_&;ʥ9cc0?Z䷾u< YƢMq(Iܹ,jp=Fc~ٿxz 5YCicit.0!e7ʞv29ܻlIb)y-pL\rh6$prW1Y{ӎvh>nIC_Gth/*٢3>Z248~l0,> ttĚ+D?vIvsjE/}o[+>7iAߗ UH0?K {5ȇ|Q<16{O1,0sau]A1}AY|Aւ\OY ޑP5`e^ `U b`i5$QEWhW \ ٵ6A_ ޠVIx)hͽNI^!a&VyÕRݝr av FL!"  Y}eaFH ."A!5: %("ڟ5ͨ1 E#`)&~ F-(kĢ5f]0a&"2.#363>#4F4N#5V5^#6f6n#7v7~#88#99kC#;;=<;Cܣ:=#>>#?=$@d>&@q<>AD*? :>>#FFdr]q#FvdC8#DEfJf@$ErD=IdJJ$NdMΣE$AdHP:$rydJ$;H$8$=:IN%MƤKUJ$BʤBbKR2TBOfe?z$ZG$RG%S&STNL%PWcUBeE%N%^e]#C&e;jb^dXa\>a$`֣Y^ƤWr%bf&@>&fMgVF%@c\_QN7VM fNAV%n$mcdm$iiRJZk¦h.kʦ7^:'Diu*'hcgnfsuRv%\:ZW[35gzN'trcoofvxe|dp~rtdb>&;bw| {nO'jgwfV'F%dj2&o[rfc~gFdvb_fgf()[f$.'{vd^#)v*u֧Vh6tijrbijlj5e6YNKi_LiJy*敖'>Rc©U>])iv)tk*&.+6>+FN+V^+fn+vL2k?ikLkû kثU+Fշ+?k.l6@+Bl>2B2Dj,l*lZ+kŚkJ,SRr.,GlRɖ(+˲mkkVl- ЎF-26ÊN,lFֺb^l"&+ҭn̆2ml .r-̎Ԧz,Ll+-β+,` mkm&’.J:-ӂ,v̪n.-ll,m.*Ŏl.VᎭLmʪv֬ņ/bIn/.b>-N+.2Za)/֯*-0-鹮욭zo-6k6nn2~֬.prN,.>mҮvo~/wl SpӶp:c ̦ljmnFpo.1q kqidfޭqW, 30 / ++Sͬon&,2ro p-1܉1onl#2ڒRZ1nmβ&nn2'je o.Wa/1/33'T2K_-W2^.k.ʢ62kN8[+2ʂ3c3^0.!r+"n1*'-,4 ?#?l7&s6G̊rqq?lq8'n(4CFC"EF- :[2j? .@#KrFC-+;r4Ln4N4V߳O-S?77Bg!7pɢ0 m=OrBrD籶Y5Q5Ԛ,lѺ/JS6sIw-/$7/?kU۵53fge_f6hO`goGu15tõ%۟Z0hwZ׭_Kuc_Kq /ar5kObuVvmv)kt1DF*p>=3Bް\+,Tu20v(Fqos+R3G6:72trgպ.$wsRcO2#sϰ·tJ?xS~{wrsxr\tR{A?tS/\:xRO[+^0:nw˰pgswp/7^ s~x| 6-So012#9z] ,-{Xh9h9q\9!Wp9yz.*K#19O::WgB8?-욓/C:OUwzniyWSըMzAxc:w[:!zyy;#{Aẳ[z0zҴgy]iC7oѸ[y{y+';{{;{3'Pa/PNy_go>w>臾>闾郣LCW>?~s3}j~q31#LCJe? : D~?.J?/,.S?_~_lGN?+׾.??~ wP׏ˆbRX$F?N>%^#>C^LN2ЪK[o 5=ڐJ\]Pen(oBx4er.BȊ;o[G ;,q>f<ӏ2{/ti#Ǚ {,< >;@-lSFslE&Bz&eJ=s?=T7+/[MU\+-կJs\i5$Jm>{uT]f0ED5=oGsPTbEʎM>O&?TɂT(՚.+9ǵkʸ4=Oh*?K˛44ׇ]N{ SqںY'&0{:Ny&)Y+%i,<"/sT'Bs/"Hj /DjYTEWBiGi2hMs J7 1甧8XO{gB5> *#N U Peۚ9QТF+QqesH tP.)IYz~"a:Ji*޴:5NgS~Aj~ZT H͘Qj#f '}*5ZծLI&ViUfG=VJ3c5Z5ֶ5b_+XZW|Skl׼`)Xna{ PCma5tU!9/!+D ЖukiUuEkZYɶc[vhtn|v m9]}딯99^OYzƲ O{ya=_] Gطn*ZZ((V} v3o>vcO{da|v#[|x+U<{mlv+.=yI{_~~}ϸ?glW2k~g?oS>>>?S???@T@@ @ATAAAB#TB'B+B/C3TC7C;C?DCTDGDKDOESTEWE[E)4 ;grafx2_2.4+git20180105/share/grafx2/skins/font_Melon.png0000664000000000000000000000525113223665306021173 0ustar rootrootPNG  IHDR@ƒYPLTE~mmmX-tEXtSoftwareGrafx2SjIIDATxY0v$gSw1!pjq;x?ssGk]ϥ7e.@Wat1 L~9HOA% g).jSd+:۰n@@cwWJ=JFԝ[%9г% h~aHUӸJS2V! TIRxec|84ü"x!"i]+e[Ɏ } g8F~6A? )p:z{ [J/vъo䔱6ǞOt0jON[K !Qn:t AL!⑩tXkkI슌0I/ѯVdnp`Ȭ /`- C#Tqj %Ð/d gEPNDZf%Ģ:,dU 1! JVa`tN3-1!ܧa~Pw9i܎z OL**wz]  ݧz]2wsb+3; fԼ4d▱? H)m7؆L^C\3@ $iL&lJYiNJQ9>7%2_sT 8RYy A> Co鎔:$_>,F ETFO){uT(G8h#=Js0s-W7H  * Ow{"5.QP$/j7wVjOz٫Ԡ'l'рI5~1]NdOwK4tn b@gWr y^šM ` d!%=}Uq?t  |Ҁ nqM9ZBZ@9IBr]/m'^ֿ' @E΃*h5&~}ؐ5 `=0pmS5&P!؛gI?(;P\6C4k}g`Iut¨j@K,-62r}WytaU"5m$=}Y,w4T4C ^vcwoĀ9brHcK>VS7Ԋh~vcsAoy=7?"0WX2.r4ŭ9xH|&~`_R9:\*zcAdBڃ 32#B}0C &_SK;~S׎ nsH cL{; pPxZ95h H}0><1tx{_u~pvQ6:E6_a6ӾS ]Dtk.k2wTۑ~>F=}4\;>-]hEǣ@ /;Ϯlyp8W]gHħ@@Y{/4_6{~k<¹`|mp >v#8:?/Ϥ7dvĜrYmq59l7t:jA# šp |ٴsDRT|\}Jdl11P7gP/5n+iv]~/k/, qy߫3&o<{aܹD0Kr _֜/S9j=:7U\7@h1;pI TnW`? _֝澰U{'g˟iHoW;3x ΙuZ#|7;~Y |aSj=~!I?i󕷩; uߧͻ[Gx? <( Ҷq S!yP{jbGﰞ&L(4sf|_[CO>NzbJ}p1YzQVOξQ~]^_.|) "D6^n ; =_g-;{>?(Wcդj M,QhZv[|02gfJh@AGg6z)4wF*E!>oKTq×o_xL[ lbl鸋*4+z K*p;mǞg)U7SGr=%<jUAYc^QBճ_4><>B}H}ѱ[WPh -]D=U6?((}Lnzr uBʀO>/|b|ױ4?[n< =]\~cBIxhЮ,5:F_7~I7]kkNeZOx7tI+ =8fީ>|9fIY]kIi/V`U,: 5n~yء#i+[7vy=χ]x~w"mUo|_&4/ / tkQA hB ܞX+E}ul)ڇQ>x6}Gᏻ/ nmŔy~rLd+I`Ѭ^ -ٝpPqy; l0|a(RJ=]ek2 pk`[w0o~T ;0߲75w9' W5|we~ dV.4{Ŵ`IL~,|fʁUwގc-{W}?t.RgA;n*j>oJQcbK_6~P#xl>Wf\pfQ~DEcj|#|B%G]=޻YgooF[@4#ԧ>1a㼕îmڶɮ^>i mGӞX 4)2URU/t&͑R%N\u{~?6^~s,T)`=F_G~s4T_iL7/Wn| Ҩr?jn9Gvttk8`5EW,j$[>|j%ka`ysxbK6 4JOh F,Mmmwpa>s8;C+ .-26^947BNڥgxGcRc|w%#G< oOygD7R?zjjzj[0%pT͟WdrԇY dS^>|u4#-ד6^)`V85k7L<}WN:_$n͟W>?Fmbi6~y~ qET>4 w]qGopZ $eFLubD7ʑ}c \vko1걵*S`?M{On*bW+:vlOms4jn9Nҹ4m.ϫ;=o_oW},gЋFU;0-QF ~F-u ~= V]`?7c K*p;m{RtJx>|A>E9Y`P53Wy߫͗}J.uj;i_S`_grӓSO&D V_` cifxR v-0{~E[GwM >s\ckFkA2is?MAZSn3]L1п |f|lJ{ ~( ˠ7jdo\iPEYE_A}f QwlM}0/K@P1n@kϯ{zsyBW"XA}ixI[o>| m~d1hoغS|vh ̲Yv n ײu^SA[?6^Ѭ^ XzK X) -Co[K `n",_~"kҎ%%Kgs~ 7+Y]SϽQVC qe>&M:7|VڙF(:qe~]tx+:7MU)8>3GcOӆdk9*S3><3疣mx!{bc;* Xmmzn|m %_y_F+ :,˨SG5QM>B!=S7c9g%}ꝩܻU7*K|/(2^;6hœۏJG]{X55GƎMwc|F(ɵ >7.&glYe)qge떥V '|gk:P:90蟫8hYQ : ;-KAKx,GLh.w,%wm9<Σeneࣣeࣣeࣣeࣣeࣣe/X9|o@ :%5R炉stJbXm__Q,* :%!۾#( vc<mkAew<$,(e05cYxk ~)?Mp9Z<m WSry>?Mڧ*жd~Ez>ᴬfl!{b/A_{Xk@W<qC}]~2_{"Ol(@"0'JI{~y>=͏o?a{2mh }{Q=;|1Ϻ3fۏ]&|f{ oWJ U,?sGgEvFR况?Y :%E9 /X`E /X`q95G*A̞и[֌v/۠S|õ7?וcm1p4A$dcv2;X<&`4}M{Hz~k3 brf-I0~kI7bWm)IyZq鹲MeHލI^MAR>V:ϯ_w6fבvYg2˱uמ3!M')g=0#m)x~y>x~?Bf̏d4uמ3{oLt !l 3L~IvLQA+K1X~͑?uJnNI#;%{*?s9H :%efh1G",_~",_|j]H $o3[̪ fH&' zU~}grZWuO |HTԍs\?f'wvZ%zpޅWax^ =Q|vܾO 7 zڭ*r #j߈|ET/sȪ&oC̢s7awz S ,_~",_~"}+C1 bMF}moF!]=K_~1Ziq~Ѿ/ fI+ ߱|Lrԕ$sӕ ,_{￿}7 ǩ*j~w9>`#/Wk Qo=\-bK{n ~Tߚc}^7+vgP=Z_:ee#iZ<ϭߙJ߰e?~TGE7~.^ߨ{C'<\U_t߂>+srzAƱbvF-}g[*^+?;^:/C ^^8N_9xw=?# I5JKfv1~ocڱ_J$zkXLU6E"8hǗowzeo$ ዴ(/D-wܢwΟbuu[^~dղy%'EO//KןA?-R7}_}sKw_F_,ʭ\y^W/YP~YpBxqONX `-=f!oXN,}ѓiv~9l/C􋃃GWRU%+Ny=gP&5}9A%b ׇ{A__oToK[[ +NC='l"@ayEV*pymEz-y~\ `諰|A_W˹}|W[z_tE/OAw >][+$3ځ"ObMͯ$ow_z9'/d/Tm·^ {әXTls: >mHEET=g[y~ocF૮gt}^5s^t}YvgÊujjz^[40+IbLG%+:j*Z=8x;QU/G@_wV)=juCy]/Jas_:򊾚"Qq֫ޒ.Cy#şӿ_<܋I|I_V=9: WP/}=Tt#kIxZW"zmfSW/! _ޮ.]/fW%݃AП xUxZ:(A>{#I)KKnLNP7tE7/~3n;/ʁF)yGSf6__h=EqI\#ݽ ]+"j^߮|1*N@/^%?so/aJ/pGNTN2'QI+K9j]wf>m9WN Êr(M_9Xċ̝]Eߗ_+BC6TUt$R-X{ sGKao G+3E_ h\o0@/W~w{+斒ϽZkM-3[Z">&Ft4}E6|AԁI7\A/-[!Ayoyb|^$/зЬ^BbG\~{Z_OV_|Q5`/I<_ Y~H,~~wi42K9h>?%qǎ`/%{ ߹zÇwfpm Wܤ#y-˿ݺx`=~Ǐ?GZF&?>zq;v\_,PUaky8Ncjx7[wʑQ"c`G0 \oWWCV$Œ7??_}`ZuTq99'sܮmr`8E1$%?=ïWT-"OS))6IWoַ3IUЪ{Xhoo65==._ZB-xݣVvǓ2tX~T͇45gQ^؈sU Hϟ?W܏ Nc⮿^ ܝ) d'Ś{w7Jk@߯ԪB@SQFDho/ۣnOjYGFKy7@M6g޲m!%[zO𣒋9rG g/W?I߽<~Q,n__L#>~ G_WϦҗo5/j٢g) txp\kUs|<ʘn}Kyo񷍾aou^-۹6U^B̗ap8O?F>T6.A#Ury??0ɗHEQ4><==., ϣyVDJ7k䃷ֲ"|k\й.E@$zHrł=^[?w?>t?}y<$|IFXRᚙ1>&"SMIPEAӨ[yXVb/F_8O?Ie2y&_?Du{gjws>F_p+bc?=WbVWMQ x6w㏽› Ono~|?׭>"LλG_wwÿXu~@oW'Ⱦu'ʹ-qEK? q};y&_t"[3$lf>w]G0ݽy?sOSY)+O{6O%_bz#6ȧ&|~Y@ yCDnU‰u\Mѹ/ GW[:oIfxܞ$w:W5~A݈zfq@ޟ^睂Ǐy=箇Gqφ87)zڝ/l`x;o/9ȳ(Ç{Sh|-?_>u~8(: V.W+EJLczbQ\Nӫ;{sce(u9]Ĝl,s[zH3Jf X`wҗ[vT/BBW7w~.A+wrgV@C~Oܐ_(0wiE`~sثG;5牖[?p@6"i7=/oS^:zC/-n7o}9+^SXxG;468/3 |/_jYf7ד3޳o$R<}FW nQ5^i}@~i ~B iET`E /X`E /Xz~;튧x7e^ qjxx~}gpܶXmX<]y Puc85SIr?LdJ;`ow=m99Wԫwo=I'C56zDKm56/Ͽ&S?ox|_\m+_Zj^ͧ~E9 /X`E /X`ŴjFh͂kud'm) M풹_tFTtT40 qRٙYR q6n wuk>'?C=|54oq8@dS,]X;ep)MaR6xXbƞG!l΄"|7`Wʹ6 -  8eu4wi;F 8e6vb[<XZ^KH !8K+Zfz.8k>;s`"yӧp#ۏ2rpʊy( 8 ipy«W@)0g.@/6'ϸ5QZ6e{0 @5_8o>?ԭYc NH Ư]@@PJ"1wnzA>h/ pJrlDdQ;ĎOr׿spʲQp$'#XSX Bmل6^}NyD > ?,D??>  ,dkKӞZ[ŵ =a'?\d{m~ߒ =6fÎ&E: $wMΚƷ|aRm)K k\SnNYŇ"? 1Hp OJr;knNY<_6a[(`:m)J.r.OnNY%tΥ@nNYBd{>,v8h 8es+k1j +*+>v8MY 8e3?D=rRh=)T6G65+WGL߶m) :-̙{ [Lg* 8e1t,22xۨA*}nNYأƃ`zPKaq$?${>|ן~I0OFM#҆(rpcܜm)W~",_~",3VRU}mUUDހU@kL_%[?InNYXi\-o̕3ꥂ'6̺i3Mr;~Wp _+9 y<bW+|u7'Rdº߁u-Ki 2, _1 WVǕ=as&<|ƿPε^hX4}\0m)ㆯL7@1?=7m)c]=5im)nX3jSpam+gT >l,V`/ApJ;, m)+*ӽGt~Gb{!]:g>"þ4( >%ゑ?p@wHn \MaU */ق=ҲZD_PUŁ]Z 8e2.vYeGᠼ ݙk @#|ɛ>Ky'8~ۀSV0CUd Hs=^]5EJ4χ4_E WMU~2jR2scջ=zA{|OMWh6`6`#ը7%x$vL}E0ޘۀSgŘU'zۀSֵQ?B]ۀSVnvۀSV/C_qrpcgzy =jϿ:y[S;_s]fg6cOG,Q\AO=닰8_xWO$'|R?&iCI 8eeF7\ 8e /X`E /X` T{$uԨG@]1GG3N~~Zg#_(W$b~ރo{ܫ*| _Um?`m~4Tu2!>M=V@*o>Y 94b^yf]_tRMKY&|5~oy 3k_:/۴]cm~r;ȼG}=iܹCk>r\}B=1^@J < ed8 y| 08VܑooY ~mC/fw1kvl?rLȸX-iޜ瓮+_?6·ݰjMUGJ "}n~ץ9l_y|x[іOx U{j[`N ާh4{uaDD y>03= ?5 >bzY*g׳hӪ]˶m̯aB9ۻxW&ܦrKÈ8Đ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻcJȓ+_μУK޼bǩ}޳;oW;i}??^}(\?7G yJ~!ga~a8|`?Lw` `.$GuXȉ%Y:g@i>#}4i7?HA7އbH_B=CBVh$c.XO"D#@Z&E(gT2 IՉ񘨗_6Sx]zn]BQzM&(E6U&鞙Zi>qy$x%XZe :+iI-^Z$-C9i}ٹx(B`h?&jxV(-Җ(݆+'#(B.[+p.T\*m:J[K0zNzF+H"^e_ICۤ&j_߁)4ɀsWqė'vd3̄,eIʆӒCN/XYDk:` וw5yntH(D vKbsg yd)꫇fx8Le΁R</2ƌg!Ҕ=2Bq{'n"??Y옉(?CVUXx6ʊ/dWQFt#gI[XuRH E)%1-WK2c$zE\vht)'1>Xph9G+G,Ӗ=Y 1ܧ INmE^]otHӣF/8P@#i\q|Ǿ:Fdq ['͘%: (sjFzm}Q3T*f'?sr%ʨ@V'wބ&oWVUfCk[M&Ozzc] V;j+ _X6eS!TqaY hGKҚMVPY;W5rmd1fg68-%RV}l\踜Z{6߮]I5?eY&fB(wbW8cUdN[瘪D9֝XbvK+(uҼX:fLy*,R%VXB̜x!mm!iwY0 +%r8ۊrJtʘυphh9{ vلDx'KȿINnD0mr¹Cl MuG䡞T.r982 /lD֒Io;ܛ~)5Ա>K.3Ӫ%.8H^  9UBֻ\rz7s{a(רKY+ziֈ{XӘŌ`7竘mmA[_"9OXruNFwdoreLS.&#[7I\ߤ45T=|+;(qh޲wq5RTE3q/n9]Qq jRNQ7ssWܛ<7I&6+K'씾E摔}C`NsTy?5N:nݯ}47So_B(ܜ"B//;l[6sl*6fE_U=}[ާ}{nFO;1>mI}m_{ۑlO~Ka0Wk>oL"J!]Slx]e8~~dvnw% X؀Hn6csitbS+%T;"A~D 0( ( HhYA9IKɛᛞ0֙pIWYi 8 ЙC.|-InY9#!PXj)_yIɟyaI&|)/*YTp2$WAɡiٞ *)r %W9/Ji2:9Z8*١;ڕAKY6Z֙_n i^ipɠ٢+ʙW 949(_Jg#VAVj $r1Zɟ$ Y lzɥ.PڂʨI Zσɧa131ʟ9R: ʤ$٪e#Zd `bb99.j&)*)5"2fzYߊFӜ$uٟ'D9ӺʰYi u+djSi㰿 Iia*Q);p$ciŗDߺDKP+J:IGIE-KE)ɲQmݪ &f;˯ZJ5 !{˷}h[p`ou˶ݺJ 8ZѸBpi˹Z{q+({븸 ~ej/YˋƉ>9ѻ&: @.L[9k;kjĊ?BBۦ!C+kakeAccמ0jZWkzk>*K*ۧ_9:t*ڦKY C;v0W)z\ F-<諰9{i>04to~{ux[*1|>@!0儾ThU* ~M难>^~ꨞꪾ.([. Hnޯu$Ğ̒iDܯcHr< , `뭸`rV:FsnI^|GU֞A_5碛4r)2ub1'ծ|t'~C0cFdL5|"^﷨Z _#).[[rykUx$0+~ -$m.BS6=8A)%F/ }aOC3vUH_*Qq:^/#G')j,/[S5P'~Q_T?aX#$qS"~C!?*fҹCnO2_4OPO/eϽ*0.zpo8^OW;X5´%F'BXB_ ?msN[?irAb?gOA X߽{ذƒ%NXE5nG!E$YI(6B- pp?_2Y4̄.UThB FUV$SהaŎ%[Yib j[o*:ܹu͋.߿~ۮ%\aĉ/fcȑ%O\e̙5ogСE&]iԩUfkرeϦ]mܹuo'^qɕ/B..b߮+e/%!_}gXƗ~}_O@@ T">b/ *ÁnB HDC, ‡\<0F`,FQFlTFT R ItHB$+C1\1A\IC+! ?!* .E PΫ32Fq1A?[Yv kJEu?z}p_W_8- 6`Vxavu,+b3;cCydK6dSVye[vecydjfӝ]uYh蚑YȢ>餡^>gj9Zjg;l{l:mAΙ 2ڛF6 n<ヒ{'@'Fhv3ro~\n'{oWӶ?tOӚ&7V.3- k'$:YMwbR%2cNod%?OwҚ6 POz ](<9΅Ⳛm:I͈Tե=Lp34(CKNrTA)K[jQh;)̀BuhD͹kzt8 N:͓m(NiT:lLMuSOj4jTVBQugUEZoU[Uzqv`ը^zӢ58Ɣj.yX`D,cXa>V``v,g=΂ݬhMJFemk]Vmmm{[Vmo}[@%nq{ep\ѥt ]^.r]~nZƻ.W]y;7ݝv{%q[70y jN 7A㘹J}?%:Ni/vr %&.5ܥx~NU\PŢ6 kXR;Jr4aL>Bj^׿vRD&rKn4[obCW'Ͷ:~K]nY:fw5ݐΜ|hyڸo̚u^r&7%n+e#z,.Ys|_A>Y{6k|⾋p[x-t>zHf-%\fy,Kopw[pV)?oKgsо|lsSq?j?$oɅ;?yTcHO\Xþfw}1v#oW]I3N[tkW!.ߣ\g9O/{G>C6_lc~c??辮3$;?\@$;#0>6@@0 Ԉk,K{#@s/LĈ[ TR@l4 7AB#AH[A,‹4BB$?sB('! Š`BB/$, 2>01|C3B,#\C;Cw"=C>C?C@D2 DBdJ|E|ě4RJ&# ӴҤR8QxS3  SFa2Ѩ0;AӜHBS`)5 B-&=*#biTKӚDEөI05$xԮ A1UE ` PAUJA95SZBSqT0SaMԛxUX\ QkT9$XUVU`=ɔCLRbyVhEBiMS>s]=;uO]X--TU]TTW}W0XqXJX +ՙfu .]؂.Z;Ie}X%p='ؘ[YݖCI-X2HP"eW!yوmQG֚Mx-YUT=ՐeWŊ|=<Tg%- 6_Z@ۥyTӴZnC"q%]ۑRѻS TFvڛmֺuY}[0\Q!QuNPX 3Ͻ]M.Re ^}R^٥M^]^m^}^^^^u{23^_ޅ8}$$M] S(]Jj_x{H%_^ `Vߖq͏EBu ` _S$_* `1D_`y=`A`a 6Up``XN|_ ,uV?}cJ![ } ^bT"b J'b-b.b/b0c1c2.?4Nc5^c6nc7~c8F% 8~8c>c?c@.9 cxc=dFndG~d>BJƀCF6~Y ȀdOdPIdJ6Kc6~Y c<eXeY^cQ.S>d Xc=^E Y.fc>fe[.K>K4 f Ѐ;>foXqLNPf dC>v> fUflllfnWgmg (aJftހ p\>dbƲE_k|na?R㇎%e f*cx {i&钦 iNc `&hFYbiހ xivKNdi蜾hs8j>f xgW" g `f*ȀF-yg&Xl @sFnk^i{R.hK>dE.qnl>玾l.h|.jIVj{> m 8Ckl̾hlƀ Fv웰mNgm[ͮgl E@C&~WT”Rn&k섮-Pfߦ ΀NTRpl6dVltnppvmΦc[n^ W]Vm WNf d.eNqp%ƀZ>q|~{EXkTF%薀t kWF8- Z>o~p,2w.Gzh `sNjnWU΀@O% 8쵆JtDsVu(L_MgsOqPQ'uS2-.PGgssf>tBgnNSxjf2gހfoR>l `qNmHq.wtT/0&d(r^^n4&vB:VuE' xvhni_tNf*e kkV!/kunh;ޛ w (뱎蹞% y*Kfn_al{Dsngkaj#y|o׮6pVxylf mxwy u@s|vlzty7xxvavRfu2}Gq~zlWj]{\6'wy7uhia//u]in ysv}gWSꌮc1_i^lx7v 1|d~-?~ Ηh怊~vcGvN\{e%iߧp nz ),XB8l1tAbB"PТ@3T$ Wd%H 2gJPsI'=pQIa a D2p)TD7xi{Zr+ذbǒ-k,ڴjײm=rOj0( 4=aSpTă)XPK"P|J,#vl'Tp2ʚ7YjʅAC/\a K0M,1jTsΕ 8ʗ3oxq.^ *KeBˆ_sx^U+%b_f]Z<:#[`QTRf}z!!BUdfudwm0xNAbiTA~LYCĝd`]5bPyC$9y:5Tp*^@TmyWey&iE"V7_DBb0F gOMڣTu?IEҕG]AOR @K^NT:$oFQ]@\>&m fCc&lbՁ^GZj"XjឡV h-i xkdKA'fjMP]Q'Ng0pdD|0d*¦vҋ*AW|SBExmMj쵝AxEx4ːFJRUvmBA, QBۯfm0U[s{GbYSh|@JrALqd!Q,"A7S:yً+4A0Iͅ:+OK=՝{9sYXBgjj/GjI]*}_@#3?&ei`3,AO:#TONZH#G!4D0Em$EkyG>?%{bPBTW61V찀v<"T1 RP& Qr6@ 4=!RX(.n  aȸcɆi8\б-$EE G~F<G k+[T4: qd@,l k X8Ž :X,8JZp׈=B( BP R*(i˝N|. 0 Yb5MzJ~H$(D6u )O<%h+]w۽FC# >;.ϘK4##9# I(.,"o22AZD&-lQԤ8usWRSRr\@@-T"-S,PAT`+(Вe`*L TP(C,xDGt5` g<P\=+|%@ #&k>މ?KѩvU ^`(>R :)`S^*Xa:eUiC3 @6@t!t {@Ο*`!v.~B@d~N0d+lUc=cڶQjaVagּVQ\cq-Pa JvBkj!½fM +O ]nkFVZW.5nW!^#$k+в&J') @i.Mmvo3 p߳ \aX edgI+Tau-D¬BT״U]fRf^Eo3Lc,ߞ6Gi7L׳݂@)Xi㧠*@7~\iASB O *h"29lfUi|97:)r_Cr9q&  +-ˆ,XzPiu)UY w6K8jԲV@ 432?܎a2KZ52 +:!4V`-LDz?:hiؽl( K4MBT, ;$#Sl(yÿu`?\pj=/Lf-pdUs-vW:V(dxW+R0ϥn n5O6\CԶd[6_g\Ԓ[,ӯ0,L= Gѫ{^ 4?8sO[+n@ݱvt_Z2Uh+}_9^X3~; nCŽَ: (-~Yр ;??cƳsH.|T%c6S9@kA'^39ّշU{=aɹ{Z*\oj}Y+o6ri^5;юv29~Q=j]Gɬ-__/> `T_ ]E8NH`]١ٙYH_ܟشD] a yz`v],{\Рٝ^Na(aIҾ`ML\t[ZaQ!!!!ơ!֡!!!  v@!!&"""6"&=$$Jb"N"#Z"%^"'F"'n"(@&V")vbyU&:*&b)B'Y$"+,~#". #!"-#-zb(-'Jb$ c014N1B#b2~"2&zc*U. .8/"6>b*;>#3c+b3<*c%):j#=bb.0.cAbB#9c 0V5:6n#@!:DNDN?B$$"9"b-,c}5::d6n$$$7V$3=$MnJ6YHBE$,7n"&2Wed/K"LFcGR#F"e#GFe1HeEc+>&R9&eSLWbU UeY%M%t;ڥ@.dZW!$/Z[eb"j%5$>eF20r1Z](aV"Y*,g9fW*&j&_fdd%=#dn&g&;6I^R*daeCRdb&+L&%j$Ve'm.m&(cZ&Xn"p!jq&Uex'r&I>L'G&AfoZ'*&|vprs\~rb#s%qnpfXt~#^ggvڦ~]&M&B>z$-~QY&.2(ey%d'Lhqb&z%e`|'2ڡ$k*#b6'g{fI'`ިZhF(XƣFNr&~(h%())))Ʃ)֩)oa?)J?U *\C?E^ţ)(j? IT*jHVnj)22*^ꪲU|6V*Jjbjjj~jjŰNlD +6a+"j? 룂+*Njv**jv+Fjʫz+k쬺*j!*F:++kǾ^:+kZ젮+N뱖k.k.jRlR*nllkn,v6kӎ,ƦꦂkB-춶vkʪB,+bkZ,+*-Ȃm؆ j.FmVՊ mَ,f.I.Jj&k-z*.]6mlނ*N,ʦ.*r؆.r쩦,6Ҫn6>^--ޞ.ʅ+Zbnv/,+ʭV+-.z-Ԛz/mjoqoqkl&jJ**k2&B*>`.,~x*-F ;zppfp/.*o pJp վV-*-/0/fmp*V.VXw11,Z~o嶱>-袪7qnl~  -B17G"+o lb-./>NVk7mS*"޷R1g*fmRpn22!;J)S--c+3^,G [V21l01,'0*0>o'32;-/n74wx|Oru8! qw3SYO[xig8pkz8ooCSox {06֌x~8;x/ ~O9T˸9.y7yw8sos9OSy`=9Vo3\yoŹO9yuCS_|v࡯S?zgyS:kxR/v:( z:Azz7عz7 c1pݺK{n R/7rßӪ붚{0o8gm!o,Oo>c{O@o9DGqcl--_#t49po6[#4<[ӿfO{2#b&7/w?k{q/ ă{ʺ}ʓ Ǽ<׼<<|b0W @ N}{U@_WQ}W/W=Џ` B?@@J}}ғ05*ٳ*ڇ=ѷ}+=ܟOK=GGI}=ӽpWa~~}W*?~ۗ֋>=[s>՗u*O>kӽ__~\G?1jo~Cڣ>>{{#+o~~?>~#P 0ƒ >TH B9R4Ê !D"I/Xɇ&a5Yoྃqyqbŋ7v)W\o-rrhhE6m:rjիYvi١1Lxvnݻy[xpaֶVxfs(Eڙ@eʈ>mB6w}N??zH;!wb pNt7^^ZOrh~7Ly"r)9!"A5湯REkر*m3uݽ}[yKm@<\ZQ~2⭏ݦZjz[{rlp{?Qɫ,Rd>G{5i} p³AGeZ3acg(QIAMir0VNk{ƶp{zIR(CA[<ÍJf d  #V\QorZ"Z6)2,K}a@` b>ÖUA|nVndEt~*UG_ՎDr$BKn`GG xnMfe瑦XԤIO~uү(Y !%NnZYK*w+^ &|YL`S-IWrєfКYMr3*M Y8Yp8T:߅NwÂfc3G Q+k m>$Ke+ `I?.Qɣ+Zs39,iڐУVeMYTF2wKcXx.6)x(?-bkx`n=yҖ _K~|ݶ纍&K-8[\r_n;=2cڮ5O 71yFGG^89nh>x3qk4pt>c\/>e{ȿ]st3Sj>V1<-74GJ|r\fx%b3&;e)sWYd*leX/Μ3^bL {;o=rWⓚx?@=. T&-gLGx,k>d;~y?zs;Zt }sJOiYN Yxv~y{ﳽ}˹?}?z:6V֚ސ$_7KO>g†.&/o v.ȏNo*PEЇuo,6OPPRODd)i٬9nLhHPM~.O3L$m.2,0K(8o8 ~-LͪP>8lnḚrOwPGאSl 10 Ql%ߨ : 91/+1DM2QlNʦOpMQ!qonP1Qާ+tQ#PHQP/ qkP5Eޮ60q1ő7PߑN!El!30 ݤꑧr"/% MԈO!шIfqqK؅ ύ7Q#0V/>-,Fn rZhNq:1PD2n’,-P֒--.R.../R/U//0S00 01S1112#S2'2+2/33S373;3?4CS4G4K4O5SS5W5[5_6# ;grafx2_2.4+git20180105/share/grafx2/skins/skin_modern.png0000664000000000000000000005076613223665306021416 0ustar rootrootPNG  IHDRN:PLTEa(U߂i,E$ig&LW FJ478'6ԩœzempZ_^ORLDD990++% }m]M<, }}mm]]MM<<,, }m]M<, }}mm]]MM<<,, }m]M<, Ͼ}}mm]]MM<<,,  00AAUUeeuuyiUE4$ 00AAUUeeuuyiUE4$ 00AAUUeeuuyiUE4$<]}aA <]}aA <]}aA 릊}׎qςeuYiM]AQ4E(}8q,aQA }}}}.}}E}}\}}s}}}}}}}}}}"""fffmmmݛ,utEXtSoftwareGrafx2Sj`crNg /0?@OP_`op 98 IDATx]ٖ,P&6ΜfWw<`G I`b <~*QJxQ1*#F%Ĩ}m<.]>Gmvź!gp3}.nx!ixl?SOXck7xg t:O]o]ͫi6x[jBO-~wO|lBV}tRoAuGA4.XTOu^L~_N˿p Y&փɧLw\y&GGZoت*2d6=oeϾ0[Bg!cdxHFAo?KG$֥^z0vC~_V4eKGM~"(zߤ9G+n0U`Ƀ~ˊfYD/"O;u@zP'w_l>ҢbIlтO fk7M89Tܐ4S:B!SBq_h\zė-k>Gg[S"࿛yb}5 ßm4{Vrņ?zG5Xٍ4B]JQbzeQs /QW4#(C@u5˿O `4b{giõ}>h[ [>V^xk[%ٚQGȸOI0Vt|_2Sq~6||0y?FtdyJ,j|b˹Pd\7Ì52Hq.ͦ"78'Sqڞ(;UzmY NO秫]I~v?p[NɷMO߯=8QRbK$ qm6$jD9E(}@rXύ#ƕH֦Lb oq9x?ՌM5~2O3,|NL|E|; %S)sb=g`ZDҸUa>2'(}u k9@Sx@=i|=LFSj@>^GŊ_%Jļ%E^r}N2͗M3{sl)H-Guݔ3ss&OwZ{2_I7Si#?=jJpwکj2GF>'eb/vFF1|j\7uY"KG h^T2x2h+H$VIa/D1E&j2S H2rqSʚ&"mwbe4%̽ 1J/gfdWr|1gGD~!Tֿdi8,\ĎJe>;Y]V_ 3^U/^>`9ȁI)5+s/Ɯ!?FM"_IQ:B$vLYq+&fӓ ;5_L$3ꖱsDB|#x/O^,7Wdn+!?"4e)IQ9& <1#=xC24joe&$_2=H_>7|L?{>[zT xD4'!y6d:n_ȪxO4_7ӻ"!̾&W7chI~pi$pzi捖jgݸjw4i :V,KCH{,>>IӭqaV<>b>;Doh~:#Grl]&O3L6s?CǵZns:oDo|Gi g]v&+!G'>9q7$/rO* Efj'r|4.Ea 2q |f~74<#q敷ǐ*Xf?bCLx?V>׿6Իtܝ?OewrV",ef_wOSqƎrT\K#4E|4K5;?S[)D1R٠q}6NvsG/h)"nsn w}18grQrtUC&>iH o%oT!noגMWק7qz-gr:g7:ݫ }b?&QE>kLA~S5=#c%uD;`rc*i$%g}kl./n|cΗj>K6KWn}6ҵ&ݳa >ĉ[|K|=-Λ&B)̷%&Ӓ@c]7:jɿhSZ*$KG/IAL:>i!Z .> i@oM`q9X*J[ &,?{"ߘDU\{[ͽ1t9C\{|>(4EXy\)14B4 ok݉n;m 4ۧ)}KS\zlŲ3n\5yQOãMU]Qz>n6.+gAİ\>QhEkS?:ȧ(| հ9B#xIGkdy\5䣾Et:&I[GK{&>V1GfL[O[j~g,Ɍ}!?_Mg~&ΪК]!aVV/QPXr5qFcW}~#ߒf_>U/ﭲ" yOnȢ_ ;.-ϧl=o$iIođ}ѩs\=k͏"w֧זW| )"_akV-~E~\AA*4ľH?ϏGg,u>2hԓ(OD5_ZQ \94lewygK'O}_-U6Ԫ!8Sn~$"YW m%LW~XGBLBXY kfDVO^EJA@%@>.U" qbM#i"=u>_s FaxHOIk+Ai|@|Ͽ6@mD>>E-"ߩl'd[(hTa3ex06|G40_0nhtHt_Vn`XW=+64jbagL u-~K9鵗Fɯ.N}Fi7uqJYLΣs74} p}_0FAY6|2gk 98ʒVP>Vt|_2Sq~6\'M6܂U o/>ͦ"7x_DީL~K{NO秫UI}d7Q$,qge$jD9EZ@'yZ'E= $foL4ߦ%%+G}J>; %>9WC1xD3hN4<\H8F4̾!"^iy<\BGŊDF$5\W:Le{|Lޢ\9d RbqsLY>?)}_4$ƨܝj̑I狝`74Fny:?[|ɼ葎|gCN&j2W H2rq<7q'өmo_sOˋ쌾//#23d+is}]ɧnSGon0y}%}_ +ҕ'ljYLiq^0ꖱsoKq~# *S`$#ˆȽ؆8O`uJlLclz-4|ut|ɹnB=a7 >EΓ<6>̡=twC)WWWӆK#9SSg/o4WNx~Fg2Gk6i4+w/P$y 4'B\|ųJcEsՠ1?HKni489m6n&D2&4ɏǷ|cNb_?{EȘ&;QeXE+U楪/jcR٢ٯ^dh_7#~o|GjoyIeȘHRǧ;x+}_7;?S[[Vy~XR'd'S/!H[/fDqDM9|gF~Wi[칻[˜eRR4K$zQ SV77*h VRאO7ɷXX%?цBR?NLN',V{ON?|nۙԏ9橃wΪ꜐o~6M؜ؼ hoJ~ M?7j |㱆m*-yj>ĉ[|K|-Λ*-UM7J-|'K[[fFFrw1nܨo]Вow^xُ&%+#dJ@1!CG9**C%Ĩ?bTGJQ1*#F%Ĩ:??r>UD>#1LNqVdќg "7zrHxx.;|:&Me=1YLCP;M>8c|CH>xbZ7 ~9NU x5H|E>M4ߥe<5?5ׁ'!Ls|CoJ5?>Ze6U ϫȧ.<'߽Kf)_5 Kg#|^o}++zt}aJKnt;|yQf~r w,<ɍMuye͏?|EekzOY?5N~T9ZR~^ٜVo96zʥHM(-!#sY/nIyUM('?SV2K} x(u^3c~F[uvw|UKBG4}\LL.Y^+3Y(P宒ږbPiIRHR2⩠D$&oӴOYۗˬ.-!@y ΌnuU- sQ$ٯ2m}jϬIvS:!/q oU8#F%Ĩ?bTGA=`Q]%^o,*Pa:JXɏ/eg9]>תo%jb[(\Nֶ\WQ!RSvFo?-ۈsuZr[o\w)k46oEN3c~F[uvwFat}T[CFGߥЩZ+.n7v} xgR2ET%wau-! gĨ?bTGJa lP '?@l2~|Jո;֛]^w5.Ww5.Dk: ;3o`1dcH=ך׹O2n!Xӹ4GC=W䅽}%[cGe-ZEu=pa/,jϒYkX' {55l |LfFzDot73>(YMժ^';R+l•GO^Ȫg5@j5 /A~ Rɼ6׳ }{/T޻b HۺO GQ*n/l qf@~еyQt; ?L|S5_(:'$OoTlK=俸oE(-Ǔ)]/[h\(f,|o9G*?~H%wrŝ݂u@c3VB|DuWnK,\͚Džguy{k<.O?Q_;.4ɇ,{u{Džfzlw`#ϳnJ ]; n lP lP1 {c 2$ϕ/;68reޏ8cx0e>~P]߷@ B~CIl]6LJ}.:xCF7yPbe}% &_)"WR6!6Ųc|XC;q'Xr^3cOfQ;[#՚U$ߑz˲z>a'̘nd엶J |ЫP'}%&4;CMl@Vvx$*sn"6ͲR]\ IDATcKb\$aI"[psez|R\jEO\x{n Kڷ@ Wfv^VnN9tL}4Emj<ߧ2Aw#sڇ0-wU>omޱק,EW"ggG>gcmdKpMRYQw6*7>l.Lx/֪.geS^y>ZsxGCHO>C}'\&e71lη8hi<7w.ZU+1|q|}'?8 f[:=bTGJQ1*#F%Ĩ4޻l}'L@뵌k2)_>fnmɁ Qclo -)cY㽷NMd-e-o&'W~2-o(o㰡IJVw{ךdM&*BL?ToBPmB&me1q/CzN0"\I.3#Gr$qI>Ϛ볲grzs |c ~2}%֬"ԫXT {a%u 6XoePgx?zDc0mRdmn +{}<OF7| \fٳ%\q,I侒 |ZNv.q.&p [peeLH@|:>}g&5S|r|VoU>om޳ק,EWg2g1M6|U]*+]"?SF6g2m"܅ؘZUo _tRJ+Gˑbu.hH}g[#uF7Q6FG3a~2-ǹfGK}joE;֜/_85[4 ?^eз@ u2LjQ1*#F%Ĩ?bTG k9g~xS $#C9}~#n\d8 ?js?U G1n+$͏,E;k~`CMȏ /}@BqT`7?H>?xZ >U|fzP>?lq?D>A (C gm8A>YL+a :z/&yFJQ1*#F%Ĩ?bo9}rNvrJr$^Y|}9~fzwY}y؟|]r~/[΃DKJI'1 l|SCk2 txoϿ8Kd,p ^,߷ tRd7ѰXM0x=V NjDrXY&a8;Ù5F Sr$z4FMܡsxE}'yS"n3~O+巋i>>(_ɟOq2؇n``6 }y ?>HCAڨ_69_}&' ;!@wPfV]0 0V*"pNh0H~`3a73I߷ ?h }ȉ}rÆD`ڢ+L^3{:Aul6_6;ިPn&m3p9v r#qA6BǰXoÍS~/_3@ ,njZoB( &Ϝj?NKj:B>r] `g~8EAg bC?!ԱC$NКJ~7J/!u&#z@n `WlzhE6KKO%>F.* KP- {r#G Uз v׋{d~|%  8un~Ȝm`|8sރ;~+K*7Eq@ܯpUT~"0]& OضK)J$?>u<ٷ "`c"K4ݠH>rc~-(t1PApgk$?՚ ЁϠ9?^{b pRQW#PG0Hp$[`{0C4$brH+@!A2Q95PwAfGQP@nN)l<t&'護OgvHhD7 "Pl=o`ށłrz,V^)Ib1[-WE`tsl8%Z/Upo1r ؟Ka&t5Bӷp  c i-A =u빝#P"?%~4-DgKoqB qaO7;t@A砵t5jF?l;/5;i8hdCr$8R*}QB #`w` ~pN4>k^?`XLp&(nF@~C\FWhr`˃?!!m"\{og obFyR302&%zdHe)xb aw@ =zg`Q1HX-]LC{دlrY\}md`@ 7bsb?,) ~+ŭN&0,tbP7a~,}pX=Q ]j}7Sl>0?cCĚLzw4N/6zcP,|j#54 F}C"\Fu˔Qj}yז#=`E,LDžId``Dv6Q<` }`, +c`ܯ0[wovkٜ#N0{YCf xB7 nVx<7L8  := x(ŜNO8ng} &sx1@fy,qF|;ۭs+x ه\>;oNՇE'ss*]\Ӈd(|Xhp!48;HނGLp,p^1Ost= }h|i@x~!qϡnR^BG{hgJ~Gs^^Rv!rw3 8I> y|2Nabyxċ[p<9h\Zy1vxBӓ0y78S0rNQ g'"~1=8JD sV[dOplfZ4P 2* 7!##l7_ˆ0g`y0;;>x~;rQ- !|0&M*e` |/=9=YLJ}8Eszb:Ta2k B\ȇ *Tp06 rlqv4`a3䬾䗀0|_q#?Df(PVRK/Cf=R0Nc6p.Y 鸜̾rs8UK0x㎠0-9 f=Yxz  >M[΃>GqxkD!8MQX@7[D>̣ bg<eؓļAwǽGܭqBjIP \w׿7+&|OgXHaY]`oH<A7a0 `_2ք7Gi14q.O78}!?*>2ѡϞP4f:!:|cNA OBgsB7s ad -ABď^|XCyF62Y\z ݶ=@gӬ|60ȋ`ܛC$g5(}vi*{ls:$=۷ >>HB.1F#'{ZtGp=YAaD<g4|PVOG~TQ{xF[΃ED>2/884jH5Ծ*mh:Lq|(-͹ _>}id1z{bA"=Ϗwl'fxՊAӑ= 9PF;|q9oV{x hT<p|3_h``&Nf?uWB~[WwdKL V1PHuݜz:ݚQ2#`gP; B+87 I:xj'p#(Or$|CCҗ y" -M8MxEJ̙ 8ڏ>eʪ__`l!KM#͗>wз bEqaŕ&2K"v_RݯV|uZMq/6%`q-jҎ&* m,^Kk%`p&IV A7;[gkj,3&@\5g\5Xδ~ߘL(Җ31q!j]O2\Һaq[uAN8x>pu2LjQ1*#F%Ĩ?bTG Y{_t>7;rtk_ҙ3p;[ EG&tCHY(>9Gcڒ 8'{syۺ"xotžΈ:O T>:ϓ6ȔzKW. |n$4"طY29|<;nUgG{]a>6k>5Fl} g#L<i>1Zc]2r t^|!k-wFdB;|I}h 3Wѻ՛{ (N?s+޾RD;6H g[] wo3%N[9.s:?{Ʊ7r1QU&-wF|jSK@̇c+@'LtkM0~c;#'_izrOL%]@>r-5+Kg䒥l}F:|gu6kWFw;|} 𝑙YR&Zv#DO[dxS>3M_4j`bf|ҐN%Qdqy]Jk#p 0ꌟc8ׯ4@>uM+3#IӜdFԜ6&wOI|IslW9vNj!_p{kIf?#^FS1.Z5MEw!r!*iC}AzR N}&'I8vy̯?~)-MSnɎ4LZS8)`Њu>k\_%15ѷF˚ ʚs8Η]M⨰"_]WX<tUki+W %9>M ]#B-2*6/yBOfLRу?U7%y@6}z l̼rq}䷯Յθۨ{I-wP ?|ѷ— =[ w篦+-wF$Y{7ϿQ_;(z;oF|gx-3& 缪 -wƋ(Qk[ hܼθXG|gGaѷ}s0;9} qFθÃ侒qo Tp K} qo~[[#} wDszYgSnk*} 𝡞7/&]<|ٷ$(z&{7&Cˮ-G}x/v,|6>:\zɵrN!K5S%.?5BUZ)js%~ܾ^V7lJ)"#O|g"!P7bTGJQ1*#F%ĨCr%z֦,ivğo! G%Ϧx|;[ E5kzF3<9{em#p6ֆ[syۺ"Z.n;#0?[Hzt$>O;Cd#E]F>^ it76"/j|jzo;#|?WNc|<;nUskj! ~L܃ j;#o#lwh>5gVǨky1J醌OG-wFdB;|.j`{{b ZH&՛{ (N?s+޾RD;6H -w.z\z;ѷQ-Vwq|g~k>!ŅPAWIW|ط:4NZ 5֬`H-wFNF垘"$KܻD+@os[@'ͷʒɺ_5OYK,@j99]hLm.E[M*g} QWgusZ?rn26J6|$_}gMQ} (UVѦn_k~r>eUH#aS/c)IsyE͚Õhxx1_G|gp=gph{ -:5C:2qdI&/fǦ  32R*_(['z#\ f^Q+3#IӼdFԜ6&wKIT/vFzctf){{kIf?#VFS1.hڅ,? IMnm1 aWy=^ߚQ6vy̯?WZ22#G:-B+׹qk:`4;oF|g.kT.>MspSyľ0zFVklpcߠ1h4!3}2S@&]3k4hJ9jƍ޾ &*NXSO=?E8'y!ކ-wF26ea\np5IPR{z +m%!γqIW|q _"PcӤ52jkiKuJ>')qUJL*ooRW6mJtV=B|g@mԽ;EO}1;CҾ@0L1zJz5-^znk_;#,jE(y|} K} 7wo3^΋|gs^;E(5-wyek[⨚5";oF|g"o3nrno3n ?s}D-&7FkBU5 f2F|g$ߛs=;9?@|g]5vE8]u\o3s%=u,>o?t5O=wd|gt;h^' o2:Rч‰igls.uk|\+T >U/X.]QSC s/~N*݀L!wm=&zV=>wߓ|܁8o_pզ& 1 蓲J ߃~4loCwiKZ~σ"؁=CMT5^I$=L!/C}CF7$_o_q܁?\6mKݖc."}~|m!ZlBa@&q{Hc9ͯ]TG_nڴv ^$2nK5iSSHw}vnѾ>/_깂|w)s}w!`ȿAg'FX'iF!4w/LxxbېujF&:Z{?wO%ZF<"m%e T'FߤsNa<Av7ꉞ{H۳G3TcY+5\(|stgxo.6O]{'i _4zn MmXz|diKppia 4s3m]u{Է"ߪsG1dϦMSF~~LS|{۳I\P'01ooo ͧ=^v(]3VoZsZϐ ~ƬJ+}^_TGJQ1*#F%Ĩ?bTGJQ1*#F%Ĩ?bTGJQ1*#F%Ĩ?bTGJQ1*#F%Ĩ?bTGJQ1*#F%ĨׁM/IENDB`grafx2_2.4+git20180105/share/grafx2/skins/font_Fun.png0000664000000000000000000000527213223665306020654 0ustar rootrootPNG  IHDR@ƒYPLTEmmm#tEXtSoftwareGrafx2SjZIDATxXr0$vIԙ;%Zdg >~+r}Ϋ\l ¾cnnƫ+ ,+%K+D8WufjϿ X1QcXY^a͈Z@;187&^J`NZ8ޖ@ї<0:IL?d' @ dȀYzC1p,xE FA fqwԃdDpOnT"jгS_J$(ߡsoo#Y3PTj Lnz!l1P3&>[~S&+LO7T[ ZaȍlJ @Lk4_)h\8 6%Ф ud"; 4|.Ly,ʼnWR)niЀʳZ!ܯv{}¿J \"7ys⥴Ȭ/*3.#@{yeu&Ӓ}TAiaϼ-q) THM <ICMZ8'dX"5$|>S2i!HJ%67FM3GH:#{0r|y3oq2ZL;P:dH\ԠdS5W\) |VtGlp% x 򍠚8/Q_Ksn$>A*(E5PJUJ@.//E&d8(jxa/H9A)QѽSd6@C^= `FW9a"653-"K PHSFTe L`d,fK&CAғ`$ 40 |o 0V g0Aɜ{ԃ?cU`1^__oIZ)箤E*hiPP-s| O6(N}W 9Xsa7yWĔ(w,77Q f)Ej,j \#-?j2P${BK*Ht w`biZqV!<Pk;94v&BA=}Yq?t ,}ր nv9/ͫ/DJڵ$N]6ezTlQsŁƂ>\/ 2?F)H6.(X;~~P>} l2G{ 'hy6P YX"Dmy&6y4ae"S5 ;=}YNej/XKڍRܵxRyǀY9YpS?yIcmK(fS7 jqAztc|rg7n~VEȸPAOGBUN~* L#@pc._6":܅?ƹq$jڂ)]83 I}c$`$(br@`DEv+4ٿ0O)[(\(p^@^3ff2PP4B2J͌^R#y8Ы\z!PS 3?^c*ڡ@Y:ZFu$dž+n2z!' Nsl[2 aߍi~{7ehO'׮ 8Q}?":tw><#_1 Z|q cEGq] Ǘ}I/OPlIENDB`grafx2_2.4+git20180105/share/grafx2/skins/font_DPaint.png0000664000000000000000000000514713223665306021304 0ustar rootrootPNG  IHDR@ƒYPLTEmmm:tEXtSoftwareGrafx2SjIDATxY' DɳAC4ڛ\:J%ѓ#[D`5i\nS?ʰᛛR*|m`}hRQxc"f_#}fo}"1rA_+H pG D4=7o6NO}kp3^R`⸌R X1MW at1 L~ԫ1HoA# g)RrSd*:0f UՕBb;{u (h Lѻ[Ry;dOO~dJz)܁oӁFPq4`8C&g CE;l{-G @-DldS]=452*ΡDbQAчΝSVƄ 1?io=eRu46ArNx0r;]l)F+7\(/ ;[ypm ʁr9:W %/\ v_Bqohr0RD+PZ FE` Nbgjm?|P yOމ<:gVwZ[en03d)_uX#h #k<)ư0WZ+XϪm)m/BݑRA!X pZ/BGj7 mW 6Km5cy/I{DlANm|iʀ\K1W+ "3%^Հ>b{wV6F2jjxP>Ͻk/6؜/oj9CƽХ |@h CEzELs.YEOWZ-3Yjrb($J P*Bjo ~V`1jjfUHOC?c T^';R=eĀ ;<D 0.g<>Jms0>}q?Tv lV .csV?/DrJFNy' kFǗ(rYԞ,57*39UXІrXjrr .Zы'u|2LP\6hC={Iu_Ͷ3vu8apU)I`Q|i^I80HXU {qI+O_bf] 9u!j,>j5jK~{-MM$p;!' :.%/6r9ЄfBYQQ^ܲ}7;cmU8ɃS3𰾐;;~Փ_(lp wiXD@*,d νK1'ZL|hrv `p  }hW0u5pkÀg [_Itń{;yb ^Ԁk|J~$||}O70Rk<3o>jk\ugw ]M2ւSdfsM9tN]\jE*g-n"|j$a}ksVp52K̂ }y}3ĠkG)*AAGZ{5`ۏCyr@< ϯ[|o=̑MIENDB`grafx2_2.4+git20180105/share/grafx2/skins/skin_Aurora.png0000664000000000000000000006644113223665306021360 0ustar rootrootPNG  IHDRN:PLTE"""333DDDUUUfffwww???????????K}ȼ˪~n~n`i_xrЊt}몌ȯW;;sAFP2#P7;W;PdP;sIWWssdǏآʫŇP}_iF-##AF;ssdǫ㨹܏WWs;Ws-;;;WIIsWWsnvvʏǫǏWsWW;s<#wBٞRRdGz;QM7͊Z|U;_ê~ۑ#-,Y)&-R$ܗ.#_M>t¿ٸ͜} dNDa__da@҄/% RB\{¡%#Qq޽p OsEnNsn8 [${B>VmYH&5h[H_ʄɇʷ{ z?|rhwN Dl|},K~f3Vi *T2Qkr$-MX5@&5`RWLjBB-^4Yu 'X)\la_#ttw,Nݐ36! nNsnXYP.9D-^f?mRň|`4 59knv?·iU$sx!?>*[-s5cΈBRnY}{1T5'j)0a~3{o%~^QpӘKЦ L|~ Sh s['~7 0 kNZtZ>zXCfBXOnDY.Eāyl-|9 ˞×JBs4c,Ku8Z/Afp!𠴕hd`X1:W$_Z~|;jEnV0?9ā/0 ‡bWÇ%4Y&(5~LalTnAVC47&VܽC?t²&~YhM;75{ihX3}CBWASeZ )9| uƇ[HITZ߹{~feP-|7 0U6[爡JvZ‹~xXg"L4؄Ee`&O9(R!п$ lb;(R7>uޡYacF2}@˯f<1D)P >?J=!xHNK2| a61ȘI Y>{~f{2Nw@Jf0e5;OJ+nNIH|^@mcB׾b؉4N͆ ]JwGL% X>ޛ"0BEf6iH?MF>Quni/ n#U<-vo3Rn.0! ѪB5Qm W꾂ewz㚙SĜ@(c5X9$iلba;۫'sdfSMP = Lj*{_oh2Gb,pd%4U=;{ o"ڣJ?8sŏljI;*c3bv Mx4Sۃn;ysp|3~Iu*7=q;o̕@pVqv|Y΀6j-;n4/PA]f\ɌQ (=&:\0CʄI+,}X& b3M#Z֣B&H=`D@Tq$^ ЕA],xJU*Oo v$%AoS,_:3`ؙC.dT.ł m@A|C.s˧:abKwtGl-cpa&[Q+qŋ#3^%XD]u%|,|C/+U%ۇPo /}Y>f-$>|z?B}3h(#lÇh31Oy;N!uO0 /1NH2lG>Dc G$7ShwWo}“'4^B협gf^ ؜FcSPydSg!FT8ٶjd2OEim՞ K)l"ęD14&3ŝR]Fs,?MaP2>o`ThqR7m7n'Ϸ3W {#|?EtKƏ?oN 2BsuQ {Rw"{*\g*|9ɂl.yo‹H@GFS|JmO i&S/-ߌK(ex0) 0# LVJ ք0 /1o3 փ&kUiEDhydpjf=47xge0'a/OsU>M%.^4indvdpZ~)pZf:K9 mwW],Fs(蒍4ReVY0HyE]^\E8BV%=U a*N&avmȼ Л̨0ǰPZ`*UV"'Ɓ=/v@_4 cuJƖ~i(mOshDwta xL VZ`*3?oY$.-;y}ƌ=m{Sد2}J6,?QԽ OI(.jwz`9l!ذaiF3|#F1rQFO|ⓟ>Ozg>3/g\pZh^dE]t[l_b%\r}sK-K/=t෾>;B ~=|8QwQ*uPtzzޚ̈J`jwCuPt*43Υ)" %_ؙ|y(PD,?e]v[~WXa/| +/}K+җW^yUVYuU򕯬j_WW_}5Xc5=z1cz{{ǎ;nܸO0aĉ&M~pv,|gd\o̯ff_sr2C1E ʐHQd~@&.K̤VEAӟ>C=Пgv#8#:ꨣ>c9c;?N8O:餓O>SN={9s~_zꩧv駟_3կ~_zO%|G?&IRW&d1.tW<̳:>s=;Ͽ .‹.7oۋ/w%\r饗?.˯+򪫮ꫯ?O^{u]w؅_Z~KW6W&TUJQ4wono[on_rqwy]wuws={}w?>_׿o=?#<裏=??'x':}CN%.V UbESO=O_zg}{^|ŗ^z_~W^}^{_7|ͷz;>~G?.YX%.V 53Dn"=wtG{;JU[m~uJ]*^dEJTԕ*u _z- W^_ >GP#N; o/B [)Џp{>U|;x/NƗ/dK iZW45 jkKK1b6;#3> Ji78x ?JxPB끐/Xڤ@nJ5qjm.5|P>sEWYM-N ެ$iw{ A+۴*o~wk?j|:&j|E% g"FC̅|[cV@wk,Q!CH _j+Z7Hƒ X/W|ɧW1"`P.mY;O>Vu(]ҋ5^X~’MKo 駟2\xjQb?'jF//=wkj%%(I|[ ѓk_'8zyY~3(g]}.$go+^ܼĉNÖ,>M!2 U_x!z6҈^gKLTt!cK.| iL|`D ) *n ^ /‡v>oC]s5Ÿ9_H7}̻coS+Zw[S7KIޱā/ke|?|ˇk'zA&S-P]W5e=眳ϺD:u\݆Z@UVYW]uտ??7*s;xO_ӁKe>SZPl͍u C}_S/CUH=/R+hAO ˗wNy 1 m;u/~3gT G}n!YIN>C#u269%P ߻Uxՠg 8v@_Ã1Po`XA);F)=&G.S ?V_WTBs%k}v6s722Of_3^rH,3dj4 *p}~ Os0$ԑ ҹ\s /SU# Wb/hDW24(汗V[^/ilLzZ^;?qb3}kν馛)@ߍJ)sj Tͬ ̎k@ wj5PHÇ't7\|zS=y_2.3+C R>4@?Qi8'JSҒz\yo]7ݭ[ .+-)3cz5FQqb&oNW@tufwe sU!Ucҷ|,|1A dMڣl\O0ɤ{^p,˦/WJp n ìkzⵄQ>̬-1*57svcq&ӑű|:B}Lfo>-v 4K-z_{E3bYq N$SxkƗ.2䀄gXZd,!{ |V1d ;`/2 l=y@_CcUYɳԐacfAhO$< HN~8-ɳ--ȴc?z_.|_|eS4%XBQ`s_>WCZ><5 %L 0C0x){P3-j)7l<`Źz~8!O#Jj%> Jeր% ÷zMgX ~i&ӣ7N+5*ڏU9E۴y6Zz§_(/,!l|N=<"1qz2z:0M?FݧJۺ^2':KO᧺`h{Q)?\͋^ *a(}Pcq MHŬLXfDLMqB4i MUWae.4'.Y:ju]>{>*9}Zuc Բ5L/+|4P4g'NļL!W yJ̕w?MV} V{cW^y'PT~Ֆ]BOJ_r?쯿[SwqO~rf3-\X G'LUFi7 tpU~{-3a| 4+;G{zoDN+*?iR?(JvۭzG*5qǭ3fkA[ȣZU#ʛv&~gzM[/csK$ :y~B%>m'֣i\hPq 'OT<'L_e{`sS@dzv\=#7*^VcְI@Fv$&6ٵeHX~@x OГd~ԪiTE$ν=7q'|}܅A&)Pw됰[/mC}*d~U5c<^~8PV?Kk6۟,_NX ?e??_P h_sfZ6,JݻqL:}*^(-z6_n< :'ڽ\bz)4j>zcD_o~J?>_/]Ufa$[[mwӬ7Fꖅ_L"jQtt{-9XZ IDATLUz ]J9*.ٛ0v \+f/EO+㮞;:֎KͮoOҿ\˷L/nR#ĈΉb;?F ع> ]j|EÔVǬ?8sz_o0VC_ QY^0MlVY M[̺%L8Iه}H-4_Cɮ}QY=n21Z;. ߥCӿOgok]ȉ>쭤"|iq;=O]?15O;bg;9sj|yBn*ޠK۫kuKwYjolpeˆg\6\u?% N~{Z0R'>n _E6)95g-?y%Ŗo#uq\cZV@ 񛥨)z9|~z ]L=fb]9E:!Z!)]n״T}>J?OV̢-^;ߟpAa}+#`! {xjmM%}si+wm9W{Ϯn|:ك:??}5ҿb$@m5S\rN囟p]t+_e)08G]7 TW3<UW]5c @;j*dutW^SW~^>8Ntk2دy0 jcÕرWo~JsnZ ٧:&f?6|ǧuEѴ߫/H`ъ1ښ%~4'fӳYPOj!?X: SV{. MM7e៬Z~手S_uE: ;𢡊Cax*-9qT&AJzɠd! +/RUE{pi~sT?|Og,eIi}(*njRN*N՟0X0_V{. ?7P[iNi!C=餓RkG90MΌOEsiQu_0 jcEk=kJK4|CP*~y2>losyu;KQ}-89}1@g~pN`ϪnJJ)o~WIzݵ~?e,&N0=r.7K&wPV{(ZguVWk?!^m^O]x OX-Ln~Հ3s|QVkq&J--jk`EӺJhXq+f4 VR m1wKU:11OԖC?+R|(pD^|–䖈)50ioӼrsZJPZAE案Ԓ:~Z׋[V >K4*j 5 YSdm&iGVQ+k5?fw;y^J2S| XzhVF׆baU0EVt,/vMP~b`߾?Ջ6,lߒF[5]:Ԅ);7ȃtcI2D7Z2QV{DW:wm-a^+T4EtIqj 6?:\~}O"=x?F[m~uOS+Q^zm]F[m~ur-Ȏҫ[OMrp5>lS=pU[ ?;AQV{|rOgaE^˼W+dJ6;_A۶A3/p_lFi;pi~*l4򊼨;>_\yU>8Wx8Z.wgyD0r3]kwR=sjK/ǞSAMOMR.tIz9f]5g :+Ɨ/p Xbe]XdFsoqN%K+}}~:-_.R\J34@\ЇǂZFoE bz.'ʺ$W^%+XօWcCq,j&|\Qwzo_2O=UWk[˟26?nP-_rJ7]z kP\Ҽu \d˜Drj.|# Cv~fQWJ߸q`cP&Zp^Fss 3*ٕ9o˕{ \̈́>AqgtGt{6dF >3~?aП?'Ej|\ؼc^QknZw~Yw6)ę0 7#wUZ9g]p_a1a_sO8q$?%\M?W,^qHB43fLfDz*ɫ&.'O/ǕI🌞;n|ӦMc.`?u*?4@?瑾b꫟}yo׷4<%jq\uJKFM?Bȳ|WS[n@{?o=Z;d*Sqe=~~%{|_ 6qs9yY4rM *p͏FMx>c縇._y*p͏W 1E+QmlTY#6CwR~[m~uV/7oH^\}(^W EWLS6Bv]ޜl }M>o(Z,U|q@_70@6ߌ[BvJVX~KMR4b7&O0øY>ןYˏGM|tYV"f~x*Prߪ\>$󞫉k=k:~_y%_;Z{{~Q1<) F^9f]x|fA.Ԡqc˺'1YPT0-ҿrKf-?1Cqb%XH>6ו1<@lxjX(nE- CZ!weg&^vY&pO8|J7. yz?c7i7s pjl(1t |RYW\[n}XwkM?ky1fyU+s,c*ƞ *Cof o4 _al1/Ǩ57q;_<&8fCsYTR͖oTKrTPj TK\[:=o`Wx5սTRCis9X㹃F؋¿*9o,HygI}w5B}o_}9--kEJ)뮣ïy\gmK_$[noUJK_oU+//p͏Wޣ:ܿ]#-G?BSzmZ7YpGw/r^G6?pUp̶vw-4s=lu>臙=nኢ&Q`e*$zаOnn>Ʒ;+Z}ܹΞnZv~&:y9CԌangqTN26Ϲ2Vn3 V*4eM=̙G~Cuz뭰K|\/^y yŊ9f]YqIi"iI1 )o9ZL}i7ӷ[~}I%]d_Y{y. Mڤ@2epKj (.Qc 1tS~mgFM VX9 Ņ|!]N# fu㍵үxG;y΄w^^!|2wwjQ-v~ `YkNyΊ]HZ@g5m2|\rܤ2?ϺI!fvcϚ53\ﴓ?;k~]S,/ 4 _Ÿ0mhvv?vM;cZ$#e{  6Utt{du睚~33j.gӿUdX|2eCUR˝3˾mgv[?Y^*=*|^zK6>VVC96E r"˧ӿǦ}RxsϔբUW]u=>ҏvU~Ek(z7'B0&jG#cZ_mՌ+4Gt_ZO~K6?:\>|{oCx}c5? ?WP,)Ի(G ?;YOm>훲hp:GA<8CE_v|G}YDJmﻯoSoG(< F?{*!{ׇ(^pzJW[SO},MOhQjm0VM/m壞 ?~4#z(<9x"~U% Q É΁dGE/de~)ff|gWqLpU.K]_ ^xKqYwhvP)$XnձlBQ ٽ̹> S洘.Z&'QU_h@`mhg:5o_TC'H>N887+pԔ;yLȕÔ=ٞݣρF#` }lt≖~৚w`Y~&YҜ9ΞG@6|3)D|5T}l^;ˆc9DQj~8^T~?z 2d2{\*慣!*?F AM6EԺxav;fdGnAM/йo.Zn#5!uGEһGA0=Dh]wà:@_Syh? bZjA[ChTУ%AyT <.4RE#/E#ӯQQGkD(Jү4Ӟ!ߔ =GwDSxE_@ȧ?εobuO>S[ݚuw 7|FOhլ8";B@ī Y8,-Ճ;^ K'c:|a]$LtAKپZ \ z+IY$qSb-Sa~iJzYF*HNQͮ5!Y{5I IDAT9{Y¯O֞E}mǒn2{Y B TT| v/}SL?oԁSp[s"17oٴG=bEIlwrhִwl&n^a0-VGXeNKMIisRp~{Δ)b`5 > L5zdӜI؛b^.uL`PXleSsTH+pwؔ9ST RbڧRM;L֟S?WF3_F93P i k/-Xǖ v-UuOIm|@,{9Sއ6UzSӜ``j,tHlVR3\o3Pq3]@2+ j2`=]_ 㪺љwߔ]j*O6AڛO w؜~U~uO.j"Udi{ԍHg~~SNX)Mvlm<`|֛~9UM٩~vm@Q0nQ]]-jJK適QoMKK=/xTiObOM æ BZO{|ݢ[WmO9ګ޾VUTb(ȳvW_U/{*6{`P Žx[[ĈLMLC;vs2V5߀֍ ؆%z.4?RYO.mҧ9 ]k&1&Z~aD lV$DNʭ!uʥa+"VnLꓫw'z-)wց-;lv:5OS~^eK/"|mUY~b&m\$9ORf ak|tP|LpMXD7y7W9wwӽ`>O `_v/mDXd]I[§lgrrgXCaE|:5c!nL]6w齳wFZ~))d:4(">bn4Upkj1z9|c +(@/Ym=FNLC4%5vkłoλ~yS.$.!컃S0P{.@;@~$-?6s1g` ߲6vyO}t~lJ`,&x;|;Cz (՜~ FMK DC2<>,|Z>vYl60jA|.%eKf l}WWknjf\v40nʖdzu?f #ZYd-_ fӴ}[ף=ZKT]s-gQ mQ[7eT^~z#tmclZM󦰶Yw5yn^@Kzc7;/|J-S$؍$9X%.V UbX%.V UbE&nZg ln5:0PhK"&yb6~iT_EڀzV—P # |k ,VdE~+ {eav_*/ _Zdzv_*X{d%OK|_._o`:R@- "8Ɋx3NJSRUbX%.V UbXsJP ? C_Q}J@Z uE?j*jj?>@A{/P`xGAE@uԛTSi*rሽ;!qm[/^W TeQ{ Y?Rdٟ\} & ~-Q\k~} ?{' r\NSkq a$jOԎ{kbY k~$+%P-K{[Ab ~qtjf_>85?-E~?̾RWeUe?/5+e?Tbu=/>>KEÇ?a/,LKAklT? Op"cQ+(WG1<6E/u>%"~jOwtWes_{e&Z/'We'w?Z=_*{o#Ebe? K!E|qM 1ULkkM4QwGQщkMZ(b2H{.O5E5|q\b!%1be4_L%:wi`E.f;w~O:wN{e^%F/=z?3:ƠP bMV^ma~{$AyJЅх/զZvWf.}99?cƒ-f_F){ӧ_a4e~EL _pc֯o!%l>UdGp 1ƁYQC]&}.4o~6O9=,#rؗR-}>|ރ?s1g~>~H5Ggmb7 ϴR.>?EؗC8;O+wzv|~ @SRz_hͶ݈g}*in5A;;"CqT)@w̻ EY _|г_dIM](  ?~aՖ.|7w:ȅ ?0|އ_} ? e4{e.|ރ ?> ߲3r##pYC _{. |8|?\ޤ5֘4yҘ'M%)/o0 j2. o~S*OL# @8G#9c^fbxt@1o򤉓c_{ϲg-|~TXJgau_??VMW*T7uӊ!OJ4j{0|T ? n[V!~e~ ?$9VoVAY=¿_OO?>G0vĨ~H?O *|([+}qcF?D K+-.9 t.>h㯡"qf6O@mp'왙J;f!w9inKd(-&`O*U8< oW9߯JO>vqcMNp?|t ? |~]yPG-<3QOمa?Z?LO?s{ ǂk„ ǞSɇo{/_ 3=hqXǎӖ?~{q~P|ޅ[xgg=2?GњKWX^ XsMJ$L,!+:G8}p2v:?~~H|=KŸ g.<*<P˾ޱ}Ҷ3ҠJq.{C_z|͞ÿɃ?s# < ;i} ?$p^Em K37yG0{PglPg_)%.;ƨo6n hKT- y.\wap.8g4 E ~`OL>t(ߏeW~sޱ֨}…O}3 .<>Lx.|>2/ŵP ؅?C Q.{ ?}φC=}<*'y~H5¿Pt[.|w[.{R~>{~,]w}HS}SL_s_%j/#H 7۟2gQkocgȿ ???boJcL!GYU|Ş9|͚9ux~%1Nx]zz`6ѳF ?Zk ÞÞ3+gq3e>^mcK!/د!6.Qoe@o!+%xaeW(#-K!Eku;q?NډHc_3~|"I2xiRSR$T/cSˮl*Vj|s1d<'{b^cL\U9f8gne.V| c-)Au=L>X&d&iwv\ccҭ1 n<^: ˏݼ~5lowvKcc1늳y/M9..Y,<68|&Iŀd*|%֝[mf-εxlY^&olw ;QoDSK*a4%̗N6ĦO[o{;Hy#UG{MF[UANVvG`'+llڅɭm ʯUI=uF;P! })쨁NctJ*G+FQ~iGj4iM0}7 5CQ,Aظ'k:[6!^2'*v2o>eNߛ'MYhMPh R$;~Yre?!kJ{`$ ~bSdm~~mLjt#XLɊL=J96vN/c&lSҔ&fTgw{㬭r+ʹ󙹛 YN 3ݻ:Ko\ge5qa|S? ?P)lK?*QdPo2oBj`_])*">>pW}R@ ;1f~oq)g$$e VlOVP.tNn0R.2}$KT)K G}؜Xvf8q#Hc 2yNl$v5Z,/؜ȶ zX6T>Ż36%)CJ(8@I5iBIlvG`'˅Ϭ11v.ݚC쥓@L.,_B;Z~ V=KoD򥱱uYWyO[+8|&Iok mIDATd*|SGsm_\'e>e"dZ>z,ASp|Az1Ɯ{pW i|W(e~Ө*4({ h>*bE]r3n:Oq55h퟇L  })쨁Nߠ"ޮKh [z%麽+045ymz 4Z`95C[K3d3@ &XD/Ifl)" Ǽf[hMPh !piݕږ-{h|;y'/ƕP`o'qb x;JMP'~o+df[G3 ǎ1Q>Miz0a ~˳UNV;;Y.;f8o_.DpɊ +MŚziDb*3G1 m1k32iپiSRIxWL"3}·>?4;ykݻC;;Ymj8Y?&qyN[,3Mm;ߐh޾'cí4gn2pgslǬ{Wl[%ML%slm]2NaGfHkP-UmM=p?;rO5L)kP|3TQ ~d'IN֩Bsiɾ-V#<d&VUNVD)O`"ʧvG`'閏;@Uz_#UvJ]oqd;jwv[VlwvVyl=.`/!X%.V=k_NVei;mP#U4Ⱦ߀hS?e;0TZ~2[7xsjW#U_ ;;YSҚK;sJiErʿ_iwv"G9/{3zIZI5$Og!J>,Gr0u&fI TN2iߨ"'Dd}!IZ!tV^-㮲Ev\"-. IT9WeW (-8?O(/h0/(/ʃD>NV]!/7P}*wJ]~*wJ]~+SCF1,eC}|?}'\KCWJ/b1t!o{Ͷ$4"Pc gK%Qwh GCOy4"|,r) d|;gD a6{L fi4)O|Y |e۠i 2?w n[DAe*ݚ٦ MF|Op #m39>#3glbZINp!˯(΀ϑ$ٲ9/ ^%Yy!h7Ql D蛫Ր ?k%iH ؖ!:`Zgbno#N%+d!Jui^\擵|AҸuV8Ak_jpUb 1xxf*vh<@'gjA&]י? ձ~`C#*S|wv~+jw uD@ʼn",aȆ,M5d'vt {~ELk07X[UkXDQ)7_SBv 2z>mOmָRu[^᏷zXv?RpMx]ſ6q=K?dehZ?|}>jir=JQer6T)4u~>]y*+?NqH6V $h}j14lأ_/jshUmg*/] (^|r h2hhRqkiC>n 6ۣ>hb Ϭ3YP7Kw/xo‡++>//E 5O4 X6iMG3bnh]VُjYۆ)@;G>)5$Y=7*.$vk/7؛>d[AUUo_zpp;O-@uݗ~23VQ+UIJèraI4'Gg&ܱrNZ[#is)j~TznT~78z ]7|g#Ϳ<ԓ,k;OcMoo7?<}Q#N7$q&RgUitX #| 3cY.T|^XBĹZjauWsW՞q >ig{ߪg]ih](6~3/.5bNY5O QIYa~|mi )uڬvOMqTaV~^i>)0Ng; ?k{l)Tw5J0j~F Wlu҄7< >$Z .]!ՅȊĶ#;U<?Y;k&sU{aԷ~v?ꓶ_FrdldvG|ən:;ԗFy A52n"}~ =~a5|إ}>\hBkzD/i/z0|ô%s>VU+MGsn3'f!q(*jxANWԋ6y}gjq"JQK1q-fI S^8)?V lc?S]BZ (ǹ>iY$a>OcvO: mWx/cnmIIj))MeqNڏSD#ń6J8z|Bg oړ^/Wޮp'Y@@#}WSS}&| ''ӄg~IMRӮD<&k#h_!B I3F{ 4Է+K'oq7#|KUĈDOe4w0۔ۧ>;vL41s ߊiSAF? )E$X SoG ~6S<Xmy2\ ($\a[^HOOF]V4neO=S/>QA72qT.Z6+RÏYCI^sg7ۗ2T.{ǟVVcg qyPy6ȴ5ˊqe߯ ·1=bWVFē/nMx.ë51; ):J$֍,h ѝ`ѹneEt!D3ӫ)A6C4+8#K蝆n$P+_qa6ww'n\04K:v\B~>cҜqs(~j򿾫_iNX0v'}]JCxLzGx'="ei ˷,˪(Mz!&|S5ץ ;ReF,΢EKUS:4_Iefjko"5/.x>) Œg~hjoJ Xqڌ[f%vyZnϊߝkG| NKU[r5|'Q\7<5fkoz@ m֓쳄P:a?Xx.~$~|fNzG&bVU?hBYF?/{/-3|Fh|s21|Uܝߥ뉾ƚu=bg7NMWoJ#..7Υ~[*7O; ᛪ%)h; &L_z4.w|_5r)W}~>.ѡ|g/Ӎ^]ry˼}o_N96NIߒo8j~K^+չxj~Kk @cn?j~KހFԓ/oB"XWߗU7$N 0Ps$>} @~2G?}U RX*K?`,T RX*^;WS{=-g .(Ug2jHaȞ%?c䔮 ~[R/Tխe{tM,7u2һx|5i9 ڹp\;<4M5M)gҬ]Xɔk|o3||< %^{Cȡ ҌH5'B~23V>u$bQME /ޅIMn=q5'ǵGNht" t |M@ e_C\ ?/:~z0l>'MD i6pkXV33;Q2hKH[ |e@7c,w(4.]~f|',A4{<| W1s.w]{_UU>}k8`N/<0/AE~wn뀯s5{ -w%%Tq *һM}$gPT'hR3AMٰ5QLjo$ƴ1_5hSՑ>>PG~e[+k{8s^î?X[I5_QO}aԷ~m9Z)9%g0cqw+'>&`:^S͇]Å] 7'tbNuj?ͦ> GÒ^bS(Jq^ ׃G/+ëۦᘸwt2dllՅJZ#`>8'p<7B$ilҐ.?e ~t ]LGf\.Lqz2G m2$6 .Z r<]}^/Ww+#R7Vl^MM1ߛ؋.BxJEނn5RĹd߼]J#}*c򨸲#i0|#}>B O^"8 Kgsw9|50m}WBo375|܍dfRnjb|}_qko_xMč)] bh紊ُ+O+Ad5̾KW9gŹZ7 >3n\B2n>աOIc.+RÏYCI38['9}6j glXRYb`*rb/D 2292ΥSKln8FHa^,'XR|.+nĕ}W2|*? qp_YSOO;5TG5_6)>zR|LhB*ɓX7-:Dm~:D:ӻ_F:х0O] /w|NYw*nOD_mcS݀< ) _ϻ[ڂ2mօ6¥}KR|{>LNhOh~*`_.%oǔ܅}~6:Ԃ>?j%{^~PC^E.^J߯ ߀QonRߔ:7`i?˪}FWP$N 0wPs$>} @~2G?}U RX*K?`,T RX*(󧹜ǪQ@X>{6OsWyD8 0<â1<𬼖;uJ~~!|Ok+ߔb.+KB𭆏wך muӭ1k>4m'8e٣ |6j>Nȿ{yC݋~ݯpٯK2"_;L ]Z{YyLmd4K[>{??M|G; |yDK_ /}'-7oiw ~z2 r!b>ZU%9|zv{M)W촽{}my8C RX*K?`,T 2:j+e26m ~f{*K7q[Zr^bm6T؂@W|^b6Y៖Q|_k[߹Z^76.qFR2rS[/ xFtt˫6e+Yw?̘V]ǝJ4_mw?7uW.̚]}vkw?To2YU}K}W3KZ],5;`,T Eۙo ~f,##*R#c mi]϶lSe:~4m^iʬO˨L_k[lK/vXZ껂YFSA/ xFtt{b)]*襾+gv: |UJtn+ٯ26wg$|c\̾+z,[껂Yxw,T RXM͢o ~fa֦CX2ڲ--|3⒵qYL۬^l̾+eT@BaKqv-YZHlj v-E6X껂Y BK[OۈSeRr-7{)k46 ~f)S*3i⶝h ~f󻴻:RkrAߥ. ~fKMX*K?`,9%uXRg[%~uXRg[%R(gK~>ސ)o}y:,nWO W7[Mag`Mس=՟MwEÒkjv]{|Q~h1rD&yfkVy ?>—hSTZb 碫:yXcVzzV!ޮk|6F/hݘLϔeQlvçE|#wSi;R*m5}e~􌴋Gk?ht@V5myU7_41Haymj+]9g 놟n;Q!TDw ?QR͏\TM` !#E5WLC:_OlK=ukHM~aS3^v0)m/OTdGQӅ^o|7"2|ӱcIjV)HP7;3_sJ ~zezO %Itq[%MeOI=n밤%Wty͓"zaI9oOq[%u~uXRg[%~uXRg[%KREHϿr}52I` ˗-Cb]J2+|n=]>. ˋ;rÎTcv|>xv\n?>5>^ڿ }% Ukq7LSmv(;(iRskwP覽ԲiB_IdK?`,T RXPl}J2qR@|2>k |޹wt/r| );rÎTcv|>G38LGy4;~ls< }%-}Mx22y4˖}dO M&|gq׾+d}װ_p Lo(հpghdҘhYӖW(#K!2|-:mv陽Of]LK|f__## jO\y#%:{ta:M 𯑑!MMMff9T4|6b1{Ok IDAT$'¿N"|h-[j~e2-o?jnC؋'nЧ}pH+G@;߲=?pq)GޥzO]$7K4%ӣ̸eXM|Huhg[y{4\| O ¿B.˒uJLfSnt:Іouc+kRޜ^>smwx,Ɗ+NT RX*K?`,eDSÓIHROM 2W ?Y}b-G*CFH-oሞZ— >> s@y(5}2I'9|#kO_zZo >̱>ߺWG|M _,UKߋHqh R< RX*K?`,ކ!}SK?|v!}SJ/??xa^̦d⨾)ҖpخS|9\~ξ)w?mY=XVa:b$tn]z~Ji?>>r@S3~k0B~8'f llA)v턍E]GҀ?L}R Fa1Q1VA__K Gy گ~Lt 3cE_? ? c0;F-!69XO>;n@ϦjKOߡT0*p%xDz~J16Qf1V7뿰{gl ?AB߳?.r+؍z1tKGŸ/6h秔G3F&v)΁{/;PC|:鿁cݮglf> }{է`8 Z⏓Q lﻞRF4js̖`F<'z) a'dxhv *t=| &0@t\.QgcBA6 Ɵ|1}Smǿm9'=8Bܫ fߙ}Ngz50<JnW+ vN|p u@C|.b K~Bx|V'dL=,A~YVjZPl-@Lxo;~oGYNv|\G9%[?vH?}- J߇.O`'ߓz~B(c'C$9Eǡ5 [FE|!< "+'nw}J"qG>F.P^p>t4WaGn>?x1|=ѫ 秔9E=_k-wbXtjvد_}Ssl}~ڄ/{JZPPŀ `g{"u,{ π{d &jV=?Pi@(A7=gkHhD7 " v{8|>[yrz,Z}N/U|$ q`~,-@CUb|nz gC=%p|P͖ zCX܀,"8 ;h6&H?KX.ɟ 7E8Hz~JAo?TGbaj5#G|]@X"hgwAG}[C Бo:z(? vfXn臏lABZ#&kv0렸Ы~khr`˃;"{jm΃=MA-f?!#rv@ !^`i>h=s蝁]G a95OB{-B_?  ht&ctV; ş4VҚ́)`I'S}-ˀ= 3ucrD n &?Mgj3[4IO\ĬJb `fH@g\wIaaL~|Aݐ_a)8Kۭ640l)Ö}O:lZN`k =xK(~=BSUn 6y9 B߿4[F&X"aeC ^,Pp;r _/mfc08"q]$.p/ .}ч)`mf9U` & ZMpSr{\.\t{<o<6`rn㇜u?t:) | ̦o}/=G|d1f6~ Ŋf|-g0L5^l z! ~x؅Mr1[ȿ';@b5O Tj:? [-g373E t;ݭv A1wIh_0Rro;C0~ZA0&YG6f B4:}SÅ׻! ` E8ŗ)Ԭ秔Q0A͌8~őwB \Ocl>&¤z`20 0";(.P>o@},>xorǟݛs p-+,O35\ Ow=??h.x9ίx1c^sE?Ym~1;lph z y ahEC൯bC[,-'-.V[a?w?hi_r NwO}| ~npr8f5&8uz:1Pj-9pL'I4 &s'` <8#cnˏy|=k!VfA0Ç[t9F~p.wp k^mV-@;D8Tg x1 gxK4CgmwѸpp ܇v0[Vk688/vk 1=7-S 9 ?B+`(ÜW]8Xlqg8ABo 7u=_ny^0|)C'm8G= =rOBB(vc1%'` Ft1 ]~\OQbZ  ߃S0 TS C_ a@\@!lb:2!.>>]Lj7_ |+Ap-p<-t܄`>9L2WeA< 7\?9=YLJ}V8=E3b2Ta2+L^!jm&av B1 П=@-g@ FkFrVS+ =N{(E@j2=@q9da1ř}zೄ`>Bc1AaZ c[8% j21X?p ?E4z~J:>B>Z i"024NHk};A6Lk= M n{mg-tH30 R!9Y ̦/e6\s:=]o C0{g IX$3T5&{臆iNGL#:6ON;,k䑠{ BhI^juH?Ɓ=p0C"~s>=aСShz?diCt6cN/=׃k2y 4{ ?#o*)D8|Vq[dYʫSs1Ƃtۂ"1ϲY-a` Jгn*{grt}'؞ɇR,0wl{U̩Q|qyt&r;J@H cE !dn^ ЌY1,8OZ ~R|J]T_ݲDnŻp$|+O7НsX4Ρ_ߢO<G4P'UQ=\"g}]O)#z0ݱD}d.H)(ᆍNGznCOiCӱ.| \/Oz_z_l0{O0 ;?k%#UOČ7:Ѓ8ߊcL!m\t]@5i~~``EƙS@~%{ǿ:oS``2Fow<@IT [?q6ۭ&ۖ ?ؙGcj6b:(>@a ~ݍ? ]O)@yXzەhlo#q C?~X-f2Y ~ CfzCT_7 O~cHwz~Jqbua'5\ӝE?9[.L%ӳD[|JkI>4}p 8:Wᣵ~W0bcDӷ߽mo=?M &<ħfg|B[W?GϏք|qn] ~O'_QUZ7,~ƿxsNylowI("($b]wUb 9秔[^r *{j1 |hss}y~ }Sޱso^;zVӁ vsw=?ԗ*X*K?`,T 2VOT?|c͟ ,+O,#}}ɨ+=628[Fc%?oЯK4Ai 4~/6=ZVN==~\]/'u`_-/}|yjhy>k}?Dϯqy|_GK5Yy>:cRX*K?`,T!qϓ\>Wo%dP>5'f |e%dIu!J߹^'l5%#+~V;g5y:#xmtƾ+E;O:ۀFviO >N[Cd%#uKdzF>>SӓF_WL ;k5~ן 5v ZE>unQEϓV\ ],>aQHY;4hdeuNG'ltA_Y_v/Z颂;Ua[ꗈU-C-PN[%#s}뒥}>lN: |eq}o+%ז8q)7%7 |e)WI^Z$b^&!iVZ 3`J],9|.=1$Km@.r.5 Kgܿ |e)Oo9Ku xȑNE[M*}W+K,պi͗cwiS02:5y!¿G:5I$ON -M mVDj$.䒥l}F:u |e9y47b?+ o |e:6_YF̺j7Z'PJ7j32.dI&/f' THՎG)i?i_68ZGh*3~?i6}꜂ Oq(5ElQR(k4#izFʱT#"gFΘdoh>t2ZϷy):h<*Qҭ,7Iګ6*'`%grVıc~ul~W2iCf[bģKDÁj2lZQg+wli],/ |etY3riG;w+vyľ+ehR.de+1S3Eđa̧($lLُX7)MN0Uq8R=z~h 8'y!ކ],hXqM4Hgk@V$qncoG|uvW%2o?%]Zڊ3| >ƥIa1k$\5QkiM~uI>_5|o׌)]j2zB=fͷWtzu4M#8?f8n>W],I8L>NW,| |e*],Ÿ;45g>QJϾ+5/ gkE5 |eC x}W+@^Wy}W+Ѹyh}W+Ku,' r ³+ FPWkq=# "5 ?`ϯ%Wz7?r_Y!}W+(/cuצ\)վ],)/ \IIك|Owٗg{xknpN7ZvNv,ݼ6޷os#9G/8gd9pEO &7WP5gewUpW?o_?Z9muٓ*QW>}W+Uq2'T RX*K?`$>~Na6ğk]NSL%Ww2 IDAToj;oů<̬69Ycp}!!|&O[[gOϥ ;\m"=JeiO >N[Cd%r6gCFDE!§p |e4VwIiLv ZE[LV[}-ç3kA!@@{4s|'0Zc]ƟMGW΋WOd|ڳ |e):|6j`{}b ZQztꗈU-C-PN[%WߢO"jAJs |eq}o+%ז8渌 5V''o?}wLR\Ha |z;ƾ$x@T@OdWڧ |e+mQm) yL^boim4߷ K'~{?i:U*.Yrr\hL}H&3q+ f'Zd}ڔ6|̾ }W+KSv 0lBK|!MdRpkP'-k^9y47b?+ o |exF{ݎktވ5:5C22qdI&/fǧ¿SF:F`FFmJg#poeT}{kqFO^?1XHu~BF( $q^/ژgBQT/vd#^Yfbν5p$CԠ0p~Kdj2Ϣ dt+7˾m}~^N*ZK[3.#]OSnbģKDÁsj\}ָr6 >yPFIWN5sy*&psbw&7}W+HHc-ynFQO2w+3dI=?&f0O7) 6u*ۖ|J-1*χxw[EUpt96>I[I:Z]qTXWg]"l\U8_{^0:×c|ӻFfT䚯jZ-|o|:D:TJRISeTx+::ȦTorE}[+JGr._Y񾙄}], 1| |eAI2)Ӵ֜Dsws^5Lm],uHwRX |ey8|K[0 |e=2CO7`-?TTk߿],Wέ]_Y+;8_Lo87j>:|\˥ |e/Fx],+$]'bN}Ug_YFK:&^]g}|mrzg S{],hӭxsLvopN7Zv^v,ݼ6޷os#9G/8gdypEO &7WP5gewUpW?o_?Z9muٓ*QW>}W+Uq2'T RX*K?`i%y nq9I$}k~2^]"<Ћ W_F9T#gcw/02~}JPtsr~}^F ַ4iOwh螛=iןP)tAkmL?FϪ?_l^ϏީOwI"AHm[+s<~IwmoI|57wH[ .ZZ>(+]RkG;Dͷ2t뻎?]?w`Ϣ&* `J<_AK`ƾ_?s`Rn2V^ _q{]ɱOy~4鐕ෝ6z*u[roy*GͷJ8') $>o*+yƴq6]f)@Mh]q}yƽ;]ibĩr.^9_iGyWTɉ*~iF4ެkd392뻾jFmekl,;OyXplm|?y? _άH ?3N6Z2iu67mu:e;|6̬t>شO4?԰54# +sqA鬌4P]F9?y i}v|ڞJ9 ÿP+6ʧ:UNg߱vk0ưg|Ͷ˾{A{| 'ie\qm8>y^ ēJ*|^RFҜ>ɹѾe_(NSi% 5SwN};}!^K+ dڴ Ui+y駮4u^:o_C\M ^yV$'Ly*õ׷*ͥ=7^v(]2Voҳ洶y<=fM,U RX*K?`,T RX*K?`,T RX*K?`,T RX*K?`,T RX*K?`,?0nU}IENDB`grafx2_2.4+git20180105/share/grafx2/skins/skin_Clax3.gif0000664000000000000000000005145213223665306021056 0ustar rootrootGIF89aTTTTTTTTTTTTT̼|||lll\\\LLL<<<,,, |l\L<, ||ll\\LL<<,, |l\L<, ||ll\\LL<<,, |l\L<, ̼||ll\\LL<<,,  00@@TTddttxhTD4$ 00@@TTddttxhTD4$ 00@@TTddttxhTD4$<\|`@ <\|`@ <\|`@ 褈|Ԍp̀dtXhL\@P4D(|8p,`P@ ||(||@||X||p||||||||||"""fffmmm! CRNG1.0Z /0?@OP_`op!, د~*"J pŋ3jȱǏ CIɓ(S\ɲ˗0crH` :(Qϟ@ JѣHh&N:!򤘴իXjuR~M>*g׳hӪ]˶m̯aB9ۻxW&ܦrKÈ8Đ#KL˘3k.ϠCMӨS^tIMV6o?̭ٽwp/佗ߖNzm·Cȳo&[~ݿ/!mŷ_~߀H`s`}|W ~V\6N?a"5ŏ0G}&g~ ېȢgmX"Sh!V֌xBS%J<]_,v*"ǃxP&MZ m4]d; i'ILk㝩(,{=oK>yGNf(S Yq`;v{H@cZP;5!tSIN6W xв>}+ OleU9ً~s"MR1ra.% 9W/7o~!'9y*{ĢC/wG-]Ӕ5@JHF`@=sx GO#_*4 fTkڢUXNv+^gruBU(zi)`c'DhYPg%0Yq6N]h3h9P(fᖷM(XZEcH)?+7cTH!Rh"]M/U{ܻhgA8(Ye"@ u1V_<8r,!I0+!B n( p< RG KJ5qhH0l)Ys;@nnӠg>8{N|?qYvebHSM~c19 : Ty 7i &3Ous@(_ю|IWDSS*S̜)΢z4>yF6ؚ8v\vZy.US45jrfhcҾ>_ݩZQCW)5m[± 5i[q +>7ٳسksA`ͺ.Y2Ll}#;EyUGZ\Ȼtbd.;#2/.kZWxI'XJ`Nwj^Gq_φRy6-&b_ats{ړ.*(̺rit5w-'8,Pcͩ(7Ar̂)PwNiG/+1Weho ŕocF۴PE`\+_\yKTzևߢx~ISac|(KohkL&ԯꝤw'&X'zgn;y$TjW#&%07y1'ngOyvR07x5_(*%^*16V,Vs4}Xp[8Y5ZX9Y?؃>(gfX\PR8TXPȄU\؅:]a]a8Zh)է^ /jkUehȆ%grzqP\U&~E5D@c.=7$}(:14%6EuWrmTu~iRfyh؇xg,JCREc(68fT_19Z؊Ƙ84*6Ȉ@h`xhH̸M/Ҹq}WxB؍؆p88TxSvw(xvYA8ZEu YؐfSe^xAUT UfqZ"IbYؑ,;Ə2_8N3^0h١0YyAAYr{h.J%h+6Ix}Ut [@Y33Dّ'R~DKk)’(Qtx>H:y <ճS$Egu09\HPBڴUMsZtL\ETYI~×(Y6v 8o?UHxL ‰( ZrlQÚoI%Yh7Dvi t{bfMLViKhxbǙɩh4JaYɌىnؔ4i2cbkQ ępTjkZiɖI@ i/$5  y!!ѕA)Nyox8øiI26(&Xqɢs ' 34 09tFٚJ9$i{͈gu:R:31z`zO¥5w"|Z(- +JL9b!sLz*9eY8 @NjZ7z!YI9j! !/[b"^v_g2Mӫ_ule@'A+ zغMDT&Ě: !h纮ʮ:Zzگ;[{ ۰ת[{!\5j# "رj±"K$i! )kc>wXHX84 W(s[A{J\13+ZH2U-RSDJ%+v:)uµO1ZpJthS9m:Mkea]j Zvjc=}S굎PfykCls n+X;s M=~n܇.n".ڧ}xn~Mck>ީLdLּ=ιjI}6<߫]×]Z> ޅl?R޷-Т?δ +n>_TK3M޺K;ΐ^a>J>]௜=>'΃<^G+nmMС%"?$ Oڣb,. q*{?<*HYֻ>M@oB}d%<1?A/f} ޜkhkڽi ng_Y 灏;?P䀯XyKw}7K 7߇4_҇k`elѨвo%Ql>-!?uec~z?81_反=O֒ !5ӑoߩ@unǭKo/$XP ?~\xCp D/&lq‰ +BR"?4rJcl&{9uOA%ZQI.eȐ&1N\xIUY*dX׏5M[rkG)nL ҭȈfs͌$W&\aBڵGee֥\AQ-{|jHkٮ|wjDtN&ˮ_.mܹuxĬʚ#cxBXGM:ussQna|BNyկ[.y٭ zobGyƜSmN . 30qhcB 3P) {& 3*,:L4 PTnsGpH"pA+3슓C?t (:$% L H6t1$L#&_NY CN8"T-Q9tQH*OeRL8%tS*N-ENHSUutZ2SZ?sUV`U]uW U5M^UvYfuYhvZgZ v[n_[pw\rrUw]vUlCrw^z7Ub^~o 6`׻}va9b3wT4c8C6dSVye[vecyfkfsyg{gzh6hVzivizj[s:맶Vk;&Zj 㖠~m;o[p>g»F"+ osn[[r]!Jܟ=sםa\/G=;A7)ԥw- \L&Vv_{r-zKԺ 7}lOj=G jԾ_[Ns^gnsC;OxcJwAЯ[sjd(3S'm{)B/oS?8<.x0C(uÛ]fx /$^?Xpo, @,*+| C٭Cbۣrw!4h%"r4\fG~ ߇7/;[$C3&|/l֘<um,b#)ƹ-ql C1tԝt81JQflw@H^oV'JBMsģ$O}K)0ֲ\%[i`nɺ$z;+bqw!b1}vF20ATHC4ҖC?+;rrz!}cJOL<{^!;i9bX٥@;IO,kLh.u ?^L6#1L]ʵT;iO}SUC%jQzT&UKejSTFUSP5~\[Y%WհkbYUnuhݖZVmp]%TUrqT1k_׋uS_ ÒExWr1]"8A^"f# ْj*ulGZ*wiYע%,l7ۮ`0w.h3;ָlq{nj9*,v r.Cz1!74)+a>}ms)ZJ-t ZWceȌ|˲ s `־o+wP"v0aޗ v.Y*m5aXyk/;O+N {+m;N&pekV˃rae/]3,f`ZQSl6f85os|g9Ug@ZЃ&|hD'ZыfthHGZғ UK2Ӛ޴:N1Ԙ޴KML:ը[:ְ^])=O˺ֹyQ^5_mYD4UN2BC9ԶA]mOtGnSܠ67Ei;*mmy{w]o3w]g:Qn ۜ6 n[ >qc!8-.~7r\;_\NSs{uNttzVAOz5p X tG|▸~t}ǧ^GFzOo_]7{ԯIC[>³Fԋ^rL׺#3=B6Çl^=GңNz^]Wk{zZ'~*'_g~|G_ӧ~۩c&=sK9h>ՏގLZ?,_W0~ ß\`܏ Ѡ,i\ ,1@[?Pc)!@h<  @ᨌ|@apB"$ l Aǰ" ', dALA`&(4B.4\B)ߨ@(,0T@ B|@B&<*TB-D:B lDx[NOĿP:RS:D0E_AWTXTY$[E\DAXa8>` FafEcZO$ :Иˌ5uRSjd]lQJ9,-Q<ͲOOBS1T?kՆsImJɶ. 0A 4T k⏼m̈/ipKn 0xy6[.,XN-vCHo8; K9B`@o9ƾMُ D\0i.pȋ ceQ v'vn*a ?n2-.]>qxR$pY&OBp. 8 C\p3rHgl3_ я5 /)Ao%C>qHPNsnms'1< 8/(qi?/D!Xv' W+@drnQ!((7O/־^1g\Ap%Xr<4umTWv_,r"-uʋ1dUOV'vv. bn# 4׸ nt 'tm6Cxm_Oڞv~3)]ŌEXa^l/y?yOy_yoyy? u{kc{Ȟl{FBzXyݑy̨_N1zyZky콫m=9 $oz-\c50=rsz+ ]Z>筲#ӊ.|91OBhZ]$|y|ӷr_}o}}؏}ٟ}گ}۟*b}f }?~ ~O~~ǀ~C\ Ȁ~/j~~~௖Հ ~o~~ ~,H„ 2l!Ĉ'Rh"ƌ7rx *X*Wl%̘2gҬ6hА@Kh(ҤJ2mj_ V@$ <+ذ^%`!tiܡgg:k.޼zjuWKjU,Ċ:1Y gvCr3ТGsu$ǀVz '3m =5L,A-un(۠4ҧu`…q/UC޻?FA7\@P/D&RUAفqa7!-YSq VA,Ae#iVE -A!w F?O<փ*V8ykfSq s@ҋYj%S'Xv :xf?5mN$q`*v ofT Tq9(RTYX;O?sҙsj "R%%Lq=6.8>^UN[t\{a&Agf'\z*վҲV5 bhj7#Zʷկ,DՑ_Ȭ]0;J_ʛ\zN|'{Joq9+ ,V>/)7NM# =[h4*$+<5NWjzaR!6|Q)!Xh5xl76q݆}w0i\H4p*sxV5{|-jc%,8AHfkJwf:9>Wt:)uAw1ȐG'2i=4{:'ap:8}d9Y!USKHcwR Lɓ!کC: i PLƯq y6L+bY&O? LS (oV)N@9P@BXwqAj0)fA aʽ!@!%`4~D3ChAa)K%gjkeF>)c -z&yaJj="F+k,@L ڄ\}+ĪnĈ~ĬBn),W{p(ƦhnlȎ,Ƅ)|^YK4Wܬ-&.-6>-FN-V^-fn-v?@؎ؖ-٦ٖ=ۆۺmپ---޶--@-DNJݪ&nފ->. >.6..m.*޺mzn炮芮貮6n-bnK厭j"mv..6omn&.m~TnZn/o/*Ʈ.Z22/.m bD쪯o/v//V/߭;cV0J-ݢ/o"n.-p"pnvpo gp n { ;q_R.Jo蘿/Ұ0J0jq'-Zqq1׮S1J/12 o q 1B72/ 2$$W2n%3.'!( Gq/2);22r1q&2r13-Ǟ'*).*O1(߱'q$+.8r7Gs7K5321/k1M6?q071g3t(11+1;p333??S:;0Aw".+xW_S:K>7{cs纈֫(}۷ww[y=_3x>昶ݧzo};o=׾o=}S~O7~7rC9f?>t{g_yA= 4xaB 6tbD)VxC~9vdH#I4yeJ+Qs_F3iִygNYhPCK4ziRK"_H-C{ rǬn(հ&v dSkٶutո/-+Qr*XS> -{{1ڻjٰYɁ/pEߖ6}uj"* 1͡_sŜ UGc;幹 ;Ruv۹898q!Wּưϋw=^Ž/xoYVݬ6 KovP0 8M$]|,؆ EF+<smG+6*h?#-*I7$C 2Ǥ$,\M$ɵӲ2|j;cj>G@P*<F}TD%@L5N==-=बTKUN%5U[UTUuVY]\ueR6X=wX$ YM}ڌ;[ݖ۠܃-tq ]pR)x}7ꠤ'y}VZoZY58փ&}߈}bO%#D5ڎE䒙6!EdS~G{lcmQdidTX`^^Z}~RGuYbNfA]ܭ ES^[-FZ(]Lg |P>1LvD \Uy ;Ϳ%7jչV :gp~U5M)RGcrٌ|2<+u[<@(ߜ=;gρ~\)3*~\#Ǜ4tЃ3:,$$a?:Q EH}0} aLАЅb\J Q1ShDh[!D? U'zɇbG[Wv;*[EZń|yF(-.^bXB=rEd XH.&R4bHI$ XDQ|#p^R-EJPq*D!3IGҎ`zDAZQA@pA9Q#sԡHù/جèL;~S̤)?´`,19n62O.0kt3f]ь?wP;Na"BiN~ .XņQ4EUqگ>MҚi.sS%gK?at!FZ1$OV.S)*ݙJ5$ Oω%45M#](#ʲ,C\D%83֥Fs;s͌P|ڳPB* ZNSh Ձ*I=VUwR;Ou8VPM'&jVj5I1[Zv@=j2{IE=U$-ll%%5k^oZ gZ˪Xԭ5gs]hVso}iI7dnUd6cKiƽ@W`ڭMyfVPl3WBUQe{IRL|*q|/;tM1Ml0SqC-1lҚԗE#1WE*Qj) ,(nXʔ*YT'kZn5L$}*Wo*U&n&]eY^% &8_.sJd.g<]U3zfz5Q,qy%{ ]hNVƵute֫ wx+H۞9P#p!K ^ӕµnwu ^YJ@:1nwP<)c:#piŬ=lwz ͉Zϵu|_?}Uh~ oM;]y??k6ulЂ?k~=Ьǖ pX؏ X$!w/5pguee%sEfV?QTp- kousqe'q.oj%%Ie0 pc^0,cTΈ"oP'0 E J IPSЫq" E7 dNȤKS -PO+#/vPmNO Z$pB.:ʑf1%HO ]Pq p0~} cQ^%QeP QQǑ(%BL01"g ,m_huoq1+Kܨ eqbD $ü,"33!9#+ O.2(lt",Z%Q&Nlօkf*>%I`Rr&=#hhocxe|Pl2%,c̼)\2eҟM+Pv)++K, )( I#I0+A2F2r$ҟ2)/111R ٱM2)L3-r%2S5" (SfS6k36oshsL^2'RB4 J8}s"r5 ~6+\S`s9;:)#;U3,<5y - 3s=0s;];s$-=<3'<4;Dž>,=ӚB12='M %3*B=1/C3*SCD =1t,貰8`T(F!R0sGR̓Y B:Yt%NIs 3 ?TJB%EHKQBETL4LK+BMitD3'SRLCsJ9sMjOt=, UDt]#s:FG,9|RtBߋo/QaQyR+S-POPSu@s[PU'RRIN11rSͪtUF5VtA3Xc,?T'5K!UQV%YW?uX5 Z; XUXU?MVsA&4X\;>:5L2_K?X51^CYf`$1] 8VǕA'Z Z{b_2]e_CG_V;;EPHo\ 3Og3WMl5c^,[A$sc3#MyIh&iSoZYi!)]B/{_V5gSZk?6V\ò)ctDcUVc4AStQla?4hW[-VjB]6vp-SE6\A6ggurasIVbVi"`evo Wldt\ vg74L`/rKtSwo+`%qdt5o%jUt6DIRMF)*4x7sA;W`3,Jlws56~vuh[wO neKVE6Ma)79w|3$ɶbS#mT_2Y3yztZfWhPC3AfGW`4R5"ltAUAxΝ\7WWFkewL/WQՅcX+ӑk؆osXw{؇X؈X؉X؊X؋Xǘ،Xd؍X瘎؎X؏Y ِ1% ;grafx2_2.4+git20180105/share/grafx2/skins/skin_classic.png0000664000000000000000000004176413223665306021551 0ustar rootrootPNG  IHDRN:PLTETTTTTTTTTTTTT̼|||lll\\\LLL<<<,,, |l\L<, ||ll\\LL<<,, |l\L<, ||ll\\LL<<,, |l\L<, ̼||ll\\LL<<,,  00@@TTddttxhTD4$ 00@@TTddttxhTD4$ 00@@TTddttxhTD4$<\|`@ <\|`@ <\|`@ 褈|Ԍp̀dtXhL\@P4D(|8p,`P@ ||(||@||X||p||||||||||||||"""WbzmmmqltEXtSoftwareGrafx2SjZcrNg /0?@OP_`op}* IDATx~6#>--M&K腤i.7G%0H%~eq IJyio_MTW ~j+V_W,UIխ :U*Ǵv8_WKsMo#u lni{Xq0eJ(#Is?$Ewr^a _m/L)_ʋWV+XWAu[DV7(yh{QF#.tCeTT5]$Os z kTar!A?4Ꮚ|pk?I;4ݒ!ظ^lp Q?&|L{!=R|3( l8;Ϸx'pK_ J{YfmW .{jV7u ^l5Bvv72cbs 5?q$nhx^lH϶|S^!R5oQ3` 8NER^l=|=x"J|oÏaꯈ; 7D!jdxf U(a)/qg{9hET[)H,p~G܌%Rs{(ǂP"e(sQ_̀/́+LaUlpB \9_:ȧi/Ŧ/8'z@D~&×栰(*cmVjP/m饹G`Yyw3x5h|z*'J͂/) #̒9큅A{$W(b WCw*b> pf:pCi{XqKzWs~ΏWI2aEMGhzC/L兪}L& ǐϡc?)MI Bޮ@߫(g1{9j¬j>*D OzKM|%KgX vdH2\'=\;lׇo9wCL7O>0#?Nj:PCO{%|QJ&u"KGFADfo$i#n(!GU_Vo|{) M ֵQifivIr|nQO2  =iV7*|Tb3t(;>&5<𠆆tckv~~54WAC?||S~B-߇O_2W |(u({ <|A䗔SK )5Ad͆뒄8Ӄ\z:tH={,5T3l#j?޲MT 5iN_a߃Re5O+}Ꮬtl ypVbc {$\O Kj(Z0N2H5~Ar:͆o7 ?ǤVJ!No Ӊ|kB~d,:>y!k7]S} GNbO {tq; _޻vD%`o+?xԧ9 Vt᫨^W=~çYx_)t{X>zr4Ȟ/T/́fAr:a?S8aW܌/v:4>.ts줄Oq$8E6|eNיִ;>-eo%6 ө Ψ^2=u[1%PAS7؂:VU?z\^Y/¾77ըy~ju~j~|E_|ۇ1=Ç4 h,0>-oV}Y[d/ GF~E49 f8=|.Y_wRy>ӄ|S /T/uC-;C~> e|^1PybK=fYOѧGX> *#iqα.^.*hOOS Ȣ:+#V`'CK꾬#7u^>49=yJ\B4l_{ ~hW|_SBW Ŝ+;>5h'Xke/AƓŬ?R&҇p5v-5Ĭn'h9Jqɚdm̈́q5Y[Ȟ*qa9aP~/cH|&ztl'O_V;Wu:hiCE2T+-4;9W|`נu| !B[4P1Ⱦ#Zu/(CUDp$aݭ19&*t;mM= wCV 3 s3h95GˇYo> Ş3yI9a oAӚz _FUжଚ{ι`Ğ<߻5"]W)zR&CUBC}kr]4OD\>@([_&6$C1s(+f8u>F??xHpf1Ue mR <GM|%Kg4+gwaS|8ᷡ"=ߏA?/qra{%|^)mu"oy,>ه(ì`xڈjg4cK|"1n|{ʸh"OsC_lFr$XP){>fiz7_V|`/S<+D3ʈ؀V7*xVKnɱ^Ç1D6Y3x:WD=lQqlYv2a?1QǷ _NO4b |Q#]#ƖOwe؏+-@c <;=<()d="^[?d);-mzW<,;#RRiUJ5*72M8K R24)e`7TJ# );?R>߸'/^C$SjOn R6F˓_RkP/Jvlo.I==ȕ_:xvM9RBX*m4/xV1v]K{/9u~I3c>8{+_VsSx>>5,y4׈)Uf|]bԠ(jxFZ*٦ˊ|kB>xZt|?2|+ S}XX*+ɜ[w>u 7?|OlS:z`SQ؇ӈԟOz Aq@xe UQ9JaO{|+En]O<_ydK ~"Lrތ1];_jCɤl_fDcf v E7UWay''[rakBvo[s lt NjN#`wlu.Vm`b!݊Wb5X ~j+V_W,eo;\*m%KE-p,0՚ `ʍKV˳hYqNw춅Eަi[N+ 2hВKo<2[XԼ-'D5TKs/8#ie`DTm(*ȥ^2=8 #ޝsY"Gzp,6կm[oQ4;_!NMYK֢2V,å^/{o*m%b5X ~j+V_'7̿^K d`#ņs]#v`/Gx*ym6+. ViZmKpZMElǕA㗇T _z[d,laQ6}`p+V`,~nzdϏIJ ywZlr^ihcYRi/Y H d5Tb5X ~j+֢`޴qZ)Ri/YTư ,w/6^R;ђ1l.6c@fs6CCe!db8c ,06E%m^2? 1vN:K ?|eB3#Jxʆ1w':n^6X*m%k( zh2(,m%kQ1JxZR] d5Tb5X ~j+mLjZhk]juzJ8j@i'VZ4n,?۠4k|5U)e;JlժܪW2K8W:7l_b+;jG۪zaCw>ZʼnO0 w5; VO1m[!І<~Wxo=-۟dq[U kdj5!K yqRƉ& XPޱ^7䊆 CgtUlhԥ)O H0xJˍ#3[Mتsһ/Dǭ4N/R\Vְݧ-qXVߎ-i[-)D,2P]^FM|([=|Oظw2u)uU;a.tIץ {Yf~u)0zw}R~ڨbgKYD'ZBok]>5/ ֺ󻤜j":ֺ7Qwg)֥o{ZZfMx[RmK+y^nߣ7GJGAhMeƗwoKtM o۰lL:=*>+=j>/C!˴ۿA$3. 73U£iDv o_*<^ŅǺہ5n/m5IQ?z pi٨පUh.hqݭ/m5Iq<`\HϖQ8q+*,WhY{ gwS~qd1V_ڠkBF‡b2~z>,{rE5`Dd5 V3Z3l}o+)m5ɇJE;2b{l V^`OՆ ԏ &x~CvYu0 ƒCatц r }?O.o7 ¾10P#:7X:Gx~{ӤlY{uKY7lϯ=TP~0e:k?CSunY ?F^> "rPh ['Y=70tx^d灾?|tvsikgh|:]ݿ$W%,XxL8ܶ;J/8/m5)q;W &Wb5X ~j+V_Y3Za!Tvٍ-O8Aפp¼}Oy8*50my&]"ij?G4އ-} ?,G£iDx'0o_T}1o!Ƀ3y~u)Fq9T}Q}QTb>_?_ڠk7C'9|ee1o?x" &ZV{*l ?^yjjAja_'a6ǺA$ 8/ .ϹoO?/s#arAv\m(\6 м}J$|C9eQz(R21|jмX+*<>FOu 'd `y}Eu|y9h>d떲>1OՌ'Ӽ}<O<ڞgS,G ~sMaF.eayK &:Y={t9LuO1_|?&gyxɜ_a!aB+N?%|35{!Yy|iIJkPxys/m5b5X ~j+V_W,7M͇T |E%}ʯ0MJoE ?߾7 ?1~@U Coj&f)bK{BYal9RwVKQ2AV:na_l;W-GׅrQ÷{a|aO(}MHGX*C2[.$;Կ¬>~Zo:@<> N%5Vb5X ~j+V_W[ ֫W7"uJ<LJۛv^NJxw^ /mEJmnN o;=JyR#U:t𯶙]JyRWۻ5{闶"Uח6.<_d+suvvS IDATH)eEWRnή8V΋rrәu@PWoUnZݱ?流:wwۍggnw^΋3_sbāۻ@ߗ})gW}Wt"DRտsKyA'xCQbG'qv^4כ |p_<x>;zBl$Hi>:{}?ww_3 1VOń[|-mE* k0}ᎀ6@wo6ߜyޏ,mE s킺ɕAg[ww Jjp߱tX΋YUCxꊀȻRQ8;OOnBZ{-6} CD(>6T`aWHKy<ێMG.n/obn7]Qvvyk;|x{ܧ~FCkwHI9C^\xR v]m;N Vuk7Rt?K5MYo|5ˣB?MddB>"|{gW__7͇ssB:(!S7>i٣2%w?Pڨ&r/6]$>п"b(> ^漣qln/y>\Rp}Xe!}|\v^z6f5]ޖzG7W~N绮"WU[p0?"{xuA<zy\Ht VF///owWn.n/D~mD=zr]yr&֙]}Sb%t=l7WoCzs& l$NUWƿPYWEhS||\pEn̾.-mE*57>cozOϮ;7/ʍPW_lx$f`At~ݸ.EMy__oWW]$#~\?Ti;/R;_C޷wnWS_}wJЗysIWHlbXO?;~.6A@=MG.mE*"?B_ w`s-g%?pZ.Qxt[sY$3 t!m4]΋T~LQnѭϟ?|{}V_l.C5 ^_\=B ;>*Lwȇp<۟?;Dž/W?OW ow]Ap<_חǮmv^&w7WygO.}|~<\ux?__~˗>~%}|< Ư_tGS@勋*/zqusӕ "5zѮ]kR߷g̓{@]s>>wKW]{i;/Rs2@$z_qoλORxdα .Iwދ_DP{$/O_Mh9IGO;gCR.OO_ݛ}x//+pm໺>sA(mE^ߞ`~y5o:NOO]]ٟڵ 'ԟ;P?x]J~uzQ=ïs.1f2C~ן߿=姯e};%,_w O/:_/D+w?~yX_;s~wYgea`B!lB8~/Jy34-7럞]#_d_|d'|wr$nB8~Ky~o]A{yJ%8ߕ3o{]CgΏ||q!_e` ?Xlq*m:X|iIf~ί 8!;o "w\ۼwEQ;/M3] C~|^(я&j>|Q|9 tqO>FC!x֑+~gWi;/Rjb'VQ+lvWOJEx;Ñc-X&5{ u>z~6@K'/3r*Z΋oWn>?Э~b|_s!}|To+\t |x"8XOFFPi;/Rolc!!\'_v#}h:Wo^zUu"')t W*'/b?"?C=W †5ͫHH5Tb5X ~j+V_oϯdoutӄ힆~ Fi[N=RW`^{b򦵂|| jȇ٫-{>F_Jp"!C$'?Fzs}5-\0y ᆔUڀk {`>+-9 8u2d>I14 ARsfr l3&Uڀklcza0{,2ļ 8ˌl픬HB6q; fN@ɛK=O+,eAG#YAz 6hM q9[}xq};eiYYo}PiYGu|6Y]튢5t^av5{xrFyx&YEKţC: 6Ck+?(uH7$Iϩ#&O\q-Fӌd d Oä+( f&xJpRߗ'yG?Nhr"x,%hn{q13,ғ#QNkg;yDgZfw߅lS4FaeW5I|CࡓG}PmBmF7}UziN3\1@yIaԽy{aMnΗmc:GvM҅"#Z,IB-Ҳch ꙗkvN~z!65Jp͚afv#o\fy1bO j4̙D]Jp͚eϙ\/F8Jp͊)9:צһJiYjp%>h6ڤ}؞ fusT^="#CkCE9E&*mKcK79\s#} \j1]0..{BR@U|^}\jzSC9@޴V Qw1܄!D= B  / f|þ3{~0cm?n_aS/<nH giYDB&|<0]0b:_CQ2dmt J}9Rgn6'.m5ksMt=UڀkQFb^ee 豲~yxkh"q;P9W.$t 9c R&t??ҙeOiY1|ፚęsMT@( 8:= ||C>EW×\rb\>".'E*gh\2XnF>qc9kt{AozSiYTGvA}uN$z1"2)aqs>-e\*m5 kdmCp+ƄNqCMVy2RQR(h=0b#-pmpTD2yzO> (S"-FӬd d *\qg_zE׬ViYJvD_2 -bI}nCWJƳhTXW AƱJ/Mi{&>(<)w&h,Ş/jX[Fe~~·C.](2|??$OW :5Mi14}'+rGes!65wl\dz*z ٴZ*52Qi[[z߾>SRk翍]9҆qsA+ 翭"Cۗ2Wa_3 5h,_Qۧ׬9v^b3?@xX ~j+V_Wb%&_,|}{9Ԭ>k=/ +_{y-=xst?/)N y ~uE>ƼLOן9tO8ޤ^g\\op򱇾F>us|N|@4(OgRrZVyPt}]xu/_ӺyJӽC}_>_e7@T1"ArX {1h>|~ 4Vx/7y*i?!O6:uK9, ||M4jiVf@s{Zۇ>^Y >xb&h㤍]_ߏqwޟF8|b{aV&vry,;~YX?~B?b<|#AcC{x}ty>%cwBy=ah(9y ݋o&jvꨞs 1K8a3޲3p5gZ q/'4ԡH3~/ᚵk`B1vۧ]fݎ?vxb{ t{1xҔzş5'}>!Z wEǬb_MeWb5X ~j+V_Wb5X ~j+V_Wb5X ~j+V_Wb5X ~j+V_Wb5Ѥ{IDATX ~j+V_?b1 `IENDB`grafx2_2.4+git20180105/share/grafx2/gfx2def.ini0000664000000000000000000005037513223665306017273 0ustar rootroot###### GrafX2 initialization file ###### Fichier d'initialisation de GrafX2 ## # # # # # You may modify this file with any # Vous pouvez modifier ce fichier avec # # standard ASCII text editor. # n'importe quel diteur de texte # # # ASCII standard. # # # # # Comments are preceded by ';' or # Les commentaires sont prcds par # # '#'. # ';' ou '#'. # # # # # Options are not case sensitive and # Les options ne sont pas sensibles # # spaces are ignored. # la casse et les espaces sont ignors.# # # # # You must not change the order of # Vous ne devez pas changer l'ordre # # the sections and their options. # des sections et de leurs options. # # You must not delete or put into # Vous ne devez pas effacer ou mettre # # comment any section nor option. # en commentaire une section ou option.# # # # # Each option is preceded by a # Chaque option est prcde par un # # comment which explains its meaning. # commentaire qui explique sa fonction.# # # # ############################################################################## [MOUSE] # [SOURIS] ; The sensitivity of the mouse can | La sensibilit de la souris peut ; take values from 1 to 4. The | prendre des valeurs de 1 4. Plus ; smaller values, the faster. | les valeurs sont petites, plus c'est ; This only takes effect in | rapide. Ce paramtrage n'est utilis ; fullscreen modes. | que dans les modes "plein cran". ; | X_sensitivity = 1 ; (default 1) Y_sensitivity = 1 ; (default 1) ; Unused setting, only kept for compatibility. X_correction_factor = 0 ; (default 0) Y_correction_factor = 0 ; (default 0) ; Aspect of the main cursor (cross) | Aspect du curseur principal (croix) ; 1: Solid | 1: Solide ; 2: Transparent | 2: Transparent ; 3: Thin (solid) | 3: Fin (solide) Cursor_aspect = 1 ; (default 1) [MENU] # [MENU] ; Colors of the menus (the black | Couleurs des menus (la couleur noire ; and the white colors cannot be | et la couleur blanche ne peuvent pas ; modified). | tre modifies). ; Values are in {Red,Green,Blue} | Les valeurs sont dans l'ordre {Rouge, ; order and are between 0 and 63. | Vert,Bleu} et vont de 0 63. Light_color = 42,42,42 ; (default 42,42,42) Dark_color = 27,27,27 ; (default 27,27,27) ; ; Light_color = 24,25,30 ; \_ Nightmare ; Dark_color = 13,14,19 ; / ; ; Light_color = 10,45,28 ; \_ Forest ; Dark_color = 5,27,12 ; / ; ; Light_color = 48,41,26 ; \_ Gold ; Dark_color = 26,22,15 ; / ; ; Light_color = 10,40,55 ; \_ Oceanic ; Dark_color = 10,20,32 ; / ; Aspect ratio and size of the | Proportion des menus et de la barre ; menus and the tool-bar. | d'outils. ; Possible values: | Valeurs possibles: ; 0: Do not adapt (pixels are not | 0: Ne pas adapter (les pixels ne sont ; stretched) | pas tirs) ; 1: Adapt the menus and the tool- | 1: Adapter les menus et la barre ; bar according to the resolution| d'outils suivant la rsolution ; 2: Slightly adapt the ratio of | 2: Adapter lgrement les proportions ; the menus and tool-bar | des menus et de la barre d'outils ; -1:Do not adapt (like 0) | -1:Ne pas adapter (comme 0) ; -2:Stretch by x2 maximum | -2:Etire au double de taille si possible ; -3:Stretch by x3 maximum | -3:Etire au triple de taille si possible ; -4:Stretch by x4 maximum | -3:Etire au quadruple de taille si ; | possible. Menu_ratio = -2 ; (default -2) [FILE_SELECTOR] # [SELECTEUR_DE_FICHIERS] ; Show hidden files and | Afficher les fichiers et rpertoires ; directories (values are 'yes' or | cachs (les valeurs sont 'yes' ou ; 'no'). | 'no'). Show_hidden_files = no ; (default 'no') Show_hidden_directories = no ; (default 'no') ; Delay before displaying a preview | Dlai avant d'afficher une preview ; in file-selectors (in 18.2th of | dans les slecteurs de fichiers (en ; second). Possible values range | 18.2mes de seconde) Les valeurs ; from 1 to 256. | possibles vont de 1 256. Preview_delay = 8 ; (default 8) ; Maximize the preview of the | Maximiser la preview des images pour ; pictures so that it is as big as | qu'elle soit aussi grande que ; possible. If you're not in the | possible. ; same resolution as the picture's | Si vous n'tes pas dans la mme rso- ; one, it can try to correct the | lution que celle de l'image, cela peut ; aspect ratio, but if the picture | essayer de corriger les proportions, ; does not fill the whole screen, | mais si l'image ne prend pas tout ; it can be worse. | l'cran, cela peut tre pire. Maximize_preview = no ; (default 'no') ; This option is used to place the | Cette option est utilise pour placer ; selection bar on a filename by | la barre de slection sur un nom de ; typing its first letters. | fichier en tapant ses 1res lettres. ; For example, if you want to find | Par exemple, si vous voulez trouver le ; the "PICTURE.PKM" in a directory | fichier "PICTURE.PKM" dans un rper- ; that also contains "PALETTE.PAL", | toire contenant galement le fichier ; you'll just have to type P and I. | "PALETTE.PAL", vous n'aurez qu' taper ; The different values of "FFF" | P puis I. ; indicate if you want to find the | Les different valeurs de "FFF" ; name in both files and directories| indiquent si vous voulez trouvez le nom ; or just in only one of these: | dans les fichiers ET les rpertoires ou ; 0: files and directories | simplement dans l'un OU l'autre. ; 1: files only | 0: fichiers et rpertoires ; 2: directories only | 1: fichiers seulement ; | 2: rpertoires seulement Find_file_fast = 0 ; (default 0) [LOADING] # [CHARGEMENT] ; Automatically set the resolution | Passer automatiquement dans la bonne ; when loading a picture. | rsolution lors du chargement d'une ; You should set this value to | image. ; 'yes' after disabling the video | Vous devriez dfinir cette option ; modes that are not supported by | 'yes' aprs avoir inhib les modes ; your video card or monitor. | vido qui ne sont pas supports par ; | votre matriel. Auto_set_resolution = no ; (default 'no') ; If the variable above is set to | Si la variable ci-dessus est 'yes', ; 'yes', this one tells if you want | celle-ci indique si vous voulez ; to set the resolution according | dfinir la rsolution suivant: ; to: | 1: les dimensions de "l'cran ; 1: the internal "original screen" | d'origine" internes l'image ; dimensions of the picture | 2: les vritables dimensions de ; 2: the actual dimensions of the | l'image ; picture | Set_resolution_according_to = 1 ; (default 1) ; If you load a picture with a | Si vous chargez une image ayant une ; palette of less than 256 colors, | palette de moins de 256 couleurs, ; this option defines if you want | cette option indique si vous souhaitez ; to clear the palette or to keep | effacer la palette ou bien conserver ; the colors of the previous | les couleurs de l'image prcdente qui ; picture that are over the number | se situent au-del du nombre de la ; of colors of the new picture. | nouvelle image. ; For example, if you load a | Par exemple, si vous chargez une image ; 32-color picture, the colors 32 | de 32 couleurs, les couleurs 32 255 ; to 255 will be set to black if | seront passes en noir si cette option ; this option is set to 'yes', or | est 'yes', ou bien elles resteront ; they will be kept unchanged if | inchanges si elle est 'no'. ; this option is set to 'no'. | Clear_palette = yes ; (default 'yes') [MISCELLANEOUS] # [DIVERS] ; Draw the limits of the picture. | Afficher les limites de l'image Draw_limits = yes ; (default 'yes') ; Adjust the brush grabbing in | Ajuster la capture de brosse en mode ; "grid" mode. | "grille". Adjust_brush_pick = yes ; (default 'yes') ; Coordinates: | Coordonnes: ; 1: Relative | 1: Relatives ; 2: Absolute | 2: Absolues Coordinates = 1 ; (default 1) ; Create a backup file when saving. | Crer un fichier backup lors des ; | sauvegardes. Backup = no ; (default 'no') ; Number of pages stored in memory | Nombre de pages stockes en mmoire ; for "undoing". | destines annuler les dernires ; Values are between 1 and 99. | modifications. Valeurs entre 1 et 99. Undo_pages = 20 ; (default 20) ; Speed of the scroll-bars (in VBLs | Vitesse des barre de dfilement (en ; waited) while clicking with the | VBLs attendus) lorsque l'un des ; left or right button of the mouse.| boutons de la souris est enfonc. ; Values can be between 1 and 255. | Les valeurs sont comprises entre 1 et ; The bigger values, the slower. | 255. Plus elles sont grandes, plus ; | c'est lent. Gauges_scrolling_speed_Left = 10 ; (default 10) Gauges_scrolling_speed_Right = 3 ; (default 3) ; Automatically save the configu- | Enregistre automatiquement la configu- ; ration when exiting the program. | ration lorsqu'on quitte le programme. Auto_save = yes ; (default 'yes') ; Maximum number of vertices used | Nombre maximum de vertex utiliss dans ; in filled polygons and polyforms, | les polygnes et polyformes pleins, et ; and lasso. Possible values range | le lasso. Les valeurs possibles vont ; from 2 to 16384. | de 2 16384. ; Each vertex takes 4 bytes. | Chaque vertex prend 4 octets. Vertices_per_polygon = 1024 ; (default 1024) ; Automatically zoom into the | Zoomer automatiquement la zone pointe ; pointed area when you press the | par la souris lorsque vous appuyez sur ; short-key of the Magnifier button | la touche de raccourci de la loupe. ; while being above the picture. | Fast_zoom = yes ; (default 'yes') ; Separate the colors in the tool- | Sparer les couleurs dans la barre ; bar by a black squaring. | d'outils par un quadrillage noir. Separate_colors = no ; (default 'no') ; Initial value of the feedback for | Valeur initiale du "feedback" pour les ; the drawing modes (cf. docs). | modes de dessin (cf. docs). FX_feedback = yes ; (default 'yes') ; When you reduce the palette or | Si vous rduisez la palette ou "zappez" ; "zap" some colors out of it, it is| quelques couleurs, il est possible ; possible that there are not enough| qu'il ne reste pas assez de couleurs ; colors left to draw the menus. | pour afficher les menus. Mettre cette ; Switching the following variable | variable 'yes' ramnera automatiquent ; on will bring back the colors of | les couleurs du menu s'il reste moins ; the menu if there are less than 4 | de 4 couleurs aprs une "rduction" ou ; colors left after "reducing" or | un "zapping". ; "zapping". | Safety_colors = yes ; (default 'yes') ; Display a message at startup | Afficher un message au dmarrage ; telling the version number of the | indiquant le numro de version du ; program. | programme. Opening_message = yes ; (default 'yes') ; Take the Stencil into account when| Prendre le Stencil en compte lorsqu'on ; clearing the image. | efface l'image. Clear_with_stencil = yes ; (default 'yes') ; Directly set the discontinuous | Passer automatiquement en mode de ; freehand drawing mode after brush | dessin discontinu aprs la prise d'une ; grabbing. | brosse. Auto_discontinuous = no ; (default 'no') ; Save the screen dimensions in GIF | Sauver les dimensions de l'cran dans ; files. If you want to read these | les fichiers GIF. Si vous voulez lire ; files with Photoshop or Alchemy, | ces fichiers avec Photoshop ou Alchemy, ; and maybe some other programs, you| et peut-tre d'autres programmes, vous ; must set this option to 'no'. | devez mettre cette option 'no'. Save_screen_size_in_GIF = no ; (default 'no') ; Automaticaly count the number of | Compter automatiquement le nombre de ; different colors used when opening| couleurs diffrentes utilises lors de ; the palette editor window. (Set it| d'ouverture de la fentre d'dition de ; to 'no' if you have a slow PC or | la palette. (Mettez-le 'no' si vous ; if you edit huge pictures) | avez un PC lent ou bien si vous ditez ; | d'normes images). Auto_nb_colors_used = yes ; (default 'yes') ; Default video mode at startup | Mode vido par dfaut au ; (see the list by running the | dmarrage (voir la liste en lanant ; program with argument "/?". | le programme avec l'option "/?". Default_video_mode = window ; (default 'window') ; Window dimensions. The program | Dimensions de la fentre en mode ; remembers the last window size. | fentr. Default_window_size = 640,480 ; (default '640,480') ; This setting allows you merge successive mouse movements into a single ; mouse movement. You should only use it if you are using a mouse which ; reports at 200Hz or more, and you experience lag when using discontinuous ; hand-drawing with large brushes (this tool tries to paste the brush and ; update the screen on each new mouse position) In this case, set this to 2 ; or more, to ignore some intermediate mouse reports when a more recent one ; is present. ; Note that with a value superior to 1, you lose precision with continuous ; hand-drawing, as intermediate mouse positions are skipped. Merge_movement = 0 ; (default 0) ; Number of columns in the palette of the menu bar. Can be any number from ; 1 to 256. If there is not enough room, the program will display less ; columns. But your preference will be kept, and as soon as there is more ; space in the screen, more columns will be shown. ; Palette_Cells_X = 16; (Default 16) ; Number of lines in the palette of the menu. Can be any number from ; 1 to 16. The menu can always display the number of lines you request. ; Palette_Cells_Y = 4; (Default 4) ; Bookmarked directories. Leave the directory blank for unused ones. ; Bookmark_label = Bookmark_directory = Bookmark_label = Bookmark_directory = Bookmark_label = Bookmark_directory = Bookmark_label = Bookmark_directory = ; In the classic layout, the palette in the menu has colors from left to ; right. If you prefer the colors ordered top to bottom, set this option ; to YES. ; Palette_vertical = YES; (Default YES) ; The program remembers the last window position, if the ; OS isn't able to do it by itself. (ie: Windows) Window_position = 9999,9999; (Default 9999,9999 which means: NA) ; This is the time (in milliseconds) between two clicks for Grafx2 to ; recognize a double-click. Double-click is used mostly in the palette ; area of the menu: double-click a color to open the palette. Double_click_speed = 500; (Default 500) ; When you press two digit keys in rapid succession (ex: 3 8), Grafx2 ; sets transparency to 38% (instead of 30% then 80%). This setting ; allows you to set the maximum delay between two keypresses for ; GrafX2 to recognize them as a combo. Double_key_speed = 500; (Default 500) ; Name of the skinfile you want to | Nom du fichier skin que vous voulez ; use. | utiliser. ; Default : (empty to let the program choose) Skin_file = ; Name of the font file (8x8) you | Nom du fichier police de caractre ; want to use. | 8x8 utilise dans les menus. ; Default : (empty to let the program choose) Font_file = ; This determines the color value for the grid. Each pixel of ; the grid will be displayed by XOR-ing the original color with ; the value of this setting. ; For example, if you always paint 16-color images, you can set it ; to 16 so the color of the grid are 16 for 0, 17 for 1, etc. ; Then you can set colors 16-31 as lighter/darker variants ; of your original palette, resulting in a pretty grid ! ; ; Valid values are 1 to 255. Grid_XOR_color = 255; (Default 255) ; This records the last pixel ratio used, to restore it on start. ; Valid values are from 0 to 7 for: Simple, Wide, Tall, Double, ; Triple, Wide2, Tall2, Quadruple. ; Pixel_ratio = 0; (Default 0) ; This records the visibility of toolbars, to restore them on start. ; It's a bitfield, where 1=Status, 2=Layers/Animation, 4=Tools ; Menubars_visible = 255; (Default 255) ; This enables a mode where right mouse buttons acts as ; a color picker, with most tools. ; Right_click_colorpick = NO; (Default NO) ; When this mode is active, scrolling the view (and the magnifier view) ; affects both the main image and the spare page - as long as they have ; the same dimensions. ; Sync_views = YES; (Default YES) ; This setting determines which key inverts the mouse buttons ; when it's held : A left click is then interpreted as a right-click. ; It's especially useful for one-button controllers, ; such as touchscreens and tablets. ; Possible values are 0 (none), 1 (control), 2 (alt) ; Swap_buttons = 1; (Default 1) ; Last directory browsed with the script selector. ; Leave blank to initially start in (data directory)/scripts ; Scripts_directory = ; When this setting is disabled, and you create a shortcut with a key that ; is already associated to another shortcut, Grafx2 will unset the latter. ; If you enable this mode, Grafx2 will not make such check, so you can design ; shortcuts that trigger several actions at once. ; Allow_multi_shortcuts = no; (Default no) ; Determines if the Tilemap tool should identify tiles that are mirrored ; version of other tiles, on the X axis. ; Tilemap_detect_mirrored_x = no; (Default no) ; Determines if the Tilemap tool should identify tiles that are mirrored ; version of other tiles, on the Y axis. ; Tilemap_detect_mirrored_y = no; (Default no) ; Determines if the Tilemap tool should identify tiles that are reversed ; versions of other tiles (180). ; Tilemap_detect_mirrored_xy = no; (Default no) ; Determines if the Tilemap tool should show the number of distinct tiles ; at the end of analysis. ; Tilemap_count = no; (Default no) ; Enables the virtual keyboard when the user enters a textbox. ; ; 0=Auto (guess), 1=ON, 2=OFF Use_virtual_keyboard = 0; (Default 0) ; Indicates if new images should by default use layers. The alternative ; is animation frames. ; Default_mode_layers = no; (Default no) ; end of configuration grafx2_2.4+git20180105/share/grafx2/gfx2.gif0000664000000000000000000000220213223665306016564 0ustar rootrootGIF89a b~1 !, HA*\pÃ8`` Ѣ%(@%^4P `I'SdȘiּiʠ.G\ SLCْI0yԠ^icǯO][K^j6U9Zo[G[-Q%G\-Vy Pc%S^{sd7zof3|hHl7nD vjm],߲RioٹԮ6n/a d<@Ng_ns@N>ߧ>]ЉiWwx]ng`D`w6m *h`jfS(bJ8"h 9P*~bA;grafx2_2.4+git20180105/share/grafx2/scripts/0000775000000000000000000000000013223665306016722 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/scripts/_tst_GradientBrush.lua0000664000000000000000000000016113223665306023215 0ustar rootrootw, h = getbrushsize() for x = 0, w - 1, 1 do for y = 0, h - 1, 1 do putbrushpixel(x, y, (x+y)%256); end end grafx2_2.4+git20180105/share/grafx2/scripts/_tst_dialog.lua0000664000000000000000000000415013223665306021715 0ustar rootrootlocal counter=0; local printcounter = function () windowprint(10,54, string.format("% .3d", counter)); end; windowopen(100,150, "Dialogtest"); windowbutton(6, 18, 54, 14, "Close", 27); -- 1, shortcut=ESC windowrepeatbutton(6, 38, 14, 14, "+"); -- 2 windowrepeatbutton(26, 38, 14, 14, "-"); -- 3 windowbutton(6, 70, 54, 14, "Help"); -- 4 windowinput(6, 88, 10); printcounter(); repeat local button, button2, key = windowdodialog(); if button == 2 then -- "+" counter=counter+1; printcounter(); end if button == 3 then -- "-" counter=counter-1; printcounter(); end if button == 4 then -- "Help" messagebox("Help screen"); end until key == 27 or button == 1; windowclose(); -- messagebox(tostring(button) .. " " .. tostring(button2)); ---- Open_window(149,118,"Grid"); -- Display_cursor(); -- Hide_cursor(); ---- Close_window(); ---- Update_window_area(0,0,Window_width, Window_height); ---- clicked_button=Window_clicked_button(); -- -- -- standard button ---- Window_set_normal_button(12,92,51,14,"Cancel",0,1,KEY_ESC); -- 1 -- -- repeatable button (while held) ---- Window_set_repeatable_button(202,43,13,11,"-",0,1,SDLK_LAST); -- 8 -- -- text input -- Window_set_input_button(29,24,3); -- 3 -- Window_input_content(input_x_button,str); -- Readline(31,26,str,3,INPUT_TYPE_INTEGER); -- -- -- dropdown -- Window_set_dropdown_button(216, 158, 84,14,84,"Preset...", 0,0,1,RIGHT_SIDE|LEFT_SIDE,1); -- Window_dropdown_clear_items(Button); -- Window_dropdown_add_item(Button,0,"Set"); -- -- -- vertical scroller -- mix_scroller = Window_set_scroller_button(31,20,84,256,1,Main_backups->Pages->Gradients->Range[Current_gradient].Mix); -- Window_draw_slider(mix_scroller); -- -- -- display ---- Print_in_window(11,26, "X:",MC_Dark,MC_Light); ---- Print_in_window_limited(Button->Pos_X+3+10,Button->Pos_Y+2,Config.Bookmark_label[bookmark_number],8,MC_Black,MC_Light); -- Window_display_frame_in( 6, 21,110, 52); -- Window_display_frame(6,17,130,37); -- Window_rectangle(panel->Pos_X, panel->Pos_Y, panel->Width, panel->Height+1, MC_Light); grafx2_2.4+git20180105/share/grafx2/scripts/_tst_Settings.lua0000664000000000000000000000127013223665306022256 0ustar rootroot-- Test LUA inputbox -- this script tests the inputbox w, h = getbrushsize() --[[ messagebox( "Forecolor: " .. getforecolor() .. "\n" .. "Backcolor: " .. getbackcolor() .. "\n" .. "Transparent color: " .. gettranscolor() .. "\n" .. "Brush dimensions: " .. w .. "x" .. h ) ]] ok, w, h = inputbox("Modify brush", "RGB", 1, 0, 1, -1, "HSV", 0, 0, 1, -1, "HSL", 0, 0, 1, -1, "Width", w, -900.0,900.0, 3, "Height", h, -900.0,900.0, 4, "X Flip", 0, 0, 1, 0, "Y Flip", 0, 0, 1, 0, "Degrees",1, 0, 1, -2, "Radians",0, 0, 1, -2 ); if ok == true then messagebox( "w: " .. w .. "\n" .. "h: " .. h .. "\n" ) end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/0000775000000000000000000000000013223665306020751 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/palette/0000775000000000000000000000000013223665306022407 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/palette/Desaturate.lua0000664000000000000000000000205313223665306025213 0ustar rootroot--PALETTE Adjust: Desaturate v1.1 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html -- Note: Negative values will work as INCREASED saturation, but I'm not sure if this function is 100% correct --percent = 25 OK,percent = inputbox("Desaturate Palette","Percent %", 25, 0,100,0); -- function desaturate(percent,r,g,b) -- V1.0 by Richard Fhager p = percent / 100 a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 * p r = r + (a-r*p) g = g + (a-g*p) b = b + (a-b*p) return r,g,b end -- if OK == true then for c = 0, 255, 1 do setcolor(c, desaturate(percent,getcolor(c))) end endgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/palette/SetC64Palette.lua0000664000000000000000000000243513223665306025445 0ustar rootroot--PALETTE Set: C64 Palette (16 colors) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See OK,clean = inputbox("C64 Palette:", "Remove old palette", 0, 0,1,0 ); colors = {{0, 0, 0}, -- 0 Black {62, 49,162}, -- 1 D.Blue {87, 66, 0}, -- 2 Brown {140, 62, 52}, -- 3 D.Red {84, 84, 84}, -- 4 D.Grey {141, 72,179}, -- 5 Purple {144, 95, 37}, -- 6 Orange {124,112,218}, -- 7 B.Blue {128,128,128}, -- 8 Grey {104,169, 65}, -- 9 Green {187,119,109}, -- 10 B.Red {122,191,199}, -- 11 Cyan {171,171,171}, -- 12 B.Grey {208,220,113}, -- 13 Yellow {172,234,136}, -- 14 B.Green {255,255,255} -- 15 White } if OK == true then for c = 1, #colors, 1 do setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) end if clean == 1 then for c = #colors+1, 256, 1 do setcolor(c-1,0,0,0) end end endgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/palette/Set6bit.lua0000664000000000000000000000171613223665306024437 0ustar rootroot--PALETTE Set: Full 6 Bit (64 colors) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- Generate palette of all colors possible with a given number of shades for each channel -- 2 shades = 1 bit / channel = 3 bit palette = 2^3 colors = 8 colors -- 4 shades = 2 bit / channel = 6 bit palette = 2^6 colors = 64 colors -- Channel shades (shades = 2 ^ bit-depth) shades = 4 mult = 255 / (shades-1) colors = {} col = 0 for r = 0, shades-1, 1 do for g = 0, shades-1, 1 do for b = 0, shades-1, 1 do col = col + 1 colors[col] = { r*mult, g*mult, b*mult } end end end for c = 1, #colors, 1 do setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/palette/InvertedRGB.lua0000664000000000000000000000121613223665306025225 0ustar rootroot--PALETTE Modify: Inverted RGB --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html for c = 0, 255, 1 do r,g,b = getcolor(c) r2 = (g+b)/2 g2 = (r+b)/2 b2 = (r+g)/2 setcolor(c, r2,g2,b2) end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/palette/ExpandColors.lua0000664000000000000000000001131413223665306025513 0ustar rootroot--PALETTE: Expand Colors v1.0 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Email: dawnbringer@hem.utfors.se -- MSN: annassar@hotmail.com -- -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- Continously fill the greatest void in the area of the color-cube enclosed by (or along ramps of) initial colors -- This algorithm will create lines of allowed colors (all ranges) in 3d colorspace and the pick -- new colors from the most void areas (on any line). Almost like a Median-cut in reverse. -- -- Rather than filling the colorcube symmetrically it adds intermediate colors to the existing ones. -- -- Running this script on the C64 16-color palette might be educational -- -- -- Source cols#, Expand to #, -- Ex: 15-31 means that palette colors 0-15 is expanded to 16 new colors placed at slots 16-31 -- -- Spread mode: OFF - New colors will conform to the contrast & saturation of original colors -- (new colors will stay on the ramps possible from the original colors) -- -- ON - New colors will expand their variance by each new addition (mostly notable when adding many new colors) -- Will add range lines/ramps to all new colors from old ones, but keep within max/min values of the -- original colors. 15-bit mode will dampen the spread towards extreme colors (if starting with low contrast) -- -- 15-bit colors: Higher color-resolution, 32768 possible colors rather than the 4096 of 12bit. Slower but perhaps better. -- SHADES = 16 -- Going 24bit will probably be too slow and steal too much memory, so start with 12bit (4096 colors) for now ini = 0 exp = 255 OK,ini,exp,linemode,fbit = inputbox("Expand Colors (0-255):", "Source Cols #: 1-254", 15, 1,254,0, "Expand to #: 2-255", 31, 2,255,0, "Spread mode", 0, 0,1,0, "15-bit colors (slow)", 0, 0,1,0 ); if (fbit == 1) then SHADES = 32; end function initColorCube(sha) ary = {} for z = 0, sha-1, 1 do ary[z+1] = {} for y = 0, sha-1, 1 do ary[z+1][y+1] = {} for x = 0, sha-1, 1 do ary[z+1][y+1][x+1] = {false,0} end end end return ary end -- Gravity model (think of colors as stars of equal mass/brightness in a 3d space) function addColor2Cube(cube,sha,r,g,b) star = 1000000 fade = 1000 cube[r+1][g+1][b+1] = {false,star} for z = 0, sha-1, 1 do for y = 0, sha-1, 1 do for x = 0, sha-1, 1 do d = fade / ( (x-b)^2 + (y-g)^2 + (z-r)^2 ) cube[z+1][y+1][x+1][2] = cube[z+1][y+1][x+1][2] + d end;end;end end -- Create new allowed colorlines in colorspace (ramps from which colors can be picked) function enableRangeColorsInCube(cube,sha,r1,g1,b1,r2,g2,b2) local div,r,g,b div = 256 / sha rs = (r2 - r1) / sha / div gs = (g2 - g1) / sha / div bs = (b2 - b1) / sha / div for n = 0, sha-1, 1 do r = math.floor(r1/div + rs * n) g = math.floor(g1/div + gs * n) b = math.floor(b1/div + bs * n) cube[r+1][g+1][b+1][1] = true end end function findVoid(cube,sha) weakest = 999999999999 weak_i = {-1,-1,-1} for z = 0, sha-1, 1 do for y = 0, sha-1, 1 do for x = 0, sha-1, 1 do c = cube[z+1][y+1][x+1] if c[1] == true then w = c[2] if w <= weakest then weakest = w; weak_i = {z,y,x}; end end end;end;end return weak_i[1],weak_i[2],weak_i[3] end -- if OK == true then cube = initColorCube(SHADES) -- Define allowed colorspace for y = 0, ini-1, 1 do r1,g1,b1 = getcolor(y) for x = y+1, ini, 1 do r2,g2,b2 = getcolor(x) enableRangeColorsInCube(cube,SHADES,r1,g1,b1,r2,g2,b2) end end div = 256 / SHADES -- Fill cube with initial colors for n = 0, ini, 1 do r,g,b = getcolor(n) addColor2Cube(cube,SHADES,math.floor(r/div),math.floor(g/div),math.floor(b/div)) end for n = ini+1, exp, 1 do r,g,b = findVoid(cube,SHADES) if (r == -1) then messagebox("Report:","No more colors can be found, exit at "..n); break; end mult = 255 / (SHADES - 1) setcolor(n, r*mult,g*mult,b*mult) if linemode == 1 then -- Add lines from new color to all old for x = 0, n-1, 1 do r2,g2,b2 = getcolor(x) enableRangeColorsInCube(cube,SHADES,r*mult,g*mult,b*mult,r2,g2,b2) -- uses 24bit values rgb end end addColor2Cube(cube,SHADES,r,g,b) -- rgb is in 'shade' format here end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/palette/ShiftHue.lua0000664000000000000000000000237313223665306024636 0ustar rootroot--PALETTE Adjust: Shift Hue v0.9 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html --Shift_degrees = 45 OK,Shift_degrees = inputbox("Shift Hue v0.9","Degrees", 45, 0,360,3); -- function shiftHUE(r,g,b,deg) -- V1.3 R.Fhager 2007, adopted from Evalion local c,h,mi,mx,d,s,p,i,f,q,t c = {g,b,r} mi = math.min(r,g,b) mx = math.max(r,g,b); v = mx; d = mx - mi; s = 0; if mx ~= 0 then s = d/mx; end p = 1; if g ~= mx then p = 2; if b ~= mx then p = 0; end; end if s~=0 then h=(deg/60+(6+p*2+(c[1+p]-c[1+(p+1)%3])/d))%6; i=math.floor(h); f=h-i; p=v*(1-s); q=v*(1-s*f); t=v*(1-s*(1-f)); c={v,q,p,p,t,v} r = c[1+i] g = c[1+(i+4)%6] b = c[1+(i+2)%6] end return r,g,b end -- if OK == true then for c = 0, 255, 1 do r,g,b = getcolor(c) setcolor(c, shiftHUE(r,g,b,Shift_degrees)) end endgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/palette/Set3bit.lua0000664000000000000000000000171313223665306024431 0ustar rootroot--PALETTE Set: 3 Bit (8 Primaries) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- Generate palette of all colors possible with a given number of shades for each channel -- 2 shades = 1 bit / channel = 3 bit palette = 2^3 colors = 8 colors -- 4 shades = 2 bit / channel = 6 bit palette = 2^6 colors = 64 colors -- Channel shades (shades = 2 ^ bit-depth) shades = 2 mult = 255 / (shades-1) colors = {} col = 0 for r = 0, shades-1, 1 do for g = 0, shades-1, 1 do for b = 0, shades-1, 1 do col = col + 1 colors[col] = { r*mult, g*mult, b*mult } end end end for c = 1, #colors, 1 do setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/palette/FillColorCube.lua0000664000000000000000000000446013223665306025602 0ustar rootroot--PALETTE: Fill ColorCube voids v1.0 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Email: dawnbringer@hem.utfors.se -- MSN: annassar@hotmail.com -- -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- -- Create a palette by continously filling the greatest void in the RGB color-cube -- SHADES = 16 -- Going 24bit will probably be too slow and steal too much memory, so we're 12bit (4096 colors) for now ini = 0 exp = 255 OK,ini,exp = inputbox("Fill Palette Color voids", "From/Keep #: 0-254", 0, 0,254,0, "Replace to #: 1-255", 31, 1,255,0 ); function initColorCube(sha) ary = {} for z = 0, sha-1, 1 do ary[z+1] = {} for y = 0, sha-1, 1 do ary[z+1][y+1] = {} end end return ary end function addColor2Cube(cube,sha,r,g,b) -- Gravity model star = 1000000 fade = 1000 cube[r+1][g+1][b+1] = star for z = 0, sha-1, 1 do for y = 0, sha-1, 1 do for x = 0, sha-1, 1 do d = fade / ( (x-b)^2 + (y-g)^2 + (z-r)^2 ) if cube[z+1][y+1][x+1] ~= nil then cube[z+1][y+1][x+1] = cube[z+1][y+1][x+1] + d else cube[z+1][y+1][x+1] = d end end;end;end end function findVoid(cube,sha) weakest = 999999999999 weak_i = {-1,-1,-1} for z = 0, sha-1, 1 do for y = 0, sha-1, 1 do for x = 0, sha-1, 1 do w = cube[z+1][y+1][x+1] if w <= weakest then weakest = w; weak_i = {z,y,x}; end end;end;end return weak_i[1],weak_i[2],weak_i[3] end -- if OK == true then cube = initColorCube(SHADES) -- Fill cube with initial colors for n = 0, ini-1, 1 do r,g,b = getcolor(n) div = SHADES addColor2Cube(cube,SHADES,math.floor(r/div),math.floor(g/div),math.floor(b/div)) end if ini == 0 then -- With no inital color, some inital data must be added to the colorcube. addColor2Cube(cube,SHADES,0,0,0) setcolor(0, 0,0,0) ini = ini + 1 end for n = ini, exp, 1 do r,g,b = findVoid(cube,SHADES) mult = 255 / (SHADES - 1) setcolor(n, r*mult,g*mult,b*mult) addColor2Cube(cube,SHADES,r,g,b) end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/demo/0000775000000000000000000000000013223665306021675 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/demo/SierpinskyTriangle.lua0000664000000000000000000000240013223665306026222 0ustar rootroot--PICTURE: Pattern - Sierpinsky triangle v1.0 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Email: dawnbringer@hem.utfors.se -- MSN: annassar@hotmail.com -- -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html -- frac = {{1,1},{1,0}} iter = 15 -- function pattern(x,y,p,n,i) -- Fractal Pattern V1.0 by Richard Fhager (mod allows for wrapping) py = #p px = #p[1] while ((p[1+math.abs(math.floor(y*py))%py][1+math.abs(math.floor(x*px))%px]) == 1 and n -- -- rot: Rotation in degrees -- stp: Step is # of line segments (more is "better") -- a & b are axis-radius function ellipse2(x,y,a,b,stp,rot,col) local n,m=math,rad,al,sa,ca,sb,cb,ox,oy,x1,y1,ast m = math; rad = m.pi/180; ast = rad * 360/stp; sb = m.sin(-rot * rad); cb = m.cos(-rot * rad) for n = 0, stp, 1 do ox = x1; oy = y1; sa = m.sin(ast*n) * b; ca = m.cos(ast*n) * a x1 = x + ca * cb - sa * sb y1 = y + ca * sb + sa * cb if (n > 0) then drawline(ox,oy,x1,y1,col); end end end -- setpicturesize(300,300) setcolor(0,96,96,96) setcolor(1,255,255,128) r1 = 100 r2 = 50 rt = 0 frames = 100 while (1 < 2) do r1t = 10 + math.random() * 140 r2t = 10 + math.random() * 140 rtt = math.random() * 360 for n = 0, frames-1, 1 do clearpicture(0) f2 = n / frames f1 = 1 - f2 r1a = r1*f1 + r1t*f2 r2a = r2*f1 + r2t*f2 rta = rt*f1 + rtt*f2 -- x, y, r1, r2, stp, rot, col ellipse2(150, 150, r1a, r2a, 50, rta, 1) statusmessage('press ESC to stop') updatescreen();if (waitbreak(0)==1) then return end end r1,r2,rt = r1a,r2a,rta end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/demo/3DPalette.lua0000664000000000000000000002701613223665306024173 0ustar rootroot--3D-Palette viewer V0.72 (HSL-models added, 3D-World added, Pen-color only cycles thru unique colors, InputBox) --by Richard 'Dawnbringer' Fhager -- Mouse: Rotate Cube (Stops animation) -- Arrow-keys: Move Cube (in 3D world) -- F1: Start/Stop animation -- F2: Reset -- F3: Increase Color-Size -- F4: Decrease Color-Size -- F5: (Wip) Cycle thru selected PenColor (Note that only unique colors are displayed) -- F9: RGB-space model --F10: HSL-space model --F11: HSLcubic-space model -- "+" (Num): Zoom In -- "-" (Num): Zoom Out -- Esc: Exit script -- Drawing updated, rectangle missing, Sep11 run("../libs/dawnbringer_lib.lua") BRIDIAG_SHOW = 1 -- Show brightness/Grayscale diagonal (1 = on, 0 = off) ANIM = 1 -- Animation (1 = on, 0 = off) BOX_DRK = 8 -- Darkest color used for box (0-255) BOX_BRI = 112 -- Brightest color used for box (0-255) COLSIZE_BASE = 26 -- Colors base size (value to adjusted by palette-size, with 2 cols maxsize is v / 1.23) -- OK,RGB,HSL,HSLC,BOX_BRI,COLSIZE_BASE,SET800x600 = inputbox("3D-Palette Viewer Settings", "1. RGB space [F9]", 1, 0,1,-1, "2. HSL space [F10]", 0, 0,1,-1, "3. HSL-cubic space [F11]",0, 0,1,-1, "Box Brightness (16-255)", BOX_BRI, 16,255,0, "Col Size (1-100) [F3/F4]", COLSIZE_BASE, 1,100,0, "Set Screen to 800x600", 1,0,1,0 ); -- if OK then if SET800x600 == 1 then setpicturesize(800,600); end SPACE = "rgb" FORM = "cube" if HSL == 1 then SPACE = "hsl" FORM = "cylinder" end if HSLC == 1 then SPACE = "hsl_cubic" FORM = "cube" end pal = db.fixPalette(db.makePalList(256)) FG = getforecolor() BG = getbackcolor() palcol = FG -- function initColors(space) for n = 1, #pal, 1 do c = pal[n]; if space == "rgb" then cols[n] = {c[1]/128-1,c[2]/128-1,c[3]/128-1,c[4]}; end if space == "hsl_cubic" then cols[n] = {} cols[n][1] = (db.getHUE(c[1],c[2],c[3],0) / 6.0 * 255) / 128 - 1 cols[n][2] = (db.getSaturation(c[1],c[2],c[3])) / 128 - 1 cols[n][3] = (db.getLightness(c[1],c[2],c[3])) / 128 - 1 cols[n][4] = c[4] end if space == "hsl" then cols[n] = {} hue = db.getHUE(c[1],c[2],c[3],0) / 6.0 * math.pi*2 rad = db.getSaturation(c[1],c[2],c[3]) / 256 cols[n][1] = math.cos(hue) * rad cols[n][2] = math.sin(hue) * rad cols[n][3] = (db.getLightness(c[1],c[2],c[3])) / 128 - 1 cols[n][4] = c[4] end end end -- cols = {} -- Make points of palette colors colz = {} -- To hold calculated points initColors(SPACE) function initPointsAndLines(form,bridiag) if form == "cube" then pts = {{-1,1,-1},{1,1,-1},{1,-1,-1},{-1,-1,-1}, -- The box {-1,1, 1},{1,1, 1},{1,-1, 1},{-1,-1, 1}} lin = {{1,2},{2,3},{3,4},{4,1},{5,6},{6,7},{7,8},{8,5},{1,5},{2,6},{3,7},{4,8}} -- Box Lines if bridiag == 1 then lin[13] = {4,6}; end end if form == "cylinder" then p = 28 pts = {} lin = {} for n = 1, p, 1 do x = math.cos(math.pi*2 / p * (n-1)) y = math.sin(math.pi*2 / p * (n-1)) pts[n] = {x,y,-1} lin[n] = {n,1 + (n%p)} pts[n + p] = {x,y,1} lin[n + p] = {n+p,p + 1 + (n%p)} end lin[p*2+1] = {1,p+1} -- Red (0 degrees) lin[p*2+2] = {p+1,p+1+math.ceil(p/2)} -- Lightness end (needs an even # of points to work) end end boxp = {} -- To hold the calculated points initPointsAndLines(FORM,BRIDIAG_SHOW) w,h = getpicturesize() CX,CY = w/2, h/2 function initAndReset() XANG, YANG, ZANG, ZOOM, COLSIZE_ADJ, XD, YD, WORLD_X, WORLD_Y, ZSELECT = 0,0,0,0,0,0,0,0,0,0 end initAndReset() SIZE = math.min(w,h)/4 DIST = 5 -- Distance perspective modifier, ~5 is nominal, more means "less 3D" CMAXSIZE = math.floor(COLSIZE_BASE / ((#pal)^0.3)) --CMAXSIZE = 8 CMINSIZE = 1 -- Negative values are ok. Color are never smaller than 1 pix BOX_LINE_DIV = 20 -- Number of colors/segments that a box-line can be divided into (depth) BOX_DIV_MULT = BOX_LINE_DIV / (math.sqrt(3)*2) -- Box depth colors box_div = {} for n = 0, BOX_LINE_DIV-1, 1 do c = BOX_DRK + (BOX_BRI / (BOX_LINE_DIV - 1)) * n --box_div[BOX_LINE_DIV - n] = matchcolor(c,c,c) box_div[BOX_LINE_DIV - n] = db.getBestPalMatchHYBRID({c,c,c},pal,0.5,true) end --BOX_COL = matchcolor(80,80,80) BKG_COL = matchcolor(0,0,0) --CUR_COL = matchcolor(112,112,112) function rotate3D(x,y,z,Xsin,Ysin,Zsin,Xcos,Ycos,Zcos) -- PrecCalced cos&sin for speed local x1,x2,x3,y1,y2,y3,f,xp,yp x1 = x y1 = y * Xcos + z * Xsin z1 = z * Xcos - y * Xsin x2 = x1 * Ycos - z1 * Ysin y2 = y1 z2 = x1 * Ysin + z1 * Ycos x3 = x2 * Zcos - y2 * Zsin y3 = x2 * Zsin + y2 * Zcos z3 = z2 return x3,y3,z3 end function do3D(x,y,z,zoom,dist,Xsin,Ysin,Zsin,Xcos,Ycos,Zcos) -- PrecCalced cos&sin for speed local x1,x2,x3,y1,y2,y3,f,xp,yp x1 = x y1 = y * Xcos + z * Xsin z1 = z * Xcos - y * Xsin x2 = x1 * Ycos - z1 * Ysin y2 = y1 z2 = x1 * Ysin + z1 * Ycos x3 = x2 * Zcos - y2 * Zsin y3 = x2 * Zsin + y2 * Zcos z3 = z2 f = dist/(z3 + dist + zoom) xp = x3 * f yp = y3 * f return xp,yp,z3 end function draw3Dline(x1,y1,z1,x2,y2,z2,div,mult,depthlist) local s,xt,yt,xd,yd,zd,xf,yf xd = (x2 - x1) / div yd = (y2 - y1) / div zd = (z2 - z1) / div xf,yf = x1,y1 for s = 1, div, 1 do -- Depth assumes a 1-Box (z ranges from -sq(3) to sq(3)) depth = math.floor(1 + (z1+zd*s + 1.732) * mult) xt = x1 + xd*s -- + math.random()*8 yt = y1 + yd*s -- + math.random()*8 c = depthlist[depth] if c == null then c = 1; end -- Something isn't perfect, error is super rare but this controls it --db.line(xf,yf,xt,yt,c) drawline(xf,yf,xt,yt,c) xf = xt yf = yt end end function killinertia() XD = 0 YD = 0 end -- If using 1-box, z is -sq(3) to sq(3) minz = math.sqrt(3) totz = minz * 2 maxrad = CMAXSIZE - CMINSIZE --q = 0 --delay = 4 --move = 0.03 while 1 < 2 do -- Time-for-space-wiggle...or somekindof attempt --WORLD_X = -move --q = (q + 1) % delay --if q < delay/2 then WORLD_X = move; end clearpicture(BKG_COL) Xsin = math.sin(XANG); Xcos = math.cos(XANG) Ysin = math.sin(YANG); Ycos = math.cos(YANG) Zsin = math.sin(ZANG); Zcos = math.cos(ZANG) -- Rotate Box points for n = 1, #pts, 1 do p = pts[n] x,y,z = p[1],p[2],p[3] XP,YP,zp = rotate3D(x,y,z,Xsin,Ysin,Zsin,Xcos,Ycos,Zcos) boxp[n] = {XP,YP,zp} end -- Rotate Colors in palette for n = 1, #cols, 1 do p = cols[n] x,y,z,c = p[1],p[2],p[3],p[4] XP,YP,zp = rotate3D(x,y,z,Xsin,Ysin,Zsin,Xcos,Ycos,Zcos) colz[n] = {XP,YP,zp,c} end ------------------------------------ -- Control world ------------------------------------ -- Calculate points anew -- Worldize Box points for n = 1, #boxp, 1 do s = SIZE v = boxp[n] x = v[1] + WORLD_X y = v[2] + WORLD_Y z = v[3] f = DIST/(z + DIST + ZOOM) XP = CX + x * f * s YP = CY + y * f * s boxp[n] = {XP,YP,z} end -- Worldize Colors in palette for n = 1, #colz, 1 do s = SIZE v = colz[n] x = v[1] + WORLD_X y = v[2] + WORLD_Y z = v[3] c = v[4] f = DIST/(z + DIST + ZOOM) XP = CX + x * f * s YP = CY + y * f * s colz[n] = {XP,YP,z,c} end ------------------------------------- ------------------------------------- -- Brightness Diagonal --if BRIDIAG_SHOW == 1 then -- p1 = boxp[4] -- p2 = boxp[6] -- x1,y1,z1 = p1[1],p1[2],p1[3] -- x2,y2,z2 = p2[1],p2[2],p2[3] -- draw3Dline(x1,y1,z1,x2,y2,z2,BOX_LINE_DIV,BOX_DIV_MULT,box_div) --end --c1 = math.min(FG,BG) --c2 = math.max(FG,BG) --p = colz[26] --XP1,YP1,zp1,c1 = p[1],p[2],p[3],p[4] --for n = #colz, 1, -1 do -- p = colz[27] -- XP2,YP2,zp2,c2 = p[1],p[2],p[3],p[4] -- drawline(XP1,YP1,XP2,YP2,c1) --end -- sort on z db.sorti(colz,3) -- Draw colors for n = #colz, 1, -1 do p = colz[n] XP,YP,zp,c = p[1],p[2],p[3],p[4] radius = CMINSIZE + maxrad - (zp+minz) / totz * maxrad dorad = math.floor(radius - ZOOM*2 + COLSIZE_ADJ) if dorad >= 1 then --db.drawCircle(XP,YP,dorad,c) drawdisk(XP,YP,dorad,c) --db.drawRectangle(XP,YP,dorad,dorad,c) else putpicturepixel(XP,YP,c) end if c == FG or c == BG then sz = math.max(3,dorad + 3) if c == BKG_COL then v = (c+128) % 255; c = matchcolor(v,v,v); end db.drawRectangleLine(XP-sz,YP-sz,sz*2,sz*2,c) end end -- colz -- Draw box for n = 1, #lin, 1 do l = lin[n] p1 = boxp[l[1]] p2 = boxp[l[2]] x1,y1,z1 = p1[1],p1[2],p1[3] x2,y2,z2 = p2[1],p2[2],p2[3] draw3Dline(x1,y1,z1,x2,y2,z2,BOX_LINE_DIV,BOX_DIV_MULT,box_div) end -- eof box --updatescreen(); if (waitbreak(0.00)==1) then return; end repeat old_key = key; old_mouse_x = mouse_x; old_mouse_y = mouse_y; old_mouse_b = mouse_b; updatescreen() moved, key, mouse_x, mouse_y, mouse_b = waitinput(0) if mouse_b == 1 then ANIM = 0; end if (key==27) then return; end if (key==282) then ANIM = (ANIM+1) % 2; end -- F1: Stop/Start Animation if (key==283) then initAndReset(); end -- F2: Reset all values if (key==284) then COLSIZE_ADJ = COLSIZE_ADJ + 0.5; end -- F3 if (key==285) then COLSIZE_ADJ = COLSIZE_ADJ - 0.5; end -- F4 --messagebox(key) if (key==286) then --FG = (FG + 1) % 255; palcol = (palcol + 1) % #pal FG = pal[palcol+1][4] setforecolor(FG); setcolor(0,getcolor(0)) -- Force update of palette until setforecolor() is fixed end -- F5 if (key==290) then -- F9 initColors("rgb") initPointsAndLines("cube",BRIDIAG_SHOW) end if (key==291) then -- F10 initColors("hsl") initPointsAndLines("cylinder", 0) -- Bridiag won't show even if turned on, it's only for cube end if (key==292) then -- F11 initColors("hsl_cubic") initPointsAndLines("cube",BRIDIAG_SHOW) end if (key==269) then ZOOM = ZOOM + 0.1; end if (key==270) then ZOOM = ZOOM - 0.1; end if (key==32) then ZSELECT = (ZSELECT + math.pi/2) % (2*math.pi); --YANG = ((YANG - math.pi/2) % (math.pi*2)); --XANG = ((XANG + math.pi/2) % (math.pi*2)); YANG = ((YANG + math.pi/2) % (math.pi*2)); XANG = ((XANG + math.pi/2) % (math.pi*2)); YANG = ((YANG - math.pi/2) % (math.pi*2)); end -- Rotate Z 90 Degrees SPEED = math.pi / 100 if (key==273) then WORLD_Y = WORLD_Y - 0.05; killinertia(); end if (key==274) then WORLD_Y = WORLD_Y + 0.05; killinertia(); end if (key==276) then WORLD_X = WORLD_X - 0.05; killinertia(); end if (key==275) then WORLD_X = WORLD_X + 0.05; killinertia(); end until ((mouse_b == 1 and (old_mouse_x~=mouse_x or old_mouse_y~=mouse_y)) or key~=0 or ANIM==1 or math.abs(XD)>0.01 or math.abs(YD)>0.01); if ANIM == 0 then if (mouse_b==1 and (old_mouse_x~=mouse_x or old_mouse_y~=mouse_y)) then -- Inertia XD = (mouse_y - old_mouse_y)*0.005 YD = (mouse_x - old_mouse_x)*0.005 else XD = XD*0.92 YD = YD*0.92 end XANG = ((XANG - XD) % (math.pi*2)); YANG = ((YANG + YD) % (math.pi*2)); ZANG = ZSELECT end if ANIM == 1 then XANG = (XANG + math.pi/300) % (math.pi*2) YANG = (YANG + math.pi/500) % (math.pi*2) ZANG = (ZANG + math.pi/1000) % (math.pi*2) end --XANG = ((CY-mouse_y) / 200 % (math.pi*2)); --YANG = ((mouse_x - CX) / 200 % (math.pi*2)); --ZANG = 0 statusmessage("x"..math.floor(XANG*57.3).." y"..math.floor(YANG*57.3).." z"..math.floor(ZANG*57.3).." Zm: "..math.floor(-ZOOM*10).." ") end end -- OK grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/demo/Spritesheet.lua0000664000000000000000000000213713223665306024702 0ustar rootroot--ANIM: Sprite Animator v0.15 --Spare page holds data - Plays on current --by Richard Fhager run("../libs/memory.lua") arg=memory.load({XS=16,YS=16,SPACE=1,FRAMES=8,XOFF=0,YOFF=0,FPS=10}) OK, XS, YS, SPACE, FRAMES, XOFF, YOFF, FPS = inputbox("Sprite-Sheet Animator", "Sprite X-size", arg.XS, 1, 256,0, "Sprite Y-size", arg.YS, 1, 256,0, "Spacing", arg.SPACE, 0, 32,0, "# of Frames", arg.FRAMES,2, 100,0, "X-offset", arg.XOFF, 0, 800,0, "Y-offset", arg.YOFF, 0, 800,0, "Play Speed (FPS)",arg.FPS, 1, 60,0 ); if OK == true then memory.save({XS=XS,YS=YS,SPACE=SPACE,FRAMES=FRAMES,XOFF=XOFF,YOFF=YOFF,FPS=FPS}) MAXPLAYS = 100 w,h = getpicturesize() OX = w / 2 - XS/2 OY = h / 2 - YS/2 for play = 1, MAXPLAYS, 1 do for f = 0, FRAMES-1, 1 do for y = 0, YS-1, 1 do for x = 0, XS-1, 1 do sx = x + XOFF + f * (XS + SPACE) sy = y + YOFF putpicturepixel(OX+x, OY+y, getsparepicturepixel(sx, sy)) end end updatescreen(); if (waitbreak(1/FPS)==1) then return; end end end -- plays end --OK grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/demo/SierpinskyCarpet.lua0000664000000000000000000000241313223665306025677 0ustar rootroot--PICTURE: Pattern - Sierpinsky carpet v1.0 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Email: dawnbringer@hem.utfors.se -- MSN: annassar@hotmail.com -- -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html -- frac = {{1,1,1},{1,0,1},{1,1,1}} iter = 6 -- function pattern(x,y,p,n,i) -- Fractal Pattern V1.0 by Richard Fhager (mod allows for wrapping) py = #p px = #p[1] while ((p[1+math.abs(math.floor(y*py))%py][1+math.abs(math.floor(x*px))%px]) == 1 and n w,h=getpicturesize(); ok,flipx,flipy=inputbox("flip picture","flip x",1,0,1,-1,"flip y",0,0,1,-1); if ok==true then if flipx==1 then for y=0,h-1,1 do for x=0,w/2,1 do c1=getpicturepixel(x,y);c2=getpicturepixel(w-x-1,y) putpicturepixel(x,y,c2);putpicturepixel(w-x-1,y,c1) end;end else for y=0,h/2,1 do for x=0,w-1,1 do c1=getpicturepixel(x,y);c2=getpicturepixel(x,h-y-1) putpicturepixel(x,y,c2);putpicturepixel(x,h-y-1,c1) end;end;end;end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/demo/brush/0000775000000000000000000000000013223665306023020 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/demo/brush/Amigaball.lua0000664000000000000000000000263713223665306025404 0ustar rootroot--BRUSH Scene: Amigaball 1.0 -- --Draws the famous 'Amiga ball' in the brush. -- --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project --http://goto.glocalnet.net/richard_fhager/evalion/evalion.html w, h = getbrushsize() if (w<64 or h<64) then setbrushsize(64,64) w=64 h=64 end for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do -- Fractionalize image dimensions ox = x / w; oy = y / h; -- Ball Xr = ox-0.5; Yr = oy-0.5; W = (1 - 2*math.sqrt(Xr*Xr + Yr*Yr)); -- 'FishEye' distortion / Fake 3D F = (math.cos((ox-0.5)*math.pi)*math.cos((oy-0.5)*math.pi))*0.65; ox = ox - (ox-0.5)*F; oy = oy - (oy-0.5)*F; -- Checkers V = ((math.floor(0.25+ox*10)+math.floor(1+oy*10)) % 2) * 255 * W; -- Specularities SPEC1 = math.max(0,(1-5*math.sqrt((ox-0.45)*(ox-0.45)+(oy-0.45)*(oy-0.45)))*112); SPEC2 = math.max(0,(1-15*math.sqrt((ox-0.49)*(ox-0.49)+(oy-0.48)*(oy-0.48)))*255); r = W * 255 + SPEC1 + SPEC2 g = V + SPEC1 + SPEC2 b = V + SPEC1 + SPEC2 putbrushpixel(x, y, matchcolor(r,g,b)); end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/demo/brush/ColorSphere.lua0000664000000000000000000000164513223665306025756 0ustar rootroot--BRUSH Scene: Sphere of pencolor v1.0 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project --http://goto.glocalnet.net/richard_fhager/evalion/evalion.html w, h = getbrushsize() rp,gp,bp = getcolor(getforecolor()) for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do -- Fractionalize image dimensions ox = x / w; oy = y / h; -- Sphere X = 0.5; Y = 0.5; Rd = 0.5 a = math.sqrt(math.max(0,Rd*Rd - ((X-ox)*(X-ox)+(Y-oy)*(Y-oy)))) * 1/Rd r = rp * a g = gp * a b = bp * a putbrushpixel(x, y, matchcolor(r,g,b)); end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/demo/brush/Mandelbrot.lua0000664000000000000000000000246513223665306025621 0ustar rootroot--BRUSH Scene: Mandelbrot fractal v0.5 -- --Draws a Mandelbrot fractal in the current brush. -- --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project --http://goto.glocalnet.net/richard_fhager/evalion/evalion.html colors = 64 x0 = -1.7 x1 = 0.7 ym = 0 iter = 64 ok, x0, x1, ym, iter = inputbox("Fractal data", "X0", x0, -2, 2,4, "X1", x1, -2, 2,4, "midY", ym, -2, 2,4, "Iter", iter, 1, 2048,0 ); -- -0.831116819,-0.831116815,0.2292112435,192 function mandel(x,y,l,r,o,i) -- pos. as fraction of 1, left coord, right coord, y coord, iterations local w,s,a,p,q,n,v,w s=math.abs(r-l); a = l + s*x; p = a; b = o - s*(y-0.5); q = b; n = 1; v = 0; w = 0; while (v+w<4 and n cellw = 8 cellh = 4 colors = 256 setbrushsize(cellw * 3, cellh * 3) -- function makePalList(cols) pal = {} for n = 0, cols-1, 1 do r,g,b = getcolor(n) pal[n+1] = {r,g,b} end return pal end -- -- function getBestPalMatchHYBRID(rgb,pal,briweight) local diff,diffC,diffB,best,bestcol,cols,n,c,r,g,b,p,obri,pbri cols = #pal bestcol = 0 best = 9e99 r = rgb[1] g = rgb[2] b = rgb[3] obri = math.pow(r*9,2)+math.pow(g*16,2)+math.pow(b*8,2) for n=0, cols-1, 1 do p = pal[n+1] pbri = math.pow(p[1]*9,2)+math.pow(p[2]*16,2)+math.pow(p[3]*8,2) diffB = math.abs(obri - pbri) diffC = (math.pow(r-p[1],2)+math.pow(g-p[2],2)+math.pow(b-p[3],2)) * 400 --diff = diffB + diffC diff = briweight * (diffB - diffC) + diffC if diff <= best then bestcol = n; best = diff; end end return bestcol end -- -- function drawRectangle(x1,y1,w,h,c) for y = y1, y1+h, 1 do for x = x1, x1+w, 1 do putbrushpixel(x,y,c); end end end -- palList = makePalList(colors) cf = getforecolor() cb = getbackcolor() rf,gf,bf = getcolor(cf) rb,gb,bb = getcolor(cb) ra = (rf + rb) / 2 ga = (gf + gb) / 2 ba = (bf + bb) / 2 rgb1 = {ra,ga,ba} c1 = getBestPalMatchHYBRID(rgb1,palList,0.0) c2 = getBestPalMatchHYBRID(rgb1,palList,0.75) c3 = getBestPalMatchHYBRID(rgb1,palList,0.99) q = {{cf,c1,cb}, {cf,c2,cb}, {cf,c3,cb}} for y = 0, #q-1, 1 do for x = 0, #q[1]-1, 1 do drawRectangle(x*cellw,y*cellh,cellw,cellh,q[y+1][x+1]) end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/libs/0000775000000000000000000000000013223665306021702 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/libs/memory.lua0000664000000000000000000000664313223665306023726 0ustar rootroot-- Persistence library: -- Memorize data for current function -- memory.save(tab) and tab=memory.load() -- -- The data will be stored in file called -- .dat -- in the lua directory -- -- Example 1: -- -- -- Load initial values or set defaults -- arg = memory.load({picX=320,picY=200,scale=0}) -- -- Run an inputbox -- OK,arg.picX,arg.picY,arg.scale = inputbox("Image Size")", -- "Width", arg.picX, 1,2048,0, -- "Height", arg.picY, 1,2048,0, -- "Scale", arg.scale, 0,1,0); -- if OK == true then -- -- Save the selected values -- memory.save(arg) -- end -- Example 2: -- -- -- Load initial values or set defaults -- arg = memory.load({x=320,y=200,scale=0}) -- picX=arg.x -- picY=arg.y -- scale=arg.scale -- -- Run an inputbox -- OK,picX,picY,scale = inputbox("Image Size")", -- "Width", picX, 1,2048,0, -- "Height", picY, 1,2048,0, -- "Scale", scale, 0,1,0); -- if OK == true then -- -- Save the selected values -- memory.save({x=picX,y=picY,scale=scale}) -- end memory = { serialize = function(o) if type(o) == "number" then return tostring(o) elseif type(o) == "string" then return string.format("%q", o) --elseif type(o) == "table" then -- io.write("{\n") -- for k,v in pairs(o) do -- io.write(" ", k, " = ") -- memory.serialize(v) -- io.write(",\n") -- end -- io.write("}\n") else error("cannot serialize a " .. type(o)) end end; -- Return a string identifying the calling function. -- Pass 1 for parent, 2 for grandparent etc. callername = function(level) local w local last_slash local info = debug.getinfo(level+1,"Sn") local caller=tostring(info.name) -- Function name if possible if (caller~="nil") then return caller end -- Otherwise, get file name, without extension -- Get part after directory name last_slash=0 while true do local pos = string.find(info.source, "/", last_slash+1) if (pos==nil) then break end last_slash=pos end while true do local pos = string.find(info.source, "\\", last_slash+1) if (pos==nil) then break end last_slash=pos end caller=string.sub(info.source, last_slash+1) -- Remove file extension if (string.sub(caller,-4, -1)==".lua") then caller=string.sub(caller, 1, -5) end return caller end; -- Memorize some parameters. save = function(o) local caller=memory.callername(2) --for k, v in pairs(o) do -- messagebox(tostring(k)) -- messagebox(tostring(v)) --end local f, e = io.open(caller..".dat", "w"); if (f ~= nil) then f:write("Entry {\n") for k, v in pairs(o) do if (type(v)=="number") then f:write(" "..k.."="..memory["serialize"](v)..",\n") end end f:write("}\n") f:close() end end; -- Recover some saved parameters. load = function(o) local caller=memory.callername(2) local i function Entry (b) -- Adds (or replaces) values in arg with those from b for k, v in pairs(b) do o[k]=v end end local f = (loadfile(caller..".dat")) if (f ~= nil) then f() end return o end; } return memory grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/libs/dawnbringer_lib.lua0000664000000000000000000027505113223665306025547 0ustar rootroot--DawnBringer function library v1.14 (some drawing replaced) --** THIS IS NOT A RUNNABLE SCRIPT! ** --by Richard Fhager -- http://hem.fyristorg.com/dawnbringer/ -- Email: dawnbringer@hem.utfors.se -- MSN: annassar@hotmail.com -- -- Many functions in here was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html -- -- -- You may access these functions in your own scripts by loading this library, -- just add the follwing line as one of the first instructions: -- -- run("dawnbringer_lib") -- -- or -- -- run("../libs/dawnbringer_lib.lua") -- -- -- Note that the functions must be called with the full library object-name, "db.function_name..." -- -- Global library object db = {} -- ************************************* -- *** Text & Conversions *** -- ************************************* -- -- function db.rgb2HEX(r,g,b,prefix) local c,n,s,t,z c = {r,g,b} z = {"0",""} t = "" for n = 1, 3, 1 do s = string.upper(string.format("%x",c[n])) t = t..z[#s]..s --s = tonumber(c[n],16) --t = t..s end return prefix..t end -- -- ... eof Text & Conversions ... -- -- ************************************* -- *** Custom Math Functions *** -- ************************************* -- -- function db.sign(v) local s s = 0 if v > 0 then s = 1; end if v < 0 then s = -1; end return s end -- function db.distance(ax,ay,bx,by) return math.sqrt((ax-bx)^2 + (ay-by)^2); end -- function db.rotation (rot_ang,hub_x,hub_y,x,y) -- Rotate coordinates x & y relative hub local new_ang,dist,m,xd,yd,v; m = math xd=hub_x-x; yd=hub_y-y; if (not(xd==0 and yd==0)) then v = -90; if xd < 0 then v = 90; end new_ang = m.atan(yd/xd) - (v+rot_ang) * m.pi/180; dist = m.sqrt(xd*xd+yd*yd); x = hub_x - m.sin(new_ang)*dist; y = hub_y + m.cos(new_ang)*dist; end return math.floor(x),math.floor(y) -- For drawing purposes end -- -- function db.recursiveSum(div,rlev) -- divisons per recursion,recursion levels local s,i,m s,m = 1,1 for i = 1, rlev, 1 do m = m*div s = s + m end return s end -- -- -- ... eof Custom Math Functions ... -- -- ************************************* -- *** Fractional Scenery *** -- ************************************* -- function db.setSceneryPalette() db.colorCigarr(10,28,true) -- 250 colors setcolor(250, 208,48,48) setcolor(251, 48,208,48) setcolor(252, 48,48,208) setcolor(253, 224,224,64) setcolor(254, 224,64,224) setcolor(255, 64,224,224) end -- -- function db.star(xf,yf,sx,sy,rgb,haz,out,lum) local n,c,dist; c={} dist = haz + out * math.sqrt((xf-sx)^2+(yf-sy)^2); for n = 1, 3, 1 do c[n] = (rgb[n] * lum) / dist; end return c; end -- -- function db.zoom(xf,yf,zoom,panx,pany) -- Zoom and Pan in a fractional coord-system xf = (xf-0.5)/zoom + 0.5 + panx; yf = (yf-0.5)/zoom + 0.5 + pany; return xf,yf end -- -- function db.rotationFrac(rot_ang,hub_x,hub_y,x,y) -- Rotate coordinates x & y relative hub local new_ang,dist,m,xd,yd,v; m = math xd=hub_x-x; yd=hub_y-y; if (not(xd==0 and yd==0)) then v = -90; if xd < 0 then v = 90; end new_ang = m.atan(yd/xd) - (v+rot_ang) * m.pi/180; dist = m.sqrt(xd*xd+yd*yd); x = hub_x - m.sin(new_ang)*dist; y = hub_y + m.cos(new_ang)*dist; end return x,y end -- -- function db.twirl(x,y,arms,trot,tpow,tang) local b,ang,vx,vy,vr,m,deg,tw m=math; deg=math.pi/180; tw=.5; if (not(x==.5 and y==.5)) then ang = m.atan((.5-y)/(.5-x)); b = 0; if (x>.5) then b = m.pi; end vx = .5-x; vy = .5-y; vr = m.pow(m.sqrt(vx*vx+vy*vy),tpow); tw = .5+m.sin(-tang*deg+vr*trot+(ang + b)*arms)*.5; end return tw; end -- --- Alpha filters -- function db.alpha1(x,y,amp) -- Coord, Amplify: 0..n local p,a,xh,yh,m xh=0.5-x; yh=0.5-y; m = math p = m.pow(xh*xh+yh*yh,0.7); a = m.cos(32*m.pi*p)*m.sin(8*m.pi*(xh+yh)); return 1 + (a * amp) end -- -- -- ... eof Fractional Scenery ... -- -- ************************************* -- *** Custom Array Functions *** -- ************************************* -- -- Ok, I don't know Lua that well (still unsure about some scopes & refs etc.) -- And some features may not be active in Grafx2. So, some of the follwing functions -- may exist in Lua/Grafx2...but since I'm not sure if and how they work - I'll prefer -- to add a set of my own of known performance. -- function db.newArrayInit(xs,val) local x,ary; ary = {} for x = 1, xs, 1 do ary[x] = val end return ary end -- -- function db.newArrayInit2Dim(xs,ys,val) local x,y,ary; ary = {} for y = 1, ys, 1 do ary[y] = {} for x = 1, xs, 1 do ary[y][x] = val end end return ary end -- -- -- Merge two arrays into a NEW one: array_c = db.newArrayMerge(array_b,array_b) -- function db.newArrayMerge(a,b) local n,ary; ary = {} for n = 1, #a, 1 do ary[n] = a[n] end for n = 1, #b, 1 do ary[n+#a] = b[n] end return ary end -- -- -- Generate a copy of an array with a new value added Last -- function db.newArrayInsertLast(a,val) local n,ary; ary = {} for n = 1, #a, 1 do ary[n] = a[n] end ary[#a+1] = val return ary end -- -- -- Generate a copy of an array with a new value added First -- function db.newArrayInsertFirst(a,val) local n,ary; ary = {} ary[1] = val for n = 2, #a+1, 1 do ary[n] = a[n-1] end return ary end -- -- function db.ary2txt(ary) -- One & two dimensions supported [a,b] -> "a,b". [[a,b],[c,d]] -> "a-b, c-d" local t,n,m,v t = "" for n = 1, #ary, 1 do if type(ary[n]) == "table" then t = t..ary[n][1] for m = 2, #ary[n], 1 do t = t.."-"..ary[n][m] end else t = t..ary[n]; end t = t..", " end return t end -- -- -- *** Array data manipulation *** -- -- -- InsertionSort Array, this is chaos...I'm confused and stomped...don't understand how Lua works... -- ...sorting seem be to ok but this code is ugly... -- Sort LO-HI -- -- Screwed up or confused thing here I think, perhaps lo-hi/hi-lo. This is working lo-hi but the code -- looks like hi-lo...edit this some day -- function db.sorti(d,idx) local a,j,tmp,l,e l = #d for a=2, l, 1 do tmp = d[a]; e = a for j=a, 2, -1 do e = j if d[j-1][idx] > tmp[idx] then d[j] = d[j-1]; e = j-1; else break; end; end; d[e] = tmp; -- WHY THE F**K CAN'T YOU READ j HERE!?! STUPID ASSUCKING LANGUAGE end; --return d end -- -- function db.shuffle(list) local i,n,t for n = #list, 2, -1 do i = 1+math.floor(math.random() * n) t = list[n]; list[n] = list[i]; list[i] = t end end -- -- -- ... eof Custom Array Functions ... -- -- ************************************* -- *** Misc. Logical Operations *** -- ************************************* -- -- palList [r,g,b,palindex] is expected only to contain unique colors -- index = -1 --> index of list -- function db.makeIndexList(list,index) local n,ilist ilist = {} for n = 1, #list, 1 do if (index > 0) then ilist[n] = list[n][index]; end if (index == -1) then ilist[n] = n; end end return ilist end -- -- -- Return a list of all possible (non-same) pairs from the entries in a list -- [a,b,c] --> [[a,b],[a,c],[b,c]] -- (All entries are treated as unique. i.e it's only the INDEX that counts) -- mode = 0: Only unique pairs (m = (n^2 - n)/2), [a,b] --> [[a,b]] -- mode = 1: All pairs, i.e mirror versions as well. (m = n^2 - n), [a,b] --> [[a,b], [b,a]] -- function db.pairsFromList(list,mode) local a,b,l,n,pairs pairs = {} l = #list n = 1 for a = 1, l, 1 do for b = a+1, l, 1 do pairs[n] = {list[a],list[b]}; n = n + 1 if mode == 1 then pairs[n] = {list[b],list[a]}; n = n + 1; end end end return pairs end -- function db.valueInArray(ary,val) local n,res res = false for n = 1, #ary, 1 do if ary[n] == val then res = true; break; end end return res end -- RAMP specific -- Remove initial pair (palList) colors from pallist function db.initiateRamp(pair,pallist,pal_index) local n,found,plist plist = {} found = 1 for n = 1, #pallist, 1 do if db.valueInArray(pair,pallist[n]) == false then plist[found] = pallist[n]; found = found + 1; end end pair[pal_index] = plist -- ex: ["pal"] return pair -- Is now a 2 color RAMP end -- -- Remove new col entry from ramp's pallist and add it to the ramp, returns an updated ramp -- RampList = [1,2] ["pal"] = palList = [3,4,5], addindex = 3 -- --> [1,2,3] palList = [4,5] function db.updateRamp(ramp,addindex,pal_index) local n,found,pallist,plist,newramp plist = {} pallist = ramp[pal_index] -- New palList without added color to IndexList found = 1 for n = 1, #pallist, 1 do if pallist[n] ~= addindex then plist[found] = pallist[n]; found = found + 1; end end newramp = db.newArrayInsertLast(ramplist,addindex) newramp[pal_index] = plist return rlist end -- -- Returns a list of all inital ramps from color pairs -- -- Weeds out bad pairs, attaches remaining palette colors and the first rgb-vector -- -- function db.initiateRampList(pairs,pallist,pal_index,vec_index,min,maxmult,rw,gw,bw) local n,ramplist,newpairs,accept,dist,c1,c2,max,rD,gD,bD ramplist = {} max = min + (142 / math.sqrt(#pallist)) * maxmult -- min ex: 8-12 accept = 0 for n = 1, #pairs, 1 do c1 = pallist[pairs[n][1]] c2 = pallist[pairs[n][2]] rD = c2[1] - c1[1] gD = c2[2] - c1[2] bD = c2[3] - c1[3] dist = math.sqrt( (rw*rD)^2 + (gw*gD)^2 + (bw*bD)^2 ) if dist >= min and dist <= max then accept = accept + 1; ramplist[accept] = db.initiateRamp(pairs[n],pallist,pal_index); ramplist[accept][vec_index] = {rD, gD, bD, dist}; -- Add first color vector, ONLY KEEP DISTANCE? end end return ramplist end function db.findRampExpansionColors(ramp) local clist clist = {} -- Calculate vectors here? return clist end function db.findRAMPS(min_len, max_len) local i,n,c,pallist,ramp,ramplist,pairs,spairs,palindex,vecindex,found,donelist,newlist,dones local colorlist palindex = "pal" vecindex = "vector" pallist = db.fixPalette(db.makePalList(256), 0) pairs = db.pairsFromList(db.makeIndexList(pallist,-1), 0) ramplist = db.initiateRampList(pairs,pallist,palindex,vecindex, 8,0.75, 0.26,0.55,0.19) -- MIN_LEN = 5 -- MAX_LEN = 10 -- Split Ramp-build into two parts: -- 1. Build ramps >= MIN_LEN, NONE added to 'Done' -- 2. Run til no more ramps can be expanded or reaches MAX_LEN, ALL ramps added to 'Done' for i = 1, (min_len - 2), 1 do -- Assuming 2 for inital pairs (2 color ramps) newlist = {} found = 0 for n = 1, #ramplist, 1 do ramp = ramplist[n] colorlist = db.findRampExpansionColors(ramp) -- Colors that can split the current ramp into new expanded ramps for c = 1, #colorlist, 1 do found = found + 1; newlist[found] = db.updateRamp(ramp,colorlist[c],palindex); -- Ramp is expanded by 1 color end end ramplist = newlist end donelist = {}; dones = 0 repeat newlist = {} found = 0 for n = 1, #ramplist, 1 do ramp = ramplist[n] if true == false then found = found + 1; newlist[found] = db.updateRamp(ramp,color,palindex); else dones = dones + 1; donelist[dones] = ramp; end end --ramplist = newlist until found == 0 return #pairs.." - "..#ramplist end -- -- ... eof Misc. Logical Operations ... -- -- *************************************** -- *** General RGB-Color Modifications *** -- *************************************** -- function db.makeComplementaryColor(r,g,b,brikeeplev) -- Lev: 0 = Normal, 1 = Loose, 2 = Strict local bri_o,bri_n,bdiff function cap(v) return math.max(0,math.min(v,255)); end bri_o = db.getBrightness(r,g,b) r,g,b = db.shiftHUE(r,g,b,180) if brikeeplev > 0 then for n = 0, brikeeplev*3-1, 1 do -- Must iterate to reduce brightness error bri_n = db.getBrightness(r,g,b) bdiff = (bri_o - bri_n) / 2 * brikeeplev r = cap(r + bdiff) g = cap(g + bdiff) b = cap(b + bdiff) end end return r,g,b end -- -- *** Color balance *** -- -- bri_flag: Preserve brightness -- loose_flag: Loose preservation restrictions for brightness and balance -- -- Jeez, was this a tricky sucker; color-balance is just adding and capping... -- but trying color-balance with preserved perceptual brightness is a different monster... -- ...so bad I could only solve it by iterative error correction. -- function db.ColorBalance(r,g,b,rd,gd,bd,bri_flag,loose_flag) -- preserve brightness local rw,gw,bw,ri,gi,bi,itot,rni,gni,bni,ro,go,bo,ovscale,lev,count,rt,gt,bt,rf,gf,bf,bri -- Dawn 3.0, [0.26,0.55,0.19], 0-255 bri-colorscale adjust = 1.56905 rw,gw,bw = 0.26, 0.55, 0.19 function cap(v) return math.min(255,math.max(v,0)); end bri = db.getBrightness(r,g,b) -- Loose brightness & balance preservation, a good compromise. if bri_flag == true and loose_flag == true then lev = (rd + gd + bd) / 3 rd = rd - lev gd = gd - lev bd = bd - lev brin = db.getBrightness(cap(r+rd),cap(g+gd),cap(b+bd)) itot = brin - bri rd = rd - itot gd = gd - itot bd = bd - itot end if bri_flag == true and loose_flag == false then itot = 255 count = 0 -- Normalize (Yup, it's right only to normalize once first..cont.norm. will have some counter-effect) lev = (rd + gd + bd) / 3 rd = rd - lev gd = gd - lev bd = bd - lev repeat --messagebox("Norm:"..rd..", "..gd..", "..bd) -- Calculate total brightness change -- Note: Perceptual Brightness is exponential, and can't be delta-adjusted for anything other than greyscales. -- Although the formula for the new brightness corrected normalization level can can be derived... -- ...it doesn't do much good since the bigger problem is overflow outside the 0-255 boundary. -- As for now, I see no other means to solve this issue than with iterative error-correction. rt = r+rd gt = g+gd bt = b+bd itot = 9e99 rni = rd gni = gd bni = bd -- We can get brightness of negative values etc. So bri-correction is put on hold until values are scaled down if (rt>=0 and gt>=0 and bt>=0) and (rt<256 and gt<256 and bt<256) then brin = db.getBrightness(rt,gt,bt) itot = brin - bri --messagebox("Bri Diff: "..itot) -- Brightness adjusted balance rni = rd - itot gni = gd - itot bni = bd - itot end --messagebox("Bri Adj Bal:"..rni..", "..gni..", "..bni) -- Apply balance to find overflow (as fraction of the channel change) ro = math.max( math.max((r + rni)-255,0), math.abs(math.min((r + rni),0)) ) / math.max(math.abs(rni),1) go = math.max( math.max((g + gni)-255,0), math.abs(math.min((g + gni),0)) ) / math.max(math.abs(gni),1) bo = math.max( math.max((b + bni)-255,0), math.abs(math.min((b + bni),0)) ) / math.max(math.abs(bni),1) ovscale = 1 - math.max(ro,go,bo) -- Scaling balances might be logically incorrect (as they can be seen as constant differences) -- But scaling DOWN is quite harmless and I don't see how it could be done otherwise... -- ex: +10 red, +5 blue: Scale x2 = +20 red, +10 blue -> More red over blue than ordered, a contrast behaviour. -- +10 red, +5 blue: Scale x0.5 = +5 red, +2.5 blue -> Less of everything, but a part of the order. Harmless? -- rd = rni * ovscale gd = gni * ovscale bd = bni * ovscale count = count + 1 --messagebox("Final bal:"..rd..", "..gd..", "..bd) until math.abs(itot) < 1 or count > 5 end rf = r + rd gf = g + gd bf = b + bd --messagebox("Result color:"..rf..", "..gf..", "..bf) return rf,gf,bf end -- -- -- bri_flag: Preserve brightness -- cap_flag: Cap new color at 0-255, has a desaturating effect for large values. -- function db.ColorBalanceXXX(r,g,b,rd,gd,bd,bri_flag,cap_flag) -- preserve brightness local rf,gf,bf if cap_flag == true then rd = math.min(255,math.max(0, r+rd)) - r gd = math.min(255,math.max(0, g+gd)) - g bd = math.min(255,math.max(0, b+bd)) - b end local rw,gw,bw,ri,gi,bi,itot,rni,gni,bni,ro,go,bo,ovscale -- Dawn 3.0, [0.26,0.55,0.19], 0-255 bri-colorscale adjust = 1.56905 rw,gw,bw = 0.26, 0.55, 0.19 if bri_flag == true then -- Calculate total brightness change --ri = rd * rw --gi = gd * gw --bi = bd * bw --itot = math.sqrt(ri^2 + gi^2 + bi^2) bri = db.getBrightness(r,g,b) brin = db.getBrightness(r+rd,g+gd,b+bd) itot = brin - bri -- Normalized and Brightness adjusted balance rni = rd - itot gni = gd - itot bni = bd - itot -- Apply balance to find overflow (as fraction of the channel change) ro = math.max( math.max((r + rni)-255,0), math.abs(math.min((r + rni),0)) ) / math.max(math.abs(rni),1) go = math.max( math.max((g + gni)-255,0), math.abs(math.min((g + gni),0)) ) / math.max(math.abs(gni),1) bo = math.max( math.max((b + bni)-255,0), math.abs(math.min((b + bni),0)) ) / math.max(math.abs(bni),1) ovscale = 1 - math.max(ro,go,bo) rd = rni * ovscale gd = gni * ovscale bd = bni * ovscale end rf = r + rd gf = g + gd bf = b + bd return rf,gf,bf end -- -- function db.getContrast(ch) -- Channel, returns fraction -1..0..1, negative for ch < 127.5 --return math.abs((ch / 127.5) - 1) return (ch / 127.5) - 1 end -- -- function db.getAvgContrast(r,g,b) return (math.abs(db.getContrast(r)) + math.abs(db.getContrast(g)) + math.abs(db.getContrast(b))) / 3 end -- -- -- Mode = 0: Proportional - all colors reach max contrast at 100% -- -- Mode = 1: Linear - percentage simply added -- function db.changeContrastOLD(r,g,b,prc,mode) local m,rd,gd,bd,rv,gv,bv,rc,gc,bc,base,sign base = 1; sign = 1 if prc < 0 then base = 0; sign = -1; end -- decontrast m = prc / 100 * sign -- mode 0 rc = db.getContrast(r) rd = (base - math.abs(rc)) * m * db.sign(rc) rv = (rc+rd+1) * 127.5 gc = db.getContrast(g) gd = (base - math.abs(gc)) * m * db.sign(gc) gv = (gc+gd+1) * 127.5 bc = db.getContrast(b) bd = (base - math.abs(bc)) * m * db.sign(bc) bv = (bc+bd+1) * 127.5 return rv,gv,bv end -- function db.changeContrast(r,g,b,prc) -- Photoshop style local m,rd,gd,bd,rv,gv,bv,rc,gc,bc m = 1 + math.pow((255 / 100 * prc),3) / (255*255) -- decontrast if prc < 0 then m = 1 - math.abs(prc)/100 end rc = db.getContrast(r) rd = rc * m rv = (rd+1) * 127.5 gc = db.getContrast(g) gd = gc * m gv = (gd+1) * 127.5 bc = db.getContrast(b) bd = bc * m bv = (bd+1) * 127.5 return rv,gv,bv end -- function db.getBrightness(r,g,b) -- 0-255 local bri --bri = (r+g+b)/3 --bri = r*0.3 + g*0.59 + b*0.11 -- Luma Y'601 --bri = math.sqrt((r*0.3)^2 + (g*0.59)^2 + (b*0.11)^2) -- Luma Y'601 --bri = r*0.245 + g*0.575 + b*0.18 -- Dawn 2.0 bri = math.sqrt((r*0.26)^2 + (g*0.55)^2 + (b*0.19)^2) * 1.56905 -- Dawn 3.0 return bri end -- -- -- Note on desaturation: These functions are all junk, the only way to desaturate -- is to fade a color into it's corresponding greyscale. -- -- function db.desaturate(percent,r,g,b) -- V1.0 by Richard Fhager local a,p p = percent / 100 a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 * p r = r + (a-r*p) -- a+r*(1-p) g = g + (a-g*p) b = b + (a-b*p) return r,g,b end -- -- function db.desaturateA(percent,c) -- array version local r,g,b,a r = c[1] g = c[2] b = c[3] p = percent / 100 a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 * p r = r + (a-r*p) g = g + (a-g*p) b = b + (a-b*p) return {r,g,b} end -- -- function db.desatAVG(desat,c) -- Desaturation, simpe average r = c[1] g = c[2] b = c[3] p = desat / 100 a = (r+g+b)/3 r = r + p*(a-r) g = g + p*(a-g) b = b + p*(a-b) return {r,g,b} end -- -- function db.getSaturation(r,g,b) -- HSL local M,m,c,s,l M = math.max(r,g,b) m = math.min(r,g,b) c = (M - m)/255 s = 0 if c ~= 0 then --l = (0.3*r + 0.59*g + 0.11*b)/255 -- HSLuma: Y'601 l = (M+m)/510 -- This produces a quite "correct looking" divison of saturation if l <= 0.5 then s = c / (2*l); end if l > 0.5 then s = c / (2-2*l); end end return math.min(255,s * 255) end -- -- function db.getTrueSaturationX(r,g,b) -- Distance from grayscale axis. Not HSV/HSL local sat,bri bri = (r+g+b) / 3 sat = math.min(255, math.sqrt((r-bri)^2 + (g-bri)^2 + (b-bri)^2) * 1.224744875) return sat end -- -- WIP. Trying to find a more natural model for estimating Saturation -- Current: (HSL + True) / 2 function db.getAppSaturation(r,g,b) return math.min(255, (db.getSaturation(r,g,b) + db.getTrueSaturationX(r,g,b)) / 2) end -- -- function db.saturate(percent,r,g,b) local a,m,p,mc a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 m = math.min(255-math.max(r,g,b), math.min(r,g,b)) p = percent * (m / 100) mc = math.max((r-a),(g-a),(b-a)) -- Can this be derived elsewhere? if mc ~= 0 then r = r + (r-a) * p / mc g = g + (g-a) * p / mc b = b + (b-a) * p / mc end return r,g,b end -- -- -- Super Saturate: Better than Photoshop etc. -- -- Higher than 100% power is ok -- function db.saturateAdv(percent,r,g,b,brikeeplev,greydamp) -- brikeep = 0 - 2 local a,m,p,mc,bri_o,bri_n,bdiff,mx,mi,adj,q,n function cap(v) return math.max(0,math.min(v,255)); end mx = math.max(r,g,b) mi = math.min(r,g,b) bri_o = db.getBrightness(r,g,b) a = (math.min(mx,255) + math.max(mi,0)) * 0.5 m = math.min(255-mx, mi) p = percent * (m / 100) mc = math.max((r-a),(g-a),(b-a)) -- Can this be derived elsewhere? if mc ~= 0 and m ~= 0 then adj = math.min(1,(mx - mi) / m) -- Reduce effect on low saturation if greydamp == false then adj = 1; end q = p / mc * adj r = cap( r + (r-a) * q ) g = cap( g + (g-a) * q ) b = cap( b + (b-a) * q ) end for n = 0, brikeeplev*2, 1 do -- Must iterate to reduce brightness error bri_n = db.getBrightness(r,g,b) bdiff = (bri_o - bri_n) / 2 * brikeeplev r = cap(r + bdiff) g = cap(g + bdiff) b = cap(b + bdiff) end return r,g,b end -- -- -- Lightness: Darken / Brighten color (Argument and returnvalue is a rgb-list) -- Rate of change is inversely proportional to the distance of the max/min. -- i.e. all colors/channels will reach max/min at the same time (at 0 or 100 %) -- (As opposed to 'Brightness' where all channels are changed by a constant value) -- function db.lightness(percent,c) local v,r,g,b,p r = c[1] g = c[2] b = c[3] p = math.abs(percent/100) v = 255 if percent < 0 then v = 0; end r = r + (v - r)*p g = g + (v - g)*p b = b + (v - b)*p return {r,g,b} end -- -- function db.changeLightness(r,g,b,percent) local v v = db.lightness(percent,{r,g,b}) return v[1],v[2],v[3] end -- -- function db.getLightness(r,g,b) -- HSL bi-hexcone return (math.max(r,g,b) + math.min(r,g,b)) / 2 end -- -- function db.shiftHUE(r,g,b,deg) -- V1.3 R.Fhager 2007, (Heavily derived code, hehe...) local c,h,mi,mx,d,s,p,i,f,q,t c = {g,b,r} mi = math.min(r,g,b) mx = math.max(r,g,b); v = mx; d = mx - mi; s = 0; if mx ~= 0 then s = d/mx; end p = 1; if g ~= mx then p = 2; if b ~= mx then p = 0; end; end if s~=0 then h=(deg/60+(6+p*2+(c[1+p]-c[1+(p+1)%3])/d))%6; i=math.floor(h); f=h-i; p=v*(1-s); q=v*(1-s*f); t=v*(1-s*(1-f)); c={v,q,p,p,t,v} r = c[1+i] g = c[1+(i+4)%6] b = c[1+(i+2)%6] end return r,g,b end -- -- function db.getHUE(r,g,b,greytol) -- 0-6 (6.5 = Greyscale), mult. with 60 for degrees -- 1 Color diff is roughly detected by Tolerance = 0.0078125 (Tol. incr. with lightness etc.) local c,h,mi,mx,d,s,p,i,f,q,t c = {g,b,r} mi = math.min(r,g,b) mx = math.max(r,g,b); v = mx; d = mx - mi; s = 0; if mx ~= 0 then s = d/mx; end p = 1; if g ~= mx then p = 2; if b ~= mx then p = 0; end; end h = 6.5 -- for custom graphical purposes if s>greytol then -- can't use >= h=(6+p*2+(c[1+p]-c[1+(p+1)%3])/d)%6; end return h end -- -- -- ... eof RGB color modifications ... -- -- **************************************** -- *** Custom Color / Palette functions *** -- **************************************** --# of Unique colors in palette: --#db.fixPalette(db.makePalList(256)) --# of Colors in Image: --#db.makePalListFromHistogram(db.makeHistogram()) --# of Unique colors in Image: --#db.fixPalette(db.makePalListFromHistogram(db.makeHistogram())) -- function db.rgbcap(r,g,b,mx,mi) local m = math return m.max(mi,m.min(r,mx)), m.max(mi,m.min(g,mx)), m.max(mi,m.min(b,mx)) end -- -- function db.rgbcapInt(r,g,b,mx,mi) local m = math return m.floor(m.max(mi,m.min(r,mx))), m.floor(m.max(mi,m.min(g,mx))), m.floor(m.max(mi,m.min(b,mx))) end -- -- function db.makePalList(cols) local pal,n,r,g,b pal = {} for n = 0, cols-1, 1 do r,g,b = getcolor(n) pal[n+1] = {r,g,b,n} end return pal end -- -- function db.makeSparePalList(cols) local pal,n,r,g,b pal = {} for n = 0, cols-1, 1 do r,g,b = getsparecolor(n) pal[n+1] = {r,g,b,n} end return pal end -- -- -- Use to remove the black colors (marks unused colors) from palette-list -- if it's known that no black color exists in the image. function db.stripBlackFromPalList(pallist) local i,u,c,dummy; i = 257 -- Do 'nothing' If using a full 256 col palette with no blacks for u = 1, #pallist, 1 do c = pallist[u] if (c[1]+c[2]+c[3]) == 0 then i = u; end end dummy = table.remove(pallist,i) return pallist end -- -- function db.stripIndexFromPalList(pallist,colindex) local i,u,c,dummy for u = 1, #pallist, 1 do c = pallist[u] if c[4] == colindex then i = u; end end dummy = table.remove(pallist,i) return pallist end -- -- function db.addHSBtoPalette(pallist) local n,hue,sat,rgb for n=1, #pallist, 1 do rgb = pallist[n] pallist[n][5] = db.getHUE(rgb[1],rgb[2],rgb[3],0) pallist[n][6] = db.getSaturation(rgb[1],rgb[2],rgb[3]) pallist[n][7] = db.getBrightness(rgb[1],rgb[2],rgb[3]) end return pallist -- {r,g,b,n,bri,hue,sat} end -- -- function db.makePalListRange(start,ends) local pal,n,r,g,b,a pal = {} a = 1 for n = start, ends, 1 do r,g,b = getcolor(n) pal[a] = {r,g,b,n}; a = a + 1; end return pal end -- -- function db.makePalListShade(cols,sha) -- Convert colors to less bits, colorcube operations etc. local pal,n,r,g,b,mf,div mf = math.floor div = 256 / sha pal = {} for n = 0, cols-1, 1 do r,g,b = getcolor(n) pal[n+1] = {mf(r/div),mf(g/div),mf(b/div),n} end return pal end -- -- function db.makePalListShadeSPARE(cols,sha) -- Convert colors to less bits, colorcube operations etc. local pal,n,r,g,b,mf,div mf = math.floor div = 256 / sha pal = {} for n = 0, cols-1, 1 do r,g,b = getsparecolor(n) pal[n+1] = {mf(r/div),mf(g/div),mf(b/div),n} end return pal end -- -- function db.getColorDistance_weight(r1,g1,b1,r2,g2,b2,rw,gw,bw) return math.sqrt( (rw*(r1-r2))^2 + (gw*(g1-g2))^2 + (bw*(b1-b2))^2 ) end -- -- -- Since brightness is exponential, each channel may work as a "star" drowning the color -- of a lesser channel. This algorithm is an approximation to adjust distances for this phenomenon. -- Ex: Adding 32 red to black is visually obvious, but adding 64 red to full green is almost -- impossible to detect by the naked eye. -- -- However this isn't a complete solution so we may weigh in brightness as well... -- -- If cv = 0 (0..1) then prox acts as ordinary perceptual colordistance -- if bri = 1 (0..1) then distance is only that of brightness function db.getColorDistanceProx(r1,g1,b1,r2,g2,b2,rw,gw,bw,normalizer, cv,briweight) local rp1,gp1,bp1,rp2,gp2,bp2,v,m1,m2,prox,bdiff; v = 2*255*255 m1 = math.max(r1,g1,b1) m2 = math.max(r2,g2,b2) rp1 = 1 - math.sqrt((r1-m1)^2 / v) * cv gp1 = 1 - math.sqrt((g1-m1)^2 / v) * cv bp1 = 1 - math.sqrt((b1-m1)^2 / v) * cv rp2 = 1 - math.sqrt((r2-m2)^2 / v) * cv gp2 = 1 - math.sqrt((g2-m2)^2 / v) * cv bp2 = 1 - math.sqrt((b2-m2)^2 / v) * cv bdiff = math.abs(db.getBrightness(r1,g1,b1) - db.getBrightness(r2,g2,b2)) -- weights are hardcoded in function prox = math.sqrt( (rw*(r1*rp1-r2*rp2))^2 + (gw*(g1*gp1-g2*gp2))^2 + (bw*(b1*bp1-b2*bp2))^2 ) * normalizer return prox * (1-briweight) + bdiff * briweight end -- -- function db.getBestPalMatch(r,g,b,pal,index_flag) -- pal = [r,g,b,palindex], index_flag -> return palindex if pal is sorted or reduced local diff,best,bestcol,cols,n,c,p cols = #pal bestcol = -1 best = 9e99 for n=1, cols, 1 do p = pal[n] diff = db.getColorDistance_weight(r,g,b,p[1],p[2],p[3],0.26,0.55,0.19) * 1.569 if diff < best then bestcol = n; best = diff; end end if index_flag == true then bestcol = pal[bestcol][4] + 1 end return bestcol-1 -- palList index start at 1, image-palette at 0 end -- -- Normally this function will return the (image)palette index of best color -- ...but if the palette has been sorted with 'fixPalette' it will return the index -- of the custom palList, setting index_flag will convert this value to image-palette index -- -- HYBRID means the colormatch is a combo of color and (perceptual)brightness -- -- function db.getBestPalMatchHYBRID(rgb,pal,briweight,index_flag) -- Now correctly balanced local diff,diffC,diffB,best,bestcol,cols,n,c,r,g,b,p,obri,pbri cols = #pal bestcol = -1 best = 9e99 --messagebox(briweight) -- Note: Not secured against negative values (this algorithm is SLOW, we cannot afford it) r = rgb[1] g = rgb[2] b = rgb[3] obri = db.getBrightness(r,g,b) -- 0-255 for n=1, cols, 1 do p = pal[n] pbri = db.getBrightness(p[1],p[2],p[3]) diffB = math.abs(obri - pbri) -- we need to normalize the distance by the weights diffC = db.getColorDistance_weight(r,g,b,p[1],p[2],p[3],0.26,0.55,0.19) * 1.569 diff = briweight * (diffB - diffC) + diffC if diff < best then bestcol = n; best = diff; end end if index_flag == true then bestcol = pal[bestcol][4] + 1 -- Since we detract 1 on return, God Lua is stupid end return bestcol-1 -- palList index start at 1, image-palette at 0 end -- -- -- Special version of Hybrid-remapping for mixPalette list -- -- mixpal: {score,col#1,col#2,dist,rm,gm,bm, c1_r,c1_g,c1_b, c2_r,c2_g,c2_b} -- -- returns: {col#1,col#2} (index of palette) -- function db.getBestPalMatchHybridMIX(rgb,mixpal,briweight,mixreduction) local diff,diffC,diffB,best,bestcol,cols,n,c,r,g,b,p,obri,pbri, distmult cols = #mixpal bestcol = -1 best = 9e99 -- We will simply add the the distance to the mix with the distance between the mixcolors and -- employ a user tolerance to much the latter will matter. --distmult = 255 / 9.56 / 100 * mixreduction -- 16 shades distmult = 1.56902 / 100 * mixreduction -- 24-bit, Dawn3.0 colormodel -- Note: Not secured against negative values (this algorithm is SLOW, we cannot afford it) r = rgb[1] g = rgb[2] b = rgb[3] obri = db.getBrightness(r,g,b) -- 0-255 for n=1, cols, 1 do p = mixpal[n] --pbri = db.getBrightness(p[5],p[6],p[7]) -- *** DawnBringer's exponetial color brightness dither resolution phenomena theorem *** -- Bri = color value ^ 2 -- Two adjacent pixels displayed with "normal high resolution" will NOT have the perceptual -- brightness of the resulting mixcolor. The brightness lies closer to that of the brightest pixel. -- Bri[(C1+C2)/2] = SQRT( (C1bri^2 + C2bri^2) / 2 ) -- (Brightness according to Dawn-model: bri = SQRT( (r*.26)^2 + (g*.55)^2 + (b*.19)^2 ) ) pbri = math.sqrt((db.getBrightness(p[8],p[9],p[10])^2 + db.getBrightness(p[11],p[12],p[13])^2) / 2) diffB = math.abs(obri - pbri) -- we need to normalize the distance by the weights diffC = db.getColorDistance_weight(r,g,b,p[5],p[6],p[7],0.26,0.55,0.19) * 1.569 + p[4]*distmult diff = briweight * (diffB - diffC) + diffC if diff <= best then bestcol = n; best = diff; end end return {mixpal[bestcol][2], mixpal[bestcol][3]} --return {mixpal[bestcol][2], 0} end -- -- function db.matchcolorHSB(h,s,b,pallist,index_flag) -- -- why don't we just convert HSB-diagram to RGB and do normal colormatching? -- Not the same... -- local n,c,best,bestcol,pb,ph,ps,diff,huediff,huecorr,hue_adj,sat_adj,bri_adj bestcol = -1 best = 9e99 -- higher adjust means more impact (higher hue gives more interpolation ) hue_adj = 4 sat_adj = 0.075 bri_adj = 2 huecorr = 255 / 6 -- Our Hue goes from 0.0 - 5.999 for n=1, #pallist, 1 do c = pallist[n] ph = c[5] ps = c[6] pb = c[7] huediff = math.abs(h-ph*huecorr) if huediff > 127 then huediff = huediff - (huediff % 127) * 2; end --if ph == 6.5 then huediff = 0; end -- With less saturation, exact hue becomes less important and brightness more usefull -- This allows for greyscales and low saturation colors to work smoothly. huediff = huediff * (ps /255) diff = hue_adj*huediff^2 + (s-ps)^2 * sat_adj + (b-pb)^2 * bri_adj if diff <= best then bestcol = n; best = diff; end end if index_flag == true then bestcol = pallist[bestcol][4] + 1 -- Since we detract 1 on return, God Lua is stupid end return bestcol-1 end -- -- -- Used by PaletteAnalysis.lua, FindRamps(), MixColors() etc. -- Assigns is used by ApplySpare script -- function db.fixPalette(pal,sortflag) -- Arrange palette & only keep unique colors local n,l,rgb,i,unique,bri,hue,sat,ulist,indexpal,newpal,dtot ulist = {} indexpal = {} newpal = {} local doubles,assign doubles = {}; assign = {} l = #pal unique = 1 -- ok, see how stupid lua is dtot = 0 for n=1, l, 1 do rgb = pal[n]; -- actually rgbn i = 1 + rgb[1] * 65536 + rgb[2] * 256 + rgb[3]; bri = db.getBrightness(rgb[1],rgb[2],rgb[3]) if indexpal[i] == nil then indexpal[i] = rgb; ulist[unique] = {i,bri}; unique = unique+1; assign[rgb[4]+1] = rgb[4] -- really n, but can we be sure? else doubles[rgb[4]] = true; -- Mark as double (This is wrong; starts at 0...but col 0 cannot be a double so...) dtot = dtot + 1 assign[rgb[4]+1] = indexpal[i][4] -- Reassign removed color end end -- sort ulist if sortflag == 1 then db.sorti(ulist,2); end -- sort by brightness l = #ulist for n=1, l, 1 do newpal[n] = indexpal[ulist[n][1]] end newpal["assigns"] = assign -- Complete list of image color assigns (removed cols will point to 1st occurence) newpal["doubles"] = doubles newpal.double_total = dtot --messagebox("unique colors", unique-1) return newpal end -- -- function db.drawColorspace12bit(x,y,cols,size) local r,g,b,c,rows,row,col,s16,rx,ry,xx,yy s16 = size*16 rows = math.floor(16/cols) for g = 0, 15, 1 do col = g % cols row = math.floor(g / cols) for r = 0, 15, 1 do for b = 0, 15, 1 do c = matchcolor(r*17,g*17,b*17) xx = x+col*s16+r*size yy = y+row*s16+b*size for ry = 0, size-1, 1 do for rx = 0, size-1, 1 do putpicturepixel(xx+rx,yy+ry,c) end;end end end end end -- -- function db.drawHSBdiagram(pallist,posx,posy,width,height,size,sat) --db.addHSBtoPalette(palList) local x,y,c for y = 0, height-1, 1 do for x = 0, width-1, 1 do hue = 255/width * x bri = 255/height * y c = db.matchcolorHSB(hue,sat,bri,pallist,true) db.drawRectangle(posx + x*size, posy + y*size,size,size, c) end end end -- -- function db.polarHSBdiagram(ox,oy,radius,pol,brilev,huelev,saturation,dark2bright_flag) local pal,bstep,bstep2,hstep,hstep2,bri,hue,sx,sy,cx,cy,x,y,p1,p2,c pal = db.addHSBtoPalette(db.fixPalette(db.makePalList(256))) bstep = radius / (brilev + pol) bstep2 = bstep / 2 hstep = -360 / huelev hstep2 = hstep / 2 c = 255; if dark2bright_flag then c = 0; end drawdisk(ox,oy,math.ceil(pol*bstep),matchcolor(c,c,c)) for y=pol, brilev+pol-1,1 do bri = (brilev - y + pol) * (256 / brilev) if dark2bright_flag then bri = (brilev - (brilev - y + pol)) * (256 / brilev) end for x=0, huelev-1,1 do hue = x * (360 / huelev) * 255/360 c = db.matchcolorHSB(hue,saturation,bri,pal,true) sx = ox sy = oy - y*bstep cx,cy = db.rotationFrac(x*hstep,ox,oy,sx,sy) x1,y1 = db.rotation(x*hstep-hstep2,ox,oy,ox, sy-bstep2) x2,y2 = db.rotation(x*hstep+hstep2,ox,oy,ox, sy-bstep2) x3,y3 = db.rotation(x*hstep-hstep2,ox,oy,ox, sy+bstep2) x4,y4 = db.rotation(x*hstep+hstep2,ox,oy,ox, sy+bstep2) p1 = {{x1,y1},{x2,y2},{x3,y3}} p2 = {{x3,y3},{x4,y4},{x2,y2}} db.fillTriangle(p1,c,0,true,false) -- triangle, fillcol, linecol, fill, wire db.fillTriangle(p2,c,0,true,false) end updatescreen(); if (waitbreak(0)==1) then return; end end end -- polarHSB -- -- -- Histograms, remapping etc. -- -- function db.makeHistogram() local n,y,x,c,w,h,list; list = {} w, h = getpicturesize() for n = 1, 256, 1 do list[n] = 0; end for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do c = getpicturepixel(x,y) list[c+1] = list[c+1] + 1 end end return list end -- -- function db.makeHistogramIndexed() -- With color index so it can be sorted etc. local n,y,x,c,w,h,r,g,b,list; list = {} w, h = getpicturesize() for n = 1, 256, 1 do r,g,b = getcolor(n-1) list[n] = {0,n-1,r,g,b}; end for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do c = getpicturepixel(x,y) list[c+1][1] = list[c+1][1] + 1 end end return list end -- -- function db.makeSpareHistogram() local n,y,x,c,w,h,list; list = {} w, h = getsparepicturesize() --w,h = 512,360 for n = 1, 256, 1 do list[n] = 0; end for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do c = getsparepicturepixel(x,y) list[c+1] = list[c+1] + 1 end end return list end -- -- -- Makes a palette-list from only the colors (histogram) that occurs in the image -- Assumes image/palette has not changed since histogram was created function db.makePalListFromHistogram(hist) local n,r,g,b,list,count list = {} count = 1 for n = 1, #hist, 1 do if hist[n] > 0 then r,g,b = getcolor(n-1) list[count] = {r,g,b,n-1} count = count + 1 end end return list end -- function db.makePalListFromSpareHistogram(hist) local n,r,g,b,list,count list = {} count = 1 for n = 1, #hist, 1 do if hist[n] > 0 then r,g,b = getsparecolor(n-1) list[count] = {r,g,b,n-1} count = count + 1 end end return list end -- -- function db.remap(org) -- Working with a remap-list there's no need of reading backuppixel --messagebox("Remapping") local x,y,c,i,w,h,s,f,col f = getpicturepixel s = false w, h = getpicturesize() for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do c = f(x,y) i = org[c+1] if i == null then i = matchcolor(getbackupcolor(getbackuppixel(x,y))); s = true; col = c; end -- Find color for a removed double putpicturepixel(x,y,i) end end if s then messagebox("Remapping: Not all image colors were found in remap-list (re-assign), probably due to duplicate removal. Matchcolor was used, ex: col# "..col); end end -- -- -- Same as db.remap but no comments -- function db.remapImage(colassignlist) -- assignment list is optional local x,y,c,w,i,h,assign assign = false if colassignlist ~= null then assign = true; end w,h = getpicturesize() for y = 0, h-1, 1 do for x = 0, w-1, 1 do c = getbackuppixel(x,y) i = null; if assign then i = colassignlist[c+1]; end if not assign or i == null then i = matchcolor(getbackupcolor(c)) end putpicturepixel(x,y,i) end end end -- -- -- Palette DeCluster: Color-reduction by fusing similar colors into new ones, using a desired tolerance. -- This is a method similar to Median-Cut, but more surgical. -- -- pallist: Palette list {r,g,b,palette_index} -- hist: Histogram {color 0 pixels, color 1 pixels...etc} always a full 256 color list -- crad: Cluster radius treshold in % of distance between black & white -- A value of 0 will only remove identical colors -- A value of 3-4 will usally fuse redundant colors without causing notice -- prot_pow: (0..10) Protect common colors in histogram. Distances are increased by ocurrence. -- Also gives protection to fused colors even if not using histogram (combined nominal weights) -- pixels: Pixels in image (so protection can be calculated) -- rw,gw,bw: Color weights (rw+gw+bw = 1, 0.33,0.33,0.33 is nominal) -- -- Returns: -- a new (c)palette list {r,g,b,{original palette_indices},fused flag, histogram_weight} -- a remap list (org) [image color + 1] = remap color (in the new palette) function db.deCluster(pallist, hist, crad, prot_pow, pixels, rw,gw,bw) --messagebox(pixels) local u,c,a,i,o,j,n,c1,c2,r,g,b,r1,g1,b1,r2,g2,b2,wt,rt,gt,bt,tot,pd local worst,wtot,maxdist,maxDist,distfrac,clusterExists,clustVal,count,crad1 local cList,cPalList,clusterList,fuseCol,orgcols,newPalList,org maxdist = math.sqrt(rw*rw*65025 + gw*gw*65025 + bw*bw*65025) distfrac = 100 / maxdist -- Let's just make a slightly more suitable format of the pallist (List for original color(s)) cPalList = {} for u = 1, #pallist, 1 do c = pallist[u] cPalList[u] = {c[1],c[2],c[3],{c[4]},false,hist[c[4]+1]} -- r,g,b,{original colors},fuse_marker,histogram_weight end --table.insert(cPalList,{255,255,0,{257},false,1}) clusterExists = true while clusterExists do clusterExists = false clusterList = {} crad1 = crad + 1 -- avoid divison by zero worst = 9999 for a = 1, #cPalList, 1 do c1 = cPalList[a] r1,g1,b1 = c1[1],c1[2],c1[3] wtot = c1[6] cList = {a} maxDist = 0 for b = 1, #cPalList, 1 do if (b ~= a) then c2 = cPalList[b] r2,g2,b2 = c2[1],c2[2],c2[3] wt = c2[6] pd = math.pow((1 + wt / pixels), prot_pow) -- Protection, increase distance dist = db.getColorDistance_weight(r1,g1,b1,r2,g2,b2,rw,gw,bw) * distfrac * pd if dist <= crad then wtot = wtot + wt table.insert(cList,b) maxDist = math.max(dist,maxDist) end end end -- b if #cList > 1 then clustVal = maxDist / (crad1 * #cList) * (wtot / #cList) if clustVal < worst then worst = clustVal clusterList = cList end end end -- a --t = db.ary2txt(clusterList) --messagebox("Worst cluster is "..t) -- Fuse if #clusterList > 1 then clusterExists = true -- Run another iteration and look for more clusters fuseCol = {0,0,0,{}} rt,gt,bt,tot = 0,0,0,0 for n = 1, #clusterList, 1 do i = clusterList[n] c = cPalList[i] --o = c[4][1] -- Original color (always #1 in list since fused colors can't re-fuse) o = c[4] -- Original color list --if c[5] == true then messagebox("Re-Fusing..."); end r,g,b = c[1],c[2],c[3] --wt = hist[o+1] -- Org. colors are 0-255 wt = c[6] rt = rt + r * wt gt = gt + g * wt bt = bt + b * wt tot = tot + wt cPalList[i] = -1 -- Erase color --table.insert(fuseCol[4],o) orgcols = fuseCol[4] for j = 1, #o, 1 do table.insert(orgcols,o[j]) end fuseCol[4] = orgcols end rt = rt / tot gt = gt / tot bt = bt / tot fuseCol[1] = rt fuseCol[2] = gt fuseCol[3] = bt fuseCol[5] = true -- fusecol marker fuseCol[6] = tot table.insert(cPalList,fuseCol) --messagebox(#clusterList.." Colors was fused, resulting in "..rt..", "..gt..", "..bt) newPalList = {} for n = 1, #cPalList, 1 do if cPalList[n] ~= -1 then table.insert(newPalList,cPalList[n]) --newPalList = db.newArrayInsertLast(newPalList,cPalList[n]) end end cPalList = newPalList --messagebox("Pal length: "..#cPalList) statusmessage("DC - Image colors: "..#cPalList.." "); waitbreak(0) end -- fuse end -- while -- Create remap-list org = {} count = 0 for u = 1, #cPalList, 1 do c = cPalList[u] for n = 1, #c[4], 1 do i = c[4][n] org[i+1] = count -- quick way to remap without matchcolor end count = count + 1 end return org,cPalList end; -- decluster -- ------------- MEDIAN CUT V1.0 ------------ -- -- 256 color Palette Lua-version (converted from Evalion JS-script) -- -- by Richard 'DawnBringer' Fhager -- -- -- pal: [[r,g,b,i]] Pallist -- cnum: Target number of colors in reduced palette -- (step:) 1.. Pixel picks for processing, 1 = all pixels in image, best and slowest. 2 = 25% of pixels -- qual: Flag Qualitative color selection (Normal mode) -- quant: Flag Quantative color/pixel selection (Histogram) 100% mean that it count as much as quality -- (One of or both qual/quant must be selected) -- rgbw: [3] RGB-weights []. Weigh the color channels. ex: [1,1.333,0.75] -- bits: 1-8 Bits used for each color channel in palette -- quantpow: 0..1 -- -- return: A palette! A list of [r,g,b] values -- -- NOTE: Quantity will act as a counterforce to altered colorspace (weights)... -- Ex: if Green is considered bigger, it will be split into more blocks -- but each blocks will have less colors and thus less quantity. -- -- Perceptual colorspace (rgb-weights) will generally produce the best quality of palettes, but if -- It's desirable to preserve stronger colors, esp. in small palettes, -- it can be good to just use nominal space: 1,1,1 -- -- Histogram may be useful to assign more colors to an object that already covers most of the image, -- however; if the object of interest is small in relation to a large (unimportant) background, it's -- usually best not to have any histogram at all. Histogram will dampen strong infrequent colors. function db.medianCut(pal,cnum,qual,quant,rgbw,bits,quantpow) local n,x,y,xs,ys,rgb,blocklist,blocks local len,res,chan,diff,maxdiff,maxblock,split local qualnorm, quantnorm -- Normalize 256 for quality/quantity relationship qualnorm = 1 / math.sqrt(rgbw[1]^2 + rgbw[2]^2 + rgbw[3]^2) quantnorm = 256 / #pal blocklist = {} blocklist[1] = {}; blocks = 1 for n=1, #pal, 1 do blocklist[1][n] = pal[n]; end analyzeBlock(blocklist[1],qual,quant,rgbw,qualnorm,quantnorm,quantpow) failsafe = 0 while (blocks < cnum and failsafe < 256) do failsafe = failsafe + 1 maxdiff = -1 maxblock = -1 for n=1, blocks, 1 do diff = blocklist[n].diff if (diff > maxdiff) then maxdiff = diff; maxblock = n; end -- maxchan is stored as .chan in block end split = splitBlock(blocklist,maxblock,qual,quant,rgbw,qualnorm,quantnorm,quantpow) --if (split == false){ alert("Only found " + blocks + " (24-bit) colors!"); break; } blocks = #blocklist --status.value = "MC: " +blocks end -- while return blocks2Palette(blocklist,bits) end -- -- function blocks2Palette(blocklist,bits) local n,r,g,b,c,pal,block,rgb,blen,M,dB,cB,rf,gf,bf M = math pal = {} --bits = 1 dB = M.pow(2,8-bits) cB = M.ceil(255 / (M.pow(2,bits) - 1)) for n=1, #blocklist, 1 do block = blocklist[n] r,g,b = 0,0,0 blen = #block for c=1, blen, 1 do rgb = block[c] r = r + rgb[1] g = g + rgb[2] b = b + rgb[3] end rf = M.floor(M.min(255,M.max(0,M.floor(r/blen))) / dB) * cB gf = M.floor(M.min(255,M.max(0,M.floor(g/blen))) / dB) * cB bf = M.floor(M.min(255,M.max(0,M.floor(b/blen))) / dB) * cB pal[n] = {rf, gf, bf, 0} -- col is avg. of all colors in block (index is set (to 0) for compatibility) end -- blocklist return pal end -- -- function analyzeBlock(block,qual,quant,rgbw,qualnorm,quantnorm,quantpow) local r,g,b,n,rmin,gmin,bmin,rmax,gmax,bmax,rdif,gdif,bdif,chan,d,median,diff local len,Mm,Mx,rgb,kv,qu Mx,Mm = math.max, math.min len = #block rmin,gmin,bmin = 255,255,255 rmax,gmax,bmax = 0,0,0 for n=1, len, 1 do rgb = block[n] r = rgb[1] * rgbw[1] g = rgb[2] * rgbw[2] b = rgb[3] * rgbw[3] --if (!isNaN(r) and !isNaN(g) and !isNaN(b)) then -- Ignore any erroneous data rmin = Mm(rmin,r) gmin = Mm(gmin,g) bmin = Mm(bmin,b) rmax = Mx(rmax,r) gmax = Mx(gmax,g) bmax = Mx(bmax,b) --end end rdif = (rmax - rmin) -- * rgbw[1] gdif = (gmax - gmin) -- * rgbw[2] bdif = (bmax - bmin) -- * rgbw[3] d = {{rmin,rdif,rmax},{gmin,gdif,gmax},{bmin,bdif,bmax}} chan = 1 -- Widest channel if (gdif > rdif) then chan = 2; end if (bdif > rdif and bdif > gdif) then chan = 3; end -- Ok, this is the average of the max/min value rather than an actual median -- I guess this will fill the colorspace more uniformly and perhaps select extremes to a greater extent? -- Which is better? --median = d[chan][1] + d[chan][2] / 2 -- OLD same as median with nominal weights median = (d[chan][1] + d[chan][3]) / 2 -- quantity and quality are normalized to 256 (256 is the total of colors in the set for quantity) -- Note that, regardless of forumla, quality (distance) must always be greater in any block than quantity (colors/pixels) -- Coz a block may contain many of only 1 unique color, thus rendering it impossible to split if selected. kv = 1 qu = 1 if (quant) then kv = 1 + len*quantnorm*quantpow; end if (qual) then qu = d[chan][2] * qualnorm; end diff = qu + qu*kv^2.5 block.chan = chan block.diff = diff block.median = median return {chan,diff,median,len} end -- function splitBlock(blocklist,maxblock,qual,quant,rgbw,qualnorm,quantnorm,quantpow) local n,cmax,median,blockA,blockB,len,cB,block,rgb,res blockA,blockB = {},{} block = blocklist[maxblock] res = true chan = block.chan median = block.median cB = blocklist[maxblock] -- maxblock starts at 1 when called so it should not hava a +1 len = #cB for n=1, len, 1 do rgb = cB[n] --if (rgb[chan] >= median) then blockA.push(rgb); end --if (rgb[chan] < median) then blockB.push(rgb); end if (rgb[chan]*rgbw[chan] >= median) then table.insert(blockA,rgb); end if (rgb[chan]*rgbw[chan] < median) then table.insert(blockB,rgb); end end blocklist[maxblock] = blockA -- Can't be empty right? analyzeBlock(blocklist[maxblock],qual,quant,rgbw,qualnorm,quantnorm,quantpow) if (#blockB > 0) then table.insert(blocklist,blockB) analyzeBlock(blocklist[#blocklist],qual,quant,rgbw,qualnorm,quantnorm,quantpow) -- no -1 on blocklist else res = false end return res -- false = no split end ------------ eof MEDIAN CUT -------------------------- -- ------------- MEDIAN REDUX V1.0 ------------ -- -- Divide space by greatest distance of any two colors (rather than MC-method of any given channel) -- Basically it allows colorspace to be sliced at any angles rather than the "boxing" of MC. -- -- -- by Richard 'DawnBringer' Fhager -- -- -- pal: [[r,g,b,i,h]] Pallist (h = histogram/pixelcount) -- cnum: Target number of colors in reduced palette -- (step:) 1.. Pixel picks for processing, 1 = all pixels in image, best and slowest. 2 = 25% of pixels -- qual: Flag Qualitative color selection (Normal mode) -- quant: Flag Quantative color/pixel selection (Histogram) 100% mean that it count as much as quality -- (One of or both qual/quant must be selected) -- rgbw: [3] RGB-weights []. Weigh the color channels. ex: [0.26, 0.55, 0.19] -- bits: 1-8 Bits used for each color channel in palette -- quantpow: 0..1 Quantity vs Quality (put weight into histogram/pixelcount) -- briweight: 0..1 Brightness distance weight in colordistance -- proxweight: 0..1 Primary Proximity distance weight in colordistance (ColorTheory-WIP: compensate for brightness of individual channels, the "extra power" of primary colors) -- -- return: A palette! A list of [r,g,b] values -- -- NOTE: Quantity will act as a counterforce to altered colorspace (weights)... -- Ex: if Green is considered bigger, it will be split into more blocks -- but each blocks will have less colors and thus less quantity. -- -- Perceptual colorspace (rgb-weights) will generally produce the best quality of palettes, but if -- It's desirable to preserve stronger colors, esp. in small palettes, -- it can be good to just use nominal space: 0.33, 0.33, 0.33 -- -- Histogram may be useful to assign more colors to an object that already covers most of the image, -- however; if the object of interest is small in relation to a large (unimportant) background, it's -- usually best not to have any histogram at all. Histogram will dampen strong infrequent colors. function db.medianRedux(pal,cnum,qual,quant,rgbw,bits,quantpow, briweight, proxweight) -- pal[r,g,b,i,pixelcount] local n,x,y,xs,ys,rgb,blocklist,blocks local len,res,chan,diff,maxdiff,maxblock,split local qualnorm, quantnorm,count blocklist = {} blocklist[1] = {}; blocks = 1 count = 0 for n=1, #pal, 1 do blocklist[1][n] = pal[n]; count = count + pal[n][5] end -- Normalize 256 for quality/quantity relationship qualnorm = 1 / math.sqrt(rgbw[1]^2 + rgbw[2]^2 + rgbw[3]^2) quantnorm = 256 / count -- Dist table statusmessage("MR: Making Distance Table..."); updatescreen(); if (waitbreak(0)==1) then return; end local dy,c,r1,g1,b1,i1,i2 dt = {} for n=1, #pal, 1 do c = pal[n] r1,g1,b1,i1 = c[1],c[2],c[3],c[4] dt[i1+1] = {} for m=1, #pal, 1 do dt[i1+1][pal[m][4]+1] = db.getColorDistanceProx(r1,g1,b1,pal[m][1],pal[m][2],pal[m][3],rgbw[1],rgbw[2],rgbw[3],qualnorm, proxweight, briweight) -- pri/bri end end -- statusmessage("MR: Analyzing Block 1..."); updatescreen(); if (waitbreak(0)==1) then return; end r_analyzeBlock(dt,blocklist[1],qual,quant,rgbw,qualnorm,quantnorm,quantpow) statusmessage("MR: Analyzing Blocks..."); updatescreen(); if (waitbreak(0)==1) then return; end failsafe = 0 while (blocks < cnum and failsafe < 256) do failsafe = failsafe + 1 maxdiff = -1 maxblock = -1 for n=1, blocks, 1 do diff = blocklist[n].diff if (diff > maxdiff) then maxdiff = diff; maxblock = n; end -- maxchan is stored as .chan in block end split = r_splitBlock(dt,blocklist,maxblock,qual,quant,rgbw,qualnorm,quantnorm,quantpow) if (split == false) then messagebox("Only found "..blocks.." (24-bit) colors!"); break; end blocks = #blocklist statusmessage("MR: "..blocks); updatescreen(); if (waitbreak(0)==1) then return; end end -- while return r_blocks2Palette(blocklist,bits) end -- -- function r_blocks2Palette(blocklist,bits) local n,r,g,b,c,pal,block,rgb,blen,M,dB,cB,rf,gf,bf M = math pal = {} --bits = 1 dB = M.pow(2,8-bits) cB = M.ceil(255 / (M.pow(2,bits) - 1)) for n=1, #blocklist, 1 do block = blocklist[n] r,g,b = 0,0,0 blen = #block for c=1, blen, 1 do rgb = block[c] r = r + rgb[1] g = g + rgb[2] b = b + rgb[3] end rf = M.floor(M.min(255,M.max(0,M.floor(r/blen))) / dB) * cB gf = M.floor(M.min(255,M.max(0,M.floor(g/blen))) / dB) * cB bf = M.floor(M.min(255,M.max(0,M.floor(b/blen))) / dB) * cB pal[n] = {rf, gf, bf} -- col is avg. of all colors in block end -- blocklist return pal end -- -- function r_analyzeBlock(dt,block,qual,quant,rgbw,qualnorm,quantnorm,quantpow) local r,g,b,n,m,rmin,gmin,bmin,rmax,gmax,bmax,rdif,gdif,bdif,chan,d,median,diff local len,Mm,Mx,rgb,kv,qu local maxdist,dist,r1,g1,b1,r2,g2,b2,c1,c2,count Mx,Mm = math.max, math.min len = #block rmin,gmin,bmin = 255,255,255 rmax,gmax,bmax = 0,0,0 maxdist,c1,c2,count = 0,-1,-1,0 for n=1, len, 1 do rgb1 = block[n] count = count + rgb1[5] -- pixelcount for color for m=n+1, len, 1 do rgb2 = block[m] --dist = db.getColorDistanceProx(r1,g1,b1,r2,g2,b2,0.26,0.55,0.19,1.569, 0.1, 0.25) -- pri/bri dist = dt[rgb1[4]+1][rgb2[4]+1] if dist > maxdist then maxdist = dist c1 = rgb1[4]+1 c2 = rgb2[4]+1 end end end -- quantity and quality are normalized to 256 (256 is the total of colors in the set for quantity) -- Note that, regardless of forumla, quality (distance) must always be greater in any block than quantity (colors/pixels) -- Coz a block may contain many of only 1 unique color, thus rendering it impossible to split if selected. kv = 1 qu = 1 if (quant) then kv = math.pow(1 + count*quantnorm*quantpow, 0.5); end if (qual) then qu = maxdist * qualnorm; end diff = qu*(1-quantpow) + qu*kv block.chan = -1 block.diff = diff block.median = -1 block.c1 = c1 block.c2 = c2 return {diff,len} end -- function r_splitBlock(dt,blocklist,maxblock,qual,quant,rgbw,qualnorm,quantnorm,quantpow) local n,cmax,median,blockA,blockB,len,cB,block,rgb,res local c1,c2,dist1,dist2,medr,medg,medb,r1,g1,b1,r2,g2,b2,rgb1,rgb2 blockA,blockB = {},{} block = blocklist[maxblock] res = true --chan = block.chan --median = block.median c1 = block.c1 c2 = block.c2 --rgb1 = block[c1] --r1,g1,b1 = rgb1[1],rgb1[2],rgb1[3] --rgb2 = block[c2] --r2,g2,b2 = rgb2[1],rgb2[2],rgb2[3] --medr = (r1+r2)/2 --medg = (g1+g2)/2 --medb = (b1+b2)/2 cB = blocklist[maxblock] -- maxblock starts at 1 when called so it should not hava a +1 len = #cB if len < 2 then return false; end for n=1, len, 1 do rgb = cB[n] dist1 = dt[rgb[4]+1][c1] dist2 = dt[rgb[4]+1][c2] if (dist1 <= dist2) then table.insert(blockA,rgb); end if (dist1 > dist2) then table.insert(blockB,rgb); end end blocklist[maxblock] = blockA -- Can't be empty right? r_analyzeBlock(dt,blocklist[maxblock],qual,quant,rgbw,qualnorm,quantnorm,quantpow) if (#blockB > 0) then table.insert(blocklist,blockB) r_analyzeBlock(dt,blocklist[#blocklist],qual,quant,rgbw,qualnorm,quantnorm,quantpow) -- no -1 on blocklist else res = false end return res -- false = no split end ------------ eof MEDIAN REDUX -------------------------- -- -- ... eof Custom Color / Palette functions ... -- -- ***************************** -- *** Custom Draw functions *** -- ***************************** -- function db.line(x1,y1,x2,y2,c) -- Coords should be integers or broken lines are possible local n,st,m,xd,yd; m = math st = m.max(1,m.abs(x2-x1),m.abs(y2-y1)); xd = (x2-x1) / st yd = (y2-y1) / st for n = 0, st, 1 do putpicturepixel(m.floor(x1 + n*xd), m.floor(y1 + n*yd), c ); end end -- -- function db.lineTransp(x1,y1,x2,y2,c,amt) -- amt: 0-1, 1 = Full color local n,st,m,x,y,r,g,b,r1,g1,b1,c2,org; m = math org = 1 - amt st = m.max(1,m.abs(x2-x1),m.abs(y2-y1)); for n = 0, st, 1 do x = m.floor(x1+n*(x2-x1)/st) y = m.floor(y1+n*(y2-y1)/st) r,g,b = getcolor(getpicturepixel(x,y)) r1,g1,b1 = getcolor(c) c2 = matchcolor(r1*amt+r*org, g1*amt+g*org, b1*amt+b*org) putpicturepixel(x, y, c2 ); end end -- -- function db.drawBrushRectangle(x1,y1,w,h,c) local x,y for y = y1, y1+h-1, 1 do for x = x1, x1+w-1, 1 do putbrushpixel(x,y,c); end end end -- -- function db.drawRectangle(x1,y1,w,h,c) local x,y for y = y1, y1+h-1, 1 do for x = x1, x1+w-1, 1 do putpicturepixel(x,y,c); end end end -- -- function db.drawRectangleNeg(x1,y1,w,h,c) local x,y,xs,ys xs = db.sign(w) ys = db.sign(h) if xs == 0 then xs = 1; end if ys == 0 then ys = 1; end for y = y1, y1+h-1, ys do for x = x1, x1+w-1, xs do putpicturepixel(x,y,c); end end end -- -- function db.drawRectangleLine(x,y,w,h,c) w = w-1 h = h-1 db.line(x,y,x+w,y,c) db.line(x,y,x,y+h,c) db.line(x,y+h,x+w,y+h,c) db.line(x+w,y,x+w,y+h,c) end -- -- function db.drawRectangleMix(x1,y1,w,h,c1,c2) local x,y,c,n c = {c1,c2} n = 0 for y = y1, y1+h-1, 1 do n = n + 1 for x = x1, x1+w-1, 1 do n = n + 1 putpicturepixel(x,y,c[n%2+1]); end end end -- -- function db.drawCircle(x1,y1,r,c) -- ok, lottsa weird adjustments here, can probably be optimized... local x,y,d,r5,r25,r2,xr5,yr5 r5,r25,r2,xr5,yr5 = r+0.5,r-0.25,r*2, x1-r-0.5, y1-r-0.5 for y = 0, r2, 1 do for x = 0, r2, 1 do d = math.sqrt((x-r5)^2 + (y-r5)^2) if d < r25 then putpicturepixel(x + xr5, y + yr5,c); end end end end -- -- function db.drawBrushCircle(x1,y1,r,c) -- ok, lottsa weird adjustments here, can probably be optimized... local x,y,d for y = 0, r*2, 1 do for x = 0, r*2, 1 do d = math.sqrt((x-r-0.5)^2 + (y-r-0.5)^2) if d < r-0.25 then putbrushpixel(x1+x-r-0.5,y1+y-r-0.5,c); end end end end -- -- -- Rotation in degrees -- Step is # of line segments (more is "better") -- a & b are axis-radius function db.ellipse2(x,y,a,b,stp,rot,col) local n,m=math,rad,al,sa,ca,sb,cb,ox,oy,x1,y1,ast m = math; rad = m.pi/180; ast = rad * 360/stp; sb = m.sin(-rot * rad); cb = m.cos(-rot * rad) for n = 0, stp, 1 do ox = x1; oy = y1; sa = m.sin(ast*n) * b; ca = m.cos(ast*n) * a x1 = x + ca * cb - sa * sb y1 = y + ca * sb + sa * cb --if (n > 0) then db.line(ox,oy,x1,y1,col); end if (n > 0) then drawline(ox,oy,x1,y1,col); end end end -- --[[ var ER = 0.3 var DR = 0.15 ellipse(0.5*xx,0.5*yy,DR*xx,6,Math.PI*0) function ellipse(x,y,r,stp,rot){ var n,deg=360,m=Math,rad=Math.PI/180,rn var ox,oy,x1,y1,x2,y2,d1,r1 = ER * xx for (n=0; n<=deg; n+=stp){ ox = x2; oy = y2, rn = rad * n d1 = rn - rot x1 = x + m.sin(d1) * r y1 = y + m.cos(d1) * r x2 = x1 + m.sin(-rn) * r1 y2 = y1 + m.cos(-rn) * r1 if (n > 0){ line_rgb(MX,[0,0,0],0,ox,oy,x2,y2) } } } } ellipse2(0.5*xx,0.5*yy,15,8,200,22,[0,0,0],0.5) function ellipse2(x,y,a,b,stp,rot,rgb,transp){ var n,m=Math,rad=m.PI/180,al,sa,ca,sb,cb,ox,oy,x1,y1 sb = m.sin(-rot * rad); cb = m.cos(-rot * rad) for (n=0; n<=stp; n++){ ox = x1; oy = y1; al = rad * 360/stp * n sa = m.sin(al) * b; ca = m.cos(al) * a x1 = x + ca * cb - sa * sb y1 = y + ca * sb + sa * cb if (n > 0){ line_rgb(MX,rgb,transp,ox,oy,x1,y1) } } } ]] function db.obliqueCube(side,x,y,r,g,b,bri,cols) local n,c,depth,x1,y1,x2,y2,f asscols = false if cols >= 0 and cols<250 then asscols = true c = cols; setcolor(cols,r,g,b); cols = cols + 1 cP50 = cols; q = bri*0.5; setcolor(cols,r+q,g+q,b+q); cols = cols + 1; cP75 = cols; q = bri*0.75; setcolor(cols,r+q,g+q,b+q); cols = cols + 1; cM50 = cols; q = -bri*0.5; setcolor(cols,r+q,g+q,b+q); cols = cols + 1; cM100= cols; q = -bri; setcolor(cols,r+q,g+q,b+q); cols = cols + 1; end f = matchcolor if asscols == false then c = f(r,g,b) cP50 = f(r+bri*0.5,g+bri*0.5,b+bri*0.5) cP75 = f(r+bri*0.75,g+bri*0.75,b+bri*0.75) cM50 = f(r-bri*0.5,g-bri*0.5,b-bri*0.5) cM100 = f(r-bri,g-bri,b-bri) end depth = math.floor(side / 2) for n = 0, depth-1, 1 do db.line(x+side+n,y-1-n,x+side+n,y+side-n-1,cM50) --drawline(x+side+n,y-1-n,x+side+n,y+side-n-1,cM50) end for n = 0, depth-1, 1 do db.line(x+n,y-1-n,x+side+n-1,y-1-n,cP50) --drawline(x+n,y-1-n,x+side+n-1,y-1-n,cP50) end -- / -- --db.line(x+side,y-1,x+side+depth-1,y-depth,c) -- Smoothing & Shade -- -- / --db.line(x+side,y+side-1,x+side+depth-1,y+side-depth,cM100) --db.line(x,y,x+side-2,y,cP75) --db.line(x,y,x,y+side-2,cP75) db.drawRectangle(x,y,side,side,c) return cols end function db.obliqueCubeBRI(side,x,y,r,g,b,bri,pallist,briweight,index_flag) local n,c,depth,x1,y1,x2,y2 --f = db.getBestPalMatchHYBRID c = db.getBestPalMatchHYBRID({r,g,b}, pallist, briweight, index_flag) cP50 = db.getBestPalMatchHYBRID({r+bri*0.5,g+bri*0.5,b+bri*0.5}, pallist, briweight, index_flag) cP75 = db.getBestPalMatchHYBRID({r+bri*0.75,g+bri*0.75,b+bri*0.75}, pallist, briweight, index_flag) cM50 = db.getBestPalMatchHYBRID({r-bri*0.5,g-bri*0.5,b-bri*0.5}, pallist, briweight, index_flag) cM100 = db.getBestPalMatchHYBRID({r-bri,g-bri,b-bri}, pallist, briweight, index_flag) depth = math.floor(side / 2) db.drawRectangle(x,y,side,side,c) for n = 0, depth-1, 1 do db.line(x+side+n,y-1-n,x+side+n,y+side-n-1,cM50) --drawline(x+side+n,y-1-n,x+side+n,y+side-n-1,cM50) end for n = 0, depth-1, 1 do db.line(x+n,y-1-n,x+side+n-1,y-1-n,cP50) --drawline(x+n,y-1-n,x+side+n-1,y-1-n,cP50) end -- / -- db.line(x+side,y-1,x+side+depth-1,y-depth,c) --drawline(x+side,y-1,x+side+depth-1,y-depth,c) -- Smoothing & Shade -- -- / --db.line(x+side,y+side-1,x+side+depth-1,y+side-depth,cM100) --db.line(x,y,x+side-2,y,cP75) --db.line(x,y,x,y+side-2,cP75) end -- function db.fillTriangle(p,fcol,lcol,fill,wire) -- p = list of 3 points local n,x,y,x1,x2,y1,y2,xf,yf,len,mr mr = math.floor -- Convert to screen/matrix-coordinates --if (mode == 'percent') then xf = xx / 100; yf = yy / 100; end --if (mode == 'fraction') then xf = xx; yf = yy; end --if (mode ~= 'absolute') then screenilizeTriangle(p,xf,yf); end if (fill) then local Ax,Ay,Bx,By,Cx,Cy,xd,a,b,yc,ABdy,BCdy,ABix,BCix,ACix xd = {} --sort(p,1) -- Find top and middle y-point db.sorti(p,2) Ay = p[1][2]; Ax = p[1][1] By = p[2][2]; Bx = p[2][1] Cy = p[3][2]; Cx = p[3][1] ABdy = By - Ay BCdy = Cy - By ABix = (Bx - Ax) / ABdy BCix = (Cx - Bx) / BCdy ACix = (Cx - Ax) / (Cy - Ay) a=1; b=2; if (ACix < ABix) then a=2; b=1; end for y = 0, ABdy-1, 1 do -- Upper -1 xd[a] = mr(Ax + ABix * y) xd[b] = mr(Ax + ACix * y) yc = y+Ay; for x=xd[1], xd[2], 1 do putpicturepixel(x,yc,fcol) end end a=1; b=2; if (BCix < ACix) then a=2; b=1; end for y = 0, BCdy, 1 do -- Lower xd[a] = mr(Cx - BCix * y); xd[b] = mr(Cx - ACix * y) yc = Cy-y; for x = xd[1], xd[2], 1 do putpicturepixel(x,yc,fcol) end end end -- eof fill if (wire) then for n = 0, 2, 1 do -- Outline x1 = p[n+1][1]; y1 = p[n+1][2] x2 = p[1 + (n+1) % 3][1]; y2 = p[1 + (n+1) % 3][2] --db.line(x1,y1,x2,y2,lcol) drawline(x1,y1,x2,y2,lcol) end end end -- eof fillTriangle -- -- -- ... eof Custom Draw functions ... -- -- ****************************** -- *** Filters & Convolutions *** -- ****************************** function db.applyConvolution2Pic(convmx,divisor,bias,neg,amt) local r,g,b,mx,my,cx,cy,mxh,myh,mp,rb,gb,bb,xx,yy,x,y,w,h,div,n1,n2,amtr,ro,go,bo n1 = 1 n2 = bias if neg == 1 then n1 = -1 n2 = 255 + bias end amtr = 1 - amt w, h = getpicturesize() cy = #convmx cx = #convmx[1] mxh = math.floor(cx / 2) + 1 myh = math.floor(cy / 2) + 1 for y = 0, h-1, 1 do for x = 0, w-1, 1 do r,g,b = 0,0,0 ro,go,bo = getcolor(getbackuppixel(x,y)) div = divisor for my = 1, cy, 1 do for mx = 1, cx, 1 do xp = mx-mxh yp = my-myh mp = convmx[my][mx] xx = x + xp yy = y + yp if yy>=0 and yy=0 and xx 0 and n 0 and n0) then x = x*px - fx y = y*py - fy nfrac = nfrac + spfrac end n = n+1 end --return 1 - n/i; return 1 - nfrac/i end -- -- function db.mandel(x,y,l,r,o,i) -- pos. as fraction of 1, left coord, right coord, y coord, iterations local w,s,a,p,q,n,v,w s=math.abs(r-l); a = l + s*x; p = a; b = o - s*(y-0.5); q = b; n = 1; v = 0; w = 0; while (v+w<4 and n weakest then weakest = w; weak_i = {z,y,x}; end end end;end;end return weak_i[1],weak_i[2],weak_i[3] end -- -- -- -- Nearest color version: void is selected by the point that has the greatest distance -- to the nearest color. Higher value means greater void. -- function db.addColor2Cube(cube,sha,r,g,b,rw,gw,bw) local star,x,y,z,d,rd,gd,bd,cu1,cu2 star = 0 cube[r+1][g+1][b+1] = {false, star} for z = 0, sha-1, 1 do rd = (rw*(z-r))^2 cu2 = cube[z+1] for y = 0, sha-1, 1 do gd = (gw*(y-g))^2 cu1 = cu2[y+1] for x = 0, sha-1, 1 do d = rd + gd + (bw*(x-b))^2 --cube[z+1][y+1][x+1][2] = math.min(d, cube[z+1][y+1][x+1][2]) -- Don't add, use nearest color cu1[x+1][2] = math.min(d, cu1[x+1][2]) end;end;end end -- -- Should be same as original, but not 100% verified. Using a rgb+1 trick to speed up handling -- function db.addColor2Cube_test(cube,sha,r,g,b,rw,gw,bw) local star,x,y,z,d,rd,gd,bd,cu1,cu2 star = 0 r = r+1; g = g+1; b = b+1 cube[r][g][b] = {false, star} for z = 1, sha, 1 do rd = (rw*(z-r))^2 cu2 = cube[z] for y = 1, sha, 1 do gd = (gw*(y-g))^2 cu1 = cu2[y] for x = 1, sha, 1 do cu1[x][2] = math.min(rd+gd+(bw*(x-b))^2, cu1[x][2]) end;end;end end -- -- Create new allowed colorlines in colorspace (ramps from which colors can be picked) function db.enableRangeColorsInCube(cube,sha,r1,g1,b1,r2,g2,b2) local div,r,g,b,n,rs,gs,bs div = 256 / sha rs = (r2 - r1) / sha / div gs = (g2 - g1) / sha / div bs = (b2 - b1) / sha / div for n = 0, sha-1, 1 do r = math.floor(r1/div + rs * n) g = math.floor(g1/div + gs * n) b = math.floor(b1/div + bs * n) cube[r+1][g+1][b+1][1] = true end end -- function db.colorCigarr(shades,radius,fill_flag) local s,rad,radsq,step,shalf,bas,cols,found,x,y,z,bri,con,d,n radius = radius / 100 step = math.floor(255 / (shades-1)) shalf = math.floor(shades / 2) s = shades - 1 rad = math.floor(shades / 2 * radius) radsq = rad^2 bas = 0 cols = {} found = 0 for z = 0, s, 1 do for y = 0, s, 1 do for x = 0, s, 1 do --0.26,0.55,0.19 bri = (x + y + z ) / 3 --bri = math.sqrt(((x*0.26)^2 + (y*0.55)^2 + (z*0.19)^2)) * 1.5609 con = math.floor((shades - math.abs(bri - shalf)*2) * radius) d = math.floor(math.sqrt((bri-x)^2 + (bri-y)^2 + (bri-z)^2)) --d = math.floor(math.sqrt(((bri-x)*0.26)^2 + ((bri-y)*0.55)^2 + ((bri-z)*0.19)^2)) * 1.5609 -- Filled cigarr: Less or Equal, cigarr shell: Equal if d == con or (d < con and fill_flag) then found = found + 1 r = bas + x * step g = bas + y * step b = bas + z * step cols[found] = {r,g,b} end end; end; end --messagebox("Colors found: "..found.."\n\n".."Run AnalyzePalette to examine") for n = 0, 255, 1 do if n < found then c = cols[n+1] setcolor(n,c[1],c[2],c[3]) else setcolor(n,0,0,0) end end end -- eof colorcigarr -- -- ... eof Color Cube ... -- -- COLORMIX -- -- -- Returns a list of mixcolors palette entries, that are ranked by by quality & usefulness -- -- This whole junk my partly locked on 16 shades (4096 colors/ 12bit palette precision) so don't use anything else... -- -- function db.colormixAnalysis(sha,spare_flag,cust_dist) -- Interface local shades,pallist,ilist,custom_max_distance shades = sha -- 16 is good --messagebox(shades) custom_max_distance = -1 if cust_dist ~= null then custom_max_distance = cust_dist -- in % end if spare_flag == true then -- No shades here for now --pallist = db.makePalListShadeSPARE(256,shades) -- 16 shades so Colorcube processes is possible pallist = db.makeSparePalList(256) pallist = db.fixPalette(pallist,0) -- Remove doubles, No need to sort? ilist = db.makeIndexList(pallist, -1) -- -1, use list order as index else pallist = db.makePalListShade(256,shades) -- 16 shades so Colorcube processes is possible pallist = db.fixPalette(pallist,0) -- Remove doubles, No need to sort? ilist = db.makeIndexList(pallist, -1) -- -1, use list order as index end if shades > 0 then return db.colormixAnalysisEXT(shades,pallist,ilist,custom_max_distance) -- max distance in % end if shades == -1 then return db.colormixAnalysisEXTnoshade(pallist,ilist,custom_max_distance) -- max distance in % end end -- -- function db.colormixAnalysisEXT(SHADES,pallist,ilist,custom_max_distance) -- Shades, most number of mixes returned local n,m,c1,c2,pairs,cube,rm,gm,bm local mix,total,found,dist,void,ideal,mini,maxi,bestmix,bestscore --messagebox("will now make pairs") pairs = db.pairsFromList(ilist,0) -- 0 for unique pairs only, pairs are entries in pallist --messagebox(#pairs.." will now add colors to cube") cube = db.initColorCube(SHADES,{true,9999}) for n = 1, #pallist, 1 do c1 = pallist[n] db.addColor2Cube_test(cube,SHADES,c1[1],c1[2],c1[3],0.26,0.55,0.19) end -- these values are adjusted for a 12bit palette (0-15) and perceptual weight where r+g+b = 1.0 -- Ideal distance = 2.5 Green steps = 1.375 -- Minimum distance = 1 Green step = 0.55 --messagebox("colorcube done") VACT = 1 DACT = 1 total = 9.56 -- Max distance possible with 16 shades ideal = 0.45 -- 1 step = 0.637 mini = 0.35 maxi = ideal + (total - ideal) / math.max(1, #pallist / 16) if custom_max_distance ~= -1 then maxi = total * (custom_max_distance / 100) end mix = {} --mix[1] = {9e99,0,0,9e99,0,0,0} bestmix = -1 bestscore = 9e99 found = 0 for n = 1, #pairs, 1 do c1 = pallist[pairs[n][1]] c2 = pallist[pairs[n][2]] --0.26,0.55,0.19 dist = db.getColorDistance_weight(c1[1],c1[2],c1[3],c2[1],c2[2],c2[3],0.26,0.55,0.19) -- Not normalized rm = math.floor((c1[1]+c2[1])/2) gm = math.floor((c1[2]+c2[2])/2) bm = math.floor((c1[3]+c2[3])/2) -- Mix color adjustment (perhaps less than perfect, but probably good enough) mixbri = db.getBrightness(rm,gm,bm) truebri = math.sqrt((db.getBrightness(c1[1],c1[2],c1[3])^2 + db.getBrightness(c2[1],c2[2],c2[3])^2) / 2) diff = truebri - mixbri rm = math.max(0,math.min(15,math.floor(rm + diff))) gm = math.max(0,math.min(15,math.floor(gm + diff))) bm = math.max(0,math.min(15,math.floor(bm + diff))) newbri = db.getBrightness(rm,gm,bm) delta = math.abs(newbri - truebri) --if delta > 0.9 then -- messagebox(pallist[pairs[n][1]][4]..", "..pallist[pairs[n][2]][4].." delta = "..delta) --end -- --rm = math.floor(math.sqrt((c1[1]^2 + c2[1]^2) / 2)) --gm = math.floor(math.sqrt((c1[2]^2 + c2[2]^2) / 2)) --bm = math.floor(math.sqrt((c1[3]^2 + c2[3]^2) / 2)) void = cube[rm+1][gm+1][bm+1][2] if dist >= mini and dist <= maxi then found = found + 1 score = ((1+DACT*(dist - ideal)^2) / (1+void*VACT)) -- Lowest is best mix[found] = {score,pallist[pairs[n][1]][4],pallist[pairs[n][2]][4],dist,rm*SHADES,gm*SHADES,bm*SHADES,c1[1]*SHADES,c1[2]*SHADES,c1[3]*SHADES,c2[1]*SHADES,c2[2]*SHADES,c2[3]*SHADES} -- mix holds palette entry if score < bestscore then bestscore = score; bestmix = found; end end end if true == false then -- 2nd pass, add bestmix to colorspace. This reduces many similar mixes. m = mix[bestmix] db.addColor2Cube(cube,SHADES,m[5],m[6],m[7],0.26,0.55,0.19) for n = 1, #mix, 1 do if n ~= bestmix then m = mix[n] dist = m[4] void = cube[m[5]+1][m[6]+1][m[7]+1][2] score = ((1+DACT*(dist - ideal)^2) / (1+void*VACT)) m[1] = score end end end c1,c2 = -1,-1 if found > 0 then db.sorti(mix,1) best = mix[1] c1 = best[2] c2 = best[3] end --return found,c1,c2 return mix,found,c1,c2 end -- -- -- Mixcolor without colorcube - no scoring or sorting, 24bit colors, faster... -- function db.colormixAnalysisEXTnoshade(pallist,ilist,custom_max_distance) local n,m,c1,c2,pairs,cube,rm,gm,bm local mix,total,found,dist,void,ideal,mini,maxi,bestmix,bestscore pairs = db.pairsFromList(ilist,0) -- 0 for unique pairs only, pairs are entries in pallist total = 162.53 -- Max distance possible with 24-bit palette ad Dawn3.0 color weights 162.53 ideal = 0 mini = 0 maxi = ideal + (total - ideal) / math.max(1, #pallist / 16) if custom_max_distance ~= -1 then maxi = total * (custom_max_distance / 100) end statusmessage("Mixcol Analysis ("..#pairs.." pairs) "); updatescreen(); if (waitbreak(0)==1) then return; end mix = {} found = 0 for n = 1, #pairs, 1 do c1 = pallist[pairs[n][1]] c2 = pallist[pairs[n][2]] --0.26,0.55,0.19 dist = db.getColorDistance_weight(c1[1],c1[2],c1[3],c2[1],c2[2],c2[3],0.26,0.55,0.19) -- Not normalized rm = math.floor((c1[1]+c2[1])/2) gm = math.floor((c1[2]+c2[2])/2) bm = math.floor((c1[3]+c2[3])/2) -- Mix color adjustment mixbri = db.getBrightness(rm,gm,bm) truebri = math.sqrt((db.getBrightness(c1[1],c1[2],c1[3])^2 + db.getBrightness(c2[1],c2[2],c2[3])^2) / 2) diff = truebri - mixbri rm = math.max(0,math.min(255,math.floor(rm + diff))) gm = math.max(0,math.min(255,math.floor(gm + diff))) bm = math.max(0,math.min(255,math.floor(bm + diff))) newbri = db.getBrightness(rm,gm,bm) delta = math.abs(newbri - truebri) --if delta > 0.9 then -- messagebox(pallist[pairs[n][1]][4]..", "..pallist[pairs[n][2]][4].." delta = "..delta) --end -- if dist >= mini and dist <= maxi then found = found + 1 score = 1 mix[found] = {score,pallist[pairs[n][1]][4],pallist[pairs[n][2]][4],dist,rm,gm,bm,c1[1],c1[2],c1[3],c2[1],c2[2],c2[3]} -- mix holds palette entry end end --messagebox(#mix) return mix,found,-1,-1 end -- -- Fuse a palettelist into an extended mix-anlysis list function db.fusePALandMIX(pal,mix,max_score,max_dist) local n,c,mixlist,tot,score,dist,c1,c2,rm,gm,bm mixlist = {} tot = 0 -- {r,g,b,n} for n = 1, #pal, 1 do tot = tot + 1 c = pal[n] mixlist[tot] = {0,c[4],c[4],0,c[1],c[2],c[3],c[1],c[2],c[3],c[1],c[2],c[3]} end -- {score,col#1,col#2,dist,rm,gm,bm} low score is best for n = 1, #mix, 1 do score = mix[n][1] dist = mix[n][4] if score <= max_score and dist <= max_dist then tot = tot + 1 mixlist[tot] = mix[n] end end return mixlist end -- -- ******************************************** -- *** L-system (fractal curves & "plants") *** -- ******************************************** -- -- function db.Lsys_makeData(a) local n,i; i = {} for n = 1, #a, 1 do i[a[n][2]] = a[n]; end return i end -- -- function db.Lsys_makeSet(seed,iter,data) local s,n,i,nset,set set = seed for n = 1, iter, 1 do nset = '' for i = 1, #set, 1 do s = string.sub(set,i,i) nset = nset..data[s][3] end set = nset end return set end -- function db.Lsys_draw(set,data,cx,cy,size,rot,rgb,rng,transp, speed) local p,M,DEG,l,n,d,i,v,q,c,tx,ty,posx,posy,dval,col,w,h,s,cl,count if speed == nil then speed = 50; end -- speed is drawing operations per update function ang(d) return (d % 360 + 360) * DEG; end w,h = getpicturesize() p = 0 M = math DEG = math.pi/180 l = #set posx={}; posy={}; dval={} if (rgb == null) then rgb = {0,0,0}; end if (transp == null) then transp = 0; end col = db.newArrayMerge(rgb,{}) q = 255 / l count = 0 for n = 1, l, 1 do s = string.sub(set,n,n) d = data[s] i = d[1] v = d[4] --messagebox(i) if (i == 'Left') then rot = rot - v; end if (i == 'Right') then rot = rot + v; end if (i == 'Save') then p=p+1; posx[p] = cx; posy[p] = cy; dval[p] = rot; end if (i == 'Load') then cx = posx[p]; cy = posy[p]; rot = dval[p]; p=p-1; end if (i == 'Draw') then tx = cx + M.sin(ang(rot)) * size ty = cy + -M.cos(ang(rot)) * size for c = 1, 3, 1 do if (rng[c] > 0) then col[c] = rgb[c] + (n * q) * rng[c]; end if (rng[c] < 0) then col[c] = rgb[c] + (n * q) * rng[c]; end end cl = matchcolor(col[1],col[2],col[3]) --putpicturepixel(cx*w,cy*h,cl); --db.line(cx*w,cy*h,tx*w,ty*h,cl) db.lineTransp(cx*w,cy*h,tx*w,ty*h,cl,transp) cx = tx; cy = ty end count = count + 1 if count == speed then count = 0; updatescreen(); if (waitbreak(0)==1) then return end; end end return {cx,cy,rot} end -- draw -- -- eof L-system -- --------------------------------------------------------------------------------------- -- ******************************************** -- *** COMPLEX SPECIAL FUNCTIONS *** -- ******************************************** -- --------------------------------------------------------------------------------------- -- -- Render engine for mathscenes (Full Floyd-Steinberg dither etc) -- function db.fsrender(f,pal,ditherprc,xdith,ydith,percep,xonly, ord_bri,ord_hue,bri_change,hue_change,BRIWEIGHT, wd,ht,ofx,ofy) -- f is function local w,h,i,j,c,x,y,r,g,b,d,fl,v,v1,v2,vt,vt1,vt2,dither,m,mathfunc,dpow,fsdiv,ord,d1a,d1b,briweight local d1,d2,o1,o2,ox,oy -- percep is no longer used, matchcolor2 is always active, but the code is kept if there's ever a need to -- study the effect of perceptual colorspaces versus matchcolor if ord_bri == null then ord_bri = 0; end if ord_hue == null then ord_hue = 0; end if bri_change == null then bri_change = 0; end if hue_change == null then hue_change = 0; end if BRIWEIGHT == null then BRIWEIGHT = 0; end briweight = BRIWEIGHT / 100 ord = {{0,4,1,5}, {6,2,7,3}, {1,5,0,4}, {7,3,6,2}} --i = ((ord[y % 4 + 1][x % 4 + 1])*28.444 - 99.55556)/100 * 16 function hue(r,g,b,deg) local i,brin,diff,brio,r2,g2,b2 r2,g2,b2 = db.shiftHUE(r,g,b,deg) brio = db.getBrightness(r,g,b) for i = 0, 5, 1 do -- 6 iterations, fairly strict brightness preservation brin = db.getBrightness(r2,g2,b2) diff = brin - brio r2,g2,b2 = db.rgbcap(r2-diff, g2-diff, b2-diff, 255,0) end return r2,g2,b2 end fsdiv = 16 if xonly == 1 then fsdiv = 7; end -- Only horizontal dither dither = 0; if ditherprc > 0 then dither = 1; end -- When using standard error-diffusion brightness-matching is not really compatible --matchfunc = matchcolor2 --if dither == 1 then matchfunc = matchcolor; end dpow = ditherprc / 100 if wd == null then w,h = getpicturesize() else w = wd; h = ht end if ofx == null then ox,oy = 0,0 else ox = ofx; oy = ofy end function cap(v) return math.min(255,math.max(0,v)) end -- fl = {} fl[1] = {} fl[2] = {} i = 1 j = 2 -- -- Read the first 2 lines v1 = ydith/2 + 0%2 * -ydith v2 = ydith/2 + 1%2 * -ydith for x = 0, w - 1, 1 do d1a,d1b = 0,0 if ord_bri > 0 then o1 = ord[0 % 4 + 1][x % 4 + 1] d1a = (o1*28.444 - 99.55556)/100 * ord_bri o2 = ord[1 % 4 + 1][(x+2) % 4 + 1] -- +2 To get it in right sequence for some reason d1b = (o2*28.444 - 99.55556)/100 * ord_bri end -- We skip Hue-ordering for now vt1 = v1 + xdith/2 + (x+math.floor(0/2))%2 * -xdith + d1a vt2 = v2 + xdith/2 + (x+math.floor(1))%2 * -xdith + d1b -- Ok, not sure why 1/2 doesn't make for a nice pattern so we just use 1 r,g,b = f(x, 0, w, h) fl[i][x] = {cap(r+vt1),cap(g+vt1),cap(b+vt1)} r,g,b = f(x, 1, w, h) fl[j][x] = {cap(r+vt2),cap(g+vt2),cap(b+vt2)} end for y = 0, h-1, 1 do for x = 0, w-1, 1 do o = fl[i][x] r = o[1] + bri_change g = o[2] + bri_change b = o[3] + bri_change if hue_change ~= 0 then r,g,b = hue(r,g,b,hue_change) end --if percep == 0 then c = matchfunc(r,g,b); end --if percep == 1 then -- --c = db.getBestPalMatchHYBRID({r,g,b},pal,0,true) --c = matchcolor2(r,g,b,briweight) --end c = matchcolor2(r,g,b,briweight) putpicturepixel(x+ox,y+oy,c) if dither == 1 then if x>1 and x 0 then o = ord[y % 4 + 1][x % 4 + 1] d1 = (o*28.444 - 99.55556)/100 * ord_bri end vt = v + xdith/2 + (x+math.floor(y/2))%2 * -xdith + d1 r,g,b = f(x, y+2, w, h) if ord_hue > 0 then o = ord[y % 4 + 1][x % 4 + 1] d2 = (((o + 3.5) % 7) / 7 - 0.5) * ord_hue r,g,b = hue(r,g,b,d2) end fl[j][x] = {cap(r+vt),cap(g+vt),cap(b+vt)} end updatescreen(); if (waitbreak(0)==1) then return; end end end ------------------------------------------------------------------------------- -- -- ROTATE Image or Brush -- -- target: 1 = Brush, 2 = Picture, 3 = Brush-to-Picture -- rot: Rotation in degrees -- mode: 1 = Simple, 2 = Cosine Interpolation, 2 = BiLinear Interpolation -- spritemode: 0 = Off, 1 = On (Only match adjacent colors, use with Bilinear-Ip. for good result) -- resize: 0 = No, 1 = Yes (Resize Image/Brush to fit all gfx, otherwise clip) -- update: 0 = No, 1 = Yes (Update screen while drawing) -- xoffset: For use with Brush-to-Picture operations -- yoffset: For use with Brush-to-Picture operations -- function db.doRotation(target,rot,mode,spritemode,resize,update, xoffset,yoffset) local trg,f,w,h,x,y,r,g,b,c,hub_x,hub_y,x1,y1,x2,y2,x3,y3,x4,y4,dX,dY,dXs,dYs,ox,oy,mx,my,xp,yp,pal,func function donothing(n) end func = { {getsize=getbrushsize, setsize=setbrushsize, clear=donothing, get=getbrushbackuppixel, put=putbrushpixel}, {getsize=getpicturesize, setsize=setpicturesize, clear=clearpicture, get=getbackuppixel, put=putpicturepixel}, {getsize=getbrushsize, setsize=donothing, clear=donothing, get=getbrushbackuppixel, put=putpicturepixel} } trg = func[target] -- function bilinear(ox,oy,w,h,func,mode) local xp1,xp2,yp1,yp2,r1,r2,r3,r4,g1,g2,g3,g4,b1,b2,b3,b4,r,g,b, c1,c2,c3,c4,pal,adjx,adjy xp2 = ox - math.floor(ox) yp2 = oy - math.floor(oy) if mode == 1 then -- Cosinus curve (rather than linear), slightly sharper result (probably same as Photoshop) xp2 = 1 - (math.cos(xp2 * math.pi) + 1)/2 yp2 = 1 - (math.cos(yp2 * math.pi) + 1)/2 end xp1 = 1 - xp2 yp1 = 1 - yp2 c1 = func(math.floor(ox),math.floor(oy)); c2 = func(math.ceil(ox),math.floor(oy)); c3 = func(math.floor(ox),math.ceil(oy)); c4 = func(math.ceil(ox),math.ceil(oy)); r1,g1,b1 = getcolor(c1); r2,g2,b2 = getcolor(c2); r3,g3,b3 = getcolor(c3); r4,g4,b4 = getcolor(c4); pal = {{r1,g1,b1,c1},{r2,g2,b2,c2},{r3,g3,b3,c3},{r4,g4,b4,c4}} -- for SpriteMode ColorMatching r = (r1*xp1 + r2*xp2)*yp1 + (r3*xp1 + r4*xp2)*yp2; g = (g1*xp1 + g2*xp2)*yp1 + (g3*xp1 + g4*xp2)*yp2; b = (b1*xp1 + b2*xp2)*yp1 + (b3*xp1 + b4*xp2)*yp2; return r,g,b, pal end -- f = db.rotationFrac w,h = trg.getsize() hub_x = w / 2 - 0.5 -- Rotates 90,180 perfectly, not 45 hub_y = h / 2 - 0.5 --hub_x = w / 2 --hub_y = h / 2 x1,y1 = f (-rot,hub_x,hub_y,0,0) -- Rot is negative coz we read destination and write to source x2,y2 = f (-rot,hub_x,hub_y,w-1,0) x3,y3 = f (-rot,hub_x,hub_y,0,h-1) x4,y4 = f (-rot,hub_x,hub_y,w-1,h-1) dX = (x2 - x1) / w dY = (y2 - y1) / w dXs = (x4 - x2) / h dYs = (y3 - y1) / h adjx,adjy = 0,0 ox,oy = 0,0 if resize == 1 then mx = math.ceil(math.max(math.abs(x1-hub_x),math.abs(x3-hub_x))) * 2 + 2 my = math.ceil(math.max(math.abs(y1-hub_y),math.abs(y3-hub_y))) * 2 + 2 if target == 3 then -- Center gfx at Brush-to-Picture adjx = -mx/2 adjy = -my/2 end ox = (mx - w) / 2 oy = (my - h) / 2 trg.setsize(mx,my) end trg.clear(0) for y = -oy, h-1+oy, 1 do RE,GE,BE = 0,0,0 for x = -ox, w-1+ox, 1 do xp = x1 + dX * x + dXs * y yp = y1 + dY * x + dYs * y if mode == 2 or mode == 3 then r,g,b,pal = bilinear(xp,yp,w,h,trg.get, mode_co) if spritemode == 1 then c = db.getBestPalMatchHYBRID({r+RE,g+GE,b+BE},pal,0.65,true) -- Brightness do very little in general with 4 set colors else c = matchcolor2(r+RE,g+GE,b+BE) end else c = trg.get(xp,yp) end --rn,gn,bn = getcolor(c) --RE = (r - rn)*0.5 --GE = (g - gn)*0.5 --BE = (b - bn)*0.5 trg.put(x+ox+xoffset+adjx,y+oy+yoffset+adjy, c) end if update == 1 then statusmessage("Working... %"..math.floor(((y+oy) / (h-1+2*oy))*100)) updatescreen(); if (waitbreak(0)==1) then return; end end end end; -- doRotation ------------------------------------------------------------------------------- -- -- PARTICLE v1.0 -- -- Draw Sphere or Disc to any target with gradients that may fade to background -- -- type: "sphere" - volmetric planet-like disc -- "disc" - plain disc -- mode: "blend" - mix graphics with background color -- "add" - add graphics to background color -- wd,ht: - Max Width/Height of drawing area, i.e. screen size (needed if drawing to an array-buffer) -- sx,sy: - drawing coordinates (center) -- xrad,yrad: - x & y radii -- rgba1: - rgb+alpha array of center color: {r,g,b,a}, alpha is 0..1 where 1 is no transparency, Extreme rgb-values allowed -- rgba2: - rgb+alpha array of edge color: {r,g,b,a}, alpha is 0..1 where 1 is no transparency, Extreme rgb-values allowed -- update_flag: - Display rendering option (and add break feature) -- f_get: - Get pixel function: use getpicturepixel if reading from image (set null for image default) -- f_put: - Put pixel function: use putpicturepixel if drawing to image (set null for image default) -- f_recur: - Optional custom control-function for recursion (set null if not used) -- recur_count - Recursion depth counter, for use in combination with a custom function (f_recur), 0 as default -- -- Ex: particle("sphere","add", w,h, w/2,h/2, 40,40, {500,400,255, 0.8},{0,-150,-175, 0.0}, true, null, null, null, 0) -- function db.particle(type,mode,wd,ht,sx,sy,xrad,yrad,rgba1,rgba2, update_flag, f_get, f_put, f_recur, recur_count) local x,y,rev,dix,diy,r3,g3,b3,px,py,alpha,ralpha,add,q,rgb,rgb1,rgb2,rgb3,n,def_get,def_put function def_get(x,y) local r,g,b r,g,b = getcolor(getpicturepixel(x,y)); return {r,g,b} end function def_put(x,y,r,g,b) putpicturepixel(x,y, matchcolor2(r,g,b,0.65)); end if f_get == null then f_get = def_get; end if f_put == null then f_put = def_put; end q = {[true] = 1, [false] = 0} rgb,rgb1,rgb2 = {},{},{} if mode == 'blend' then add = 1 end if mode == 'add' then add = 0 end dix = xrad*2 diy = yrad*2 for y = 0, diy, 1 do py = sy+y-yrad; oy = y / diy; if (py >= 0 and py < ht) then for x = 0, dix, 1 do px = sx+x-xrad; ox = x / dix; if (px >= 0 and px < wd) then if type == 'sphere' then -- Sphere a = math.sqrt(math.max(0,0.25 - ((0.5-ox)^2+(0.5-oy)^2))) * 2 end if type == 'disc' then -- Disc a = 1-math.sqrt((0.5-ox)^2+(0.5-oy)^2)*2 end if a>0 then rev = 1-a rgb3 = f_get(px,py) alpha = rgba1[4] * a + rgba2[4] * rev ralpha = 1 - alpha * add for n = 1, 3, 1 do rgb1[n] = q[rgba1[n]==-1]*rgb3[n] + q[rgba1[n]~=-1]*rgba1[n] -- Fade from background? rgb2[n] = q[rgba2[n]==-1]*rgb3[n] + q[rgba2[n]~=-1]*rgba2[n] -- Fade to background? rgb[n] = (rgb1[n] * a + rgb2[n] * rev) * alpha + rgb3[n] * ralpha end f_put(px, py, rgb[1],rgb[2],rgb[3]); end end -- if x is good end -- x if update_flag then updatescreen(); if (waitbreak(0)==1) then return; end; end end -- if y is good end -- y if f_recur ~= null then -- recursion f_recur(type,mode,wd,ht,sx,sy,xrad,yrad,rgba1,rgba2, update_flag, f_get, f_put, f_recur, recur_count); updatescreen(); if (waitbreak(0)==1) then return; end; end end -- eof PARTICLE -- -- MedianCut a larger palette-list from a MathScene to produce a high-quality BriSorted palette for the final render/colormatching -- function db.makeSamplePal(w,h,colors,frend) local n,x,y,r,g,b,pal n,pal = 0,{} for y = 0, h, math.ceil(h/63) do for x = 0, w, math.ceil(w/63) do r,g,b = frend(x,y,w,h) n = n+1 r,g,b = db.rgbcapInt(r,g,b,255,0) pal[n] = {r,g,b,0} end;end return db.fixPalette(db.medianCut(pal, colors, true, false, {0.26,0.55,0.19}, 8, 0),1) -- pal, cols, qual, quant, weights, bits, quantpower end -- -- -- Backdrop/Gradient Render (May be written to a matrix for rendering with db.fsrender) -- function db.backdrop(p0,p1,p2,p3,fput,ip_mode) -- points:{x,y,r,g,b}, IpMode "linear" is default local x,y,ox,oy,xr,yr,r,g,b,ax,ay,w,h ax,ay = p0[1],p0[2] w = p1[1] - p0[1] h = p2[2] - p0[2] for y = 0, h, 1 do -- +1 to fill screen with FS-render oy = y/h if ip_mode == "cosine" then oy = 1 - (math.cos(oy * math.pi) + 1)/2; end yr = 1 - oy for x = 0, w, 1 do ox = x/w if ip_mode == "cosine" then ox = 1 - (math.cos(ox * math.pi) + 1)/2; end xr = 1 - ox r = (p0[3]*xr + p1[3]*ox)*yr + (p2[3]*xr + p3[3]*ox)*oy; g = (p0[4]*xr + p1[4]*ox)*yr + (p2[4]*xr + p3[4]*ox)*oy; b = (p0[5]*xr + p1[5]*ox)*yr + (p2[5]*xr + p3[5]*ox)*oy; fput(x+ax,y+ay,r,g,b) end;end end -- eof backdrop -- -- SPLINES -- -- function db.splinePoint(x0,y0,x1,y1,x2,y2,points,point) local x,y,sx1,sy1,sx2,sy2,f f = point * 1 / points sx1 = x0*(1-f) + x1*f sy1 = y0*(1-f) + y1*f sx2 = x1*(1-f) + x2*f sy2 = y1*(1-f) + y2*f x = sx1 * (1-f) + sx2 * f y = sy1 * (1-f) + sy2 * f return x,y end -- -- zx = 2*x1 - (x0+x2)/2 -- function db.drawSplineSegment(x0,y0,x1,y1,x2,y2,x3,y3,points,col) -- Does spline segment p1-p2 local n,x,y,sx1,sy1,sx2,sy2,mid,zx1,zy1,zx2,zy2,fx,fy mid = math.floor(points / 2) -- Extended Bezier points zx1 = 2*x1 - (x0+x2)/2 zy1 = 2*y1 - (y0+y2)/2 zx2 = 2*x2 - (x1+x3)/2 zy2 = 2*y2 - (y1+y3)/2 fx,fy = x1,y1 -- Segment to be drawn (0),1 - 2,(3) for n = 0, mid, 1 do f = n * 1 / points * 2 sx1,sy1 = db.splinePoint(x0,y0,zx1,zy1,x2,y2,mid*2, mid + n) sx2,sy2 = db.splinePoint(x1,y1,zx2,zy2,x3,y3,mid*2, n) x = sx1 * (1-f) + sx2 * f y = sy1 * (1-f) + sy2 * f --putpicturepixel(x,y,col) db.line(fx,fy,x,y,col) fx,fy = x,y end end -- -- eof Splines grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/codenetsend.lua0000664000000000000000000001156113223665306023753 0ustar rootroot-- Codenet send for grafx2 2.4 and up, by Michael Ilsaas. -- Sends the latest saved picture. Set the IP address of the C64 in the line below. ip = "192.168.0.64"; -- <-- IP address of the C64. fn, fp = getfilename(); picfile = assert(io.open(fp .. '/' .. fn ,"r")); picsize = picfile:seek("end") picfile:close(); if picsize == 9000 or picsize == 9002 then -- check for hires os.execute("echo AQgLCAoAnjIwNjIAAAAArQDdKfwJAo0A3ak4jRjQqQiNFtCpO40R0KkAjSDQogC9DA6dAGC9DA+dAGG9DBCdAGK9DBGdAGO9DBKdAGS9DBOdAGW9DBSdAGa9DBWdAGe9DBadAGi9DBedAGm9DBidAGq9DBmdAGu9DBqdAGy9DBudAG29DBydAG69DB2dAG/o4ADQm6IAvQwenQBwvQwfnQBxvQwgnQByvQwhnQBzvQwinQB0vQwjnQB1vQwknQB2vQwlnQB3vQwmnQB4vQwnnQB5vQwonQB6vQwpnQB7vQwqnQB8vQwrnQB9vQwsnQB+vQwtnQB/6OAA0JuiAL1MLZ0ATL1MLp0ATb1ML50ATr1MMJ0AT+jgANDjvUUJnQDAvUUKnQDBvUULnQDCvUUMnQDDvUUNnQDEvUUOnQDF6OAA0NdMAMCpwI00A6mojTUDqQCNNgOpQI03A60B3gkBjQHeor+gxCBbwxAJqQagwqkITLnESKkYoMJoqQ14IP7DEPtYIOH/0ANMucR4IP7DMPGtRAPJCNDqrUUD8ArJBtDhIA/DTDzArUYDyUXQ1K1MAym/DU0D0MqtTwPJEfA2yQHwCKkCIKzCTDzArVoDyQjQIKkAjVoDGK1cA2kIjVwDkAruXQPQBe5cA/D2IDjCIJnCTDzArVwDyRnQB61dA8k+8AipAyCswkw8wK1iA8nK0OCtYwPJH9DZrWUDSKkBjWUDqQCNSAONXgONYAOF+oX7qSCNSQOpGI1fA6kRjWEDrVoDrlwDjloDjVwDrVsDrl0DjlsDjV0DGKISpft9UwOF+6X6fVIDhfrKyhDukAjm+9AE5vrw+KX6Sf+NYAOl+0n/jWEDTl8DIDjCIJnCrWYDhf2tZwOF/K5oA6xpA2jJBPAPyQXwPskG8GvJB/B6TDzAziDQpQFIKfgJA4UBrmkDoAC5agOR/MjK0PdohQHuINAYmGX8ha6FLaX9aQCFr4UuTDzAqTOFAZhIivASrWoDoACR/MiR/MjQ+Ob9ytDzaKrwC61qA6AAkfzIytD6qTeFAUw8wKX80ALG/cb8pf1IpfxIqQhMucSiCL35wZ1AA8oQ96kDSKk/SKkITLnEIFmmIDOlTK6nQkNERk5PIFJSLU5FVCBGT1VORC4NAFJSLU5FVCBGT1VORC4gQ1M4OTAwQSBSRVZJU0lPTiAAogO9UgOdVgO9NAOdUgPKEPGpgI1OA6kAjVADjVEDhfqF+xiiEqX7fUcDhful+n1GA4X6ysoQ7pAI5vvQBOb68Pil+kn/jVADpftJ/41RA6IFvT4DnTgDvb/EnT4DyhDxYBitSQNpDqqtSANpANAEikxpxGBIohy9RgOdXgPKEPeiB6kAnVoDytD6hfqF+41IA6k0jUkDqQGNTwOpA41aA2iNWwMYoh6l+31bA4X7pfp9WgOF+srKEO6QCOb70ATm+vD4pfpJ/41cA6X7Sf+NXQMgOMJMmcKiB71Tw91GA9A5yhD1ogO9NAPdXgPQLMoQ9akCjU0Dogm9TgOdWAO9v8SdTgPKEPGiA700A51UA8oQ9yCHwqk8TGnEYAABCAAGBAABhvyE/SC5wxABYEip/4X6oACYSBhprCDtw4ol+oX6mCX6hfpoqMjAA9DnpfrJ/9AaoACx/KrImEix/KhoSEoJrCDcw2ioyMAG0OipgqIFoA8g3MOpiaLToAAg3MNoYKkAIO3D4A7QF8Bj0BOpASDtw4rQC8ALsAeYOOkHkAFgqf9gCo0C3qkAKo0D3o4E3owF3mAKjQLeqQAqjQPergTerAXeYKmSIO3DmCl/0AOp/2CtCd6tCN6sCd6uCN6Y0CngyLAlikoIqvAToACtCN6ZOAPIrQnemTgDyMrQ7yiQBq0I3pk4A6kAYIpImPAOogCtCN6tCd7o0PeI0PRoqvAMrQjeyvAGrQneytD0qf9gosmODN6iAI4N3o0O3o4P3kipkiDtw5gpf/ASrQnerQjerAnergjeIEPETHrEqZwg7cOYKQHw2mhKaQCqoAC5OAONCN7IuTgDjQneyMrQ72CpAI0g0GAAgBCxMhg= | base64 -d > /tmp/picview.prg"); else os.execute("echo AQgLCAoAnjIwNjIAAAAArQDdKfwJAo0A3ak4jRjQqRiNFtCpO40R0K0/NY0h0KkAjSDQogC9Lw6dAGC9Lw+dAGG9LxCdAGK9LxGdAGO9LxKdAGS9LxOdAGW9LxSdAGa9LxWdAGe9LxadAGi9LxedAGm9LxidAGq9LxmdAGu9LxqdAGy9LxudAG29LxydAG69Lx2dAG/o4ADQm6IAvS8enQBwvS8fnQBxvS8gnQByvS8hnQBzvS8inQB0vS8jnQB1vS8knQB2vS8lnQB3vS8mnQB4vS8nnQB5vS8onQB6vS8pnQB7vS8qnQB8vS8rnQB9vS8snQB+vS8tnQB/6OAA0JuiAL1vLZ0ATL1vLp0ATb1vL50ATr1vMJ0AT+jgANDjvVcxnQDYvVcynQDZvVcznQDavVc0nQDb6OAA0OO9aAmdAMC9aAqdAMG9aAudAMK9aAydAMO9aA2dAMS9aA6dAMXo4ADQ10wAwKnAjTQDqaiNNQOpAI02A6lAjTcDrQHeCQGNAd6iv6DEIFvDEAmpBqDCqQhMucRIqRigwmipDXgg/sMQ+1gg4f/QA0y5xHgg/sMw8a1EA8kI0OqtRQPwCskG0OEgD8NMPMCtRgPJRdDUrUwDKb8NTQPQyq1PA8kR8DbJAfAIqQIgrMJMPMCtWgPJCNAgqQCNWgMYrVwDaQiNXAOQCu5dA9AF7lwD8PYgOMIgmcJMPMCtXAPJGdAHrV0DyT7wCKkDIKzCTDzArWIDycrQ4K1jA8kf0NmtZQNIqQGNZQOpAI1IA41eA41gA4X6hfupII1JA6kYjV8DqRGNYQOtWgOuXAOOWgONXAOtWwOuXQOOWwONXQMYohKl+31TA4X7pfp9UgOF+srKEO6QCOb70ATm+vD4pfpJ/41gA6X7Sf+NYQNOXwMgOMIgmcKtZgOF/a1nA4X8rmgDrGkDaMkE8A/JBfA+yQbwa8kH8HpMPMDOINClAUgp+AkDhQGuaQOgALlqA5H8yMrQ92iFAe4g0BiYZfyFroUtpf1pAIWvhS5MPMCpM4UBmEiK8BKtagOgAJH8yJH8yND45v3K0PNoqvALrWoDoACR/MjK0PqpN4UBTDzApfzQAsb9xvyl/Uil/EipCEy5xKIIvfnBnUADyhD3qQNIqT9IqQhMucQgWaYgM6VMrqdCQ0RGTk8gUlItTkVUIEZPVU5ELg0AUlItTkVUIEZPVU5ELiBDUzg5MDBBIFJFVklTSU9OIACiA71SA51WA700A51SA8oQ8amAjU4DqQCNUAONUQOF+oX7GKISpft9RwOF+6X6fUYDhfrKyhDukAjm+9AE5vrw+KX6Sf+NUAOl+0n/jVEDogW9PgOdOAO9v8SdPgPKEPFgGK1JA2kOqq1IA2kA0ASKTGnEYEiiHL1GA51eA8oQ96IHqQCdWgPK0PqF+oX7jUgDqTSNSQOpAY1PA6kDjVoDaI1bAxiiHqX7fVsDhful+n1aA4X6ysoQ7pAI5vvQBOb68Pil+kn/jVwDpftJ/41dAyA4wkyZwqIHvVPD3UYD0DnKEPWiA700A91eA9AsyhD1qQKNTQOiCb1OA51YA72/xJ1OA8oQ8aIDvTQDnVQDyhD3IIfCqTxMacRgAAEIAAYEAAGG/IT9ILnDEAFgSKn/hfqgAJhIGGmsIO3DiiX6hfqYJfqF+mioyMAD0Oel+sn/0BqgALH8qsiYSLH8qGhISgmsINzDaKjIwAbQ6KmCogWgDyDcw6mJotOgACDcw2hgqQAg7cPgDtAXwGPQE6kBIO3DitALwAuwB5g46QeQAWCp/2AKjQLeqQAqjQPejgTejAXeYAqNAt6pACqNA96uBN6sBd5gqZIg7cOYKX/QA6n/YK0J3q0I3qwJ3q4I3pjQKeDIsCWKSgiq8BOgAK0I3pk4A8itCd6ZOAPIytDvKJAGrQjemTgDqQBgikiY8A6iAK0I3q0J3ujQ94jQ9Giq8AytCN7K8AatCd7K0PSp/2CiyY4M3qIAjg3ejQ7ejg/eSKmSIO3DmCl/8BKtCd6tCN6sCd6uCN4gQ8RMesSpnCDtw5gpAfDaaEppAKqgALk4A40I3si5OAONCd7IytDvYKkAjSDQYACAELEyGA== | base64 -d > /tmp/picview.prg"); end if picsize == 9000 or picsize == 10001 then -- check for loadaddress, add two bytes if not found os.execute('echo a >> /tmp/picview.prg'); end os.execute('cat '.. fp .. '/' .. fn .. ' >> /tmp/picview.prg'); -- append pic to c64 binary os.execute("codenet -x /tmp/picview.prg -n "..ip); -- send file to c64 grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/0000775000000000000000000000000013223665306022424 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/ThomsonConstraints.lua0000664000000000000000000000142113223665306027004 0ustar rootroot-- Thomson Constraints checker -- Check wether picture is compatible with Thomson computers video modes -- (8x1 cells with 2 colors out of 16 in each cell) w,h=getpicturesize() xcell = 8 selectlayer(1) clearpicture(0) selectlayer(0) -- foreach grid cell for y=0,h-1,1 do for x1=0,w-1,xcell do -- initialize our two colors for the cell, c1 is the color of the first -- pixel, and we will look for c2 in the following pixels c1 = getpicturepixel(x1,y) c2 = -1 for x2=0,xcell-1,1 do c = getpicturepixel(x1+x2, y) -- is it a new color ? if c ~= c1 and c ~= c2 then if c2 == -1 then -- C2 is free, we can use it for this new color c2 = c else -- out of colors ! selectlayer(1) putpicturepixel(x1+x2,y,17); selectlayer(0) end end end end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/Rainbow-Dark2Bright.lua0000664000000000000000000000123113223665306026626 0ustar rootroot--PICTURE: Rainbow - Dark to Bright v1.1 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Email: dawnbringer@hem.utfors.se -- MSN: annassar@hotmail.com -- --dofile("dawnbringer_lib.lua") run("../libs/dawnbringer_lib.lua") --> db.shiftHUE(r,g,b, deg) w, h = getpicturesize() for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do -- Fractionalize image dimensions ox = x / w; oy = y / h; r = 255 * math.sin(oy * 2) g = (oy-0.5)*512 * oy b = (oy-0.5)*512 * oy r, g, b = db.shiftHUE(r,g,b,ox * 360); c = matchcolor(r,g,b) putpicturepixel(x, y, c); end updatescreen(); if (waitbreak(0)==1) then return; end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/DrawGridOrthogonal_RGB.lua0000664000000000000000000000125413223665306027363 0ustar rootroot-- draw grid - rgb (matchcolor) - Copyright 2010 Paulo Silva -- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. See w,h=getpicturesize() ok,xsiz,ysiz,r,g,b=inputbox("draw grid - rgb (matchcolor)","x size",8,1,64,5,"y size",8,1,64,6,"r",128,0,255,6,"g",128,0,255,6,"b",128,0,255,6); if ok==true then c=matchcolor(r,g,b) for y=0,h-1,1 do for x=0,w-1,xsiz do putpicturepixel(x,y,c); end;end for y=0,h-1,ysiz do for x=0,w-1,1 do putpicturepixel(x,y,c); end;end;end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/Tiler.lua0000664000000000000000000000513213223665306024207 0ustar rootroot--Picture Tiler by Adrien Destugues --Extract unique tiles from the spare page --to the main one. Main page is erased. -- -- Copyright 2011 Adrien Destugues -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- Copy palette from spare to main -- TODO -- Grid size -- TODO : get it from GrafX2 xgrid = 16; ygrid = 16; -- picture size w, h = getpicturesize(); -- We may need less if there are duplicates setsparepicturesize(xgrid, w*h/xgrid); tileid = 0; -- blit part of the spare to picture function blitpicturetospare(srcx, srcy, dstx, dsty, width, height) local x,y; for y = 0, height - 1, 1 do for x = 0, width - 1, 1 do putsparepicturepixel(dstx+x, dsty+y, getpicturepixel(srcx + x, srcy + y)); end end end function comparesparewithpicture(srcx, srcy, dstx, dsty, width, height) local x,y,color for y = 0, height - 1, 1 do for x = 0, width - 1, 1 do color = getsparepicturepixel(srcx + x, srcy + y); if color ~= getpicturepixel(dstx+x, dsty+y) then -- they are different return false; end end end -- they are identical return true; end -- compute checksum of a picture area -- it may not be unique, we use it as a key for an hashmap function checksum(srcx, srcy, width, height) local sum,x,y sum = 0; for y = 0, height - 1, 1 do for x = 0, width - 1, 1 do sum = sum + getpicturepixel(srcx+x, srcy+y); end end return sum; end tilemap = {} -- foreach tile for y = 0, h-1, ygrid do for x = 0, w - 1, xgrid do -- existing one ? csum = checksum(x,y,xgrid,ygrid); if tilemap[csum] ~= nil then -- potential match -- Find matching tileid found = false; for id in pairs(tilemap[csum]) do -- is it a match ? if comparesparewithpicture(x,y,0,id*ygrid, xgrid, ygrid) then -- found it ! tilemap[csum][id] = tilemap[csum][id] + 1; found = true; break; end end -- Add tile anyway if needed if not found then desty = tileid * ygrid; blitpicturetospare(x, y, 0, desty, xgrid, ygrid); -- add it to the tilemap tilemap[csum][tileid] = 1; -- give it a tile id tileid = tileid + 1; end else -- Copy to spare desty = tileid * ygrid; blitpicturetospare(x, y, 0, desty, xgrid, ygrid); -- add it to the tilemap tilemap[csum] = {} tilemap[csum][tileid] = 1; -- give it a tile id tileid = tileid + 1; end end end setsparepicturesize(xgrid, (tileid-1)*ygrid) --updatescreen(); grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/others-8bit/0000775000000000000000000000000013223665306024574 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/others-8bit/lib/0000775000000000000000000000000013223665306025342 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/others-8bit/lib/ostro_other.lua0000664000000000000000000000764313223665306030426 0ustar rootroot-- ostro_zx.lua : converts a color image into a -- ZX-like image (8+8 fixed colors with color clash) -- using Ostromoukhov's error diffusion algorithm. -- -- Version: 03/21/2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See run('../../thomson/lib/ostromoukhov.lua') -- get screen size local screen_w, screen_h = getpicturesize() OtherDither = {} function OtherDither:new(a) local o = { -- default ZX values -- width of the screen width=a and a.width or 256, -- height of the screen height=a and a.height or 192, -- size of Nx1 clash size clash_size=a and a.clash_size or 8, -- normalize the picture levels (like in imagemagick) normalize=a and a.normalize or 0.005, -- put a pixel pset=a and a.pset or function(self,x,y,c) if c<0 then c=-c-1 end self.screen[x+y*self.width] = c end, -- init gfx data setGfx=a and a.setGfx or function(self) self.screen={} end, -- update gfx to screen updatescreen=a and a.updatescreen or function(self) for i=0,255 do setcolor(i,0,0,0) end for y=0,self.height-1 do for x=0,self.width-1 do putpicturepixel(x,y,self.screen[x+y*self.width] or 0) end end -- refresh palette for i,v in ipairs(self.pal) do local r=v % 16 local g=math.floor(v/16) % 16 local b=math.floor(v/256) % 16 setcolor(i+thomson._palette.offset-1, thomson.levels.pc[r+1], thomson.levels.pc[g+1], thomson.levels.pc[b+1]) end updatescreen() end, -- palette with thomson ordering (to use thomson's -- lib support) pal= a and a.pal or { 0x000,0xF00,0x00F,0xF0F,0x0F0,0xFF0,0x0FF,0xFFF, 0x000,0x200,0x002,0x202,0x020,0x220,0x022,0x222 } } setmetatable(o, self) self.__index = self return o end -- Converts ZX coordinates (0-255,0-191) into screen coordinates function OtherDither:to_screen(x,y) local i,j; if screen_w/screen_h < self.width/self.height then i = x*screen_h/self.height j = y*screen_h/self.height else i = x*screen_w/self.width j = y*screen_w/self.width end return math.floor(i), math.floor(j) end -- return the Color @(x,y) in linear space (0-255) -- corresonding to the other platform screen OtherDither._getLinearPixel = {} -- cache function OtherDither:getLinearPixel(x,y) local k=x+y*self.width local p = self._getLinearPixel and self._getLinearPixel[k] if not p then local x1,y1 = self:to_screen(x,y) local x2,y2 = self:to_screen(x+1,y+1) if x2==x1 then x2=x1+1 end if y2==y1 then y2=y1+1 end p = Color:new(0,0,0) for j=y1,y2-1 do for i=x1,x2-1 do p:add(getLinearPictureColor(i,j)) end end p:div((y2-y1)*(x2-x1)) --:floor() if self._getLinearPixel then self._getLinearPixel[k]=p end end return self._getLinearPixel and p:clone() or p end function OtherDither:ccAcceptCouple(c1,c2) -- bright colors can't mix with dimmed ones return c1~=c2 and ((c1<=8 and c2<=8) or (c1>8 and c2>8)) end function OtherDither:dither() local NORMALIZE=Color.NORMALIZE Color.NORMALIZE=self.normalize local dither=OstroDither:new(self.pal) dither.ccAcceptCouple = function(dither,c1,c2) return self:ccAcceptCouple(c1,c2) end dither.clash_size = self.clash_size dither.attenuation = .9 self:setGfx() dither:ccDither(self.width,self.height, function(x,y) return self:getLinearPixel(x,y) end, function(x,y,c) self:pset(x,y,c) end, true, function(y) thomson.info("Converting...", math.floor(y*100/self.height),"%") end,true) -- refresh screen setpicturesize(self.width,self.height) self:updatescreen() finalizepicture() Color.NORMALIZE=NORMALIZE end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/others-8bit/ostro_oric.lua0000664000000000000000000000137513223665306027467 0ustar rootroot-- ostro_zx.lua : converts a color image into a -- Oric image (8+8 fixed colors with color clash) -- using Ostromoukhov's error diffusion algorithm. -- -- Version: 03/21/2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See run('lib/ostro_other.lua') OtherDither:new{ width=240, height=200, clash_size=6, pal={0x000,0x00F,0x0F0,0x0FF,0xF00,0xF0F,0xFF0,0xFFF}, pset=function(self,x,y,c) if x<6 then c=0 end if c<0 then c=-c-1 end self.screen[x+y*self.width] = c end }:dither() grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/others-8bit/ostro_zx.lua0000664000000000000000000000107513223665306027171 0ustar rootroot-- ostro_zx.lua : converts a color image into a -- ZX image (8+8 fixed colors with color clash) -- using Ostromoukhov's error diffusion algorithm. -- -- Version: 03/21/2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See run('lib/ostro_other.lua') OtherDither:new{width=256,height=192,clash_size=8}:dither() grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/Pic2isometric.lua0000664000000000000000000000316413223665306025647 0ustar rootroot--PICTURE (part of): 2 Isometric v0.1b --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Email: dawnbringer@hem.utfors.se -- MSN: annassar@hotmail.com -- -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- Color 0 is assumed to be the background -- iso = {{0, 0, 1, 1, 1, 1, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1}, {2, 2, 1, 1, 1, 1, 3, 3}, {2, 2, 2, 2, 3, 3, 3, 3}, {2, 2, 2, 2, 3, 3, 3, 3}, {2, 2, 2, 2, 3, 3, 3, 3}, {0, 0, 2, 2, 3, 3, 0, 0}} isowidth = 8 isoheight = 7 xoff = 0.5 yoff = 0 xstep = 4 ystep = 2 zstep = 4 -- Part of screen from top-left (4 = 1/4) xsize = 5 ysize = 4 w, h = getpicturesize() xo = math.floor(w * xoff) -- just don't render more than can be fittted right now w = math.floor(w / xsize) h = math.floor(h / ysize) for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do isox = x * xstep - y * xstep isoy = y * ystep + x * ystep cb = getbackuppixel(x,y) -- if cb ~= 0 then r,g,b = getbackupcolor(cb); c1 = matchcolor(r,g,b); c2 = matchcolor(r+64, g+64, b+64); c3 = matchcolor(r-64, g-64, b-64); cols = {0,c1,c2,c3} for iy = 1, isoheight, 1 do for ix = 1, isowidth, 1 do i = iso[iy][ix] c = cols[i+1] if i ~= 0 then putpicturepixel(xo + isox+ix-1, isoy+iy-1, c); end end end end -- end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/CellColourReducer.lua0000664000000000000000000000343013223665306026504 0ustar rootroot-- cell colour reducer - jan'11, from Paulo Silva, with help from people from GrafX2 google group (DawnBringer, Adrien Destugues (PulkoMandy), and Yves Rizoud) -- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. See w,h=getpicturesize() ok,xcell,ycell=inputbox("Modify cell pixel size","xcell",8,1,16,4,"ycell",8,1,16,4); if ok==true then function grayscaleindexed(c) r,g,b=getcolor(c);return math.floor((b*11+r*30+g*59)/100);end celcnt={};for n=0,255,1 do celcnt[n+1]=0;end -- Arraycounter must have initial value for y1=0,h-1,ycell do for x1=0,w-1,xcell do for i=0,255,1 do celcnt[i+1]=0;end for y2=0,ycell-1,1 do for x2=0,xcell-1,1 do x=x1+x2;y=y1+y2;u=getpicturepixel(x,y) celcnt[u+1]=celcnt[u+1]+(1000*xcell*ycell)+math.random(0,950);end;end ikattr=0;paattr=0;ikcnt=0;pacnt=0 for i=0,255,1 do if ikcntgrayscaleindexed(paattr) then tmpr=ikattr;ikattr=paattr;paattr=tmpr;end wmid=math.floor((grayscaleindexed(paattr)+grayscaleindexed(ikattr))/2) for y2=0,ycell-1,1 do for x2=0,xcell-1,1 do x=x1+x2;y=y1+y2;u=getpicturepixel(x,y) if u==ikattr then idou=ikattr elseif u==paattr then idou=paattr else idou=ikattr if grayscaleindexed(u)>wmid then idou=paattr;end end putpicturepixel(x,y,idou) end;end;end;end;end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/DrawGridIsometric.lua0000664000000000000000000000116613223665306026515 0ustar rootroot-- Draw isometric grid - Copyright 2010 Paulo Silva -- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. See w,h=getpicturesize(); ok,gsiz,ik=inputbox("draw isometric grid","size",16,0,128,5,"colour",1,0,255,6); if ok==true then for y=0,h-1,gsiz do for x=0,w-1,1 do putpicturepixel(x,y+(x/2)%gsiz,ik); end;end for y=0,h-1,gsiz do for x=0,w-1,1 do putpicturepixel(x+((gsiz/2)-1),y+(gsiz-1)-((x/2)%gsiz),ik); end;end;end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/GlassGridFilter.lua0000664000000000000000000000130713223665306026155 0ustar rootroot-- Glass grid filter - Copyright 2010 Paulo Silva -- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. See w,h=getpicturesize(); ok,xsiz,ysiz=inputbox("message","xsize",8,0,64,5,"ysize",8,0,64,6); if ok==true then for y1=0,h-1,xsiz do for x1=0,w-1,ysiz do for y2=0,(ysiz/2)-1,1 do for x2=0,xsiz-1,1 do c1=getpicturepixel(x1+x2,y1+y2);c2=getpicturepixel(x1+(xsiz-1)-x2,y1+(ysiz-1)-y2) putpicturepixel(x1+x2,y1+y2,c2);putpicturepixel(x1+(xsiz-1)-x2,y1+(ysiz-1)-y2,c1) end;end;end;end;end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/XBitColourXpaceFromPalette.lua0000664000000000000000000000133413223665306030306 0ustar rootroot-- Copyright 2010 Paulo Silva -- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. See w,h=getpicturesize(); ok,bitd=inputbox("colourspace from palette","bitdepth:",4,1,8,5); if ok==true then bitd3=(2^bitd);bitd8=(2^(math.floor(bitd/2)));bitd9=(2^((math.floor((bitd-1)/2))+1)) for y1=0,(bitd8-1),1 do for x1=0,(bitd9-1),1 do for y2=0,(bitd3-1),1 do for x2=0,(bitd3-1),1 do putpicturepixel(x1*bitd3+x2,y1*bitd3+y2,matchcolor((y2*255)/(bitd3-1),((y1*8+x1)*255)/(bitd3-1),(x2*255)/(bitd3-1))) end;end;end;end;end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/RemapImage2RGB.lua0000664000000000000000000000173213223665306025556 0ustar rootroot--SCENE: Remap pic to RGB, diag.dith --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- Set Palette (to a predefined one) colors = {{ 0, 0, 0}, {255, 0, 0}, { 0,255, 0}, { 0, 0,255} } chm = {1,0,0} for c = 1, #colors, 1 do setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) end for c = #colors, 255, 1 do setcolor(c,0,0,0) end w, h = getpicturesize() for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do r,g,b = getbackupcolor(getbackuppixel(x,y)); rn = r * chm[1+(y+0+x)%3] gn = g * chm[1+(y+1+x)%3] bn = b * chm[1+(y+2+x)%3] n = matchcolor(rn,gn,bn); putpicturepixel(x, y, n); end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/RemapImage2RGB_ed.lua0000664000000000000000000000253013223665306026223 0ustar rootroot--SCENE: Remap pic 2 RGB, 1lineED-dith. (Same line simple error-diffusion dither) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See power = 0.615 c1 = 0.8 -- Error weight (white is green) c2 = 0.2 -- RGB weight (white is r+g+b) -- Set Palette (to a predefined one) colors = {{ 0, 0, 0}, {255, 0, 0}, { 0,255, 0}, { 0, 0,255} } chm = {1,0,0} for c = 1, #colors, 1 do setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) end for c = #colors, 255, 1 do setcolor(c,0,0,0) end w, h = getpicturesize() for y = 0, h - 1, 1 do re = 0 ge = 0 be = 0 for x = (y%2), w - 1, 1 do r,g,b = getbackupcolor(getbackuppixel(x,y)); rn = re * c1 + r * chm[1+(y+0+x)%3] * c2 gn = ge * c1 + g * chm[1+(y+1+x)%3] * c2 bn = be * c1 + b * chm[1+(y+2+x)%3] * c2 n = matchcolor(rn,gn,bn); putpicturepixel(x, y, n); rn,gn,bn = getcolor(getpicturepixel(x,y)); re = (re + (r - rn)) * power ge = (ge + (g - gn)) * power be = (be + (b - bn)) * power end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/RemapImageTo3bitPal.lua0000664000000000000000000000247213223665306026665 0ustar rootroot--SCENE: Remap pic to 3bit, LineEDdith. (Same line simple error-diffusion dither) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- -- Just a demonstration. -- power = 0.6 -- Channel shades (shades = 2 ^ bit-depth) shades = 2 mult = 255 / (shades-1) colors = {} col = 0 for r = 0, shades-1, 1 do for g = 0, shades-1, 1 do for b = 0, shades-1, 1 do col = col + 1 colors[col] = { r*mult, g*mult, b*mult } end end end for c = 1, #colors, 1 do setcolor(c-1,colors[c][1],colors[c][2],colors[c][3]) end for c = #colors, 255, 1 do setcolor(c,0,0,0) end w, h = getpicturesize() for y = 0, h - 1, 1 do re = 0 ge = 0 be = 0 for x = (y%2), w - 1, 1 do r,g,b = getbackupcolor(getbackuppixel(x,y)); rn = re + r gn = ge + g bn = be + b n = matchcolor(rn,gn,bn); putpicturepixel(x, y, n); rn,gn,bn = getcolor(getpicturepixel(x,y)); re = (re + (r - rn)) * power ge = (ge + (g - gn)) * power be = (be + (b - bn)) * power end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/DrawgridOrthogonal_Index.lua0000664000000000000000000000114313223665306030055 0ustar rootroot-- draw grid - indexed colour - Copyright 2010 Paulo Silva -- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. See w,h=getpicturesize(); ok,xsiz,ysiz,c=inputbox("draw grid - indexed colour)","x size",8,1,64,5,"y size",8,1,64,6,"colour id",0,0,255,6); if ok==true then for y=0,h-1,1 do for x=0,w-1,xsiz do putpicturepixel(x,y,c);end;end for y=0,h-1,ysiz do for x=0,w-1,1 do putpicturepixel(x,y,c);end;end;end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/0000775000000000000000000000000013223665306024113 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/none_mo5.lua0000664000000000000000000000143213223665306026335 0ustar rootroot-- ostro_mo5.lua : converts a color image into a -- MO5 image (16 fixed colors with color clash) -- using Ostromoukhov's error diffusion algorithm. -- -- Version: 02-jan-2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See run('lib/ostromoukhov.lua') local dith=OstroDither:new() local tmp=dith.setLevelsFromPalette dith.setLevelsFromPalette = function(self) tmp(self) self.attenuation=0 end dith:dither40cols(function(w,h,getLinearPixel) local pal={} for i=0,15 do pal[i+1] = thomson.palette(i) end return pal end)grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/lib/0000775000000000000000000000000013223665306024661 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/lib/color_reduction.lua0000664000000000000000000003333013223665306030560 0ustar rootroot-- color_reduction.lua : support for reducing the -- colors for a thomson image. -- -- Inspire by Xiaolin Wu v2 (Xiaolin Wu 1992). -- Greedy orthogonal bipartition of RGB space for -- variance minimization aided by inclusion-exclusion -- tricks. (Author's description) -- http://www.ece.mcmaster.ca/%7Exwu/cq.c -- -- Version: 02-jan-2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See run('color.lua') run('bayer.lua') run('thomson.lua') run('convex_hull.lua') if not ColorReducer then -- clamp a value in the 0-255 range local function clamp(v) v=math.floor(v+.5) return v<0 and 0 or v>255 and 255 or v end local Voxel = {} function Voxel:new() local o = {m2 = 0, wt=0, mr=0, mg=0, mb=0} setmetatable(o, self) self.__index = self return o end function Voxel:rgb() local n=self.wt; n=n>0 and n or 1 return clamp(self.mr/n), clamp(self.mg/n), clamp(self.mb/n) end function Voxel:toThomson() local r,g,b=self:rgb() return thomson.levels.linear2to[r]-1, thomson.levels.linear2to[g]-1, thomson.levels.linear2to[b]-1 end function Voxel:toPal() local r,g,b=self:toThomson() return r+g*16+b*256 end function Voxel:tostring() local n=self.wt local r,g,b=self:rgb() return "(n="..math.floor(n*10)/10 .." r=" .. r.. " g="..g .. " b=" .. b.. " rgb=".. table.concat({self:toThomson()},',').. ")" end function Voxel:addColor(color) local r,g,b=color:toRGB() self.wt = self.wt + 1 self.mr = self.mr + r self.mg = self.mg + g self.mb = self.mb + b self.m2 = self.m2 + r*r + g*g + b*b return self end function Voxel:add(other,k) k=k or 1 self.wt = self.wt + other.wt*k self.mr = self.mr + other.mr*k self.mg = self.mg + other.mg*k self.mb = self.mb + other.mb*k self.m2 = self.m2 + other.m2*k return self end function Voxel:mul(k) return self:add(self,k-1) end function Voxel:module2() return self.mr*self.mr + self.mg*self.mg + self.mb*self.mb end ColorReducer = {} function ColorReducer:new() local o = {} setmetatable(o, self) self.__index = self return o end function ColorReducer:v(r,g,b) local i=(r*17+g)*17+b if not self[i] then self[i]=Voxel:new() end return self[i] end function ColorReducer:add(linearColor) local r,g,b=linearColor:toRGB() r,g,b=thomson.levels.linear2to[clamp(r)], thomson.levels.linear2to[clamp(g)], thomson.levels.linear2to[clamp(b)] self:v(r,g,b):addColor(linearColor) -- if r==1 and g==1 and b==1 then messagebox(self:v(r,g,b).wt) end end function ColorReducer:M3d() -- convert histogram into moments so that we can -- rapidly calculate the sums of the above quantities -- over any desired box. for r=1,16 do local area={} for i=0,16 do area[i]=Voxel:new() end for g=1,16 do local line=Voxel:new() for b=1,16 do local v = self:v(r,g,b) -- v:mul(0):add(self:v(r-1,g,b)):add(area[b]:add(line:add(v)) line:add(v) area[b]:add(line) v:mul(0):add(self:v(r-1,g,b)):add(area[b]) end end end end function ColorReducer:Vol(cube) -- Compute sum over a box of all statistics return Voxel:new() :add(self:v(cube.r1,cube.g1,cube.b1), 1) :add(self:v(cube.r1,cube.g1,cube.b0),-1) :add(self:v(cube.r1,cube.g0,cube.b1),-1) :add(self:v(cube.r1,cube.g0,cube.b0), 1) :add(self:v(cube.r0,cube.g1,cube.b1),-1) :add(self:v(cube.r0,cube.g1,cube.b0), 1) :add(self:v(cube.r0,cube.g0,cube.b1), 1) :add(self:v(cube.r0,cube.g0,cube.b0),-1) end -- The next two routines allow a slightly more efficient -- calculation of Vol() for a proposed subbox of a given -- box. The sum of Top() and Bottom() is the Vol() of a -- subbox split in the given direction and with the specified -- new upper bound. function ColorReducer:Bottom(cube,dir) -- Compute part of Vol(cube, mmt) that doesn't -- depend on r1, g1, or b1 (depending on dir) local v=Voxel:new() if dir=="RED" then v:add(self:v(cube.r0,cube.g1,cube.b1),-1) :add(self:v(cube.r0,cube.g1,cube.b0), 1) :add(self:v(cube.r0,cube.g0,cube.b1), 1) :add(self:v(cube.r0,cube.g0,cube.b0),-1) elseif dir=="GREEN" then v:add(self:v(cube.r1,cube.g0,cube.b1),-1) :add(self:v(cube.r1,cube.g0,cube.b0), 1) :add(self:v(cube.r0,cube.g0,cube.b1), 1) :add(self:v(cube.r0,cube.g0,cube.b0),-1) elseif dir=="BLUE" then v:add(self:v(cube.r1,cube.g1,cube.b0),-1) :add(self:v(cube.r1,cube.g0,cube.b0), 1) :add(self:v(cube.r0,cube.g1,cube.b0), 1) :add(self:v(cube.r0,cube.g0,cube.b0),-1) end return v end function ColorReducer:Top(cube,dir,pos) -- Compute remainder of Vol(cube, mmt), substituting -- pos for r1, g1, or b1 (depending on dir) local v=Voxel:new() if dir=="RED" then v:add(self:v(pos,cube.g1,cube.b1), 1) :add(self:v(pos,cube.g1,cube.b0),-1) :add(self:v(pos,cube.g0,cube.b1),-1) :add(self:v(pos,cube.g0,cube.b0), 1) elseif dir=="GREEN" then v:add(self:v(cube.r1,pos,cube.b1), 1) :add(self:v(cube.r1,pos,cube.b0),-1) :add(self:v(cube.r0,pos,cube.b1),-1) :add(self:v(cube.r0,pos,cube.b0), 1) elseif dir=="BLUE" then v:add(self:v(cube.r1,cube.g1,pos), 1) :add(self:v(cube.r1,cube.g0,pos),-1) :add(self:v(cube.r0,cube.g1,pos),-1) :add(self:v(cube.r0,cube.g0,pos), 1) end return v end function ColorReducer:Var(cube) -- Compute the weighted variance of a box -- NB: as with the raw statistics, this is really the variance * size local v = self:Vol(cube) return v.m2 - v:module2()/v.wt end -- We want to minimize the sum of the variances of two subboxes. -- The sum(c^2) terms can be ignored since their sum over both subboxes -- is the same (the sum for the whole box) no matter where we split. -- The remaining terms have a minus sign in the variance formula, -- so we drop the minus sign and MAXIMIZE the sum of the two terms. function ColorReducer:Maximize(cube,dir,first,last,cut,whole) local base = self:Bottom(cube,dir) local max = 0 cut[dir] = -1 for i=first,last-1 do local half = Voxel:new():add(base):add(self:Top(cube,dir,i)) -- now half is sum over lower half of box, if split at i if half.wt>0 then -- subbox could be empty of pixels! local temp = half:module2()/half.wt half:mul(-1):add(whole) if half.wt>0 then temp = temp + half:module2()/half.wt if temp>max then max=temp; cut[dir] = i end end end end return max end function ColorReducer:Cut(set1,set2) local whole = self:Vol(set1) local cut = {} local maxr = self:Maximize(set1,"RED", set1.r0+1,set1.r1, cut, whole) local maxg = self:Maximize(set1,"GREEN",set1.g0+1,set1.g1, cut, whole) local maxb = self:Maximize(set1,"BLUE", set1.b0+1,set1.b1, cut, whole) local dir = "BLUE" if maxr>=maxg and maxr>=maxb then dir = "RED" if cut.RED<0 then return false end -- can't split the box elseif maxg>=maxr and maxg>=maxb then dir = "GREEN" end set2.r1=set1.r1 set2.g1=set1.g1 set2.b1=set1.b1 if dir=="RED" then set1.r1 = cut[dir] set2.r0 = cut[dir] set2.g0 = set1.g0 set2.b0 = set1.b0 elseif dir=="GREEN" then set1.g1 = cut[dir] set2.g0 = cut[dir] set2.r0 = set1.r0 set2.b0 = set1.b0 else set1.b1 = cut[dir] set2.b0 = cut[dir] set2.r0 = set1.r0 set2.g0 = set1.g0 end local function vol(box) local function q(a,b) return (a-b)*(a-b) end return q(box.r1,box.r0) + q(box.g1,box.g0) + q(box.b1,box.b0) end set1.vol = vol(set1) set2.vol = vol(set2) return true end function ColorReducer:boostBorderColors() -- Idea: consider the convex hull of all the colors. -- These color can be mixed to produce any other used -- color, so they are kind of really important. -- Unfortunately most color-reduction algorithm do not -- retain these color ue to averaging property. The idea -- here is not artifically increase their count so that -- the averaging goes into these colors. -- do return self end -- for testing local hull=ConvexHull:new(function(v) return {v:rgb()} end) -- collect set of points local pts,tot={},0 for i=0,17*17*17-1 do local v = self[i] if v then pts[v] = true tot=tot+v.wt end end -- build convex hull of colors. for v in pairs(pts) do hull:addPoint(v) end -- collect points near the hull local bdr, hsz, hnb, max = {},0,0,0 for v in pairs(pts) do if hull:distToHull(v)>-.1 then bdr[v] = true hnb = hnb+1 hsz = hsz+v.wt max = math.max(max,v.wt) end end if tot>hsz then -- heuristic formula to boost colors of the hull -- not too little, not to much. It might be tuned -- over time, but this version gives satisfying -- result (.51 is important) for v in pairs(bdr) do v:mul(math.min(max,tot-hsz,v.wt*(1+.51*max*hnb/hsz))/v.wt) end end return self end function ColorReducer:buildPalette(max, forceBlack) if self.palette then return self.palette end forceBlack=forceBlack or true self:M3d() local function c(r0,g0,b0,r1,g1,b1) return {r0=r0,r1=r1,g0=g0,g1=g1,b0=b0,b1=b1} end local cube = {c(0,0,0,16,16,16)} local n,i = 1,2 local vv = {} while i<=max do cube[i] = c(0,0,0,1,1,1) if forceBlack and i==max then local ko = true; for j=1,max-1 do if self:Vol(cube[j]):toPal()==0 then ko = false break end end if ko then break end -- forcingly add black end if self:Cut(cube[n], cube[i]) then vv[n] = cube[n].vol>1 and self:Var(cube[n]) or 0 vv[i] = cube[i].vol>1 and self:Var(cube[i]) or 0 else vv[n] = 0 cube[i] = nil i=i-1 end n = 1; local temp = vv[n] for k=2,i do if vv[k]>temp then temp=vv[k]; n=k; end end if temp<=0 then break end -- not enough color i = i+1 end -- helper to sort the palette local pal = {} for _,c in ipairs(cube) do local r,g,b=self:Vol(c):toThomson() table.insert(pal, {r=r+1,g=g+1,b=b+1}) end -- messagebox(#pal) -- sort the palette in a nice color distribution local function cmp(a,b) local t=thomson.levels.pc a = Color:new(t[a.r],t[a.g],t[a.b]) b = Color:new(t[b.r],t[b.g],t[b.b]) local ah,as,av=a:HSV() local bh,bs,bv=b:HSV() as,bs=a:intensity()/255,b:intensity()/255 -- function lum(a) return ((.241*a.r + .691*a.g + .068*a.b)/255)^.5 end -- as,bs=lum(a),lum(b) local sat,int=32,256 local function quant(ah,as,av) return math.floor(ah*8), math.floor(as*sat), math.floor(av*int+.5) end ah,as,av=quant(ah,as,av) bh,bs,bv=quant(bh,bs,bv) -- if true then return ah255 and 255 or x)*m) end local k=f(linearPixel.r)+M*(f(linearPixel.g)+M*f(linearPixel.b)) local c=self[k] if c==nil then local dm=1e30 for i,palette in ipairs(self.linear) do local d = palette:dist2(linearColor) if d=b then return v end while v=t and b or a end local t = mat[1+(x%mx)][1+(y%my)] local p=getLinearPixel(x,y) p.r = dith(p.r, t) p.g = dith(p.g, t) p.b = dith(p.b, t) return p end return self:analyze(w,h, function(x,y) return dith(x,y) -- :mul(4):add(getLinearPixel(x,y)):div(5) -- :add(getLinearPixel(x-1,y)) -- :add(getLinearPixel(x+1,y)) -- :div(3) end, info) end --[[ function ColorReducer:analyzeBuildWithDither(w,h,max,getLinearPixel,info) if not info then info=function(y) wait(0) end end local dith = ColorReducer:new() dith:analyze(w,h,getLinearPixel,function(y) info(y/2) end) local ostro = OstroDither:new(dith:buildPalette(max), thomson.levels.linear, .9) ostro:dither(w,h, function(x,y,xs,err) local p = getLinearPixel(x,y) self:add(err[x]:clone():add(p)) self:add(p) return p end, function(x,y,c) -- self:add(ostro:_linearPalette(c+1)) end,true, function(y) info((h+y)/2) end ) return self:buildPalette(max) end --]] end -- ColorReductiongrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/lib/bayer.lua0000664000000000000000000000257613223665306026500 0ustar rootroot-- bayer.lua : bayer matrix suppport. -- -- Version: 02-jan-2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See if not bayer then bayer = {} -- doubles a matrix rows and columns function bayer.double(matrix) local m,n=#matrix,#matrix[1] local r = {} for j=1,m*2 do local t = {} for i=1,n*2 do t[i]=0; end r[j] = t; end -- 0 3 -- 2 1 for j=1,m do for i=1,n do local v = 4*matrix[j][i] r[m*0+j][n*0+i] = v-3 r[m*1+j][n*1+i] = v-2 r[m*1+j][n*0+i] = v-1 r[m*0+j][n*1+i] = v-0 end end return r; end -- returns a version of the matrix normalized into -- the 0-1 range function bayer.norm(matrix) local m,n=#matrix,#matrix[1] local max,ret = 0,{} for j=1,m do for i=1,n do max = math.max(max,matrix[j][i]) end end -- max=max+1 for j=1,m do ret[j] = {} for i=1,n do ret[j][i]=matrix[j][i]/max end end return ret end -- returns a normalized order-n bayer matrix function bayer.make(n) local m = {{1}} while n>1 do n,m = n/2,bayer.double(m) end return bayer.norm(m) end end -- Bayergrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/lib/color.lua0000664000000000000000000002212113223665306026500 0ustar rootroot-- color.lua : a color class capable of representing -- and manipulating colors in PC-space (gamma=2.2) or -- in linear space (gamma=1). -- -- Version: 02-jan-2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See if not Color then Color = {ONE=255,NORMALIZE=.005} function Color:new(r,g,b) local o = {}; o.r = type(r)=='number' and r or r and r.r or 0; o.g = type(g)=='number' and g or r and r.g or 0; o.b = type(b)=='number' and b or r and r.b or 0; setmetatable(o, self) self.__index = self return o end Color.black = Color:new(0,0,0) function Color.clamp(v,...) if v then return v<0 and 0 or v>Color.ONE and Color.ONE or v,Color.clamp(...) end end function Color:clone() return Color:new(self.r, self.g, self.b) end function Color:tostring() return "(r=" .. self.r .. " g=" .. self.g .. " b=" .. self.b .. ")" end function Color:HSV() local max=math.floor(.5+math.max(self.r,self.g,self.b)) local min=math.floor(.5+math.min(self.r,self.g,self.b)) local H=(max<=min and 0 or max<=self.r and (self.g-self.b)/(max-min)+6 or max<=self.g and (self.b-self.r)/(max-min)+2 or max<=self.b and (self.r-self.g)/(max-min)+4)/6 % 1.0 local S=(max==0 or max<=min) and 0 or 1-min/max local V=max/Color.ONE return H,S,V end function Color:intensity() return .3*self.r + .59*self.g + .11*self.b end function Color:mul(val) self.r = self.r * val; self.g = self.g * val; self.b = self.b * val; return self; end function Color:div(val) return self:mul(1/val); end function Color:add(other) self.r = self.r + other.r; self.g = self.g + other.g; self.b = self.b + other.b; return self; end function Color:sub(other) self.r = self.r - other.r; self.g = self.g - other.g; self.b = self.b - other.b; return self; end function Color:dist2(other) return self:euclid_dist2(other) -- return Color.dE2000(self,other)^2 -- return Color.dE2fast(self,other) end function Color:euclid_dist2(other) return (self.r - other.r)^2 + (self.g - other.g)^2 + (self.b - other.b)^2 end function Color:floor() self.r = math.min(math.floor(self.r),Color.ONE); self.g = math.min(math.floor(self.g),Color.ONE); self.b = math.min(math.floor(self.b),Color.ONE); return self; end function Color:toPC() local function f(val) val = val/Color.ONE -- if val<=0.018 then val = 4.5*val; else val = 1.099*(val ^ (1/2.2))-0.099; end -- works much metter: https://fr.wikipedia.org/wiki/SRGB if val<=0.0031308 then val=12.92*val else val = 1.055*(val ^ (1/2.4))-0.055 end return val*Color.ONE end; self.r = f(self.r); self.g = f(self.g); self.b = f(self.b); return self; end function Color:toLinear() local function f(val) val = val/Color.ONE -- if val<=0.081 then val = val/4.5; else val = ((val+0.099)/1.099)^2.2; end -- works much metter: https://fr.wikipedia.org/wiki/SRGB#Transformation_inverse if val<=0.04045 then val = val/12.92 else val = ((val+0.055)/1.055)^2.4 end return val*Color.ONE end; self.r = f(self.r); self.g = f(self.g); self.b = f(self.b); return self; end function Color:toRGB() return self.r, self.g, self.b end -- return the Color @(x,y) on the original screen in linear space local screen_w, screen_h, _getLinearPictureColor = getpicturesize() function getLinearPictureColor(x,y) if _getLinearPictureColor==nil then _getLinearPictureColor = {} for i=0,255 do _getLinearPictureColor[i] = Color:new(getbackupcolor(i)):toLinear(); end if Color.NORMALIZE>0 then local histo = {} for i=0,255 do histo[i] = 0 end for y=0,screen_h-1 do for x=0,screen_w-1 do local r,g,b = getbackupcolor(getbackuppixel(x,y)) histo[r] = histo[r]+1 histo[g] = histo[g]+1 histo[b] = histo[b]+1 end end local acc,thr=0,Color.NORMALIZE*screen_h*screen_w*3 local max for i=255,0,-1 do acc = acc + histo[i] if not max and acc>=thr then max = Color:new(i,i,i):toLinear().r end end for _,c in ipairs(_getLinearPictureColor) do c:mul(Color.ONE/max) c.r,c.g,c.b = Color.clamp(c.r,c.g,c.b) end end end return (x<0 or y<0 or x>=screen_w or y>=screen_h) and Color.black or _getLinearPictureColor[getbackuppixel(x,y)] end -- http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html function Color.RGBtoXYZ(R,G,B) return 0.4887180*R +0.3106803*G +0.2006017*B, 0.1762044*R +0.8129847*G +0.0108109*B, 0.0102048*G +0.9897952*B end function Color.XYZtoRGB(X,Y,Z) return 2.3706743*X -0.9000405*Y -0.4706338*Z, -0.5138850*X +1.4253036*Y +0.0885814*Z, 0.0052982*X -0.0146949*Y +1.0093968*Z end -- https://fr.wikipedia.org/wiki/CIE_L*a*b* function Color.XYZtoCIELab(X,Y,Z) local function f(t) return t>0.00885645167 and t^(1/3) or 7.78703703704*t+0.13793103448 end X,Y,Z=X/Color.ONE,Y/Color.ONE,Z/Color.ONE return 116*f(Y)-16, 500*(f(X)-f(Y)), 200*(f(Y)-f(Z)) end function Color.CIEALabtoXYZ(L,a,b) local function f(t) return t>0.20689655172 and t^3 or 0.12841854934*(t-0.13793103448) end local l=(L+16)/116 return Color.ONE*f(l), Color.ONE*f(l+a/500), Color.ONE*f(l-b/200) end function Color:toLab() return Color.XYZtoCIELab(Color.RGBtoXYZ(self:toRGB())) end -- http://www.brucelindbloom.com/Eqn_DeltaE_CIE2000.html function Color.dE1976(col1,col2) local L1,a1,b1 = col1:toLab() local L2,a2,b2 = col2:toLab() return ((L1-L2)^2+(a1-a2)^2+(b1-b2)^2)^.5 end function Color.dE1994(col1,col2) local L1,a1,b1 = col1:toLab() local L2,a2,b2 = col2:toLab() local k1,k2 = 0.045,0.015 local kL,kC,kH = 1,1,1 local c1 = (a1^2 + b1^2)^.5 local c2 = (a2^2 + b2^2)^.5 local dA = a1 - a2 local dB = b1 - b2 local dC = c1 - c2 local dH2 = dA^2 + dB^2 - dC^2 local dH = dH2>0 and dH2^.5 or 0 local dL = L1 - L2 local sL = 1 local sC = 1 + k1*c1 local sH = 1 + k2*c1 local vL = dL/(kL*sL) local vC = dC/(kC*sC) local vH = dH/(kH*sH) return (vL^2 + vC^2 + vH^2)^.5 end -- http://www.color.org/events/colorimetry/Melgosa_CIEDE2000_Workshop-July4.pdf -- https://en.wikipedia.org/wiki/Color_difference#CIEDE2000 function Color.dE2000(col1,col2) local L1,a1,b1 = col1:toLab() local L2,a2,b2 = col2:toLab() local kL,kC,kH = 1,1,1 local l_p = (L1 + L2)/2 function sqrt(x) return x^.5 end function norm(x,y) return sqrt(x^2+y^2) end function mean(x,y) return (x+y)/2 end local function atan2(a,b) local t=math.atan2(a,b)*180/math.pi return t<0 and t+360 or t end local function sin(x) return math.sin(x*math.pi/180) end local function cos(x) return math.cos(x*math.pi/180) end local c1 = norm(a1,b1) local c2 = norm(a2,b2) local c_ = mean(c1,c2) local G = 0.5*(1-sqrt(c_^7/(c_^7+25^7))) local a1p = a1*(1+G) local a2p = a2*(1+G) local c1p = norm(a1p,b1) local c2p = norm(a2p,b2) local c_p = mean(c1p,c2p) local h1p = atan2(b1,a1p) local h2p = atan2(b2,a2p) local h_p = mean(h1p,h2p) + (math.abs(h1p - h2p)<=180 and 0 or h1p+h2p<360 and 180 or -180) local T = 1 - 0.17 * cos( h_p - 30) + 0.24 * cos(2 * h_p ) + 0.32 * cos(3 * h_p + 6) - 0.20 * cos(4 * h_p - 63) local dhp = h2p - h1p + (math.abs(h1p - h2p)<=180 and 0 or h2p<=h1p and 360 or -360) local dLp = L2 - L1 local dCp = c2p - c1p local dHp = 2*sqrt(c1p*c2p)*sin(dhp/2) local sL = 1 + 0.015*(l_p - 50)^2/sqrt(20+(l_p-50)^2) local sC = 1 + 0.045*c_p local sH = 1 + 0.015*c_p*T local d0 = 30*math.exp(-((h_p-275)/25)^2) local rC = 2*sqrt(c_p^7/(c_p^7+25^7)) local rT = -rC * sin(2*d0) return sqrt( (dLp / (kL*sL))^2 + (dCp / (kC*sC))^2 + (dHp / (kH*sH))^2 + (dCp / (kC*sC))*(dHp / (kH*sH))*rT ) end function Color.dE2fast(col1,col2) -- http://www.compuphase.com/cmetric.htm#GAMMA local r1,g1,b1 = Color.clamp(col1:toRGB()) local r2,g2,b2 = Color.clamp(col2:toRGB()) local rM = (r1+r2)/(Color.ONE*2) return ((r1-r2)^2)*(2+rM) + ((g1-g2)^2)*(4+1) + ((b1-b2)^2)*(3-rM) end function Color:hash(M) M=M or 256 local m=(M-1)/Color.ONE local function f(x) return math.floor(.5+(x<0 and 0 or x>Color.ONE and Color.ONE or x)*m) end return f(self.r)+M*(f(self.g)+M*f(self.b)) end end -- Color defined grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/lib/thomson.lua0000664000000000000000000002673413223665306027067 0ustar rootroot-- thomson.lua : lots of utility for handling -- thomson screen. -- -- Version: 02-jan-2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See if not thomson then run("color.lua") -- optionnal thomson = {optiMAP=true} -- RAM banks thomson.ramA = {} thomson.ramB = {} function thomson.clear() for i=1,8000 do thomson.ramA[i] = 0 thomson.ramB[i] = 0 end end -- color levels thomson.levels = { -- in pc-space (0-255): pc = {0,100,127,142,163,179,191,203,215,223,231,239, 243,247,251,255}, -- in linear space (0-255): linear = {}, -- maps pc-levels (0-255) to thomson levels (1-16) pc2to={}, -- maps linear-levels (0-255) to thomson levels (1-16) linear2to={} }; -- pc space to linear space local function toLinear(val) -- use the version from Color library if not Color then val = val/255 if val<=0.081 then val = val/4.5; else val = ((val+0.099)/1.099)^2.2; end val = val*255 return val; else return Color:new(val,0,0):toLinear().r end end for i=1,16 do thomson.levels.linear[i] = toLinear(thomson.levels.pc[i]) end for i=0,255 do local r,cm,dm; r,cm,dm = toLinear(i),0,1e30 for c,v in ipairs(thomson.levels.linear) do local d = math.abs(v-r); if d=0 and i=0 and i 00 02 aa bb if default and num==1 and partial[1]==1 then partial = {0,2,partial[2],car} default = false end -- 00 n xx xx xx 01 bb ==> 00 n+1 xx xx xx bb if default and num==1 and partial[1]==0 and partial[2]<255 then addCarToPartial(car) default = false end -- 00 n xx xx xx 02 bb ==> 00 n+2 xx xx xx bb bb (pas utile mais sert quand combin la regle ci-dessus) if default and num==2 and partial[1]==0 and partial[2]<254 then addCarToPartial(car) addCarToPartial(car) default = false end end if default then thomson._append(result, partial) partial = {num,car} end p=p+1 end thomson._append(result, partial) return result end -- save a map file corresponging to the current file -- if a map file already exist, a confirmation is -- prompted to the user local function save_current_file() local function exist(file) local f=io.open(file,'rb') if not f then return false else io.close(f); return true; end end local name,path = getfilename() local mapname = string.gsub(name,"%.%w*$","") .. ".map" local fullname = path .. '/' .. mapname local ok = not exist(fullname) if not ok then selectbox("Ovr " .. mapname .. "?", "Yes", function() ok = true; end, "No", function() ok = false; end) end if ok then thomson.savep(fullname) end end -- saves the thomson screen into a MAP file function thomson.savep(name) if not name then return save_current_file() end wait(0) -- allow for key handling local data = thomson._get_map_data() local tmp = {0, math.floor(#data/256), #data%256,0,0} thomson._append(tmp,data,{255,0,0,0,0}) local function save(name, buf) local out = io.open(name,"wb") out:write(buf) out:close() end save(name, string.char(unpack(tmp))) -- save raw data as well ? local moved, key, mx, my, mb = waitinput(0.01) if key==4123 then -- shift-ESC ==> save raw files as well save(name .. ".rama", string.char(unpack(thomson.ramA))) save(name .. ".ramb", string.char(unpack(thomson.ramB))) local pal = "" for i=0,15 do local val = thomson.palette(i) pal=pal..string.char(math.floor(val/256),val%256) end save(name .. ".pal", pal) messagebox('Saved MAP + RAMA/RAMB/PAL files.') end end waitbreak(0.01) function thomson.info(...) local txt = "" for _,t in ipairs({...}) do txt = txt .. t end statusmessage(txt); if waitbreak(0)==1 then local ok=false selectbox("Abort ?", "Yes", function() ok = true end, "No", function() ok = false end) if ok then error('Operation aborted') end end end -- copy ramA/B onto GrafX2 screen function thomson.updatescreen() -- back out for i=0,255 do setcolor(i,0,0,0) end -- refresh screen content clearpicture(thomson._palette.offset + thomson.border()) for y=0,thomson.h-1 do for x=0,thomson.w-1 do local p = thomson.point(x,y) if p<0 then p=-p-1 end thomson._putpixel(x,y,thomson._palette.offset + p) end end -- refresh palette for i=1,thomson._palette.max do local v=thomson._palette[i] local r=v % 16 local g=math.floor(v/16) % 16 local b=math.floor(v/256) % 16 setcolor(i+thomson._palette.offset-1, thomson.levels.pc[r+1], thomson.levels.pc[g+1], thomson.levels.pc[b+1]) end updatescreen() end -- bitmap 16 mode function thomson.setBM16() -- put a pixel onto real screen function thomson._putpixel(x,y,c) putpicturepixel(x*2+0,y,c) putpicturepixel(x*2+1,y,c) end -- put a pixel in thomson screen function thomson.pset(x,y,c) local bank = x%4<2 and thomson.ramA or thomson.ramB local offs = math.floor(x/4)+y*40+1 if x%2==0 then bank[offs] = (bank[offs]%16)+c*16 else bank[offs] = math.floor(bank[offs]/16)*16+c end -- c=c+thomson._palette.offset -- putpicturepixel(x*2+0,y,c) -- putpicturepixel(x*2+1,y,c) end -- get thomson pixel at (x,y) function thomson.point(x,y) local bank = x%4<2 and thomson.ramA or thomson.ramB local offs = math.floor(x/4)+y*40+1 if x%2==0 then return math.floor(bank[offs]/16) else return bank[offs]%16 end end -- return internal MAP file function thomson._get_map_data() local tmp = {} for x=1,40 do for y=x,x+7960,40 do table.insert(tmp, thomson.ramA[y]) end for y=x,x+7960,40 do table.insert(tmp, thomson.ramB[y]) end wait(0) -- allow for key handling end local pal = {} for i=1,16 do pal[2*i-1] = math.floor(thomson._palette[i]/256) pal[2*i+0] = thomson._palette[i]%256 end -- build data local data={ -- BM16 0x40, -- ncols-1 79, -- nlines-1 24 }; thomson._compress(data, tmp) thomson._append(data,{0,0}) -- padd to word if #data%2==1 then table.insert(data,0); end -- tosnap thomson._append(data,{0,128,0,thomson.border(),0,3}) thomson._append(data, pal) thomson._append(data,{0xa5,0x5a}) return data end thomson.w = 160 thomson.h = 200 thomson.palette(0,thomson.default_palette) thomson.border(0) thomson.clear() end -- mode MO5 function thomson.setMO5() -- put a pixel onto real screen thomson._putpixel = putpicturepixel -- helpers local function bittst(val,mask) -- return bit32.btest(val,mask) return (val % (2*mask))>=mask; end local function bitset(val,mask) -- return bit32.bor(val, mask) return bittst(val,mask) and val or (val+mask) end local function bitclr(val,mask) -- return bit32.band(val,255-mask) return bittst(val,mask) and (val-mask) or val end -- put a pixel in thomson screen function thomson.pset(x,y,c) local offs = math.floor(x/8)+y*40+1 local mask = 2^(7-(x%8)) if c>=0 then thomson.ramB[offs] = (thomson.ramB[offs]%16)+c*16 thomson.ramA[offs] = bitset(thomson.ramA[offs],mask) else c=-c-1 thomson.ramB[offs] = math.floor(thomson.ramB[offs]/16)*16+c thomson.ramA[offs] = bitclr(thomson.ramA[offs],mask) end end -- get thomson pixel at (x,y) function thomson.point(x,y) local offs = math.floor(x/8)+y*40+1 local mask = 2^(7-(x%8)) if bittst(thomson.ramA[offs],mask) then return math.floor(thomson.ramB[offs]/16) else return -(thomson.ramB[offs]%16)-1 end end -- convert color from MO5 to TO7 (MAP requires TO7 encoding) local function mo5to7(val) -- MO5: DCBA 4321 -- __ -- TO7: 4DCB A321 local t=((val%16)>=8) and 0 or 128 val = math.floor(val/16)*8 + (val%8) val = (val>=64 and val-64 or val+64) + t return val end -- return internal MAP file function thomson._get_map_data() -- create columnwise data local tmpA,tmpB={},{}; for x=1,40 do for y=x,x+7960,40 do table.insert(tmpA, thomson.ramA[y]) table.insert(tmpB, thomson.ramB[y]) end wait(0) -- allow for key handling end if thomson.optiMAP then -- optimize for i=2,8000 do local c1,c2 = math.floor(tmpB[i-0]/16),tmpB[i-0]%16 local d1,d2 = math.floor(tmpB[i-1]/16),tmpB[i-1]%16 if tmpA[i-1]==255-tmpA[i] or c1==d2 and c2==c1 then tmpA[i] = 255-tmpA[i] tmpB[i] = c2*16+c1 elseif tmpA[i]==255 and c1==d1 or tmpA[i]==0 and c2==d2 then tmpB[i] = tmpB[i-1] end end else for i=1,8000 do local c1,c2 = math.floor(tmpB[i]/16),tmpB[i]%16 if tmpA[i]==255 or c1 run('color.lua') run('thomson.lua') if not OstroDither then OstroDither = {} local function default_levels() return {r={0,Color.ONE},g={0,Color.ONE},b={0,Color.ONE}} end function OstroDither:new(palette,attenuation,levels) local o = { attenuation = attenuation or .9, -- works better than 1 palette = palette or thomson.default_palette, levels = levels or default_levels(), clash_size = 8 -- for color clash } setmetatable(o, self) self.__index = self return o end function OstroDither:setLevelsFromPalette() local rLevels = {[1]=true,[16]=true} local gLevels = {[1]=true,[16]=true} local bLevels = {[1]=true,[16]=true} local default_palette = true for i,pal in ipairs(self.palette) do local r,g,b=pal%16,math.floor(pal/16)%16,math.floor(pal/256) rLevels[1+r] = true gLevels[1+g] = true bLevels[1+b] = true if pal~=thomson.default_palette[i] then default_palette = false end end local levels = {r={},g={},b={}} for i,v in ipairs(thomson.levels.linear) do if false then if rLevels[i] and gLevels[i] and bLevels[i] then table.insert(levels.r, v) table.insert(levels.g, v) table.insert(levels.b, v) end else if rLevels[i] then table.insert(levels.r, v) end if gLevels[i] then table.insert(levels.g, v) end if bLevels[i] then table.insert(levels.b, v) end end end self.levels = levels if default_palette then self.attenuation = .98 self.levels = default_levels() else self.attenuation = .9 self.levels = levels end end function OstroDither:_coefs(linearLevel,rgb) if self._ostro==nil then -- original coefs, about to be adapted to the levels local t={ 13, 0, 5, 13, 0, 5, 21, 0, 10, 7, 0, 4, 8, 0, 5, 47, 3, 28, 23, 3, 13, 15, 3, 8, 22, 6, 11, 43, 15, 20, 7, 3, 3, 501, 224, 211, 249, 116, 103, 165, 80, 67, 123, 62, 49, 489, 256, 191, 81, 44, 31, 483, 272, 181, 60, 35, 22, 53, 32, 19, 237, 148, 83, 471, 304, 161, 3, 2, 1, 459, 304, 161, 38, 25, 14, 453, 296, 175, 225, 146, 91, 149, 96, 63, 111, 71, 49, 63, 40, 29, 73, 46, 35, 435, 272, 217, 108, 67, 56, 13, 8, 7, 213, 130, 119, 423, 256, 245, 5, 3, 3, 281, 173, 162, 141, 89, 78, 283, 183, 150, 71, 47, 36, 285, 193, 138, 13, 9, 6, 41, 29, 18, 36, 26, 15, 289, 213, 114, 145, 109, 54, 291, 223, 102, 73, 57, 24, 293, 233, 90, 21, 17, 6, 295, 243, 78, 37, 31, 9, 27, 23, 6, 149, 129, 30, 299, 263, 54, 75, 67, 12, 43, 39, 6, 151, 139, 18, 303, 283, 30, 38, 36, 3, 305, 293, 18, 153, 149, 6, 307, 303, 6, 1, 1, 0, 101, 105, 2, 49, 53, 2, 95, 107, 6, 23, 27, 2, 89, 109, 10, 43, 55, 6, 83, 111, 14, 5, 7, 1, 172, 181, 37, 97, 76, 22, 72, 41, 17, 119, 47, 29, 4, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 1, 65, 18, 17, 95, 29, 26, 185, 62, 53, 30, 11, 9, 35, 14, 11, 85, 37, 28, 55, 26, 19, 80, 41, 29, 155, 86, 59, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 305, 176, 119, 155, 86, 59, 105, 56, 39, 80, 41, 29, 65, 32, 23, 55, 26, 19, 335, 152, 113, 85, 37, 28, 115, 48, 37, 35, 14, 11, 355, 136, 109, 30, 11, 9, 365, 128, 107, 185, 62, 53, 25, 8, 7, 95, 29, 26, 385, 112, 103, 65, 18, 17, 395, 104, 101, 4, 1, 1, 4, 1, 1, 395, 104, 101, 65, 18, 17, 385, 112, 103, 95, 29, 26, 25, 8, 7, 185, 62, 53, 365, 128, 107, 30, 11, 9, 355, 136, 109, 35, 14, 11, 115, 48, 37, 85, 37, 28, 335, 152, 113, 55, 26, 19, 65, 32, 23, 80, 41, 29, 105, 56, 39, 155, 86, 59, 305, 176, 119, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 5, 3, 2, 155, 86, 59, 80, 41, 29, 55, 26, 19, 85, 37, 28, 35, 14, 11, 30, 11, 9, 185, 62, 53, 95, 29, 26, 65, 18, 17, 4, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 1, 119, 47, 29, 72, 41, 17, 97, 76, 22, 172, 181, 37, 5, 7, 1, 83, 111, 14, 43, 55, 6, 89, 109, 10, 23, 27, 2, 95, 107, 6, 49, 53, 2, 101, 105, 2, 1, 1, 0, 307, 303, 6, 153, 149, 6, 305, 293, 18, 38, 36, 3, 303, 283, 30, 151, 139, 18, 43, 39, 6, 75, 67, 12, 299, 263, 54, 149, 129, 30, 27, 23, 6, 37, 31, 9, 295, 243, 78, 21, 17, 6, 293, 233, 90, 73, 57, 24, 291, 223, 102, 145, 109, 54, 289, 213, 114, 36, 26, 15, 41, 29, 18, 13, 9, 6, 285, 193, 138, 71, 47, 36, 283, 183, 150, 141, 89, 78, 281, 173, 162, 5, 3, 3, 423, 256, 245, 213, 130, 119, 13, 8, 7, 108, 67, 56, 435, 272, 217, 73, 46, 35, 63, 40, 29, 111, 71, 49, 149, 96, 63, 225, 146, 91, 453, 296, 175, 38, 25, 14, 459, 304, 161, 3, 2, 1, 471, 304, 161, 237, 148, 83, 53, 32, 19, 60, 35, 22, 483, 272, 181, 81, 44, 31, 489, 256, 191, 123, 62, 49, 165, 80, 67, 249, 116, 103, 501, 224, 211, 7, 3, 3, 43, 15, 20, 22, 6, 11, 15, 3, 8, 23, 3, 13, 47, 3, 28, 8, 0, 5, 7, 0, 4, 21, 0, 10, 13, 0, 5, 13, 0, 5} local function process(tab) local tab2={} local function add(i) i=3*math.floor(i+.5) local c0,c1,c2=t[i+1],t[i+2],t[i+3] local norm=self.attenuation/(c0+c1+c2) table.insert(tab2,c0*norm) table.insert(tab2,c1*norm) table.insert(tab2,c2*norm) end local function level(i) return tab[i]*255/Color.ONE end local a,b,j=level(1),level(2),3 for i=0,255 do if i>b then a,b,j=b,level(j),j+1; end add(255*(i-a)/(b-a)) end return tab2 end self._ostro = {r=process(self.levels.r), g=process(self.levels.g), b=process(self.levels.b)} end local i = math.floor(linearLevel[rgb]*255/Color.ONE+.5) i = 3*(i<0 and 0 or i>255 and 255 or i) return self._ostro[rgb][i+1],self._ostro[rgb][i+2],self._ostro[rgb][i+3] end function OstroDither:_linearPalette(colorIndex) if self._linear==nil then self._linear = {} local t=thomson.levels.linear for i,pal in ipairs(self.palette) do local r,g,b=pal%16,math.floor(pal/16)%16,math.floor(pal/256) self._linear[i] = Color:new(t[1+r],t[1+g],t[1+b]) end end return self._linear[colorIndex] end function OstroDither:getColorIndex(linearPixel) local k=linearPixel:hash(64) local c=self[k] if c==nil then local dm=1e30 for i=1,#self.palette do local d = self:_linearPalette(i):dist2(linearPixel) if d M and M or a end local c0,c1,c2=self:_coefs(linearColor,rgb) if err0 and c0>0 then err0[rgb] = f(err0[rgb],c0) end if err1 and c1>0 then err1[rgb] = f(err1[rgb],c1) end if err2 and c2>0 then err2[rgb] = f(err2[rgb],c2) end end d("r"); d("g"); d("b") return c end function OstroDither:dither(screen_w,screen_h,getLinearPixel,pset,serpentine,info) if not info then info = function(y) thomson.info() end end if not serpentine then serpentine = true end local err1,err2 = {},{} for x=-1,screen_w do err1[x] = Color:new(0,0,0) err2[x] = Color:new(0,0,0) end for y=0,screen_h-1 do -- permute error buffers err1,err2 = err2,err1 -- clear current-row's buffer for i=-1,screen_w do err2[i]:mul(0) end local x0,x1,xs=0,screen_w-1,1 if serpentine and y%2==1 then x0,x1,xs=x1,x0,-xs end for x=x0,x1,xs do local p = getLinearPixel(x,y,xs,err1) local c = self:_diffuse(p,err1[x],err1[x+xs], err2[x-xs],err2[x]) pset(x,y,c-1) end info(y) end end function OstroDither:ccAcceptCouple(c1,c2) return c1~=c2 end function OstroDither:ccDither(screen_w,screen_h,getLinearPixel,pset,serpentine,info) -- dither with color clash local c1,c2 self.getColorIndex = function(self,p) return p:dist2(self:_linearPalette(c1))b.n or a.n==b.n and a.cdm then break end end return d else return dm end end dm=eval() if histo:num(1)>=self.clash_size/2+1 then local z=c2 for i=1,#self.palette do c2=i local d=eval() if d0 and 0 or self.clash_size-1) then findC1C2(x,y,xs,err1) end return getLinearPixel(x,y) end self:dither(screen_w,screen_h,_getLinearPixel,_pset,serpentine,info) end function OstroDither:dither40cols(getpalette,serpentine) -- get screen size local screen_w, screen_h = getpicturesize() -- Converts thomson coordinates (0-159,0-199) into screen coordinates local function thom2screen(x,y) local i,j; if screen_w/screen_h < 1.6 then i = x*screen_h/200 j = y*screen_h/200 else i = x*screen_w/320 j = y*screen_w/320 end return math.floor(i), math.floor(j) end -- return the Color @(x,y) in linear space (0-255) -- corresonding to the thomson screen (x in 0-319, -- y in 0-199) local function getLinearPixel(x,y) local with_cache = true if not self._getLinearPixel then self._getLinearPixel = {} end local k=x+y*thomson.w local p = self._getLinearPixel[k] if not p then local x1,y1 = thom2screen(x,y) local x2,y2 = thom2screen(x+1,y+1) if x2==x1 then x2=x1+1 end if y2==y1 then y2=y1+1 end p = Color:new(0,0,0); for j=y1,y2-1 do for i=x1,x2-1 do p:add(getLinearPictureColor(i,j)) end end p:div((y2-y1)*(x2-x1)) --:floor() if with_cache then self._getLinearPixel[k]=p end end return with_cache and p:clone() or p end -- MO5 mode thomson.setMO5() self.palette = getpalette(thomson.w,thomson.h,getLinearPixel) -- compute levels from palette self:setLevelsFromPalette() -- convert picture self:ccDither(thomson.w,thomson.h, getLinearPixel, thomson.pset, serpentine or true, function(y) thomson.info("Converting...", math.floor(y*100/thomson.h),"%") end,true) -- refresh screen setpicturesize(thomson.w,thomson.h) thomson.updatescreen() thomson.savep() finalizepicture() end end -- OstroDithergrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/lib/convex_hull.lua0000664000000000000000000001076113223665306027717 0ustar rootroot-- convxhull.lua : support for computing the convex -- hull of a set of points. -- -- inspired from: https://gist.github.com/anonymous/5184ba0bcab21d3dd19781efd3aae543 -- -- Version: 02-jan-2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See if not ConvexHull then local function sub(u,v) return {u[1]-v[1],u[2]-v[2],u[3]-v[3]} end local function mul(k,u) return {k*u[1],k*u[2],k*u[3]} end local function cross(u,v) return {u[2]*v[3] - u[3]*v[2], u[3]*v[1] - u[1]*v[3], u[1]*v[2] - u[2]*v[1]} end local function dot(u,v) return u[1]*v[1] + u[2]*v[2] + u[3]*v[3] end local function unit(u) local d=dot(u,u) return d==0 and u or mul(1/d^.5, u) end ConvexHull = {} function ConvexHull:new(coordFct) local o = { points={}, coord=coordFct } setmetatable(o, self) self.__index = self return o end function ConvexHull.coord(elt) return {elt[1],elt[2],elt[3]} end function ConvexHull:vect(a,b) return sub(self.coord(b),self.coord(a)) end function ConvexHull:normal(face) local u=self:vect(face[1],face[2]) local v=self:vect(face[1],face[3]) return cross(u,v) end function ConvexHull:printPoint(p) return '('..table.concat(self.coord(p),',')..')' end function ConvexHull:printFace(F) return '['..self:printPoint(F[1])..' '.. self:printPoint(F[2])..' '.. self:printPoint(F[3])..']' end function ConvexHull:seen(face,p) local N=self:normal(face) local P=self:vect(face[1],p) return dot(N,P)>=0 end function ConvexHull:bdry(faces) local code={n=0} function code.encode(pt,...) if pt then local k = code[pt] if not k then k = code.n+1 code[k] = pt code[pt] = k code.n = k end local rest = code.encode(...) return rest and (k..','..rest) or ""..k end end function code.decode(str) local i = str:find(',') if i then local k = str:sub(1,i-1) return code[tonumber(k)],code.decode(str:sub(i+1)) else return code[tonumber(str)] end end local set = {} local function add(...) set[code.encode(...)] = true end local function rem(...) set[code.encode(...)] = nil end local function keys() local r = {} for k in pairs(set) do r[{code.decode(k)}] = true end return r end for F in pairs(faces) do add(F[1],F[2]) add(F[2],F[3]) add(F[3],F[1]) end for F in pairs(faces) do rem(F[1],F[3]) rem(F[3],F[2]) rem(F[2],F[1]) end return keys() end function ConvexHull:addPoint(p) -- first 3 points if self.points then if p==self.points[1] or p==self.points[2] then return end table.insert(self.points,p) if #self.points==3 then self.hull={ {self.points[1],self.points[2],self.points[3]}, {self.points[1],self.points[3],self.points[2]} } self.points=nil end else local seenF,n = {},0 for _,F in ipairs(self.hull) do if F[1]==p or F[2]==p or F[3]==p then return end if self:seen(F,p) then seenF[F]=true;n=n+1 end end if n==#self.hull then -- if can see all faces, unsee ones looking "down" local N for F in pairs(seenF) do N=self:normal(F); break; end for F in pairs(seenF) do if dot(self:normal(F),N)<=0 then seenF[F] = nil n=n-1 end end end -- remove (old) seen faces local z=#self.hull for i=#self.hull,1,-1 do if seenF[self.hull[i]] then table.remove(self.hull,i) end end -- insert new boundaries with seen faces for E in pairs(self:bdry(seenF)) do table.insert(self.hull,{E[1],E[2],p}) end end return self end function ConvexHull:verticesSet() local v = {} if self.hull then for _,F in ipairs(self.hull) do v[F[1]] = true v[F[2]] = true v[F[3]] = true end end return v end function ConvexHull:verticesSize() local n = 0 for _ in pairs(self:verticesSet()) do n=n+1 end return n end function ConvexHull:distToFace(F,pt) local N=unit(self:normal(F)) local P=self:vect(F[1],pt) return dot(N,P) end function ConvexHull:distToHull(pt) local d for _,F in ipairs(self.hull) do local t = self:distToFace(F,pt) d = d==nil and t or (0<=t and t=t and t>d) and t or d if d==0 then break end end return d end end -- ConvexHullgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/ostro_to8.lua0000664000000000000000000000412113223665306026554 0ustar rootroot-- ostro_to8.lua : convert a color image to a BM16 -- (160x200x16) thomson image using the Ostromoukhov's -- error diffusion algorithm. -- -- Version: 02-jan-2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See run('lib/thomson.lua') run('lib/ostromoukhov.lua') run('lib/color_reduction.lua') -- run('lib/zzz.lua') -- get screen size local screen_w, screen_h = getpicturesize() -- Converts thomson coordinates (0-159,0-199) into screen coordinates local function thom2screen(x,y) local i,j; if screen_w/screen_h < 1.6 then i = x*screen_h/200 j = y*screen_h/200 else i = x*screen_w/320 j = y*screen_w/320 end return math.floor(i*2), math.floor(j) end -- return the Color @(x,y) in normalized linear space (0-1) -- corresonding to the thomson screen (x in 0-319, y in 0-199) local function getLinearPixel(x,y) local x1,y1 = thom2screen(x,y) local x2,y2 = thom2screen(x+1,y+1) if x2==x1 then x2=x1+1 end if y2==y1 then y2=y1+1 end local p = Color:new(0,0,0); for j=y1,y2-1 do for i=x1,x2-1 do p:add(getLinearPictureColor(i,j)) end end p:div((y2-y1)*(x2-x1)) --:floor() return p end local red = ColorReducer:new():analyzeWithDither(160,200, getLinearPixel, function(y) thomson.info("Collecting stats...",math.floor(y/2),"%") end) -- BM16 mode thomson.setBM16() -- define palette local palette = red:boostBorderColors():buildPalette(16) thomson.palette(0, palette) -- convert picture OstroDither:new(palette) :dither(thomson.h,thomson.w, function(y,x) return getLinearPixel(x,y) end, function(y,x,c) thomson.pset(x,y,c) end, true, function(x) thomson.info("Converting...",math.floor(x*100/160),"%") end) -- refresh screen setpicturesize(320,200) thomson.updatescreen() finalizepicture() -- save picture thomson.savep() grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/bayer4_to8.lua0000664000000000000000000001617113223665306026604 0ustar rootroot-- bayer4_to8.lua : converts an image into BM16 -- mode for thomson machines (MO6,TO8,TO9,TO9+) -- using bayer matrix and a special palette. -- -- Version: 02-jan-2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See -- This is my first code in lua, so excuse any bad -- coding practice. -- use a zig zag. If false (recommended value), this gives -- a raster look and feel local with_zig_zag = with_zig_zag or false -- debug: displays histograms local debug = false -- enhance luminosity since our mode divide it by two local enhance_lum = enhance_lum or true -- use fixed levels (default=false, give better result) local fixed_levels = fixed_levels or false -- use void-and-cluster 8x8 matrix (default=false) local use_vac = use_vac or false -- get screen size local screen_w, screen_h = getpicturesize() run("lib/thomson.lua") run("lib/color.lua") run("lib/bayer.lua") -- Converts thomson coordinates (0-159,0-99) into screen coordinates local function thom2screen(x,y) local i,j; if screen_w/screen_h < 1.6 then i = x*screen_h/100 j = y*screen_h/100 else i = x*screen_w/160 j = y*screen_w/160 end return math.floor(i), math.floor(j) end -- return the pixel @(x,y) in linear space corresonding to the thomson screen (x in 0-159, y in 0-99) local function getLinearPixel(x,y) local x1,y1 = thom2screen(x,y) local x2,y2 = thom2screen(x+1,y+1) if x2==x1 then x2=x1+1 end if y2==y1 then y2=y1+1 end local p,i,j = Color:new(0,0,0); for i=x1,x2-1 do for j=y1,y2-1 do p:add(getLinearPictureColor(i,j)) end end return p:div((y2-y1)*(x2-x1)):floor() end --[[ make a bayer matrix function bayer(matrix) local m,n=#matrix,#matrix[1] local r,i,j = {} for j=1,m*2 do local t = {} for i=1,n*2 do t[i]=0; end r[j] = t; end -- 0 3 -- 2 1 for j=1,m do for i=1,n do local v = 4*matrix[j][i] r[m*0+j][n*0+i] = v-3 r[m*1+j][n*1+i] = v-2 r[m*1+j][n*0+i] = v-1 r[m*0+j][n*1+i] = v-0 end end return r; end --]] -- dither matrix local dither = bayer.make(4) if use_vac then -- vac8: looks like FS dither = bayer.norm{ {35,57,19,55,7,51,4,21}, {29,6,41,27,37,17,59,45}, {61,15,53,12,62,25,33,9}, {23,39,31,49,2,47,13,43}, {3,52,8,22,36,58,20,56}, {38,18,60,46,30,5,42,28}, {63,26,34,11,64,16,54,10}, {14,48,1,44,24,40,32,50} } end -- get color statistics local stat = {}; function stat:clear() self.r = {} self.g = {} self.b = {} for i=1,16 do self.r[i] = 0; self.g[i] = 0; self.b[i] = 0; end end function stat:update(px) local pc2to = thomson.levels.pc2to local r,g,b=pc2to[px.r], pc2to[px.g], pc2to[px.b]; self.r[r] = self.r[r] + 1; self.g[g] = self.g[g] + 1; self.b[b] = self.b[b] + 1; end function stat:coversThr(perc) local function f(stat) local t=-stat[1] for i,n in ipairs(stat) do t=t+n end local thr = t*perc; t=-stat[1] for i,n in ipairs(stat) do t=t+n if t>=thr then return i end end return 0 end return f(self.r),f(self.g),f(self.b) end stat:clear(); for y = 0,99 do for x = 0,159 do stat:update(getLinearPixel(x,y)) end thomson.info("Collecting stats...",y,"%") end -- enhance luminosity since our mode divide it by two local gain = 1 if enhance_lum then -- findout level that covers 98% of all non-black pixels local max = math.max(stat:coversThr(.98)) gain = math.min(2,255/thomson.levels.linear[max]) if gain>1 then -- redo stat with enhanced levels -- messagebox('gain '..gain..' '..table.concat({stat:coversThr(.98)},',')) stat:clear(); for y = 0,99 do for x = 0,159 do stat:update(getLinearPixel(x,y):mul(gain):floor()) end thomson.info("Enhancing levels..",y,"%") end end end -- find regularly spaced levels in thomson space local levels = {} function levels.compute(name, stat, num) local tot, max = -stat[1],0; for _,t in ipairs(stat) do max = math.max(t,max) tot = tot + t end local acc,full=-stat[1],0 for i,t in ipairs(stat) do acc = acc + t if acc>tot*.98 then full=thomson.levels.linear[i] break end end -- sanity if fixed_levels or full==0 then full=255 end local res = {1}; num = num-1 for i=1,num do local p = math.floor(full*i/num) local q = thomson.levels.linear2to[p] if q==res[i] and q<16 then q=q+1 end if not fixed_levels and ires[i]+1 and stat[q-1]>stat[q] then q=q-1 end if q>res[i]+1 and stat[q-1]>stat[q] then q=q-1 end -- 3 corrections? no need... -- if q>res[i]+1 and stat[q-1]>stat[q] then q=q-1 end end res[1+i] = q end -- debug if debug then local txt = "" for _,i in ipairs(res) do txt = txt .. i .. " " end for i,t in ipairs(stat) do txt = txt .. "\n" .. string.format("%s%2d:%3d%% ", name, i, math.floor(100*t/(tot+stat[1]))) .. string.rep('X', math.floor(23*t/max)) end messagebox(txt) end return res end function levels.computeAll(stat) levels.grn = levels.compute("GRN",stat.g,5) levels.red = levels.compute("RED",stat.r,4) levels.blu = levels.compute("BLU",stat.b,3) end levels.computeAll(stat) -- put a pixel at (x,y) with dithering local function pset(x,y,px) local thr = dither[1+(y % #dither)][1+(x % #dither[1])] local function dither(val,thr,lvls) local i=#lvls local a,b = thomson.levels.linear[lvls[i]],1e30 while i>1 and val=thr*(b-a) and 0 or -1) end local r = dither(px.r, thr, levels.red); local g = dither(px.g, thr, levels.grn); local b = dither(px.b, thr, levels.blu); local i = r + b*4 local j = g==0 and 0 or (11 + g) if with_zig_zag and x%2==1 then thomson.pset(x,y*2+0,j) thomson.pset(x,y*2+1,i) else thomson.pset(x,y*2+0,i) thomson.pset(x,y*2+1,j) end end -- BM16 mode thomson.setBM16() -- define palette for i=0,15 do local r,g,b=0,0,0 if i<12 then -- r = bit32.band(i,3) -- b = bit32.rshift(i,2) b = math.floor(i/4) r = i-4*b else g = i-11 end r,g,b=levels.red[r+1],levels.grn[g+1],levels.blu[b+1] thomson.palette(i,b*256+g*16+r-273) end -- convert picture for y = 0,99 do for x = 0,159 do pset(x,y, getLinearPixel(x,y):mul(gain):floor()) end thomson.info("Converting...",y,"%") end -- refresh screen setpicturesize(320,200) thomson.updatescreen() finalizepicture() -- save picture do local function exist(file) local f=io.open(file,'rb') if not f then return false else io.close(f); return true; end end local name,path = getfilename() local mapname = string.gsub(name,"%.%w*$","") .. ".map" local fullname = path .. '/' .. mapname -- fullname = 'D:/tmp/toto.map' local ok = not exist(fullname) if not ok then selectbox("Ovr " .. mapname .. "?", "Yes", function() ok = true; end, "No", function() ok = false; end) end if ok then thomson.savep(fullname) end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/ostro_to9.lua0000664000000000000000000000230413223665306026556 0ustar rootroot-- ostro_mo5.lua : converts a color image into a -- TO9 image (320x200x16 with color clashes) -- using Ostromoukhov's error diffusion algorithm. -- -- Version: 02-jan-2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See run('lib/ostromoukhov.lua') run('lib/color_reduction.lua') OstroDither:new():dither40cols(function(w,h,getLinearPixel) local c16 = h==200 and w==320 for y=0,h-1 do for x=0,w-1 do if getbackuppixel(x,y)>15 then c16 = false end end end local pal if c16 then pal = {} for i=0,15 do local r,g,b=getbackupcolor(i) r = thomson.levels.pc2to[r] g = thomson.levels.pc2to[g] b = thomson.levels.pc2to[b] pal[i+1] = r+g*16+b*256-273 end else pal=ColorReducer:new():analyzeWithDither(w,h, getLinearPixel, function(y) thomson.info("Building palette...",math.floor(y*100/h),"%") end):boostBorderColors():buildPalette(16) end thomson.palette(0, pal) return pal end)grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/none_to8.lua0000664000000000000000000000412413223665306026350 0ustar rootroot-- ostro_to8.lua : convert a color image to a BM16 -- (160x200x16) thomson image using the Ostromoukhov's -- error diffusion algorithm. -- -- Version: 02-jan-2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See run('lib/thomson.lua') run('lib/ostromoukhov.lua') run('lib/color_reduction.lua') -- run('lib/zzz.lua') -- get screen size local screen_w, screen_h = getpicturesize() -- Converts thomson coordinates (0-159,0-199) into screen coordinates local function thom2screen(x,y) local i,j; if screen_w/screen_h < 1.6 then i = x*screen_h/200 j = y*screen_h/200 else i = x*screen_w/320 j = y*screen_w/320 end return math.floor(i*2), math.floor(j) end -- return the Color @(x,y) in normalized linear space (0-1) -- corresonding to the thomson screen (x in 0-319, y in 0-199) local function getLinearPixel(x,y) local x1,y1 = thom2screen(x,y) local x2,y2 = thom2screen(x+1,y+1) if x2==x1 then x2=x1+1 end if y2==y1 then y2=y1+1 end local p = Color:new(0,0,0); for j=y1,y2-1 do for i=x1,x2-1 do p:add(getLinearPictureColor(i,j)) end end p:div((y2-y1)*(x2-x1)) --:floor() return p end local red = ColorReducer:new():analyzeWithDither(160,200, getLinearPixel, function(y) thomson.info("Collecting stats...",math.floor(y/2),"%") end) -- BM16 mode thomson.setBM16() -- define palette local palette = red:boostBorderColors():buildPalette(16) thomson.palette(0, palette) -- convert picture OstroDither:new(palette, 0) :dither(thomson.h,thomson.w, function(y,x) return getLinearPixel(x,y) end, function(y,x,c) thomson.pset(x,y,c) end, true, function(x) thomson.info("Converting...",math.floor(x*100/160),"%") end) -- refresh screen setpicturesize(320,200) thomson.updatescreen() finalizepicture() -- save picture thomson.savep() grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/bayer4_mo5.lua0000664000000000000000000001353113223665306026567 0ustar rootroot-- bayer4_mo5.lua : converts an image into TO7/70-MO5 -- mode for thomson machines (MO6,TO8,TO9,TO9+) -- using special bayer matrix that fits well with -- color clashes. -- -- Version: 02-jan-2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See -- get screen size local screen_w, screen_h = getpicturesize() run("lib/thomson.lua") run("lib/color.lua") run("lib/bayer.lua") -- Converts thomson coordinates (0-319,0-199) into screen coordinates local function thom2screen(x,y) local i,j; if screen_w/screen_h < 1.6 then i = x*screen_h/200 j = y*screen_h/200 else i = x*screen_w/320 j = y*screen_w/320 end return math.floor(i), math.floor(j) end -- return the pixel @(x,y) in normalized linear space (0-1) -- corresonding to the thomson screen (x in 0-319, y in 0-199) local function getLinearPixel(x,y) local x1,y1 = thom2screen(x,y) local x2,y2 = thom2screen(x+1,y+1) if x2==x1 then x2=x1+1 end if y2==y1 then y2=y1+1 end local p,i,j = Color:new(0,0,0); for i=x1,x2-1 do for j=y1,y2-1 do p:add(getLinearPictureColor(i,j)) end end p:div((y2-y1)*(x2-x1)*Color.ONE) return p end local dither = bayer.norm(bayer.double(bayer.double({{1,2},{3,4}}))) local dx,dy=#dither,#dither[1] -- get thomson palette pixel (linear, 0-1 range) local linearPalette = {} function linearPalette.get(i) local p = linearPalette[i] if not p then local pal = thomson.palette(i-1) local b=math.floor(pal/256) local g=math.floor(pal/16)%16 local r=pal%16 p = Color:new(thomson.levels.linear[r+1], thomson.levels.linear[g+1], thomson.levels.linear[b+1]):div(Color.ONE) linearPalette[i] = p end return p:clone() end -- distance between two colors local distance = {} function distance.between(c1,c2) local k = c1..','..c2 local d = distance[k] if false and not d then d = linearPalette.get(c1):euclid_dist2(linearPalette.get(c2)) distance[k] = d end if not d then local x = linearPalette.get(c1):sub(linearPalette.get(c2)) local c,c1,c2,c3=1.8,8,11,8 local f = function(c,x) return math.abs(x)*c end d = f(c1,x.r)^c + f(c2,x.g)^c + f(c3,x.b)^c distance[k] = d end return d end -- compute a set of best couples for a given histogram local best_couple = {n=0} function best_couple.get(h) local k = (((h[1]or 0)*8+(h[2]or 0))*8+(h[3]or 0))*8+(h[4]or 0) .. ',' .. (((h[5]or 0)*8+(h[6]or 0))*8+(h[7]or 0))*8+(h[8]or 0) local best_found = best_couple[k] if not best_found then local dm=1000000 for i=1,15 do for j=i+1,16 do local d=0 for p,n in pairs(h) do local d1,d2=distance.between(p,i),distance.between(p,j) d = d + n*(d1dm then break; end end if d< dm then dm,best_found=d,{} end if d<=dm then table.insert(best_found, {c1=i,c2=j}) end end end if best_couple.n>10000 then -- keep memory usage low best_couple = {n=0, get=best_couple.get} end best_couple[k] = best_found best_couple.n = best_couple.n+1 end return best_found end -- TO7/70 MO5 mode thomson.setMO5() -- convert picture local err1,err2 = {},{} local coefs = {0,0.6,0} for x=-1,320 do err1[x] = Color:new(0,0,0) err2[x] = Color:new(0,0,0) end for y = 0,199 do err1,err2 = err2,err1 for x=-1,320 do err2[x]:mul(0) end for x = 0,319,8 do local h,q = {},{} -- histo, expected color for z=x,x+7 do local d=dither[1+(y%dx)][1+(z%dx)] local p=getLinearPixel(z,y):add(err1[z]) local c=((p.r>d) and 1 or 0) + ((p.g>d) and 2 or 0) + ((p.b>d) and 4 or 0) + 1 -- theorical color table.insert(q,c) h[c] = (h[c] or 0)+1 end local c1,c2 for c,_ in pairs(h) do if c1==nil then c1=c elseif c2==nil then c2=c else c1=nil; break; end end if c1~=nil then c2 = c2 or c1 else -- get best possible couples of colors local best_found = best_couple.get(h) if #best_found==1 then c1,c2 = best_found[1].c1,best_found[1].c2 else -- keep the best of the best depending on max solvable color clashes function clamp(v) return v<0 and -v or v>1 and v-1 or 0 end local dm=10000000 for _,couple in ipairs(best_found) do local d=0 for k=1,8 do local q=q[k] local p=distance.between(q,couple.c1) run('lib/ostromoukhov.lua') OstroDither:new():dither40cols(function(w,h,getLinearPixel) local pal={} for i=0,15 do pal[i+1] = thomson.palette(i) end return pal end)grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/none_to9.lua0000664000000000000000000000253313223665306026353 0ustar rootroot-- ostro_mo5.lua : converts a color image into a -- TO9 image (320x200x16 with color clashes) -- using Ostromoukhov's error diffusion algorithm. -- -- Version: 02-jan-2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See run('lib/thomson.lua') thomson.optiMAP = false run('lib/ostromoukhov.lua') run('lib/color_reduction.lua') local dith=OstroDither:new() local tmp=dith.setLevelsFromPalette dith.setLevelsFromPalette = function(self) tmp(self) self.attenuation=0 end dith:dither40cols(function(w,h,getLinearPixel) local c16 = true for y=0,h-1 do for x=0,w-1 do if getbackuppixel(x,y)>15 then c16 = false end end end local pal if c16 then pal = {} for i=0,15 do local r,g,b=getbackupcolor(i) r = thomson.levels.pc2to[r] g = thomson.levels.pc2to[g] b = thomson.levels.pc2to[b] pal[i+1] = r+g*16+b*256-273 end else pal=ColorReducer:new():analyzeWithDither(w,h, getLinearPixel, function(y) thomson.info("Building palette...",math.floor(y*100/h),"%") end):buildPalette(16) end thomson.palette(0, pal) return pal end)grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/thomson/ostro_to7.lua0000664000000000000000000000122013223665306026550 0ustar rootroot-- ostro_mo5.lua : converts a color image into a -- TO7 image (8 fixed colors with color clash) -- using Ostromoukhov's error diffusion algorithm. -- -- Version: 02-jan-2017 -- -- Copyright 2016-2017 by Samuel Devulder -- -- This program is free software; you can redistribute -- it and/or modify it under the terms of the GNU -- General Public License as published by the Free -- Software Foundation; version 2 of the License. -- See run('lib/ostromoukhov.lua') OstroDither:new():dither40cols(function(w,h,getLinearPixel) local pal={} for i=0,7 do pal[i+1] = thomson.palette(i) end return pal end)grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/PaletteToPicture.lua0000664000000000000000000000111713223665306026364 0ustar rootroot-- palette to picture - Copyright 2010 Paulo Silva -- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. See w,h=getpicturesize(); ok,xsiz,ysiz=inputbox("palette to picture","x size",8,1,16,5,"y size",8,1,16,6); if ok==true then for y1=0,7,1 do for x1=0,31,1 do for y2=0,ysiz-1,1 do for x2=0,xsiz-1,1 do putpicturepixel(x1*xsiz+x2,y1*ysiz+y2,y1+x1*8) end;end;end;end;end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/picture/FontConvert.lua0000664000000000000000000000103713223665306025377 0ustar rootroot--Font Extractor by Adrien Destugues --Cut the picture in characters and save them --to a binary file -- --Copyright 2013, Adrien Destugues -- --this file is distributed under the terms of the MIT licence w,h = getpicturesize(); f = io.open("file.bin","w") for y = 0, h-1, 8 do for x = 0, w-1, 8 do for y2 = 0, 7, 1 do word = 0; for x2 = 0,7,1 do word = word * 2 + getpicturepixel(x+x2,y+y2); -- read one word from the current line end f:write(string.char(word)); end end end f:close() grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/brush/0000775000000000000000000000000013223665306022074 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/brush/ApplyColor.lua0000664000000000000000000000725513223665306024674 0ustar rootroot--BRUSH Remap: Apply PenColor --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See run("../libs/dawnbringer_lib.lua") OK,tin,clz,fade,amt,brikeep,falloff,nobg,nopen,briweight = inputbox("Apply PenColor 2 Brush", "1. Tint", 1, 0,1,-1, "2. Colorize", 0, 0,1,-1, "BG->FG color Fade", 0, 0,1,0, "AMOUNT % (0-100)", 100, 0,100,0, "Preserve Brightness", 1, 0,1,0, "Bri/Dark FallOff", 1, 0,1,0, "Exclude Background", 1,0,1,0, "Exclude PenColor", 0,0,1,0, "ColMatch Bri-Weight %", 25, 0,100,0 ); if OK == true then function cap(v) return math.min(255,math.max(v,0)); end w, h = getbrushsize() fg = getforecolor() bg = getbackcolor() fR,fG,fB = getcolor(fg) bR,bG,bB = getcolor(bg) pal = db.fixPalette(db.makePalList(256)) if nobg == 1 then pal = db.stripIndexFromPalList(pal,bg) -- Remove background color from pallist end if nopen == 1 then pal = db.stripIndexFromPalList(pal,fg) -- Remove Pencolor from pallist end amtA = amt / 100 amtR = 1 - amtA -- Normalize Pen Color lev = (fR+fG+fB)/3 fR = fR - lev fG = fG - lev fB = fB - lev --------------------------------------------------- -- Colorize (Colourant) (just apply colorbalance) -- Tint (make grayscale and apply colorbalance) -- -- I think it should be the other way around since colorize is the process of adding color to B&W film... -- But this is the what Brilliance and others call it -- if clz == 1 or tin == 1 then cols = {} for n = 0, 255, 1 do r,g,b = getcolor(n) a = db.getBrightness(r,g,b) mR,mG,mB = fR,fG,fB -- Fade between bg & fg pencolor across dark-bright if fade == 1 then lf = a / 255 lr = 1 - lf mR = bR*lr + fR*lf mG = bG*lr + fG*lf mB = bB*lr + fB*lf lev = (mR+mG+mB)/3 mR = mR - lev mG = mG - lev mB = mB - lev end fr,fg,fb = mR,mG,mB if brikeep == 1 then -- Loose Brightness preservation (ex: applying full red to dark colors) brin = db.getBrightness(cap(r+mR),cap(g+mG),cap(b+mB)) itot = brin - a fr = mR - itot fg = mG - itot fb = mB - itot end -- Falloff (Effect weakens at dark and bright colors) if falloff == 1 then fo = 1 - math.abs((a - 127.5)/127.5)^2 fr = fr * fo fg = fg * fo fb = fb * fo end if tin == 1 then --cols[n+1] = matchcolor((a+fr)*amtA + r*amtR, (a+fg)*amtA + g*amtR, (a+fb)*amtA + b*amtR) cols[n+1] = db.getBestPalMatchHYBRID({(a+fr)*amtA+r*amtR, (a+fg)*amtA + g*amtR, (a+fb)*amtA + b*amtR},pal,briweight / 100,true) end if clz == 1 then --cols[n+1] = matchcolor((r+fr)*amtA + r*amtR, (g+fg)*amtA + g*amtR, (b+fb)*amtA + b*amtR) cols[n+1] = db.getBestPalMatchHYBRID({(r+fr)*amtA+r*amtR, (g+fg)*amtA + g*amtR, (b+fb)*amtA + b*amtR},pal,briweight / 100,true) end end if nobg == 1 then cols[getbackcolor()+1] = getbackcolor(); end for x = 0, w - 1, 1 do for y = 0, h - 1, 1 do putbrushpixel(x, y, cols[getbrushpixel(x,y) + 1]); end end end; -- eof Colorize & Tint -------------------------------------------------------- end -- OK grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/brush/Fisheye.lua0000664000000000000000000000162513223665306024177 0ustar rootroot--BRUSH Distortion: FishEye --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project --http://goto.glocalnet.net/richard_fhager/evalion/evalion.html w, h = getbrushsize() for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do ox = x / w; oy = y / h; v = (math.cos((ox-0.5)*math.pi)*math.cos((oy-0.5)*math.pi))*0.85; ox = (1 + ox - (ox-0.5)*v) % 1; oy = (1 + oy - (oy-0.5)*v) % 1; c = getbrushbackuppixel(math.floor(ox*w),math.floor(oy*h)); putbrushpixel(x, y, c); end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/brush/Halfsmooth.lua0000664000000000000000000000156013223665306024705 0ustar rootroot--BRUSH: Halfsize with smoothscaling --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See w, h = getbrushsize() setbrushsize(math.floor(w/2),math.floor(h/2)) for x = 0, w - 1, 2 do for y = 0, h - 1, 2 do r1,g1,b1 = getcolor(getbrushbackuppixel(x,y)); r2,g2,b2 = getcolor(getbrushbackuppixel(x+1,y)); r3,g3,b3 = getcolor(getbrushbackuppixel(x,y+1)); r4,g4,b4 = getcolor(getbrushbackuppixel(x+1,y+1)); r = (r1 + r2 + r3 + r4 ) / 4; g = (g1 + g2 + g3 + g4 ) / 4; b = (b1 + b2 + b3 + b4 ) / 4; c = matchcolor(r,g,b); putbrushpixel(x/2, y/2, c); end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/brush/GrayscaleDesat.lua0000664000000000000000000000166613223665306025503 0ustar rootroot--BRUSH Remap: Grayscale (desaturate) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project --http://goto.glocalnet.net/richard_fhager/evalion/evalion.html percent = 100 -- function desaturate(percent,r,g,b) -- V1.0 by Richard Fhager p = percent / 100 a = (math.min(math.max(r,g,b),255) + math.max(math.min(r,g,b),0)) * 0.5 * p r = r + (a-r*p) g = g + (a-g*p) b = b + (a-b*p) return r,g,b end -- w, h = getbrushsize() for x = 0, w - 1, 1 do for y = 0, h - 1, 1 do putbrushpixel(x, y, matchcolor(desaturate(percent,getcolor(getbrushpixel(x,y))))); end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/brush/GrayscaleAvg.lua0000664000000000000000000000106313223665306025147 0ustar rootroot--BRUSH Remap: Grayscale (average) --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See w, h = getbrushsize() for x = 0, w - 1, 1 do for y = 0, h - 1, 1 do r, g, b = getcolor(getbrushpixel(x,y)) a = (r+g+b)/3 putbrushpixel(x, y, matchcolor(a,a,a)); end end grafx2_2.4+git20180105/share/grafx2/scripts/samples_2.4/brush/Waves.lua0000664000000000000000000000200413223665306023660 0ustar rootroot--BRUSH Distortion: Waves v1.0 --by Richard Fhager --http://hem.fyristorg.com/dawnbringer/ -- Copyright 2010 Richard Fhager -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation; version 2 -- of the License. See -- This script was adopted from Evalion, a Javascript codecrafting/imageprocessing project -- http://goto.glocalnet.net/richard_fhager/evalion/evalion.html --frq = 2 --amp = 0.3 -- Adjust power of frequency & amplitude frq_adj = 2 amp_adj = 0.02 ok,frq,amp = inputbox("Settings", "Frequency 1-10", 3, 1,10,0, "Amplitude 1-10", 3, 1,10,0 ); w, h = getbrushsize() for y = 0, h - 1, 1 do for x = 0, w - 1, 1 do ox = x / w; oy = y / h; ox = (1 + ox + math.sin(oy*math.pi*frq*frq_adj)*amp*amp_adj) % 1; c = getbrushbackuppixel(math.floor(ox*w),y); putbrushpixel(x, y, c); end end grafx2_2.4+git20180105/share/grafx2/scripts/libs/0000775000000000000000000000000013223665306017653 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/scripts/libs/gui.lua0000664000000000000000000001305413223665306021145 0ustar rootroot-- -- Event-driven GUI library -- -- gui = { -- -- colors -- black = 0, dark = 1, light = 2, white = 3, -- "do nothing" function. Used as default callback donothing = function(self) end, -- Metatable that hides the field "value" behind a property, -- and calls render() after it's set. propvalue = { __newindex = function(self, index, value) if index == "value" then self._value = value -- extra processing self:render() else rawset(self, index, value) end end, __index = function(self, index ) if index == "value" then return self._value else return rawget( self, index ) end end }, -- -- dialog() -- dialog = function(args) local dia = { title = args.title, w = args.w, h = args.h, -- widgets = {}, -- an indexed array, starting at 1. Used for calling the relevant -- callback when a numbered control is clicked. callbacks = {}, -- -- dialog.run() -- -- run = function(self) windowopen(self.w,self.h, self.title or ""); -- examine all elements for _,widget in ipairs(self.widgets) do widget:create() end repeat local button, button2, key = windowdodialog(); if button > 0 then local c = self.callbacks[button] if c ~= nil then -- run the callback local retvalue = c:click() -- stop the form if it returns non-nil if retvalue ~= nil then windowclose(); return retvalue; end end end until key == 27; windowclose(); end } local id = 1; -- examine all elements for _,value in ipairs(args) do -- all arguments that are tables are assumed to be widgets if type(value)=="table" then table.insert(dia.widgets, value) -- clickable widgets take up an auto-numbered id if (value.click) then dia.callbacks[id] = value id=id+1 end end end return dia; end, -- -- button() -- button = function(args) local but = { x = args.x, y = args.y, w = args.w, h = args.h, key = args.key, label = args.label, click = args.click or gui.donothing, create = args.repeatable and function(self) windowrepeatbutton(self.x, self.y, self.w, self.h, self.label, self.key or -1); end or function(self) windowbutton(self.x, self.y, self.w, self.h, self.label, self.key or -1); end } return but; end, -- -- label() -- label = function(args) local lbl = { x = args.x, y = args.y, _value = args.value, format = args.format, fg = args.fg or gui.black, bg = args.bg or gui.light, render = function(self) if type(self.format) then windowprint(self.x, self.y, string.format(self.format, self._value), self.fg, self.bg); else windowprint(self.x, self.y, self._value, self.fg, self.bg); end end, } lbl.create = lbl.render setmetatable(lbl, gui.propvalue) return lbl; end, -- -- textbox -- textbox = function(args) local txtbox = { x = args.x, y = args.y, nbchar = args.nbchar, -- visible size in characters --format = args.format, -- numeric, decimal, path decimal = args.decimal or 0, min = args.min, max = args.max, maxchar = args.maxchar, -- internal size _value = args.value, change = args.change or gui.donothing, --fg = args.fg or gui.black, --bg = args.bg or gui.light, create = function(self) windowinput(self.x, self.y, self.nbchar) self:render() end, render = function(self) local val = tostring(self._value) if string.len(val) < self.nbchar then val = string.rep(" ",self.nbchar - string.len(val)) .. val; elseif string.len(val) > self.nbchar then val = string.sub(val, 1, self.nbchar-1) .. gui.char.ellipsis end windowprint(self.x, self.y, val, gui.black, gui.light); end, click = function(self) local inputtype if (type(self._value) == "number" and ((self.min ~= nil and self.min<0) or self.decimal > 0)) then inputtype = 3 -- entry as double elseif (type(self._value) == "number") then inputtype = 1 -- entry as unsigned int else inputtype = 0 -- entry as string end local accept, val = windowreadline(self.x, self.y, self._value, self.nbchar, self.maxchar, self.decimal, inputtype); if accept then if (inputtype == 1 or inputtype == 3) then val = tonumber(val) -- round the decimal places val = gui.round(val, self.decimal) end if (self.min ~= nil and val < self.min) then val = self.min end if (self.max ~= nil and val > self.max) then val = self.max end self._value = val end self:render() end } setmetatable(txtbox, gui.propvalue) return txtbox; end } gui.round = function(val, ipt) local mult = 10^ipt return math.floor(val * mult + 0.5) / mult end -- Character constants. May be useful in screens gui.char = { ellipsis = string.char(133), -- ... arrowup = string.char(24), arrowdown = string.char(25), arrowleft = string.char(27), arrowright = string.char(26), vertical = string.char(18), -- double-ended arrow horizontal = string.char(29) -- double-ended arrow }grafx2_2.4+git20180105/share/grafx2/scripts/_tst_AAFilter.lua0000664000000000000000000000165213223665306022111 0ustar rootroot-- Apply a kind of AA filter on picture -- Get the picture size w, h = getpicturesize(); -- Here is the filtering matrix matrix = { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 }}; -- Loop trough all the pixels -- To make this script simpler we don't handle the picture borders -- (the matrix would get pixels outside the picture space) -- for var = start_value, end_value, step do ... for y = 1, h - 2, 1 do for x = 1, w - 2, 1 do filtered = matrix[1][1] * getbackuppixel(x - 1, y - 1) + matrix[1][2] * getbackuppixel(x , y - 1) + matrix[1][3] * getbackuppixel(x + 1, y - 1) + matrix[2][1] * getbackuppixel(x - 1, y ) + matrix[2][2] * getbackuppixel(x , y ) + matrix[2][3] * getbackuppixel(x + 1, y ) + matrix[3][1] * getbackuppixel(x - 1, y + 1) + matrix[3][2] * getbackuppixel(x , y + 1) + matrix[3][3] * getbackuppixel(x + 1, y + 1); putpicturepixel(x,y,filtered); end end grafx2_2.4+git20180105/share/grafx2/scripts/_tst_dialog2.lua0000664000000000000000000000224313223665306022000 0ustar rootroot-- -- test of GUI library -- run("libs/gui.lua") local counter = gui.label{x=10, y=54, value=0, format="% .3d"} local form = gui.dialog{ title="Dialogtest", w=100, h=150, counter, gui.button{ label="+", x=6, y=38, w=14, h=14, repeatable=true, click=function() counter.value=counter.value+1; end}, gui.button{ label="-", x=26, y=38, w=14, h=14, repeatable=true, click=function() counter.value=counter.value-1; end}, gui.button{ label="Help", x=6, y=70, w=54, h=14, click=function() messagebox("Help screen"); end}, gui.button{ label="Close", x=6, y=18, w=54, h=14, key=27, click=function() return true; -- causes closing end}, gui.textbox{ x=6, y=90, nbchar=8, decimal=1, min=450, max=1450, maxchar=8, value = 1234, change=function() -- do nothing end }, gui.textbox{ x=6, y=104, nbchar=10, maxchar=20, value = "test" }, gui.textbox{ x=6, y=118, nbchar=8, decimal=0, min=0, maxchar=8, value = 456, change=function() -- do nothing end }, } form:run() grafx2_2.4+git20180105/share/grafx2/fonts/0000775000000000000000000000000013223665306016364 5ustar rootrootgrafx2_2.4+git20180105/share/grafx2/fonts/8pxfont.png0000664000000000000000000000336013223665306020502 0ustar rootrootPNG  IHDRA loZPLTETTTTTTTTTTTTT̼|||lll\\\LLL<<<,,, |l\L<, ||ll\\LL<<,, |l\L<, ||ll\\LL<<,, |l\L<, ̼||ll\\LL<<,,  00@@TTddttxhTD4$ 00@@TTddttxhTD4$ 00@@TTddttxhTD4$<\|`@ <\|`@ <\|`@ 褈|Ԍp̀dtXhL\@P4D(|8p,`P@ ||(||@||X||p||||||||||||||||l0(pGLk pHYs  ~IDAThXْ0Td|$y<4Ml51-<| n^ց"ʋ%ܪ٫?wO'!}'k_ƍ<{vlaxoy^-ϯC^\ \/XCPen @pfqDXR9syy@|c%U;0^-č.v& 2]EWO>Y8V} ;]a|CzkqmH烰[[o ,o$\zH*z,`W *Εy4m5 E'V78 8v<]Wq+*;E/t~3o~YΣ' ]/ 6wmTym'UpsՌ E1>FFSFr ⇮w_AZ)L~qWPwqplR"l{/3}2n^_|iy(yCerXJ\:#JH&pUq?Z'9(|7 ÒtC{\ɏ;_xUcdǣ:h1N8o⌻OŲ 73F}*7)VW~E*2 oI*}I4Xm0_gGwƙlEW$b츢JA ׍2ؐ:(lbWp[}h96% oAbD36IgVs_ѡ<2~@)ya}:ޟpD.Nʇ*@v8d|b+`;||Ԙ@ȕ&v@3woUjs_pbmg;gxYWxǵ gٵ{@wh=IENDB`grafx2_2.4+git20180105/share/grafx2/fonts/PF_Tempesta_5__.png0000664000000000000000000000252713223665306021771 0ustar rootrootPNG  IHDRn 0^.!PLTEIH"""fffBftEXtSoftwareGrafx2SjIDAThYr ommdivYCqlz;f}FY>:yEL |R.gwWs߮&&^5`64Q_M%S=}z,kh|>ʶ>HRDìl8VFzz +,^Du1JYIў`M6bʪjہ:32+¡SVI"m+\rÕv,] &`ܺ91\2~+w͎@Miǜ2Iʓ:?}p:.O rfG',k|b!F}vYB~XQR)UFznnַ?^{{,ҒغNAR+s))|G:!} {wK럨ԯ"0/y?{"_n>o^!!tEXtSoftwareGrafx2Sj/IDAThYn0 ,~gF}N[G?Jp>_BuYgFmpH72WS溲6Рs6s@3n.'v+rrߞ4|%"0M2q'K|1 Gk2mݛp79PL'ea&!v7>ꍪeaEt9pWᦅ`B)GwUs)=O1b8c:'LGDI$`0~ iPl?0d-kqNu0W %(&S2&B#]V{`i&,t-y Vvf4$W}PS Ðxf=X֮lDy $|F澅jo&X1M,Anp .|D d<0qu _'x3_oK2Md8}-zo"FLVOme~!Q=Kq9p% Iʼ>,{̉@)z5'02csM@lp۩2VhdB[jw RNێ O~tȞ{t x9wpFc1Aա\|(N=!!D :OyrکQ)A/gUC=Xw& 8sN1[x1 lP`%͢vŢ1kLa5tEX8fVs~#vc30=P4='2sи5v_<9.5t?dc?/5McXPXIENDB`grafx2_2.4+git20180105/share/grafx2/fonts/PF_Westa_7__.png0000664000000000000000000000340713223665306021272 0ustar rootrootPNG  IHDR!PLTEIH"""fffBftEXtSoftwareGrafx2SjIDAThZے0koΜ=m $9Ne6kdq*t# s %DVwp 9r1 "bY>/VȵQnXԥ$l-핼Z܉#-P(F8ҕh,&9WR|u oԜ?j ŨwQc2YJ|JZ 0}hSRp7(fZf MnB CI'~:Q_(2HH0b5Xa=BrM(JQԇ>H,T(ՔsM$j4uIy@<@!$a/J}PxtN_ m *K? c,nmzJ-k}IE( hm>ζ/fbW9&M٤ឣITY"h*Zn{B30Af;6b9OQI +&AH>s/ ?xt*@9 cY5cTfokAEf9m93fIENDB`grafx2_2.4+git20180105/share/grafx2/fonts/GrafX2_Black.gif0000664000000000000000000000327713223665306021251 0ustar rootrootGIF89aN TTTTTTTTTTTTT̼|||lll\\\LLL<<<,,, |l\L<, ||ll\\LL<<,, |l\L<, ||ll\\LL<<,, |l\L<, ̼||ll\\LL<<,,  00@@TTddttxhTD4$ 00@@TTddttxhTD4$ 00@@TTddttxhTD4$<\|`@ <\|`@ <\|`@ 褈|Ԍp̀dtXhL\@P4D(|8p,`P@ ||(||@||X||p||||||||||||||||lll!,N Hp"<aÂ.48aň'bǎ nQdI'!eK/YqM7a攉N< J&PCSSG&$MO6UkTSV],BΦE[-۳ K-ݶw=߿k7]"b}GF츱1cŔ!3̗siҨGW6v≮K-pӉA6[ؽ[˕lj/g|^ȝسkw76xܭ/ok,;hԇ?-~u ^}y ڇ`Uhw)(yHa a٭ }ֵ8ߋȞnWQ(`fEyu\}ȟ&>ٕE:9oehb$b^~Q%lR9fy "y%XmYdY6&iuc}xz!r}cV!G7ۜeJW]tvrzYo'kn Vv Xp|jߢJ\ 鯸暌(禺jJʂ8&+j^J)#'v(xxmbi풭Viú!F;*bW(zkV٠Jb,é9񸑊k#o+3mq:,t J# W)x#:(BA:T[T}4V1alc\uXv^׍o ᢜuy7]r*iH Wm7-*Ra:(<Ϛ9c]2Qo&ŦpZ{ݬ3S9OZ}.q~+S~{}ήƍs?/;grafx2_2.4+git20180105/share/grafx2/fonts/PF_Arma_5__.png0000664000000000000000000000247313223665306021067 0ustar rootrootPNG  IHDR aPLTEMM"""fff>!tEXtSoftwareGrafx2SjIDATXXr oέ rB޵e uY[[Kk`?ңΫ%:S yDkՊrverVoK񔷒 vXԔ7^یhKasft@V(q]Gl)tBV־lcb}zq!!nuۅ+;zAW2\Bve*g`>?g/J$ӬKmz6&d* 8p mT-6)2rwv9zezb(SVB;;Dl&!Uf6چ\ZT$Ź-wEnGӨCD鶙?gb=\م.h5e2ZzHzIWp?9 DHC@IENDB`grafx2_2.4+git20180105/share/grafx2/fonts/PF_Tempesta_5___.png0000664000000000000000000000264713223665306022133 0ustar rootrootPNG  IHDR PLTEIH"""fffBftEXtSoftwareGrafx2SjGIDAThZю0koN &IF2F1t۫׿sSW/x R]dR;L!I Dx WM9Fe+K| k,,2Ysatpo!ET1dKV|-u9vzXm*9YzwG3gFj` !VAڢ32e}<[{~Ik]XoC=giz^E틀Yf7*Vq)q |%K}e1m,YTbPl#%pX$btyl/ԛHi`0EPぬk 5fk`ݟ $RSVij4T){3C+V-n*g(ʹ` Kk&+ ȋ_j@rp>)cLLӌN&8ifLۢfp)êp}Lֳ>h26܌&2"Q h 0X4ZF[K ^~w:g Z*D5wzKYH:%" F'DrY[R䆦 z^g}q >P.^-b GUugK0*_L"pOTri|ػxH| QlfG]>`tO/[WVX~f0=++ͫVh1M'y*xHm}VoM}&t(patY]+} o̍S Z0O ,S OC-7ENr=ȳm((ȴ7)1&o`xp~jimcSr%r+Hp+Y#T1sڥezkp{wZCw-˂ߎ%DccC]qoU۸scաAgo5mPwq֘D~TR*y:cQ`\%9E__A_hrR_Ɲm<,rNѧ |}''>-fMy?i?cfIENDB`grafx2_2.4+git20180105/share/grafx2/fonts/colorfont.pcx0000664000000000000000000000730013223665306021105 0ustar rootroot X ```@@@ Z ```@@@ grafx2_2.4+git20180105/share/grafx2/fonts/PF_Tempesta_7___.png0000664000000000000000000000324413223665306022127 0ustar rootrootPNG  IHDROaPLTEIH"""fffBftEXtSoftwareGrafx2SjDIDAThZ0loP6rHOvl cB1OCӤ&nߒ;v"x Y\-v!`e"\qSHG;m  s )IZ0. ϝmv-ɛw3[pPP:,N4g۾L/ s]˕6o$J%y^"jlрA-9oIENDB`grafx2_2.4+git20180105/share/grafx2/fonts/Tuffy.ttf0000664000000000000000000004401413223665306020203 0ustar rootrootFFTMEQ\GGDEF)FPGPOSF^GSUBltFp OS/2kVcmap+Bcvt !y8gaspFHglyfҺ4headB 6hhea ΎD$hmtxwJlocaR<maxph name/d=posteHDh 4_< //??]bT@_P0 PfEd ==hg5zhd~$)Z!~Ngbmg(pdppmfqpXpppophpqqKTBX\9X)HydyvyzySdytqyQyyy5\KyZ\My7-XyP(TJL-dr+~X`TLIb}I((fI`f(xR^D5(xZZp}?5(P`TX?VJ1Z+L)h;m^?V1&a~yub R R R R R RlSxzzzz 1f1f1f1f1fAl p`V1\ ^ ^ ^ ^ ^ ^TVllllxsR$p&p&p&p$pwV(((((? S_cjQaq[A<        !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a}~pcdhtnjriqfsxblkwy|u{zov!y0pdZrbDV$8L <*n^  ` t   0 @ R d p @ v $ L n  : p Jf*"Vp(2@ $LXdp|(4Bfr~6BNZfr~ ,8DP\$jgB #.546324632#"&'&#");'(=@,':?,':"!'77%-?1$,?0% ;&46;2#"&'4&%46;2#"&'&+'"+)"Dv$(v$( 5{!#!#!5!!5!3!3!!!\\Vii#RaaR{{e*3:3.'#5.'7.5467>54&ŁВ}#wK:oeL-ӴQ~fL- ;5O-S|k9ԝ]t7.54>32+'n_c[eaw|!Jg[ZL6RY(Ro_t3LLgiv4su]:Hy^P]; #u`lc46;2#"&'&+)"Dv$( ) &5473n{suTIUZ #654'3 tjyTJ]!y9#"'&54?"&5463'&547632763272#'#"&'q!& 0*" (*om*( "*0 &! (#)!)' (( ')!)#( NB !3!!#!N34̍7Ɏ7g#>%'65"&'&54632>%8H':@,':^,XM/gK/% -?1$m3!!m[g>74632#"&'&g@,':?,':^-?1$,?0% T3#3͞d&4>32#"'&732>54'.#"dByo.mܓ."mPI&!kPL(ך|ڈ ڄxpms#73#F\Pm/'6$32!!4>7>54&#"'AxlP/*@:M3C *b`?u4PypG ?"=#-kdV7 GeY3bOO8>#,\ny/^\2*0%96F%q /?32654.+532654&+"'>32#"&q&S9_s=Nba_Py 5{euBN'&TM3}/RhIwK(}pdUI@i^mRM @]GX 3##!;!`^ }ts#V&"'!!632#"&'732654'.\!;1%$^B[# kч.T߄ ' KT7¤?>݉Ţ,'r)4'.#"326632#"&'&54>73oqiEI@! Bse /";N%gu!f~ɛ+3N~N͓*-:snDd Ho7 #!57նPh/@%2654'.#"32654'.#"2#"$'&54>7&'&546Fs`oewU# 3SQ) q" n&oVbqQa -n'l((w͠4,NY9V'0*32654'.#"#"&'&54>32#%qiI@! )PmQ 1A#fv"fɛ2->~pW3Γ,+:rr>mqH'  q#H&  T% 3 PdXBfbb!!!!B  \%# 3#eZ9-=#54>7> 54&#"'>324632#"&'&=6(E  |RHV~KJ>I21@,':?,':-P6="9 $}Z|92`aa?7'4G9-?1$,?0% )FV%# &54$32#"&'#"&'&5463232654'.#"32632654'.#"M^7`Ј6Tb-7x(,OzȎv R38f osc.[]uKZmqBTfWRP_]wC@K^89+54'.#32>54'.#"&'!2#2#!?FqK4S}F+ %HU˱vo? WHvK- *KcZ#!7KR,#^ud'!0C9#<9!4Ye:*#u5X^3$$"BWKL5!d)#".54>32.+"3267Lp_wȋa-.awLbN1hhi87#!!2*JcUi0ODOAs[4jTχpzy !!!!!!y0gy !!!!#y0\d0".54>32.#"32>5!5!#*P-bwI:jgi99igFvP53#"&'&q o\Fͥ&45}ggGy 33 ##yxϼsy3!!yeݍy 33 3##yϙTT!P\Ly 333#y䝑wPZ\34'.#"32>%4>32#".'&H=^V]\==^U]\>&Z{yƆV'Z{xƆVvmStAPVokRq@MzUeΞc\ltmdʚ`Zkjy 3 4'.+';2+# ,SbΞ BՊΞ#)E?#-(WsB\94'.#"3267'764>32'#".'&PAaVde5=a[6{"Xg ([yb|b=U?ZLnd}b=rjVuAi{mdRvC)"teΞc?hVokRyu54&+ ##;2^R2Sמ3Ʀ"5LF(|wx- <732654.'.54632.#"#"&-s,G=Z7S%5H26!)ps2-G4S(@T?B*ۋGWr)L:9'* ))=CZ3êHq|^$>.+!! 13HNf8TX!!#!XD7##y3#"$'&5332>5-#zKe9g+rV?~ЇP3#3GBPT 333# #T+P3J 3 3 # #Jjc;˾^)'JLd3 3#LddBX<d!!!!Pliݍ#!!#3u`Z\!31 53#5!`@}5#'#35}VX5!XB獍`w!&'&547632#"c  "$  TbB +"32654&'254&#"'632#=#"&546ol`{h uEz"Nۋ+Dh6Fcgcfm1`+"hm{=>,Χ">32#".'#&"320Fd>e\..\f>dF-蠠ts-GA#]poŤ`#@E-LlF!.#"32>7#"&54>32xF+O6! z@Um;u(PmTr6)2c#60M)HA&Vj=zaI#3#5#".54>3232654&".Ed?RZ>.\e>dF0stR-E@#@lXpš]#AG-pbF"!.#"3267#".>32 pLw<[e I }##5354>32.#"3;X`':M+m((9V325332654&"FsM[e<\h-Fd>RZ>.\e>dF0Lstck;Agt8Wu!-E@#@lXpš]#AG-p!#3>32#4."rRd732>32#4.#"V+K3ژ/1L.tm+A+#HnrK/a1&/@$ihs;^dH<gN!#3>32#4."rRd732#".732>54.#"f9kia_Ɍa BoJIoB 7ab7wʗUZyDDyZyuuTN">32#".'#&"320Fd>e\..\f>dF-蠠ts1-GA#]poŤ`#@E-"I? N'3"&=".54>325332654&"4B5Ȝ[..\e>dF0Lst=5u͸y\anpš]#AG-pN&#"#3>32P1>Y{5qR*xw1Yy`HJ6.54672&#" #"&'732654.+ȔQR0 6Pu-52 ?"?%6!&ؗ&h\et&G? :Ab;-JG%zOG$<$  " .0="pCH`U(@-fP+#53533#;#"&5􎎗uFFx-uox13#5#".532>5rRd7=#".532>53L{MՖjg1^R2rRd7&67>7&#"327.'&'&'&Z@T! ,9F'+Z <.<"Y,'F:, (f}w"  P-M+>   " '@W} 33}R=532676=4>7&'&=4'&'.#"5@T! ,:F',Y <.?"Z+'F9, 'i|"  T+Q-9  " %R?3\>3232>7#".#"?1H$800: D7!!5D" ?403$B1+!-,+,--+^PN!.'&54>753&#"327#}k 8]`4cdZPkU~pPRZ< w,9L|M. W_Pz[!&S]jZ`4T'(#5332.#"!!!>7!>7j^I: g ^.P  &&(; TBTktFdQ}N! s *?w-w132654'.#""'#53&'&547#536253#3# cAKi bALidPP+;yPPy&B>QjK>Qj779F$gQ{77{4B%hWJu!5!3 33!!!#!5!DX1Ϙ7D6ׇLZ#53鏏{z+h,;632#"&'7;26754"#"&'&54>32.+"4'.#";2& ];S Ga - " N[avFF^!Q% Ö0,Wd #pX 7:nxH\S{QL4632#"&'&%4632#"&'&#8&!48&!4)8&!48&!4F&8+  '8+! &8+  '8+!)7(8#"&'&54632&"327%32654'.#"432#"&'&uCSJqyV[;N"L84!.sssu bC\GUy;R8& ,D%o&nŖ2)Ŗ+;^ 3# 3#ч^"#"!}#5!5!!͏mm^X,:M32>54'.#"4>32#".'&%32>54&5.+'32#'# Qlv;DtH Vpu5EtGu?gE& kʡ 3"/0]KRRq -dAR2,JuG$5aZ.(KzH&1^_ftR&߰96}U{8q "N:> ,?j!!?]j1=32654'.#"4632#"&'& N4=S N4=Svm^m^3AW?3BXBktY ltY'HPa+632#"'&'&54i$:!  ufh%#332>53#5#".) $.N5%.u:,E*(J+6L8'@QQ&b9D$yu,23"3"&#.'&54>;0GM*$)A/%=^^A0 s  !!6O2!5!   ,7O1*)b`3neE'{uqJ>54'.'7u'@8*J  "  .8>H 81,b;^ #!#^"#"#}"{R}'C'\$ R'rX$ Rq'A$ RJ'a$ R'i/$ R'pf1$ Sg!#!!!!!!53OFF{JxX'v&'C^( 'r`^( Z'A( 'i1( A'Cjs, 'rX, If'A, 9'iZ!, #53!2+324'.+!F}82⛝(,bhE^S5'a+1 f'CP2 f'r 2 fs'A2 fJ'a32 f'iB2 lJ7,-c,`,9%#7&'&54>3273#"'32>54'&' &#"J|/6[xczaE55\wc5VoYZ=#OIXYZ<)FokRvD2EmtRsB;LzTtod`&O}Txd'C=s8 'rs8 w'A8 'iB8 Vn'r^<  2>54'&!3 ##/WlC.E7gc&;b@&(SX>!\]G>32!"'732>54'.+"5;2>54'&#" #67,DXQ'+^eNPj[ ( ?d_?&$*Y)JsO3!  *-8cF:" ,GnA'h5{ $;`@o;xJ'%#CP7bzY ^l#'CD ^l'r;D ^l&AD ^l'ayLD ^l^'i^D ^lV'pD T`FWa"32654'.>32!32>7#".'#"&'&546326&74'&#"'>32!&'&#"i_"\mf:zd!aV8m'@5$,,5U8 ȘWR$ "AP'N55Q3^t /:X/Zl1$h(Ob4_Y^} - IG]~ 7nk 9 %71&7035,6+&'f(YsG9BmuV]vF'v F l+'C H l5'r9 H l&A5H l`'iH -/3#&'&547632#"!  "1$   #3#632#"'&'&54$1:!  s# 3##'#31^VR#3#4632#"&'&%4632#"&'&8&!48&!4)8&!48&!41&8+  '8+! &8+  '8+!R@32654'.#"#"&'&54324'.''7&#"'6327 Iqg;h9C ݠ)G/30 h8cGY)J7`.2u׆%sjMo$!8BҸHP$. )^1dFm'aXQ p''CR p1'rhR p&A3R p'a/R pZ'ioR w[& VJ 1 32>54'&'&#"7&'&54>3273#"'ATEj< ZASAh>! s7__1q9_c0DNNVD2?L{LWG+%YwZVKOZuQ\NN'CX 'rGX &A1/X b'iuX ?'rK\ +!#3>32#"./4'.#"326/DU4":[^8d6fD5hU5Jr)54ȢXeZkA.7]Rp6c4:jDAQDr'Ha>'Jq2[>| 0#53>32.#"!!!!3267#"&'#53&54'}q}M`2XQ<_,"i0E\>`<9[7&:K`3+ZJ MW+Da/!!zs) +[x    D   g y R   9  l ~ & & & k "-SCreated by Thatcher Ulrich (http://tulrich.com) with FontForge 1.0 (http://fontforge.sf.net) This font, including hint instructions, has been donated to the Public Domain. Do whatever you want with it. Created by Thatcher Ulrich (http://tulrich.com) with FontForge 1.0 (http://fontforge.sf.net) This font, including hint instructions, has been donated to the Public Domain. Do whatever you want with it. TuffyTuffyRegularRegularFontForge 1.0 : Tuffy Regular : 11-2-2007FontForge 1.0 : Tuffy Regular : 11-2-2007Tuffy RegularTuffy RegularVersion 001.100 Version 001.100 TuffyTuffyThatcher UlrichThatcher Ulrichhttp://tulrich.com http://tulrich.com http://tulrich.com http://tulrich.com Public Domain Public Domain MagerKursivNormalCursiva1KG=K9C@A82VanligKursivNormaleCursivoNormlDQltStandardKursivNormalItaliqueRegelmatigCursief2  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghjikmlnoqprsutvwxzy{}|~ softhyphen figuredash quotereverseduni201FEuro  latn ,latnkern6<BX^djtzq&79+Y\Z5)72$7$w$Xy$ (H$H$BD?qYWDQRWX\MuMP[MHMu$(*.2379:<?DHIJMRTU\?.grafx2_2.4+git20180105/share/grafx2/fonts/GrafX2_Dark.gif0000664000000000000000000000327713223665306021116 0ustar rootrootGIF89aN TTTTTTTTTTTTT̼|||lll\\\LLL<<<,,, |l\L<, ||ll\\LL<<,, |l\L<, ||ll\\LL<<,, |l\L<, ̼||ll\\LL<<,,  00@@TTddttxhTD4$ 00@@TTddttxhTD4$ 00@@TTddttxhTD4$<\|`@ <\|`@ <\|`@ 褈|Ԍp̀dtXhL\@P4D(|8p,`P@ ||(||@||X||p||||||||||||||||lll!,N Hp"<aÂ.48aň'bǎ nQdI'!eK/YqM7a攉N< J&PCSSG&$MO6UkTSV], ΦE[-۳ K-ݶw=߿k7]"b}GF츱1cŔ!3̗siҨGW6v≮K-pӉA6[ؽ[˕lj/g|^ȝسkw76xܭ/ok,;hԇ?-~u ^}y ڇ`Uhw)(yHa a٭ }ֵ8ߋȞnWQ(`fEyu\}ȟ&>ٕE:9oehb$b^~Q%lR9fy "y%XmYdY6&iuc}xz!r}cV!G7ۜeJW]tvrzYo'kn Vv Xp|jߢJ\ 鯸暌(禺jJʂ8&+j^J)#'v(xxmbi풭Viú!F;*bW(zkV٠Jb,é9񸑊k#o+3mq:,t J# W)x#:(BA:T[T}4V1alc\uXv^׍o ᢜuy7]r*iH Wm7-*Ra:(<Ϛ9c]2Qo&ŦpZ{ݬ3S9OZ}.q~+S~{}ήƍs?/;grafx2_2.4+git20180105/share/grafx2/fonts/PF_Tempesta_5_.png0000664000000000000000000000247413223665306021633 0ustar rootrootPNG  IHDR Qc[JPLTEIH"""fffBftEXtSoftwareGrafx2SjIDATXXr04j.uz6'?%kMsk:39Wfd#>GS|V y-_<_ sуM n}zl`_bp@aF\D]zzJ fڿynBiOpK^um+ϛe"`Oh=,':ws *A 4мn&gf x_1*E&s)v~DK_oInYPBLQ0'oK[DDxmS2wq%&z<|1_4_w=Mb8ⷲFt6\4yrB .@]6r&߱Qf*@U٨;bF$ЙBQoKލq,Q~ㄲꃩ3 YCL*_q0orA6lV=/Йa@ tn\Mk;-vIENDB`grafx2_2.4+git20180105/share/grafx2/fonts/PF_Ronda_7__.png0000664000000000000000000000314413223665306021250 0ustar rootrootPNG  IHDRdC8PLTEMM"""fff>!tEXtSoftwareGrafx2SjIDAThZn mmږ0-k6Ԁm{[e]??0WT x9cnzo3eyˢڙWI>ƆGgntV3p;ԧ2+a aLD+DhksQ"EW}ۈJ QFNK35r HV~nCA+'y?‡fbI y0F9q Ȭ^qR<#t=Hކ<؇0ucH4t?pt!(1//A;0\ BA$w9hy])"ʝ3A^`?1pLXpD^؄X|!djR}R N@ h6@(=<חڵy" ¦IqJ4Pnylʚ@%)1|.6M.9$*f(2V׶>C[WS]H0y< Cw(}Mh1Cm?lن~!ndBoM} p rƦ~oPiٺw+b#5WU|KG8 zX@)xfbns4J+};dϖK,1 f# IdԿiO@D>3I'\ 7yQGmbyIENDB`grafx2_2.4+git20180105/share/grafx2/fonts/PF_Easta_7__.png0000664000000000000000000000350013223665306021236 0ustar rootrootGIF89aMM"""fff!,௠ "Dh† *@ '^ԘbD<#E%7zH/CsD4e3%˘:R *cNDw&,T)ϡHJi)ԜRz#ז%jڳkKMUZ-:,IN㢕ѳYڽ[,F~ <È+^̸ǐ#KL˘3k̹ϛMӨS^ͺװc˞M6cѶs4ѿ=q?μ#.ێ+>⢗kPzC߃<vuuo?H '\ a "xh${Y}!vq'ތ'!{.GQ &:PH*& ;grafx2_2.4+git20180105/share/icons/0000775000000000000000000000000013223665306015155 5ustar rootrootgrafx2_2.4+git20180105/share/icons/grafx2.svg0000664000000000000000000005426113223665306017077 0ustar rootroot image/svg+xml grafx2_2.4+git20180105/doc/0000775000000000000000000000000013223665306013505 5ustar rootrootgrafx2_2.4+git20180105/doc/README-SDL_image.txt0000664000000000000000000000127213223665306016767 0ustar rootrootThe following file SDL_image.dll is the runtime environment for the library SDL_image 1.2.10 by Sam Lantiga and Mattias Engdegrd. This library is distributed under the terms of the GNU LGPL license: http://www.gnu.org/copyleft/lesser.html The source is available from the libraries page at the SDL website: http://www.libsdl.org/ ========================= Compiled by yrizoud on 16/06/2010 with static builds of : libjpeg (JPEG library http://www.ijg.org/ release 6b of 27-Mar-1998 : jpegsr6.zip) libtiff (TIFF library ftp://ftp.sgi.com/graphics/tiff/ : tiff-v3.4-tar.gz) And dynamic version of : libpng (http://www.libpng.org/pub/png/libpng.html) v1.4.2 --> libpng14-14.dll requirement grafx2_2.4+git20180105/doc/README-SDL_ttf.txt0000664000000000000000000000051113223665306016475 0ustar rootrootThe following files: SDL_ttf.dll libfreetype-6.dll are the runtime environment for the library SDL_ttf 2.0 by Sam Lantiga. This library is distributed under the terms of the GNU LGPL license: http://www.gnu.org/copyleft/lesser.html The source is available from the libraries page at the SDL website: http://www.libsdl.org/ grafx2_2.4+git20180105/doc/quickstart.rtf0000664000000000000000000020261013223665306016415 0ustar rootroot{\rtf1\ansi\ansicpg1252\uc1 \deff0\deflang1033\deflangfe1036{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;} {\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f14\fnil\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings;} {\f16\froman\fcharset238\fprq2 Times New Roman CE;}{\f17\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f19\froman\fcharset161\fprq2 Times New Roman Greek;}{\f20\froman\fcharset162\fprq2 Times New Roman Tur;} {\f21\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f22\fswiss\fcharset238\fprq2 Arial CE;}{\f23\fswiss\fcharset204\fprq2 Arial Cyr;}{\f25\fswiss\fcharset161\fprq2 Arial Greek;}{\f26\fswiss\fcharset162\fprq2 Arial Tur;} {\f27\fswiss\fcharset186\fprq2 Arial Baltic;}{\f28\fmodern\fcharset238\fprq1 Courier New CE;}{\f29\fmodern\fcharset204\fprq1 Courier New Cyr;}{\f31\fmodern\fcharset161\fprq1 Courier New Greek;}{\f32\fmodern\fcharset162\fprq1 Courier New Tur;} {\f33\fmodern\fcharset186\fprq1 Courier New Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255; \red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{\nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid \snext0 Normal;}{\s2\fi-432\li792\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx792\ls7\ilvl1\adjustright \b\i\f1\fs28\lang1036\cgrid \sbasedon0 \snext0 heading 2;}{\s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar \jclisttab\tx1440\ls7\ilvl2\adjustright \b\f1\fs26\lang1036\cgrid \sbasedon0 \snext0 heading 3;}{\*\cs10 \additive Default Paragraph Font;}{\s15\li200\nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid \sbasedon0 \snext0 \sautoupd toc 2;}{ \s16\li400\nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid \sbasedon0 \snext0 \sautoupd toc 3;}{\*\cs17 \additive \ul\cf2 \sbasedon10 Hyperlink;}{\*\cs18 \additive \ul\cf12 \sbasedon10 FollowedHyperlink;}}{\*\listtable{\list\listtemplateid575419804 {\listlevel\levelnfc255\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'00;}{\levelnumbers;}\fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext \'02\'01\'00;}{\levelnumbers\'01\'02;}\fi-432\li792\jclisttab\tx792 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'06\'00.\'01.\'02.;}{\levelnumbers\'01\'03\'05;}\fi-504\li1224\jclisttab\tx1440 }{\listlevel \levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'08\'00.\'01.\'02.\'03.;}{\levelnumbers\'01\'03\'05\'07;}\fi-648\li1728\jclisttab\tx1800 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0 {\leveltext\'0a\'00.\'01.\'02.\'03.\'04.;}{\levelnumbers\'01\'03\'05\'07\'09;}\fi-792\li2232\jclisttab\tx2520 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0c\'00.\'01.\'02.\'03.\'04.\'05.;}{\levelnumbers \'01\'03\'05\'07\'09\'0b;}\fi-936\li2736\jclisttab\tx2880 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0e\'00.\'01.\'02.\'03.\'04.\'05.\'06.;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\fi-1080\li3240 \jclisttab\tx3600 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'10\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\fi-1224\li3744\jclisttab\tx3960 }{\listlevel \levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'12\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08.;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fi-1440\li4320\jclisttab\tx4680 }{\listname ;}\listid470052352} {\list\listtemplateid-128001682{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\fi-360\li720\jclisttab\tx720 }{\listlevel\levelnfc4\leveljc0\levelfollow0\levelstartat1 \levelspace360\levelindent0{\leveltext\'02\'01.;}{\levelnumbers\'01;}\fi-360\li1440\jclisttab\tx1440 }{\listlevel\levelnfc2\leveljc2\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'02\'02.;}{\levelnumbers\'01;}\fi-180\li2160 \jclisttab\tx2160 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'02\'03.;}{\levelnumbers\'01;}\fi-360\li2880\jclisttab\tx2880 }{\listlevel\levelnfc4\leveljc0\levelfollow0\levelstartat1\levelspace360 \levelindent0{\leveltext\'02\'04.;}{\levelnumbers\'01;}\fi-360\li3600\jclisttab\tx3600 }{\listlevel\levelnfc2\leveljc2\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'02\'05.;}{\levelnumbers\'01;}\fi-180\li4320\jclisttab\tx4320 } {\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'02\'06.;}{\levelnumbers\'01;}\fi-360\li5040\jclisttab\tx5040 }{\listlevel\levelnfc4\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext \'02\'07.;}{\levelnumbers\'01;}\fi-360\li5760\jclisttab\tx5760 }{\listlevel\levelnfc2\leveljc2\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'02\'08.;}{\levelnumbers\'01;}\fi-180\li6480\jclisttab\tx6480 }{\listname ;}\listid767509828} {\list\listtemplateid427569282{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat2\levelspace0\levelindent0{\leveltext\'01-;}{\levelnumbers;}\fbias0 \fi-360\li720\jclisttab\tx720 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1 \levelspace0\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li2160 \jclisttab\tx2160 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1 \levelspace0\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li4320 \jclisttab\tx4320 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1 \levelspace0\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li6480 \jclisttab\tx6480 }{\listname ;}\listid1120421335}{\list\listtemplateid-1089596470{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 } {\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0 {\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li2160\jclisttab\tx2160 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880 \jclisttab\tx2880 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360 \levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li4320\jclisttab\tx4320 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040 \jclisttab\tx5040 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360 \levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li6480\jclisttab\tx6480 }{\listname ;}\listid1142233685}{\list\listtemplateid-2112569274{\listlevel\levelnfc255\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0 {\leveltext\'00;}{\levelnumbers;}\fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'01\'00;}{\levelnumbers\'01\'02;}\s2\fi-432\li792\jclisttab\tx792 }{\listlevel\levelnfc0 \leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'04\'00\'01.\'02;}{\levelnumbers\'01\'02\'04;}\s3\fi-504\li1224\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext \'08\'00.\'01.\'02.\'03.;}{\levelnumbers\'01\'03\'05\'07;}\fi-648\li1728\jclisttab\tx1800 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0a\'00.\'01.\'02.\'03.\'04.;}{\levelnumbers\'01\'03\'05\'07\'09;} \fi-792\li2232\jclisttab\tx2520 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0c\'00.\'01.\'02.\'03.\'04.\'05.;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\fi-936\li2736\jclisttab\tx2880 }{\listlevel \levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0e\'00.\'01.\'02.\'03.\'04.\'05.\'06.;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\fi-1080\li3240\jclisttab\tx3600 }{\listlevel\levelnfc0\leveljc0\levelfollow0 \levelstartat1\levelspace0\levelindent0{\leveltext\'10\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\fi-1224\li3744\jclisttab\tx3960 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0 \levelindent0{\leveltext\'12\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08.;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fi-1440\li4320\jclisttab\tx4680 }{\listname ;}\listid1531260534}{\list\listtemplateid-1005028302{\listlevel\levelnfc23\leveljc0 \levelfollow0\levelstartat2\levelspace0\levelindent0{\leveltext\'01-;}{\levelnumbers;}\fbias0 \fi-360\li720\jclisttab\tx720 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li2160\jclisttab\tx2160 }{\listlevel\levelnfc23\leveljc0\levelfollow0 \levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li4320\jclisttab\tx4320 }{\listlevel\levelnfc23\leveljc0\levelfollow0 \levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li6480\jclisttab\tx6480 }{\listname ;}\listid1703751460} {\list\listtemplateid2045416826{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listlevel\levelnfc23\leveljc0\levelfollow0 \levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;} \f14\fbias0 \fi-360\li2160\jclisttab\tx2160 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880 }{\listlevel\levelnfc23\leveljc0 \levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext \'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li4320\jclisttab\tx4320 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040 } {\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0 {\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li6480\jclisttab\tx6480 }{\listname ;}\listid1926844993}}{\*\listoverridetable{\listoverride\listid767509828\listoverridecount0\ls1}{\listoverride\listid1703751460\listoverridecount0\ls2} {\listoverride\listid1926844993\listoverridecount0\ls3}{\listoverride\listid1142233685\listoverridecount0\ls4}{\listoverride\listid1120421335\listoverridecount0\ls5}{\listoverride\listid470052352\listoverridecount0\ls6}{\listoverride\listid1531260534 \listoverridecount0\ls7}}{\info{\title Getting started}{\author vig}{\operator vig}{\creatim\yr2009\mo12\dy24\hr18\min58}{\revtim\yr2010\mo1\dy18\min10}{\version5}{\edmins34}{\nofpages7}{\nofwords2810}{\nofchars16017}{\*\company }{\nofcharsws0}{\vern73}} \paperw11906\paperh16838\margl1417\margr1417\margt1417\margb1417 \deftab708\widowctrl\ftnbj\aenddoc\hyphhotz425\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\formshade\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot \fet0\sectd \linex0\headery709\footery709\colsx709\endnhere\sectdefaultcl {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4 \pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (} {\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 \par }\pard \qc\nowidctlpar\widctlpar\adjustright {\fs96\lang1033 Grafx2 \par }{\fs48\lang1033 Quick start guide \par }\pard \nowidctlpar\widctlpar\adjustright {\lang1033 \par \par }\pard\plain \s15\li200\nowidctlpar\widctlpar\tx600\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\field\fldedit{\*\fldinst {\lang1033 TOC \\o "1-3" \\h \\z \\u }}{\fldrslt {\lang1033 1\tab Introduction\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444332 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300330032000000}}}{\fldrslt {\lang1024 3}}}{\lang1033 \par 2\tab Fundamentals\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444333 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300330033000000}}}{\fldrslt {\lang1024 3}}}{ \lang1033 \par }\pard\plain \s16\li400\nowidctlpar\widctlpar\tx1000\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 2.1\tab Indexed colors\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444334 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300330034000000}}}{\fldrslt {\lang1024 3}}}{\lang1033 \par 2.2\tab 2-button drawing\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444335 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300330035000000}}}{\fldrslt {\lang1024 3}}} {\lang1033 \par 2.3\tab Brushes\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444336 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300330036000000}}}{\fldrslt {\lang1024 3}}}{ \lang1033 \par 2.4\tab Drawing tools (general)\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444337 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300330037000000}}}{\fldrslt { \lang1024 4}}}{\lang1033 \par 2.5\tab Spare page\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444338 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300330038000000}}}{\fldrslt {\lang1024 4}}}{ \lang1033 \par 2.6\tab Drawing effects\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444339 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300330039000000}}}{\fldrslt {\lang1024 4}}}{ \lang1033 \par }\pard\plain \s15\li200\nowidctlpar\widctlpar\tx600\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 3\tab Helpers\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444340 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300340030000000}}}{\fldrslt {\lang1024 4}}}{\lang1033 \par }\pard\plain \s16\li400\nowidctlpar\widctlpar\tx1000\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 3.1\tab Contextual help\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444341 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300340031000000}}}{\fldrslt {\lang1024 4}}}{\lang1033 \par 3.2\tab Keyboard shortcuts\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444342 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300340032000000}}}{\fldrslt {\lang1024 5} }}{\lang1033 \par 3.3\tab Use the spare page to store parts you will need later\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444343 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300340033000000}}}{\fldrslt {\lang1024 5}}}{\lang1033 \par 3.4\tab Use the color picker\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444344 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300340034000000}}}{\fldrslt {\lang1024 5}}}{\lang1033 \par 3.5\tab Magnifier (Zoom)\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444345 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300340035000000}}}{\fldrslt {\lang1024 5}}} {\lang1033 \par 3.6\tab I made a mistake: Undo / Redo\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444346 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300340036000000}}}{\fldrslt { \lang1024 5}}}{\lang1033 \par }\pard\plain \s15\li200\nowidctlpar\widctlpar\tx600\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 4\tab Customization\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444347 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300340037000000}}}{\fldrslt {\lang1024 6}}}{\lang1033 \par }\pard\plain \s16\li400\nowidctlpar\widctlpar\tx1000\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 4.1\tab Keyboard shortcuts\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444348 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300340038000000}}}{\fldrslt {\lang1024 6}}}{\lang1033 \par 4.2\tab Settings\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444349 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300340039000000}}}{\fldrslt {\lang1024 6}}}{ \lang1033 \par 4.3\tab Bookmark directories\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444350 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300350030000000}}}{\fldrslt {\lang1024 6}}}{\lang1033 \par 4.4\tab Skinability\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444351 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300350031000000}}}{\fldrslt {\lang1024 6}}}{ \lang1033 \par }\pard\plain \s15\li200\nowidctlpar\widctlpar\tx600\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 5\tab Drawing tools (detailed)\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444352 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300350032000000}}}{\fldrslt {\lang1024 6}}}{\lang1033 \par 6\tab Palette manipulation\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444353 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300350033000000}}}{\fldrslt {\lang1024 6} }}{\lang1033 \par }\pard\plain \s16\li400\nowidctlpar\widctlpar\tx1000\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 6.1\tab Using shade mode and defining your color ranges\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444354 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300350034000000}}}{\fldrslt {\lang1024 6}}}{\lang1033 \par 6.2\tab Converting images (remapping)\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444355 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300350035000000}}}{\fldrslt { \lang1024 6}}}{\lang1033 \par 6.3\tab Color replacer tool\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444356 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300350036000000}}}{\fldrslt {\lang1024 6 }}}{\lang1033 \par }\pard\plain \s15\li200\nowidctlpar\widctlpar\tx600\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 7\tab Tiles and game mockups\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444357 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300350037000000}}}{\fldrslt {\lang1024 7}}}{\lang1033 \par }\pard\plain \s16\li400\nowidctlpar\widctlpar\tx1000\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 7.1\tab Grid mode\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444358 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300350038000000}}}{\fldrslt {\lang1024 7}}}{\lang1033 \par }\pard\plain \s15\li200\nowidctlpar\widctlpar\tx600\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 8\tab Bitmap effects\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444359 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300350039000000}}}{\fldrslt {\lang1024 7}}}{\lang1033 \par }\pard\plain \s16\li400\nowidctlpar\widctlpar\tx1000\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 8.1\tab Text\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444360 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300360030000000}}}{\fldrslt {\lang1024 7}}}{\lang1033 \par 8.2\tab Outline, nibble\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444361 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300360031000000}}}{\fldrslt {\lang1024 7}}}{ \lang1033 \par 8.3\tab Mirror\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444362 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300360032000000}}}{\fldrslt {\lang1024 7}}}{ \lang1033 \par 8.4\tab Resize\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444363 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300360033000000}}}{\fldrslt {\lang1024 7}}}{ \lang1033 \par 8.5\tab Rotate\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444364 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300360034000000}}}{\fldrslt {\lang1024 7}}}{ \lang1033 \par 8.6\tab Distort\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444365 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300360035000000}}}{\fldrslt {\lang1024 7}}}{ \lang1033 \par }\pard\plain \s15\li200\nowidctlpar\widctlpar\tx600\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 9\tab Low resolution art\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444366 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300360036000000}}}{\fldrslt {\lang1024 7}}}{\lang1033 \par }\pard\plain \s16\li400\nowidctlpar\widctlpar\tx1000\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 9.1\tab Pixel scalers\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444367 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300360037000000}}}{\fldrslt {\lang1024 7}}}{\lang1033 \par 9.2\tab Mouse sensitivity\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444368 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300360038000000}}}{\fldrslt {\lang1024 7} }}{\lang1033 \par }\pard\plain \s15\li200\nowidctlpar\widctlpar\tx800\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 10\tab Low colors\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444369 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300360039000000}}}{\fldrslt {\lang1024 7}}}{\lang1033 \par }\pard\plain \s16\li400\nowidctlpar\widctlpar\tx1000\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 10.1\tab Customize the menu palette\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444370 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300370030000000}}}{\fldrslt {\lang1024 7}}}{\lang1033 \par 10.2\tab Less than 256 values in RGB components\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444371 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300370031000000}} }{\fldrslt {\lang1024 8}}}{\lang1033 \par }\pard\plain \s15\li200\nowidctlpar\widctlpar\tx800\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 11\tab Layers\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444372 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300370032000000}}}{\fldrslt {\lang1024 8}}}{\lang1033 \par }\pard\plain \s16\li400\nowidctlpar\widctlpar\tx1000\tqr\tldot\tx9062\adjustright \fs20\lang1036\cgrid {\lang1033 11.1\tab System of transparency\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444373 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300370033000000}}}{\fldrslt {\lang1024 8}}}{\lang1033 \par 11.2\tab User interface\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444374 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300370034000000}}}{\fldrslt {\lang1024 8}}}{ \lang1033 \par 11.3\tab File formats\tab }{\field{\*\fldinst {\lang1033 PAGEREF _Toc249444375 \\h }{\lang1033 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003200340039003400340034003300370035000000}}}{\fldrslt {\lang1024 8}}}{ \lang1033 \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid }}\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 \par {\*\bkmkstart _Toc249444332}{\listtext\pard\plain\s2 \b\i\f1\fs28\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 1\tab}}\pard\plain \s2\fi-432\li792\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx792\ls7\ilvl1\outlinelevel1\adjustright \b\i\f1\fs28\lang1036\cgrid {\lang1033 Introduction{\*\bkmkend _Toc249444332} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 This guide is designed to help people get comfortable with Grafx2, it's recommended to read the table of contents and the fundamentals, scanning q uickly when you're already familiar with a concept, only stopping to read in-depth details when something surprising or interesting catches your eye. \par Each chapter begins with basic information. \par }{\i\lang1033 \par Then there are advanced details and techniques, in italic. You can safely ignore them until you are confident in using the basics. \par }{\lang1033 \par This document tries to avoid repeating lengthy explanations that belong to the user manual, so if you wonder where is a tool or what it does, please refer to the manual itself or Grafx2's contextual help. \par \par {\*\bkmkstart _Toc249444333}{\listtext\pard\plain\s2 \b\i\f1\fs28\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 2\tab}}\pard\plain \s2\fi-432\li792\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx792\ls7\ilvl1\outlinelevel1\adjustright \b\i\f1\fs28\lang1036\cgrid {\lang1033 Fundamentals{\*\bkmkend _Toc249444333} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 By default when you run Grafx2, it starts a new image as large as the program\rquote s window, with a default 256-color palette. \par To change the canvas dimensions, click the Resolution icon, then click the image Width or Height to change it and click OK. \par When an image is bigger than the editing window, you can use the cursor keys to scroll the view. \par To load or save an image, use the Load/Save icon \par To exit the program, press the \lquote Quit\rquote icon, on the right edge of the tool bar. Grafx2 will propose to save your changes, if you have not saved yet. \par {\*\bkmkstart _Toc249444334}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 2.1\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Indexed colors{\*\bkmkend _Toc249444334} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 Grafx2 is made for drawing with a system called indexed colors. This means that your image defines a palette of colors, 256 at most, and when you draw with \'93red\'94, or \'93black\'94, in fact the program remember which color number you used. The big difference with a program like MS Paint or Gimp is that you can later alter your image\rquote s palette, and this will affect all the places where you used the modified colors. \par A typical file format for indexed colors is GIF. \par \par }{\i\lang1033 See the chapter \lquote Palette manipulation\rquote for useful palette actions. \par Grafx2 can import 24bit images fr om a few file formats such as Jpeg, creating a custom palette by selecting 256 colors using a mathematical method (Median cut in the RGB color space) Be aware that the result can never be good with photographic images and the like, it\rquote s mostly useful to convert screenshots of computer applications. \par Grafx2 saves only indexed colors formats: for example it uses the PNG variant which keeps the palette. \par {\*\bkmkstart _Toc249444335}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 2.2\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Two-button drawing{\*\bkmkend _Toc249444335} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 Usually, clicking on the image with the left mouse button paints with the foreground color (FG), and clicking with the right mouse button paints with the background colors (BG). Some other tools will use left click for confirm and right to cancel/stop. In any case, it\rquote s rare to get the same effect from left-clicking and right-clicking, and the right mouse button is as useful as the left one. \par The current FG and BG are shown next to the palette, and clicking on the palette itself with the left and right mouse button will set the FG and BG colors, respectively. \par Setting two useful colors can save you a lot of time when drawing, as you won\rquote t need to change the active color so often. \par \par }{\i\lang1033 If you have a third mouse button, it\rquote s not used for drawing. You can assign a shortcut to the button and to wheel movements to perform punctual actions, for example to activate the color picker or the magnifier. \par {\*\bkmkstart _Toc249444336}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 2.3\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Brushes{\*\bkmkend _Toc249444336} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 The program allows you to draw using single pixels, of course. \par You can also use one of the built-in monochrome shapes, like circles, squares, horizontal lines etc. They are called monochrome because they automatically use your foreground and background colors when drawing. \par To select a monochrome brush, open the Paintbrush window and click the button with the shape you want to use. Note that the single pixel is proposed, top left. \par \par The last type is the Color Brush, often called simply \'93brush\'94. It\rquote s a group of colored pixels that you get by grabbing with the rectangular grab tool, or the freeh and grab. You can use a color brush to draw a texture, or displace part of a picture for example. \par Note that the current Background color acts as transparent for your brush: pixels of this color will not be drawn. Drawing with the right mouse button will paste the background color only, in the shape of your brush. \par \par In the toolbar, the paintbrush icon shows which brush you\rquote re currently using. A special symbol indicates when you\rquote re using a color brush. \par \par }{\i\lang1033 The monochrome brushes are resizable, you can use shortcuts xxx and xxx to increase and decrease your current brush\rquote s size. This allows you to pick sizes that are not available in the Paintbrush screen. \par A very useful shortcut sets the paintbrush to single-pixel: DEL. (actually it\rquote s a circle of size 1) \par Many actions can be performed on the color brush, see the Brush FX menu. \par You can use your color brush in monochrome mode by right-clicking the Paintbrush icon. It does not alter the brush contents, only the way it\rquote s displayed and drawn. \par Right-clicking the \lquote pick brush\rquote icon recovers the last color brush you had. This is useful after using a built-in monochrome brush, or after turning your brush monochrome. \par {\*\bkmkstart _Toc249444337}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 2.4\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Drawing tools (general){\*\bkmkend _Toc249444337} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 A lot of drawing tools work by pasting your brush repeatedly at several positions: \par {\listtext\pard\plain\f3\fs20\lang1033\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\nowidctlpar\widctlpar\jclisttab\tx720\ls3\adjustright {\lang1033 at all the mouse positions (freehand drawing), \par {\listtext\pard\plain\f3\fs20\lang1033\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}in straight lines from one position to the next, \par {\listtext\pard\plain\f3\fs20\lang1033\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}outlining a circle, etc. \par }\pard \nowidctlpar\widctlpar\adjustright {\lang1033 While such tool is active, the current brush is shown \'93stuck\'94 under your mouse cursor, as a preview. \par The current brush is not shown when you\rquote re using \'93Flood fill\'94 and other tools that don\rquote t use your current brush. \par \par }{\i\lang1033 A more in-depth description of drawing tools is in Drawing tools (detailed), but feel free to experiment. Some tools work by single clic k, or while dragging the mouse and releasing; but a few ones use a more complicated series of clicks. If the usage or effect of a tool is not clear, use the contextual help on its button to get immediate information. \par {\*\bkmkstart _Toc249444338}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 2.5\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Spare page{\*\bkmkend _Toc249444338} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 Grafx2 keeps two different images open at the same time. The image you see is called the \'93Main page\'94, and the one you don\rquote t see is called the \'93Spare page\'94 . You can exchange them by clicking the icon xxx or using the shortcut TAB : The Spare becomes the Main (and visible), the Main becomes the Spare (hidden). \par When editing a single image, the spare is often used as \'93rough paper\'94, to save pieces of your main image or brushes, for future use. \par The program keeps track of them independently: file name, modified since last save, history of modifications for undo/redo, etc. Their palette can be different, but then a brush that you grab in an image will look different in another. \par {\*\bkmkstart _Toc249444339}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 2.6\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Drawing effects{\*\bkmkend _Toc249444339} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 Grafx2 has a system of Effects, allowing you for example to darken a piece of picture, or protect some colors against drawing on them. \par If drawing doesn't seem to give the right colors, maybe it's because you have accidentally activated an effect : Check the Effects screen. \par When an effect is active, the 'FX' button appears pressed, though it's not very noticeable. \par \par }{\i\lang1033 This guide will describe some of the effects, when they are most relevant \par {\*\bkmkstart _Toc249444340}{\listtext\pard\plain\s2 \b\i\f1\fs28\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 3\tab}}\pard\plain \s2\fi-432\li792\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx792\ls7\ilvl1\outlinelevel1\adjustright \b\i\f1\fs28\lang1036\cgrid {\lang1033 Helpers{\*\bkmkend _Toc249444340} \par {\*\bkmkstart _Toc249444341}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 3.1\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Contextual help{\*\bkmkend _Toc249444341} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 There are extensive help scre ens for all drawing tools and all windows. By default, the associated key is F1. If a specific window was open, it will show the explanations about this window. When no window is open, and your mouse cursor is positioned over one of the buttons of the too lbar, it will show the help for this tool (and/or the related options window) \par The help screens also show the current keyboard shortcuts, and allow you to change them immediately. \par {\*\bkmkstart _Toc249444342}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 3.2\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Keyboard shortcuts{\*\bkmkend _Toc249444342} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 There are more than a hundred actions which can have a shortcut key. As soon as you have found the functions you use a lot, it\rquote s recommended to check the associated shortcut key, this can save you a lot of back-and-forth between the toolbar and the drawing area. If the default key combination doesn\rquote t suit you, redefine it. \par To view a shortcut, open the relevant page of contextual help: the highlighted key names are the actual shortcuts with your current configuration. Click the name to edit the shortcut. \par \par }{\i\lang1033 Some shortcuts which are often useful: \par }\pard \li708\nowidctlpar\widctlpar\tx3261\adjustright {\i\lang1033 Scroll picture:\tab cursor arrows \par Magnifier:\tab M \par Zoom in/out when magnified:\tab + and - \par Grab brush:\tab B \par Choose single-pixel brush\tab DEL \par Color picker:\tab ~ \par Swap to spare:\tab TAB \par }\pard \nowidctlpar\widctlpar\adjustright {\i\lang1033 The keys SHIFT, ALT, CONTROL, and META (on Mac) can be used to make more combinations \endash so you can\rquote t associate anything to \'93just Shift\'94. \par With a wheel mouse, you can also associate shortcuts to the third button (\'93Mouse3\'94), and to WheelUp and WheelDown. Again, Control, Shift etc. can be used to make more combination s. You can set at most 2 key combinations for the same shortcut, so for example you can associate both ~ and Mouse3 to the Colorpicker tool. \par {\*\bkmkstart _Toc249444343}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 3.3\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Use the spare page to store parts you will need later{\*\bkmkend _Toc249444343} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 The spare page is very handy to store pieces of your main image. For example you can pick a part of your image with the rectangular brush tool, paste it somewhere in the spare over a solid color background, clean out the background (still on the spare) until it has just the contour you need, then grab it again, and switch back to the original Main page: you will have a clean brush with no leftover pixels, that you can paste anywhere. \par {\*\bkmkstart _Toc249444344}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 3.4\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Use the color picker{\*\bkmkend _Toc249444344} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 There is a color picker tool (also called pipette) to pick a color from the picture. By default the shortcut is the easy-to-reach ~ key. Using it can spare a lot of time, especially when your palette has more colors than can be displayed in the toolbar\rquote s palette. \par While the tool is active, you have a specific mouse cursor, and the status bar displays both the color you\rquote re currently highlighting and its RGB values. Click with left mouse button to pick \par {\*\bkmkstart _Toc249444345}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 3.5\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Magnifier (Zoom){\*\bkmkend _Toc249444345} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 A magnifier is available to zoom in on your picture. It\rquote s very u seful to draw on detailed parts of picture, without needing extreme mouse precision, and easier on your eyes. \par Activate it or disable by clicking the magnifying glass icon. \par While active, your editing area is split in two, with the normal view on the left and the zoomed-in part on the right. You can drag the separator bar to adjust the proportions. \par You can draw in either areas, both update in real time. \par If the mouse cursor is over the picture when you use the keyboard shortcut of the magnifier (default: M), Grafx2 instantly zooms and centers the zoomed part on the place where your mouse cursor was. \par By default, the cursor arrows are used to scroll the zoomed area around. \par {\*\bkmkstart _Toc249444346}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 3.6\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 I made a mistake: Undo / Redo{\*\bkmkend _Toc249444346} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 Your drawing actions are memori zed, so you can easily Undo any number of drawing steps, and Redo them if you go too far in history. A single step is generally all the changes you do from the moment you click on the picture, to the moment you release the mouse button. \par To Undo or Redo, click the \'93Oops\'94 with the left mouse button and the right mouse button, respectively. \par \par }{\i\lang1033 The maximum number of steps that can be recorded is in the settings, you can go up to 99. \par The system uses a circular buffer, so it behaves a bit different from usual: When you Undo until you reach the oldest step and then Undo once more, you\rquote re back on the more recent step. \par {\*\bkmkstart _Toc249444347}{\listtext\pard\plain\s2 \b\i\f1\fs28\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 4\tab}}\pard\plain \s2\fi-432\li792\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx792\ls7\ilvl1\outlinelevel1\adjustright \b\i\f1\fs28\lang1036\cgrid {\lang1033 Customization{\*\bkmkend _Toc249444347} \par {\*\bkmkstart _Toc249444348}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 4.1\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Keyboard shortcuts{\*\bkmkend _Toc249444348} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 Don\rquote t hesitate to change the keyboard shortcuts to ones that are easy to use and remember for you. The default configuration is a lot like Deluxe Paint, but not many people are used to it. \par {\*\bkmkstart _Toc249444349}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 4.2\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Settings{\*\bkmkend _Toc249444349} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 Some general program settings are available in the Settings screen \par A few other, less-used ones can be defined in the file gfx2.ini, that you can check and modify with a text editor. This file is located in %appdata%\\Grafx2 (Windows) or ~/.grafx2 (Linux), and self-documented with comments. \par This file, as well as gfx2.cfg which contains for example the keyboard shortcuts, are defined for each user of your computer and automatically re-created with default values when they are missing. \par }{\i\lang1033 \par (Windows) You can carry Grafx2 on a flash drive and use it on any computer by simply copying the program\rquote s directory on your flash drive, and adding the two files gfx2.cfg and gfx2.ini with the executable. In this case, Grafx2 will not read or write configuration files on the computer\rquote s hard disk when running, leaving no trace. \par {\*\bkmkstart _Toc249444350}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 4.3\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Bookmark directories{\*\bkmkend _Toc249444350} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 The file selector windows have little icons with stars in them. They are used as bookmarks, to quickly change to a directory. This is useful to memorize the usual places where you need to read and write images. \par Left-click a bookmark to use it, \par Right-click (and hold) a bookmark to open a dropdown menu to set it (store the current directory). \par {\*\bkmkstart _Toc249444351}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 4.4\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 Skinability{\*\bkmkend _Toc249444351} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 Several sets of icons are available, and you c an make your own (or only modify the icon or mouse cursor that you find annoying). The skins and the fonts are stored in the program\rquote s directory under \'93skins\'94. They are plain image files, so you can edit them\'85 in Grafx2 for example. (You can reload the skin without leaving Grafx2) \par There are many graphical constraints, such as using only 4 colors for GUI elements; but don\rquote t worry, Grafx2 will check everything before loading, and if there\rquote s something it doesn\rquote t like, it will cancel the loading and display a ve ry verbose message, telling you exactly what pixel is the problem. \par {\*\bkmkstart _Toc249444352}{\listtext\pard\plain\s2 \b\i\f1\fs28\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 5\tab}}\pard\plain \s2\fi-432\li792\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx792\ls7\ilvl1\outlinelevel1\adjustright \b\i\f1\fs28\lang1036\cgrid {\lang1033 Drawing tools (detailed){\*\bkmkend _Toc249444352} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 \par {\*\bkmkstart _Toc249444353}{\listtext\pard\plain\s2 \b\i\f1\fs28\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 6\tab}}\pard\plain \s2\fi-432\li792\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx792\ls7\ilvl1\outlinelevel1\adjustright \b\i\f1\fs28\lang1036\cgrid {\lang1033 Palette manipulation{\*\bkmkend _Toc249444353} \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 6.1\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444354}Using shade mode and defining your color ranges{\*\bkmkend _Toc249444354} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 6.2\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444355}Converting images (remapping){\*\bkmkend _Toc249444355} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 6.3\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444356}Color replacer tool{\*\bkmkend _Toc249444356} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 \par {\*\bkmkstart _Toc249444357}{\listtext\pard\plain\s2 \b\i\f1\fs28\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 7\tab}}\pard\plain \s2\fi-432\li792\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx792\ls7\ilvl1\outlinelevel1\adjustright \b\i\f1\fs28\lang1036\cgrid {\lang1033 Tiles and game mockups{\*\bkmkend _Toc249444357} \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 7.1\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444358}Grid mode{\*\bkmkend _Toc249444358} \par {\*\bkmkstart _Toc249444359}{\listtext\pard\plain\s2 \b\i\f1\fs28\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 8\tab}}\pard\plain \s2\fi-432\li792\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx792\ls7\ilvl1\outlinelevel1\adjustright \b\i\f1\fs28\lang1036\cgrid {\lang1033 Bitmap effects{\*\bkmkend _Toc249444359} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 A very common technique with Grafx2 is to grab a brush, alter it, and paste it somewhere else. \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 8.1\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444360}Text{\*\bkmkend _Toc249444360} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 8.2\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444361}Outline, nibble{\*\bkmkend _Toc249444361} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 8.3\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444362}Mirror{\*\bkmkend _Toc249444362} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 8.4\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444363}Resize{\*\bkmkend _Toc249444363} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 8.5\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444364}Rotate{\*\bkmkend _Toc249444364} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 8.6\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444365}Distort{\*\bkmkend _Toc249444365} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 \par {\*\bkmkstart _Toc249444366}{\listtext\pard\plain\s2 \b\i\f1\fs28\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 9\tab}}\pard\plain \s2\fi-432\li792\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx792\ls7\ilvl1\outlinelevel1\adjustright \b\i\f1\fs28\lang1036\cgrid {\lang1033 Low resolution art{\*\bkmkend _Toc249444366} \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 9.1\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444367}Pixel scalers{\*\bkmkend _Toc249444367} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 LCD displays look very bad when using something else than their native resolutions, and low resolutions are very rarely supported or proposed. \par If you find yourself squinting at your screen because pixels are too small and too close, Grafx2 can scale its own display to x2, x3 and x4, thus giving larger pixel units. This works as well in full screen mode than in a window. The whole display area of Grafx2 gets zoomed in: mouse cursor, menus, fonts. Since Grafx2 was designed in the era of MCGA, the minimum resolution for GUI windows is 320x200, so if you're running in 1024x768 you can scale to x3, You need at least 1280x800 to scale x4. \par The scaling is done in software, so you won't get any blurring (linear interpolation). \par \par In addition, Grafx2 can propose some non-square modes where it zooms differently on each axis: Wide modes and Tall modes. \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 9.2\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444368}Mouse sensitivity{\*\bkmkend _Toc249444368} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 \par {\*\bkmkstart _Toc249444369}{\listtext\pard\plain\s2 \b\i\f1\fs28\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 10\tab}}\pard\plain \s2\fi-432\li792\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx792\ls7\ilvl1\outlinelevel1\adjustright \b\i\f1\fs28\lang1036\cgrid {\lang1033 Low colors{\*\bkmkend _Toc249444369} \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 10.1\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444370}Customize the menu palette{\*\bkmkend _Toc249444370} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 The little palette on the bottom right of the menu displays 64 colors by default. If you\rquote re working on 16-color graphics, \'be of the space is wasted. So, Gafx2 allows you to set the number of colors in this palette : less colors will mean bigger buttons, which are more comfortable to use. \par To edit this setting, open the \lquote Secondary palette menu\rquote , by right-clicking the \lquote Pal\rquote icon. \par You can set the number of rows, the number of columns, and if the colors are ordered from left to right, or from top to bottom. \par {\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 10.2\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 \tab {\*\bkmkstart _Toc249444371}Less than 256 values in RGB components{\*\bkmkend _Toc249444371} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 By default, Grafx2 allows you to set RGB values of palette with 256 levels of precision, but if you are drawing graphics for older technologies (or inspired by them), you may want a rougher scale: the relevant setting is \'93}{\ul\lang1033 RGB scale}{ \lang1033 \'94. \par To edit this setting, open the \lquote Secondary palette menu\rquote , by right-clicking the \lquote Pal\rquote icon. \par Example values that you can use are 64 (VGA) 16 (classic Commodore Amiga, 4096 combinations), or even 3 (Amstrad CPC) \par A smaller scale means that the RGB sliders in the palette are more blocky, they move by bigger units, and they show numbers from zero to 'scale' minus 1. \par In HSV mode, the palette sliders are not affected, however the program will really search the closest-match RGB by taking the setting into account. \par {\*\bkmkstart _Toc249444372}{\listtext\pard\plain\s2 \b\i\f1\fs28\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 11\tab}}\pard\plain \s2\fi-432\li792\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx792\ls7\ilvl1\outlinelevel1\adjustright \b\i\f1\fs28\lang1036\cgrid {\lang1033 Layers{\*\bkmkend _Toc249444372} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\lang1033 Layers are a late addition to Grafx2, so don\rquote t be surprised if the functions seem a bit separate from the rest of the program. \par The concept of layers in Grafx2 is exactly the same as in Gimp, Photoshop etc. Here's a tentative introduction: \par \par }\pard \li708\nowidctlpar\widctlpar\adjustright {\lang1033 An image is made of several images of same dimensions, placed on top of each others (the 'layers'). The transparent parts in a layer allow you to see the layer directly below, and the complete image is what you see when looking down from the top. \par \par }\pard \nowidctlpar\widctlpar\adjustright {\lang1033 As you can edit each layer separately, designing your image as layers will allow you to modify/displace an element in the foreground without having to redraw the background, since the background is memorized in its own unchanged layer. \par For more beginner explanations, try searching online tutorials on \'93using layers\'94. \par }{\i\lang1033 \par An understanding of the concept of layers is assumed for the following sub-chapters. \par {\*\bkmkstart _Toc249444373}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 11.1\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 System of transparency{\*\bkmkend _Toc249444373} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\i\lang1033 Grafx2 handles layer transparency by marking a single color as t ransparent, for example color 0. All pixels drawn with this color are considered fully transparent; all other colors are considered fully opaque. No values in-between are possible, so no alpha channel is used. The result is like a 1-bit alpha channel, but a color is reserved, so you can only draw in 255 colors when using layers \endash except in the bottom layer, where this color is shown anyway in Grafx2.There is no eraser tool, because anything that paints with the transparent color will actually erase : you ca n erase with a monochrome brush of any size, with a filled circle, or with a polygon ! \par {\*\bkmkstart _Toc249444374}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 11.2\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 User interface{\*\bkmkend _Toc249444374} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\i\lang1033 The layer-specific tools are located in an optional toolbar that can be shown or hidden. \par To open the layer toolbar, left-click the button on the status bar. \par In the layer toolbar, you can see: \par {\listtext\pard\plain\fs20\lang1033\cgrid \hich\af0\dbch\af0\loch\f0 -\tab}}\pard \fi-360\li720\nowidctlpar\widctlpar\jclisttab\tx720\ls5\adjustright {\i\lang1033 how many layers you have : the numbered buttons \par {\listtext\pard\plain\fs20\lang1033\cgrid \hich\af0\dbch\af0\loch\f0 -\tab}which one is the active layer where you draw : white button \par {\listtext\pard\plain\fs20\lang1033\cgrid \hich\af0\dbch\af0\loch\f0 -\tab}which layers are temporarily hidden : black buttons. \par }\pard \nowidctlpar\widctlpar\adjustright {\i\lang1033 \par {\*\bkmkstart _Toc249444375}{\listtext\pard\plain\s3 \b\f1\fs26\lang1033\cgrid \hich\af1\dbch\af0\loch\f1 11.3\tab}}\pard\plain \s3\fi-504\li1224\sb240\sa60\keepn\nowidctlpar\widctlpar\jclisttab\tx1440\ls7\ilvl2\outlinelevel2\adjustright \b\f1\fs26\lang1036\cgrid {\lang1033 File formats{\*\bkmkend _Toc249444375} \par }\pard\plain \nowidctlpar\widctlpar\adjustright \fs20\lang1036\cgrid {\i\lang1033 Only GIF supports layers at this moment. If you use any other format to save your layered image, the layer data will be lost and only the flattened image will be saved. (Grafx2 reminds you when you do). \par If you use PNG or GIF transparency, then the transparent color of layers will also act as transparent in all editing programs and web browsers that display your image. \par \par }}grafx2_2.4+git20180105/doc/gpl-2.0.txt0000664000000000000000000004310313223665306015326 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. grafx2_2.4+git20180105/doc/COMPILING.txt0000664000000000000000000002314113223665306015570 0ustar rootrootGrafx2 compilation and installation =================================== === Requirements === * gcc C compiler (other compilers may work, but are not officially supported) * GNU make (other similar "make" tools may work, but are not supported) * SDL library v1.2 * SDL_image library * libpng (not on MacOSX) * FreeType library (optional, for truetype fonts) * SDL_ttf library (optional, for truetype fonts) * Lua library v5.1 or v5.2 (optional, for Lua scripting) Extra requirements for Windows: * a POSIX environment: MSYS is fine, maybe Cygwin would work as well. * use Mingw C compiler instead of gcc Extra requirements for UNIX/X11 (Linux, FreeBSD, ...): * pkg-config (optional, for Lua scripting) * X11 headers (optional, for truetype fonts) On Debian-based distributions you should be able to get all these files by simply running the following command from a terminal : sudo aptitude install gcc make libsdl1.2-dev libsdl-image1.2-dev libsdl-ttf2.0-dev libfreetype6-dev liblua5.1-0-dev lua5.1 === Instructions === Open a shell/Terminal, enter the directory where you have the project tree, and type: cd src make If all goes well, it should build grafx2 (the main program) in the "bin" directory. Voil. If you don't have FreeType and SDL_ttf, type make NOTTF=1 instead. It will build a version without TrueType support : the Text tool will be limited to bitmap fonts, proportional fonts with .ttf extension won't be available. If you don't have lua available, type `make NOLUA=1`. You will not be able to use lua scripts to generate and alter brush and pictures. These options can be combined, for example for a build without ttf nor lua type make NOTTF=1 NOLUA=1 === Build variants === The default compilation is optimized ( -O ), with debugging symbols for GDB. Compile with OPTIM=0 to disable optimizations, if you have some real debugging to do. Compile with OPTIM=3 to use maximum optimizations. Type "make release" if you don't want the debugging symbols. Compile with USE_JOYSTICK=1 to enable joystick input : Only useful for developers, to check the input code for platforms that don't have a mouse. Compile with NOLAYERS=1 to make a version of Grafx2 that can't display several layers at a time: You will still be able to edit layered images, but you will only see one layer at a time. This option is designed for slow platforms, as it makes the program faster. === Other compilation targets === make clean Erases all generated files (intermediate objects, and executable) make depend Re-compute the dependencies (makefile.dep). Other compilation targets (make version, make ziprelease) require git and are only useful to contributors to the git repository of Grafx2. === System specifics === == Unix/Linux == sudo make install This copies the executable and data files in your system, in the /usr/local/bin and /usr/local/share directories. You then no longer need the compilation directory. sudo make uninstall Removes the copied files from your system, keeps your configuration. For both options, you can specify prefix=something to choose the target directory root: For example prefix=/usr or prefix=./test-install == gp2x == The gp2x build is very similar to the Linux one. TTF is always disabled because there is no X11 support on the gp2x. To compile a gp2x executable, type make GP2XCROSS=1 This will only work on an UNIXsystem (Linux or FreeBSD). == Windows == It is also possible to compile from linux, with this command : make WIN32CROSS=1 You will need the mingw cross-compiler, and all the librairies listed above. Here is a list of the resources used to build the Windows version: 4DOS with an alias make=mingw32-make MSYS installed in C:\MSYS Mingw installed in C:\MSYS\mingw SDL: SDL-devel-1.2.13-mingw32.tar.gz Uncompress in temporary directory make make install (no effect?) Headers are in /usr/mingw/include/SDL, copy them to /usr/include/SDL Zlib: http://gnuwin32.sourceforge.net/downlinks/zlib.php zlib-1.2.3.exe Install in c:\msys\mingw Libpng Requires: Zlib http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/l/li/libpng/ libpng-1.4.2.tar.gz (Before June 2010, we were using libpng-1.0.23.tar.gz) Uncompress in temporary directory ./configure make make install (long) Files created in /usr/local/include and /usr/local/lib .... libjpeg (optional - improves SDL_image with JPEG reading) http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/l/project/li/libjpeg/libjpeg/ jpegsr6.zip Uncompress in temporary directory ./configure --enable-shared make (make install doesn't work. Copy jpeglib.h, jmorecfg.h, jconfig.h in include, and libjpeg.a in lib) libtiff (optional - improves SDL_image with TIFF reading) ftp://ftp.sgi.com/graphics/tiff/ tiff-v3.4-tar.gz Uncompress in temporary directory ./configure i686-pc-mingw32 make Don't use 'make install', copy tiff.h libtiff.a manually instead. SDL_image: Requires: Libpng Requires optionally: libtiff Requires optionally: libjpeg http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/l/li/libsdl/ SDL_image-1.2.8.zip Uncompress in temporary directory ./configure Check in the messages that png worked Optionally check if jpeg worked too Optionally check if tiff worked too make make install prefix=/usr/mingw FreeType: http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/m/mi/mingw-cross/ mingw-freetype-2.3.7-2 Uncompress in c:/mwsys/mingw SDL_ttf: No mingw package http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/l/li/libsdl/ SDL_ttf-2.0.9-win32.zip for DLLs: libfreetype-6.dll, SDL_ttf.dll, zlib1.dll SDL_ttf-2.0.9.tar.gz Lua: (optional) http://www.lua.org/ftp/lua-5.2.1.tar.gz Uncompress in temporary directory Use sh shell make mingw (make install doesn't work, even with prefix) Copy luaconf.h, lualib.h, lua.h, lauxlib.h to c:\msys\mingw\include Copy liblua.a to c:\msys\mingw\lib Copy lua51.dll to c:\msys\mingw\bin == Atari TOS machines == The Atari build is very similar to the Linux one. The build might work on native machine with gcc 4.3> compiler, but it wasn't tested. You can also build binary for Coldfire based machines(e.g. Firebee) by replacing '-m68020-60' in makefile to '-mcpu=5475'. Preferable way is to build GRAFX2 with use of cross compiler, you can get one from Vincent Riviere site: (URL: http://vincent.riviere.free.fr/soft/m68k-atari-mint). There are versions for win32 (Cygwin) and debian packages for latest Ubuntu (32/64bit). Before compilation you have to build all the needed libraries mentioned in requirements. To compile a Atari TOS executable, type in make ATARICROSS=1 prefix=/usr/m68k-atari-mint You can also add other options like NOTTF,NOLUA,NOLAYERS etc. to enable/disable program features.. If you don't know how build libraries here's some hints. Please note that prefix path in examples below is valid only under Linux, in case of Cygwin the path will be '/opt/m68k-atari-mint'. There will be no prefix when building on native machine. You have to omit 'sudo' under Cygwin and native build. Stick to this order and you will be fine ;> ... The versions of libraries were tested, you can also try newer versions. As I mentioned earlier, replace '-m68020-60' with '-mcpu=5475' if you want to target Coldfire machines. libpng [optional](for png reading in SDL_image): ------------------------------------------------ note: you will need libzip too libpng 1.2.44 ./configure --prefix=/usr/m68k-atari-mint --disable-shared --enable-static --host=m68k-atari-mint CFLAGS="-m68020-60 -O2 -fomit-frame-pointer" sudo make install or libpng 1.4.44 ./configure --prefix=/usr/m68k-atari-mint --disable-shared --enable-static --host=m68k-atari-mint CFLAGS="-m68020-60 -O2 -fomit-frame-pointer -DPNG_NO_SETJMP" sudo make install libjpeg, libtiff [optional] (for jpeg/tiff support in SDL_image) ---------------------------------------------------------------- ./configure --prefix=/usr/m68k-atari-mint --disable-shared --enable-static --host=m68k-atari-mint CFLAGS="-m68020-60 -O2 -fomit-frame-pointer" sudo make install freetype 2.4.4 [optional] (for TTF fonts support, required by SDL_ttf) ---------------------------------------------------------------------- ./configure --prefix=/usr/m68k-atari-mint --disable-shared --enable-static --host=m68k-atari-mint CFLAGS="-m68020-60 -O2 -fomit-frame-pointer" sudo make install lua 5.0.4 [optional] (for LUA scripting support) ------------------------------------------------ Here you have to customize makefiles, add prefixes, platform has to be set as generic. SDL 1.2 [mandatory] -------------------- note: best is to grab it directly from Mercurial repository ./configure --prefix=/usr/m68k-atari-mint --disable-shared --enable-static --host=m68k-atari-mint --disable-video-opengl --disable-shared --enable-static --disable-threads CFLAGS="-m68020-60 -O2 -fomit-frame-pointer" sudo make install SDL_ttf [optional] (for ttf fonts support, depends on SDL and freetype) ------------------------------------------- ./configure --prefix=/usr/m68k-atari-mint --disable-shared --enable-static --host=m68k-atari-mint --disable-shared --enable-static --with-sdl-prefix=/usr/m68k-atari-mint --with-freetype-prefix=/usr/m68k-atari-mint CFLAGS=" -m68020-60 -O2 -fomit-frame-pointer" sudo make install SDL_image 1.2.10 [mandatory] ---------------------------- ./configure --prefix=/usr/m68k-atari-mint --disable-shared --enable-static --host=m68k-atari-mint --disable-shared --enable-static --with-sdl-prefix=/usr/m68k-atari-mint CFLAGS="-DHAVE_OPENGL=0 -m68020-60 -O2 -fomit-frame-pointer" sudo make install And that's it! :) grafx2_2.4+git20180105/doc/tech_fra.txt0000664000000000000000000010055613223665306016030 0ustar rootrootĿ Doc. technique pour GrafX 2.00 - Version 1.08 (5 octobre 1997) ۲ Ce fichier traite: - du format d'image PKM - des valeurs envoyer au CRTC pour avoir accs tous les modes vidos incroyables disponibles dans GrafX 2.00 Ŀ Le format d'image PKM - par Karl Maritaud ۲ Tout d'abord, je tiens a dire que j'ai cr ce format il y a dj quelques annes, l'poque o je ne savais pas comment charger les meilleurs formats (GIF par exemple) et que je voulais galement avoir mon propre format. Le format PKM a t conu pour tre trs simple, facile encoder et dcoder. De plus, son header est trs simple (court) et evolutif. Le seul vrai dfaut que je puisse y trouver est que l'on ne peut sauver des images qu'en 256 couleurs. Je sais que vous allez vous dire: "Oh non! Encore un nouveau format la con! J'm'en servirai jamais! En plus le taux de compression est naze! Je prefre le GIF!". Et je rpondrai: "Ouais! T'as raison. Mais si tu ne sais pas comment charger du GIF et que tu veux un format simple avec une compression correcte (du moins sur les images simples), il peut tre utile." Donc, voici la documentation de ce format... Le HEADER: Le header est la structure de 780 octets suivante. (Ne vous inquitez pas propos de la taille. C'est tout simplement parce que la palette fait partie du header). Ŀ Pos Champ Type Taille Description ͵ 0 Signature char 3 Chane constante "PKM" (SANS dlimitation de taille '\0' ou autres...) Ĵ 3 Version byte 1 Pour le moment, ce champ ne peut prendre que la valeur 0. D'autres mthodes de compression pourront la modifier mais pour l'instant il n'y en a qu'une seule. Ĵ 4 Pack_byte byte 1 Valeur de l'octet de reconnaissance pour les rptitions de couleurs codes sur 1 Octet. (Voir la section sur la mthode de compression pour plus d'informations) Ĵ 5 Pack_word byte 1 Valeur de l'octet de reconnaissance pour les rptitions de couleurs codes sur 2 Octets. (Voir la section sur la mthode de compression pour plus d'informations) Ĵ 6 Largeur word 2 Largeur de l'image (en pixels) Ĵ 8 Hauteur word 2 Hauteur de l'image (en pixels) Ĵ 10 Palette byte 768 Palette RGB (RGB RGB ... 256 fois) avec des valeurs de 0 63. Je sais que le standard dans les fichiers d'images est de 0 255 mais je trouve a crtin! C'est tellement plus simple d'envoyer la palette toute entire dans le port 3C9h avec un REP OUTSB sans avoir convertir la palette. Ĵ 778 Taille_PH word 2 Taille du Post-header. C'est le nombre d'octets entre le header et les donnes de l'image. Cette valeur peut valoir 0. Les donnes du type "word" sont stockes selon les conventions d'Intel: c'est--dire l'octet de poids le plus faible en premier. Le POST-HEADER: Le post-header a une taille variable. Il a t conu pour supporter les nouvelles fonctions de ce format sans avoir a changer compltement le format. Il est constitu d'identificateurs de champ suivis par leur taille et leur contenu. Un identificateur de champ est cod sur 1 octet ainsi que sa taille. Ces identificateurs de champ sont: (cette liste peut tre rallonge...) 0 : Commentaire sur l'image 1 : Dimensions de l'cran d'origine 2 : Couleur de fond (couleur de transparence) Si vous rencontrez un champ inconnu par votre routine de chargment, sautez simplement au del. Mais, par contre, si un champ vous dit de sauter une position qui tombe aprs le dbut thorique des donnes de l'image, alors c'est qu'il y a une erreur dans le fichier. Les champs: * Commentaire: Grce ce champ, les artistes vont pouvoir commenter leurs dessins. Notez que GrafX 2 a une taille limite de commentaire de 32 caractres. Mais vous pourrez avoir des commentaires allant jusqu' 255 caractres si vous crez votre propre viewer puisque GrafX 2 ignorera simplement les caractres en trop. Exemple: [0],[15],[Dessin de X-Man] Cette squence signifie: - le champ est un commentaire - le commentaire a une taille de 15 caractres (il n'y a pas de caractre de fin de chane puisque vous connaissez sa taille) - le commentaire est "Dessin de X-Man" * Dimensions de l'cran d'origine: Puisque GrafX 2 propose un norme choix de rsolutions, il a sembl pratique d'ajouter un champ indicant quelles taient les dimensions de l'cran d'origine. Exemple: [1],[4],[320],[256] Cette squence signifie: - Le champ dcrit les dimensions de l'cran d'origine - Les dimensions sont 2 words (donc cette valeur doit tre gale 4) - La largeur de l'cran d'origine tait de 320 pixels - La hauteur de l'cran d'origine tait de 256 pixels Notez que les words stocks dans les champs sont crits la manire Intel. La BETA-version 90% ne respectait pas cette norme (dsol). Ce n'est pas bien grve mais les images sauves avec la version 90% et recharges avec une version postrieure (91% et plus) ne passeront pas dans la bonne rsolution. * Couleur de fond: Enregistrer la couleur de fond (couleur de transparence) se rvle particulirement utile lorsque vous voulez sauvegarder une brosse. La taille de ce champ est 1 octet (indice de la couleur entre 0 et 255). Exemple: [2],[1],[255] Cette squence signifie: - le champ dcrit la couleur de fond - la valeur prend 1 octet - La couleur de transparence est 255 La METHODE DE COMPACTAGE DE L'IMAGE: La mthode de compression PKM est une sorte de "Run-Length-Compression" qui est trs efficace sur les images comportant de longues rptitions d'une mme couleur horizontalement. En fait la compression commence tre efficace s'il y a souvent plus de 3 fois la mme couleur conscutivement. Je pense qu'il est prfrable de vous donner directement l'algorithme plutt que de nager dans des explications incomprehensibles. DEBUT /* fonctions: Lire_octet(Fichier) Lit et retourne 1 octet partir de Fichier Dessiner_pixel(X,Y,Couleur) Dessine un pixel d'une certaine Couleur la position (X,Y) Taille_fichier(Fichier) Retourne la taille totale d'un Fichier en octets variables: le type de Taille_image est dword le type de Taille_donnees est dword le type de Compteur_donnees est dword le type de Compteur_pixels est dword le type de Couleur est byte le type de Octet_lu est byte le type de Word_lu est word le type de Compteur est word le type de Fichier est */ /* A cet endroit, le header et le post-header ont dj t lus. */ Taille_image <- Header.Largeur * Header.Hauteur Taille_donnees <- Taille_fichier(Fichier) - (780+Header.Taille_PH) Compteur_donnees <- 0 Compteur_pixels <- 0 /* Boucle de dcompression: */ TANT QUE ((Compteur_pixelsHeader.Pack_byte) ET (Octet_lu<>Header.Pack_word)) ALORS { Dessiner_pixel(Compteur_pixels MOD Header.Largeur, Compteur_pixels DIV Header.Largeur, Octet_lu) Compteur_pixels <- Compteur_pixels + 1 Compteur_donnees <- Compteur_donnees + 1 } SINON /* Est-ce que le nombre de pixels rpter est cod... */ { /* ... sur 1 octet ? */ SI (Octet_lu = Header.Pack_byte) ALORS { Couleur <- Lire_octet(Fichier) Octet_lu <- Lire_octet(Fichier) POUR Compteur ALLANT DE 0 A (Octet_lu-1) PAR PAS DE +1 Dessiner_pixel((Compteur_pixels+Compteur) MOD Header.Largeur, (Compteur_pixels+Compteur) DIV Header.Largeur, Couleur) Compteur_pixels <- Compteur_pixels + Octet_lu Compteur_donnees <- Compteur_donnees + 3 } SINON /* ... sur 2 octets ? */ { Couleur <- Lire_octet(Fichier) Word_lu <- (word) (Lire_octet(Fichier) SHL 8)+Lire_octet(Fichier) POUR Compteur ALLANT DE 0 A (Word_lu-1) PAR PAS DE +1 Dessiner_pixel((Compteur_pixels+Compteur) MOD Header.Largeur, (Compteur_pixels+Compteur) DIV Header.Largeur, Couleur) Compteur_pixels <- Compteur_pixels + Word_lu Compteur_donnees <- Compteur_donnees + 4 } } } FIN Par exemple, la squence suivante: (on suppose que Pack_byte=01 et Pack_word=02) 04 03 01 05 06 03 02 00 01 2C sera dcode comme: 04 03 05 05 05 05 05 05 03 00 00 00 ... (repter 0 300 fois (012Ch=300)) Les rptitions qui tiennent sur un word doivent tre crites avec leur octet de poids le plus fort en premier. Je sais que a va l'encontre du standard Intel mais puisque je lis les octets du fichier au travers d'un buffer (franchement plus rapide), Je me fous compltement de l'ordre (Dsol :)). Mais les words du header et du post-header doivent tre crits et lus la manire Intel! Conseils de compactage: * Comme vous pouvez le constater, il pourrait y avoir un problme lorsque vous devriez compacter un pixel brut de couleur gale Pack_byte ou Pack_word. Ces pixels doivent toujours tre cods comme des paquets mme s'il n'y a qu'un seul pixel. Exemple: (supposons que Pack_byte=9) 9 sera encod 9,9,1 (Le 1er 9 dans la squence... 9,9 sera encod 9,9,2 ... encode est Pack_byte) etc... * Il semble vident de trouver des valeurs pour Pack_byte et Pack_word qui ne sont jamais (ou presque) utilises. Donc, une petite routine qui trouve les 2 couleurs les moins utilises dans l'image devrait tre appele avant de commencer la compression. Ceci peut tre ralis presque instantanment en Assembleur. * Quand vous voulez crire une squence de 2 couleurs identiques, crivez simplement ces 2 couleurs l'une aprs l'autre (Couleur,Couleur) puisque a ne prend que 2 octets au lieu de 3 si vous aviez crit un paquet (Pack_byte, Couleur,2). * Si vous compressez une image extrmement simple qui comporte une squence de plus de 65535 fois la mme couleur conscutivement, vous devez "casser" la squence et continuer avec un nouveau paquet. Exemple: vous devez compacter les 65635 mmes octets conscutifs (de couleur 0 par exemple) (On suppose que Pack_byte=01 et Pack_word=02) Vous devrez alors crire: 02 00 FF FF 01 00 64 (FFFFh=65535, 64h=100) Ŀ Passer dans les modes vidos de GrafX 2.00 ۲ Toutes les procdures d'initialisation de mode sont crites en ASM 386. De toutes faons, si vous ne comprenez pas une ligne d'ASM, je ne vois vraiment pas quoi pourront vous servir ces procdures. Elles ont t conues pour tre utilises dans le modle de mmoire FLAT. Mais cela ne devrait pas vous prendre trop de temps de les adapter au modle que vous souhaitez utiliser puisqu'il n'y a que les manipulations de mmoire que cela affectera (utilisez donc DS:SI au lieu de ESI, ES:DI la place de EDI et fates attention l'adresse 0A0000h qui se transforme en l'adresse 0A000h:0000h). MCGA: (Mode VGA standard) Y-a-t'il quelqu'un sur cette plante qui ne sache toujours pas comment on passe en mode MCGA 320x200 en 256 couleurs ??!? Bon... Je suppose que vous tes un novice si vous lisez les 2 lignes suivantes :) mov ax,0013h int 10h Modes X: (Modes VGA tendus) Bon... Il me semble que le Mode X original tait en 320x240, mais maintenant tout le monde appelle "Modes X" (ou X-Modes, ou Tweaked modes) tous les modes VGA qui utilise plus de 64Ko de mmoire vido et la structure "Unchained". Afficher un pixel dans n'importe quel Mode X peut tre effectu par la mme et unique fonction (mais je ne vous expliquerai pas comment faire, il vous suffit d'indiquer la fonction la taille des plans (Largeur/4)). Si vous ne comprenez rien ce que je dis, (Unchained, plans...) il vous suffit de lire n'importe quelle bonne documentation sur le Mode X. Nous tenons remercier les auteurs de XLIB2 pour nous avoir conomis du temps en ayant crit cette fonction. Nous l'avons lgrement optimise en fonction de nos besoins, mais l'essentiel en a t conserv. mov ax,13h ; Oui! Encore le mode MCGA! Tous les Modes X doivent int 10h ; commencer partir du mode VGA standard, mais bien des ; choses changent par la suite. mov dx,3C6h ; Pour la dure de l'initialisation, on va teindre la xor al,al ; palette de faon ce que l'utilisateur ne subisse pas out dx,al ; nos triturations. mov dx,3C4h ; Nous allons demander au registre TIMING SEQUENCER de mov ax,0604h ; passer dans le mode "Unchained" (mode X), sans grer de out dx,ax ; parit, et un accs aux 256Ko de la carte vido. mov ax,0100h ; On va ensuite enclencher le reset synchrone du registre out dx,ax ; TS car on s'apprte jouer avec les registres. mov al,01h ; De la mme faon que pour la palette, on demande la out dx,al ; carte vido de ne plus scruter la mmoire pour inc dx ; afficher son contenu. Ainsi, c'est une faon de plus in al,dx ; d'viter l'affichage parasite qui arrive le temps que mov ah,al ; le mode soit totalement initialis et stabilis. mov al,01h ; De plus, on peut esprer qu'en demandant un arrt de push ax ; la lecture de la mmoire, le systme s'en voit un peu mov al,ah ; acclr, et ainsi acclrer l'initialisation du mode or al,20h ; graphique (l'espoir fait vivre :)) out dx,al ; mov esi,X_ptr ; Pointeur sur la liste des constantes envoyer au CRTC. cld lodsb ; Ceci charge dans AL une valeur qui nous dira quoi faire ; avec le registre MISCELLANEOUS, et incrmente ESI. ; La valeur est gale ZERO => Rien faire ; sinon => Envoyer AL au reg. MISC. or al,al ; Devons nous modifier le mode vido de base ? jz NonMerci ; Non?Ŀ En fait, la rponse est toujours "Oui". mov dx,3C2h ; Sauf pour quelques modes tels que le out dx,al ; 320x200 en Mode X NonMerci: ; < (mais notre mode 320x200 est en MCGA...) mov dx,3C4h ; On en a termin avec les manipulations du registre mov ax,0300h ; MISCELLANEOUS, on peut maintenant dsenclencher le out dx,ax ; reset synchrone du registre TIMING SEQUENCER. ; Et maintenant, si on jouait avec le CRTC? mov dx,3D4h ; Dans le 18me registre du CRTC, on va dsenclencher le mov al,11h ; bit de protection. Sans cela, les valeurs que nous out dx,al ; aurions envoyes aux registres du CRTC auraient t inc dx ; ignores. in al,dx and al,7Fh out dx,al dec dx ; DX pointe nouveau sur "l'entre" du registre CRTC. lodsb ; Ceci met dans AL le nombre de registres CRTC changer xor ecx,ecx ; On doit nettoyer ECX avant de commencer rpter... mov cl,al ; ...CL (AL) fois OUTSW rep outsw ; On peut envoyer la sauce aux registres du CRTC! ; Juste au cas o le 20me registre CRTC aurait t oubli dans la table ; d'initialisation, on peut le calculer nous-mmes (Ouaip, on est des ; braves gars). mov ax,Screen_width ; Vous devez indiquer la routine quelle est la shr ax,3 ; largeur de l'cran mov ah,al mov al,13h out dx,ax mov dx,3C4h ; Maintenant vous avez la bonne rsolution mais il peut mov ax,0F02h ; y avoir des pixels pourris l'cran cause de zones out dx,ax ; non nettoyes de la mmoire vido. mov edi,0A0000h ; Donc on va nettoyer la mmoire partir de 0A0000h xor eax,eax ; avec la valeur 0 (qui est le noir standard) et sur une mov ecx,4000h ; longueur de 4000h dwords (256Ko). rep stosd ; Allez, liquidez-moi tout a! mov dx,3C4h ; On peut redemander la carte VGA de relire la mmoire pop ax ; pour afficher l'cran... out dx,ax ; mov dx,3C6h ; ... et rtablir la palette pour que l'image soit mov al,0FFh ; visible l'utilisateur. out dx,al ; La table de constantes que vous devez employer est l'une des suivantes: (Ces tables sont au format C, mais elles peuvent facilement tres employes dans d'autres langages) word X320Y224[] = { 0x0BA3, 0x6F06, 0xBA07, 0x0008, 0x4109, 0x0810, 0x8A11, 0xBF12, 0x0014, 0xC715, 0x0416, 0xE317 }; word X320Y240[] = { 0x0AE3, 0x0D06, 0x3E07, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0x0014, 0xE715, 0x0616, 0xE317 }; word X320Y256[] = { 0x0CE3, 0x2306, 0xB207, 0x0008, 0x6109, 0x0A10, 0xAC11, 0xFF12, 0x2013, 0x0014, 0x0715, 0x1A16, 0xE317 }; word X320Y270[] = { 0x0BE7, 0x3006, 0xF007, 0x0008, 0x6109, 0x2010, 0xA911, 0x1B12, 0x0014, 0x1F15, 0x2F16, 0xE317 }; word X320Y282[] = { 0x0CE3, 0x6206, 0xF007, 0x6109, 0x310F, 0x3710, 0x8911, 0x3312, 0x2F13, 0x0014, 0x3C15, 0x5C16, 0xE317 }; word X320Y300[] = { 0x0DE3, 0x4606, 0x1F07, 0x0008, 0x4009, 0x3110, 0x8011, 0x2B12, 0x2013, 0x0014, 0x2F15, 0x4416, 0xE317 }; word X320Y360[] = { 0x09E3, 0x4009, 0x8810, 0x8511, 0x6712, 0x2013, 0x0014, 0x6D15, 0xBA16, 0xE317 }; word X320Y400[] = { 0x03E3, 0x4009, 0x0014, 0xE317 }; word X320Y448[] = { 0x0BA3, 0x6F06, 0xBA07, 0x0008, 0x4009, 0x0810, 0x8A11, 0xBF12, 0x0014, 0xC715, 0x0416, 0xE317 }; word X320Y480[] = { 0x0AE3, 0x0D06, 0x3E07, 0x4009, 0xEA10, 0xAC11, 0xDF12, 0x0014, 0xE715, 0x0616 , 0xE317}; word X320Y512[] = { 0x0CE3, 0x2306, 0xB207, 0x0008, 0x6009, 0x0A10, 0xAC11, 0xFF12, 0x2013, 0x0014, 0x0715, 0x1A16, 0xE317 }; word X320Y540[] = { 0x0BE7, 0x3006, 0xF007, 0x0008, 0x6009, 0x2010, 0xA911, 0x1B12, 0x0014, 0x1F15, 0x2F16, 0xE317 }; word X320Y564[] = { 0x0CE7, 0x6206, 0xF007, 0x0008, 0x6009, 0x3E10, 0x8911, 0x3312, 0x2013, 0x0014, 0x3C15, 0x5C16, 0xE317 }; word X320Y600[] = { 0x0BE7, 0xBE06, 0xF007, 0x0008, 0x6009, 0x7C10, 0x8C11, 0x5712, 0x0014, 0x5815, 0x7016, 0xE317 }; word X360Y200[] = { 0x09E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x2D13, 0x0014, 0xE317 }; word X360Y224[] = { 0x12A7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x6F06, 0xBA07, 0x0008, 0x4109, 0x0810, 0x8A11, 0xBF12, 0x2D13, 0x0014, 0xC715, 0x0416, 0xE317 }; word X360Y240[] = { 0x11E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x0D06, 0x3E07, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0x2D13, 0x0014, 0xE715, 0x0616, 0xE317 }; word X360Y256[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x2B06, 0xB207, 0x0008, 0x6109, 0x0E10, 0xAC11, 0xFF12, 0x2D13, 0x0014, 0x0715, 0x1A16, 0xE317 }; word X360Y270[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x3006, 0xF007, 0x0008, 0x6109, 0x2010, 0xA911, 0x1B12, 0x2D13, 0x0014, 0x1F15, 0x2F16, 0xE317 }; word X360Y282[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x6206, 0xF007, 0x6109, 0x310F, 0x3710, 0x8911, 0x3312, 0x2D13, 0x0014, 0x3C15, 0x5C16, 0xE317 }; word X360Y300[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x4606, 0x1F07, 0x0008, 0x4009, 0x3110, 0x8011, 0x2B12, 0x2D13, 0x0014, 0x2F15, 0x4416, 0xE317 }; word X360Y360[] = { 0x0FE7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x4009, 0x8810, 0x8511, 0x6712, 0x2D13, 0x0014, 0x6D15, 0xBA16, 0xE317 }; word X360Y400[] = { 0x0AE7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x4009, 0x2D13, 0x0014, 0xE317 }; word X360Y448[] = { 0x12A7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x6F06, 0xBA07, 0x0008, 0x4009, 0x0810, 0x8A11, 0xBF12, 0x2D13, 0x0014, 0xC715, 0x0416, 0xE317 }; word X360Y480[] = { 0x11E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x0D06, 0x3E07, 0x4009, 0xEA10, 0xAC11, 0xDF12, 0x2D13, 0x0014, 0xE715, 0x0616, 0xE317 }; word X360Y512[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x2B06, 0xB207, 0x0008, 0x6009, 0x0E10, 0xAC11, 0xff12, 0x2D13, 0x0014, 0x0715, 0x1A16, 0xE317 }; word X360Y540[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x3006, 0xF007, 0x0008, 0x6009, 0x2010, 0xA911, 0x1B12, 0x2D13, 0x0014, 0x1F15, 0x2F16, 0xE317 }; word X360Y564[] = { 0x12EB, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x6206, 0xF007, 0x0008, 0x6009, 0x3E10, 0x8911, 0x3312, 0x2D13, 0x0014, 0x3C15, 0x5C16, 0xE317 }; word X360Y600[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0xBE06, 0xF007, 0x0008, 0x6009, 0x7C10, 0x8C11, 0x5712, 0x2D13, 0x0014, 0x5815, 0x7016, 0xE317 }; word X400Y200[] = { 0x09E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x3213, 0x0014, 0xE317 }; word X400Y224[] = { 0x12A7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x6F06, 0xBA07, 0x0008, 0x4109, 0x0810, 0x8A11, 0xBF12, 0x3213, 0x0014, 0xC715, 0x0416, 0xE317 }; word X400Y240[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x0D06, 0x3E07, 0x0008, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0x3213, 0x0014, 0xE715, 0x0616, 0xE317 }; word X400Y256[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x2B06, 0xB207, 0x0008, 0x6109, 0x1310, 0xAC11, 0xFF12, 0x3213, 0x0014, 0x0715, 0x1A16, 0xE317 }; word X400Y270[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x3006, 0xF007, 0x0008, 0x6109, 0x2010, 0xA911, 0x1B12, 0x3213, 0x0014, 0x1F15, 0x2F16, 0xE317 }; word X400Y282[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x6206, 0xF007, 0x6109, 0x310F, 0x3710, 0x8911, 0x3312, 0x3213, 0x0014, 0x3C15, 0x5C16, 0xE317 }; word X400Y300[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x4606, 0x1F07, 0x0008, 0x4009, 0x3110, 0x8011, 0x2B12, 0x3213, 0x0014, 0x2F15, 0x4416, 0xE317 }; word X400Y360[] = { 0x0FE7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x4009, 0x8810, 0x8511, 0x6712, 0x3213, 0x0014, 0x6D15, 0xBA16, 0xE317 }; word X400Y400[] = { 0x0AE7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x4009, 0x3213, 0x0014, 0xE317 }; word X400Y448[] = { 0x12A7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x6F06, 0xBA07, 0x0008, 0x4009, 0x0810, 0x8A11, 0xBF12, 0x3213, 0x0014, 0xC715, 0x0416, 0xE317 }; word X400Y480[] = { 0x11E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x0D06, 0x3E07, 0x4009, 0xEA10, 0xAC11, 0xDF12, 0x3213, 0x0014, 0xE715, 0x0616, 0xE317 }; word X400Y512[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x2B06, 0xB207, 0x0008, 0x6009, 0x1310, 0xAC11, 0xFF12, 0x3213, 0x0014, 0x0715, 0x1A16, 0xE317 }; word X400Y540[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x3006, 0xF007, 0x0008, 0x6009, 0x2010, 0xA911, 0x1B12, 0x3213, 0x0014, 0x1F15, 0x2F16, 0xE317 }; word X400Y564[] = { 0x12EB, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x6206, 0xF007, 0x0008, 0x6009, 0x3E10, 0x8911, 0x3312, 0x3213, 0x0014, 0x3C15, 0x5C16, 0xE317 }; word X400Y600[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0xBE06, 0xF007, 0x0008, 0x6009, 0x7C10, 0x8C11, 0x5712, 0x3213, 0x0014, 0x5815, 0x7016, 0xE317 }; La structure: (exemple) Ceci est le nombre de valeurs envoyer aux registres CRTC. C'est en fait le nombre de words dans la table moins 1 ( cause du 1er word de la table qui n'est pas envoy au CRTC mais qui contient une valeur envoyer au registre MISCELLANEOUS et le nombre de valeurs envoyer aux registres CRTC ;) ). Ceci est la valeur envoyer au registre MISCELLANEOUS (ou 0 si aucune valeur ne doit y tre envoye). Ceci est une valeur envoyer dans un registre du CRTC. Ceci est le numro du registre du CRTC qui recevra la valeur cite prcdemment. ÿÿ ÿÿ { 0x0AE3, 0x0D06, 0x3E07, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0x0014, 0xE715, 0x0616, 0xE317 }; Vous pouvez remarquer que les registres 0 5 (et le 13h) du CRTC dfinissent la largeur de l'cran, alors que les registres 6 17h ( l'exception du 13h) definissent la hauteur de l'cran. Nous avons plus de modes en poche que les quelques-uns :) que nous avons inclus dans GrafX 2.00, mais ils ne sont ni vraiment utiles ni vraiment stables. Nous pourrons toutefois dcider de les inclure dans une prochaine version. S'il manque certains de vos modes prfres, envoyez nous simplement la liste des constantes que l'on doit balancer au CRTC la manire de la structure utilise ci-dessus. IMPORTANT! Les valeurs des constantes cites plus haut ne sont pas supportes par tous les moniteurs ou les cartes vidos. Nous avons test GrafX2 avec diffrentes configurations et avons constats que certains modes ne marchent pas du tout avec certaines cartes vidos, alors que d'autres dbordent de l'cran, sont dcentrs, assombris, trop clairs, ou tasss. Toutefois, ils marchent tous correctement avec notre pauvre petite Tseng Labs ET4000... Si vous avez dj une bonne connaissance propos du CRTC, et avez des valeurs diffrentes des notres pour certains modes, merci de nous en informer. Nous nous en servirons s'ils marchent mieux sur une majorit d'ordinateurs. VESA: (Un "pseudo-standard" pour les modes Super-VGA) Nous nous servons du VESA pour des modes qui ncessitent une largeur de 640, 800 ou 1024 pixels. Mais il existe un moyen de combiner la hauteur des Modes X avec les modes VESA, il est ainsi possible d'avoir des modes aussi timbrs qu'en Mode X. mov ax,4F02h mov bx,Video_mode int 10h Les modes VESA 256 couleur VESA sont: 100h : 640x400 101h : 640x480 103h : 800x600 105h : 1024x768 107h : 1280x1024 (non disponible dans GrafX2 parce qu'uniquement support par des cartes vido avec 2 Megaoctets ou plus de mmoire vido) Comme avec les Modes X, vous pouvez modifier les registres CRTC pour accder aux modes "VESA-X"! (Notez que certaines cartes vido ne supportent pas les modifications des registres du CRTC VGA dans les modes VESA.) Pour passer dans ces modes tendus, passez dans un mode VESA standard ayant la bonne largeur, puis appelez Modif_registres_CRTC avec la bonne table de hauteur. Exemple (640x512) : VESA_Set_mode(101h) // On passe dans un mode qui a la mme largeur Modif_registres_CRTC(Y512) // On modifie la hauteur * Tables des hauteurs: word Y224[] = { 0x09A3, 0x6F06, 0xBA07, 0x0008, 0x4109, 0x0810, 0x8A11, 0xBF12, 0xC715, 0x0416 }; word Y240[] = { 0x09E3, 0x0D06, 0x3E07, 0x0008, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0xE715, 0x0616 }; word Y256[] = { 0x0900, 0x2B06, 0xB207, 0x0008, 0x6109, 0x0A10, 0xAC11, 0xFF12, 0x0715, 0x1A16 }; word Y270[] = { 0x09E7, 0x3006, 0xF007, 0x0008, 0x6109, 0x2010, 0xA911, 0x1B12, 0x1F15, 0x2F16 }; word Y282[] = { 0x0AE3, 0x6206, 0xF007, 0x0008, 0x6109, 0x310F, 0x3710, 0x8911, 0x3312, 0x3C15, 0x5C16 }; word Y300[] = { 0x09E3, 0x4606, 0x1F07, 0x0008, 0x4009, 0x3110, 0x8011, 0x2B12, 0x2F15, 0x4416 }; word Y350[] = { 0x09A3, 0xBF06, 0x1F07, 0x0008, 0x4009, 0x8310, 0x8511, 0x5D12, 0x6315, 0xBA16 }; word Y360[] = { 0x07E3, 0x0008, 0x4009, 0x8810, 0x8511, 0x6712, 0x6D15, 0xBA16 }; word Y400[] = { 0x01E3, 0x4009 }; word Y448[] = { 0x09A3, 0x6F06, 0xBA07, 0x0008, 0x4009, 0x0810, 0x8A11, 0xBF12, 0xC715, 0x0416 }; word Y480[] = { 0x09E3, 0x0D06, 0x3E07, 0x0008, 0x4009, 0xEA10, 0xAC11, 0xDF12, 0xE715, 0x0616 }; word Y512[] = { 0x0900, 0x2B06, 0xB207, 0x0008, 0x6009, 0x0A10, 0xAC11, 0xFF12, 0x0715, 0x1A16 }; word Y540[] = { 0x09E7, 0x3006, 0xF007, 0x0008, 0x6009, 0x2010, 0xA911, 0x1B12, 0x1F15, 0x2F16 }; word Y564[] = { 0x09E7, 0x6206, 0xF007, 0x0008, 0x6009, 0x3E10, 0x8911, 0x3312, 0x3C15, 0x5C16 }; word Y600[] = { 0x09E7, 0xBE06, 0xF007, 0x0008, 0x6009, 0x7C10, 0x8C11, 0x5712, 0x5815, 0x7016 }; Modifier les registres CRTC: (inspir de l'init. des Modes X... voir plus haut pour de plus amples dtails) mov esi,XVESA_Ptr cld lodsb or al,al ; Devons nous modifier le mode vido de base ? jz NonMerci ; Non?Ŀ La rponse peut tre "Non" car les initialisations mov dx,3C2h ; de certains modes VESA mettent directement la out dx,al ; bonne valeur pour le registre MISCELLANEOUS. NonMerci: ; < mov dx,3D4h mov al,11h out dx,al inc dx in al,dx and al,7Fh out dx,al dec dx lodsb xor ecx,ecx mov cl,al rep outsw Si vous tes suffisament astucieux, vous pourrez combiner les constantes utilises dans les Modes X pour obtenir plus de modes "VESA-X" tels que le 640x200, 800x480, etc... (mais je ne pense pas que a marche convenablement avec les largeurs de 1024 pixels puisque ce mode est gnralement entrelac... Mais qui sait?...) Je pense que le plus difficile est de trouver la bonne valeur du registre MISCELLANEOUS. grafx2_2.4+git20180105/doc/doc_fra.txt0000664000000000000000000024225413223665306015654 0ustar rootroot Ŀ .00 GRAFX 2.00 96.5% - MANUEL D'UTILISATION - Ŀ SOMMAIRE - Prsentation - Equipement requis - Fichiers de configuration - Options disponibles - Let's talk about $$$, baby - Astuces de dessin - Problmes/Astuces gnrales/Questions frquentes (FAQ) Prsentation: Ce programme a t conu pour pouvoir dessiner des images en 256 couleurs dans un trs grand nombre de rsolutions (en fait, il y en a pour l'instant 60 avec quelques-unes venant du monde Amiga). Personne ne peut contester que la majeure partie des superbes GFX de la "Scne" ont t dessins sur Amiga. Mais ces GFX sont dans des rsolutions diffrentes des modes PC habituels. Alors nous avons voulu crer le premier logiciel de dessin sur PC qui pourrait visualiser ces images, et qui pourrait bien sr vous permettre de dessiner les vtres dans le mode vido que vous voulez. Ce logiciel a t prsent pour la premire fois la Wired'96 o il a eu un gros succs (bien plus que ce quoi nous nous attendions), alors nous esprons que vous l'aimerez aussi. Il consiste en un certain nombre d'outils de dessin, d'effets et de menus. Tous les effets fonctionnent avec n'importe quel outil de dessin. Sachez que ce logiciel a t cr pour VOUS, utilisateurs de PC qui enviez les possesseurs d'Amiga pour les fantastiques logiciels de dessin dont ils disposent. Ce logiciel n'a pas la prtention de remplacer les meilleurs programmes de dessin Amiga, mais tente modestement de combler le gouffre qu'il y a entre les logiciels PC et Amiga dans le domaine du dessin bitmap. Si vous rvez d'une option trs utile que nous n'ayons pas encore prvue, n'hsitez pas nous en faire part. Si nous la jugeons utile galement, et surtout s'il est possible de l'inclure dans le programme :), nous l'y mettrons ds que possible. Equipement requis: Pour pouvoir utiliser GrafX2, vous aurez besoin de: - un PC (386DX ou suprieur), - DOS 5 ou suprieur (a marche peut-tre avec le DOS 3.1 mais on ne se rappelle pas quelles sont les fonctions de l'INT 21h que nous utilisons), - une carte vido compatible VGA (une carte VLB ou PCI est fortement recom- mande), - une souris 2 boutons (et son gestionnaire), - 3 Megaoctets de RAM (a peut marcher avec moins si vous utilisez le cache disque de DOS4GW ou bien celui de Windows :/). Mais pour une utilisation plus efficace, vous aurez besoin de: - au moins un 486DX66 (pour augmenter la vitesse globale), - au moins 8 Mo de RAM pour capturer de trs grosses brosses et pour uti- liser le multi-undo, - une carte vido compatible VESA 1.2 (pour accder plus de modes vido). Fichiers de configuration: GrafX2 ncessite deux fichiers pour stocker sa configuration: 'GFX2.INI' et 'GFX2.CFG'. GFX2.INI: Ce fichier contient les paramtres dfinis dans le menu de configuration (settings) ainsi que quelques autres. Vous pouvez diter ce fichier l'aide d'un diteur de texte ASCII standard. Lorsque vous cliquez sur Reload (recharger) dans le menu des "settings", toutes les donnes contenues dans ce fichier sont restaures. Lorsque vous cliquez sur Save (sauvegarder) ou bien lorsque vous quittez le programme alors que l'option Auto-save (sauvegarde automatique) est enclenche, tous les paramtres actuels sont crits (mis jour) dans ce fichier. Si vous avez corrompu ce fichier et que vous n'arrivez pas corriger le problme, alors effacez-le et lancez GFXCFG.EXE. I crera automatiquement un fichier d'initialisation par dfaut lorsque celui-ci est absent. GFX2.CFG: Ce fichier contient la configuration du clavier ainsi que l'tat des variables du programme suivantes: modes vido tables de "shade" stencil (pochoir) masque dgrads Toutes ces variables sont enregistres lorsqu'on clique sur le bouton Save (sauvegarder) dans le menu de configuration ou bien lorsqu'on sort du programme avec l'option Auto-save (sauvegarde automatique) enclenche. Cependant, lorsque vous cliquez sur Reload (recharger) dans le menu des "settings", seul l'tat de chaque mode vido est restaur. Note: le fichier GFX2_FRA.CFG est un fichier de configuration par dfaut pour les claviers AZERTY. Si vous utilisez un clavier AZERTY, vous devriez remplacer le fichier GFX2.CFG par GFX2_FRA.CFG. Important: partir de la version 2.00 95.5%, les fichiers .CFG auront une compatibilit ascendante. Ceci signifie que vous pourrez rcuprer la majeure partie de leur contenu d'une version l'autre en copiant votre ancien fichier .CFG dans le rpertoire de votre nouvelle version de GrafX2 et en lanant GFXCFG.EXE. En effet, ce programme convertira votre ancien fichier afin qu'il soit utilisable par la nouvelle version de GrafX2. Mais, copier un fichier .CFG d'une version antrieure la version 95.5% ne marchera pas. De plus, (je ne vois pas pourquoi vous le feriez mais...) copier un fichier .CFG rcent dans une version plus ancienne ne devrait pas fonctionner non plus. Note: Nous vous recommandons de ne pas modifier les touches affectes l'mulation de la souris dans le programme GFXCFG car les valeurs que vous donneriez pourraient interfrer avec les raccourcis utiliss dans les menus. Options disponibles: Les diffrentes options disponibles dans GrafX2 seront listes et dtailles ci-dessous. Elles seront dcrites comme suit: ͻ ͻ 1 3 Les boutons triangulaires 1 / seront dtaills comme a: / 2 ͹ ͼ 2 4 ͼ 1 - Pinceaux 2 - Ajuster l'image / Effets sur l'image 3 - Bouton Dessin la main 4 - Courbes de Bzier (Splines) 5 - Lignes 6 - Arographe (Spray) 7 - Remplissage (Flood-fill) / Remplacement de couleur 8 - Polygnes / Polyformes 9 - Polygnes/Polyformes plein(e)s 10 - Rectangles vides 11 - Rectangles pleins 12 - Cercles/Ellipses vides 13 - Cercles/Ellipses plein(e)s 14 - Rectangles avec dgrad 15 - Menu de dgrad 16 - Sphres / Ellipses avec dgrad 17 - Prise de brosse / Restauration 18 - Prise de brosse par polyforme (lasso) / Restauration 19 - Effets sur la brosse 20 - Modes de dessin 21 - Texte 22 - Mode Loupe / Menu 23 - Pipette / Inverser les couleurs 24 - Taille de l'cran / Rsolution de scurit 25 - Page de brouillon / Copier vers le brouillon 26 - Sauver l'image / Sauvegarde automatique 27 - Charger une image / Recharger 28 - Paramtres gnraux (Settings) 29 - Effacer l'image 30 - Aide / Statistiques 31 - Oops (Dfaire/Refaire) 32 - Dtruire la page courante 33 - Quitter le programme 34 - Menu de palette 35 - Dplacer la palette gauche / droite 36 - Fentre de palette 37 - Cacher le menu Quand vous utiliserez n'importe quel outil de dessin, un clic gauche dessinera avec la couleur principale, tandis qu'un clic droit dessinera avec la couleur de fond. Lorsque des botes de dialogue apparatront l'cran, Cancel (ou No) sera toujours mul par la touche , et OK (ou Yes) par . Dans les diffrents menus, les titres sur les boutons contenant une lettre souligne peuvent tre muls en tapant cette lettre au clavier. Dans quelques menus, vous pouvez slectionner un bloc de couleurs dans la palette. Cela signifie que vous pouvez cliquer sur une couleur et dplacer la souris vers une autre en maintenant le bouton appuy pour slectionner un bloc de couleurs. Vous pouvez dplacer une fentre pour rendre visible l'image qui est derrire en cliquant en haut de la fentre (sur le titre) et en maintenant le bouton de la souris enfonc tout en la dplaant. 1 - Pinceaux: Clic gauche: ============> Affiche un menu ou vous pouvez choisir la forme de votre pinceau. Les pinceaux sont rangs par famille. Vous pouvez voir quelques pinceaux de la mme famille mais avec des tailles diffrentes. Il y a au moins un pinceau de chaque famille affich dans ce menu. Voici la liste de toutes les diffrentes familles de pinceaux: Carr Disque Carr Disque Losange Alatoire tram tram _______________________________________________________________ Barre Barre Slash Anti- Croix X Croix + horiz. verticale slash Les 3 derniers pinceaux dans le menu appartiennent la famille "divers" et leur taille ne peut pas tre modifie. Clic droit: ============> Transforme votre brosse actuelle en pinceau. En fait, c'est une "monochromisation" de la brosse. C'est--dire que toutes les couleurs de la brosse qui ne sont pas la couleur de fond passeront de la mme couleur que la couleur principale. Mais cette option ne modifie pas la brosse: vous n'avez qu' cliquer avec le bouton droit sur une des boutons "Get brush" pour rcuprer la brosse en couleur. Note: Lorsque vous appuyez (pas dans le menu) sur la touche (valeur par dfaut), le pinceau actuel devient le plus petit membre de la famille "Disque": c'est--dire 1 pixel. 2 - Ajuster l'image / Effets sur l'image: Clic gauche: ============> Vous permet de dplacer ("scroller") l'image pour recentrer votre graphe par exemple. Toute partie du dessin qui sort d'un cot de l'image revient par le ct oppos. Ceci est considr comme tant de la famille des outils de dessin. Clic droit: ============> *** Pas encore implment *** 3 - Bouton Dessin la main: Clic gauche: ============> Selectionne le mode dessin la main actuel comme outil de dessin actif. Il y a 3 modes de dessin la main: - Dessin continu: Lorsque vous dplacez le curseur de la souris, le pinceau est rgulirement appliqu sur l'image, reliant les diffrents points de l'cran sur lesquels vous tes passs. Cet outil de dessin autorise le changement de la couleur principale et de la couleur de fond durant son utilisation. - Dessin discontinu: Lorsque vous dplacez la souris, le pinceau est appliqu la position actuelle de la souris chaque VBL (balayage vertical de l'cran). Cet outil de dessin autorise le changement de la couleur principale et de la couleur de fond durant son utilisation. - Dessin point par point: Le pinceau est simplement appliqu la position o vous avez cliqu en premier. Clic droit: ============> Permute les diffrents modes de dessin la main, et active en mme temps l'outil de dessin la main. 4 - Courbes de Bzier (Splines): Clic gauche: ============> Selectionne le mode de courbe courant comme outil de dessin actif. Il y a deux modes de courbes diffrents: - Courbes 4 points de contrle: Dfinissez la ligne de base comme une ligne classique; puis dplacez, avec le bouton gauche de la souris, les points de contrle internes afin de choisir la forme de la courbe. Quand la courbe a la forme que vous dsirez, cliquez sur le bouton droit de la souris pour la tracer dfinitivement. - Courbes 3 points de contrle: Fonctionne comme dcrit ci-dessus, mais vous n'aurez qu'un seul point de contrle interne placer. De plus, la courbe sera trace juste aprs avoir plac ce point. Clic droit: ============> Permute les diffrents modes de courbes, et active en mme temps l'outil de dessin de courbes. 5 - Lignes: Clic gauche: ============> Selectionne le mode de dessin de lignes actuel comme outil de dessin actif. Il y a 2 modes de dessin de lignes: - Lignes classiques: En cliquant une premire fois sur l'image, vous dfinirez de dbut de la ligne. Maintenez le bouton appuy pour placer la fin de la ligne; et relchez le bouton pour tracer la ligne. - Lignes relies: Fonctionne de la mme manire que prcdemment, mais la fin d'une ligne deviendra automatiquement le dbut de la suivante. Lorsque vous voudrez arrter l'enchinement de lignes, utilisez le bouton oppos de la souris. "Le bouton oppos" signifie que si vous avez commenc tracer les lignes avec le bouton gauche (couleur principale), il faudra interrompre le traitement avec le bouton de droite; et rciproquement. - Lignes concentriques: lors du premier clic sur l'image, vous dfinirez le centre des lignes. En ralit, le centre est dfini par la position de la souris lorsque vous relchez son bouton. Ensuite vous pouvez dessiner des lignes partant du centre vers la position actuelle de la souris en cliquant. Pour arrter de dessiner des lignes concentriques, utilisez le bouton oppos de la souris. Cet outil de dessin autorise le changement de la couleur principale et de la couleur de fond durant son utilisation. Clic droit: ============> Permute les diffrents modes de dessin de lignes, et active en mme temps l'outil de dessin de lignes. 6 - Arographe (Spray): Clic gauche: ============> Selectionne l'arographe comme outil de dessin actif. Cet outil de dessin autorise le changement de la couleur principale et de la couleur de fond durant son utilisation. Clic droit: ============> Affiche le menu de configuration de l'arographe: - Size (Taille): Dfinit le diamtre du cercle dans lequel l'aro- graphe fonctionnera. - Delay (Dlai): Dfinit le nombre de VBL (balayage vertical de l'cran) qui seront attendus entre deux jets (cycles) de l'aro- graphe. - Mode: Dfinit si vous dsirez utiliser un arographe monochrome ou multicolore. - Mono-flow (flux en monochrome): Dfinit le nombre de fois que le pinceau sera alatoirement appliqu dans le cercle de l'arographe chaque jet (cycle). - Palette: Un clic gauche sur une couleur de la palette vous permettra de voir en quelle quantit elle sera utilise dans le flux multi- colore, et de la modifier en utilisant la jauge sur la droite. Si le flux de cette couleur tait gal 0, il sera mis la valeur "Init". Un clic droit sur une couleur fera automatiquement passer sa quantit 0, ce qui revient la supprimer du flux multicolore. - Clear (Effacer): Supprime toutes les couleurs du flux multicolore. En fait, cela place une valeur nulle dans l'utilisation de chacune des couleurs. - Init: Ceci vous permet de dfinir une valeur qui sera automatique- ment applique aux couleurs ayant un flux nul lorsque vous cliquerez dans la palette l'aide du bouton gauche. Cette option permet de dfinir plus rapidement un ensemble de couleurs. - +1,-1,x2,2: Modifie la valeur de toutes les couleurs selectionnes (et seulement celles-ci). 7 - Remplissage (Flood-fill) / Remplacement de couleur: Clic gauche: ============> Slectionne le remplisseur comme outil de dessin actif. Le remplisseur, comme n'importe quel outil de dessin, sera affect par tous les effets. Remarquez que seule la partie visible de l'image sera remplie (de mme que pour tous les autres outils de dessin, le remplissage n'affecte que la partie visible du dessin; ceci vitant des effets indsirables et non contrls par l'utilisateur). Clic droit: ============> Slectionne le remplacement de couleur comme outil de dessin. Chaque rgle a ses exceptions et la rgle nonce ci-dessus n'y droge pas. Cet outil est en effet le seul n'tre affect par aucun effet ( l'exception du Stencil) et pouvoir galement modifier les parties non visibles de l'image. Le but de cet outil tant de remplacer toutes les occurences d'une couleur dans l'image par une autre, il aurait t dommage de se limiter modifier uniquement la partie visible de l'image. 8 - Polygnes / Polyformes: Clic gauche: ============> Slectionne les polygnes comme outil de dessin actif. Ceci fonctionne exactement comme les lignes relies en reliant les extrmits quand vous avez termin. Clic droit: ============> Slectionne les polyformes comme outil de dessin actif. Cet outil fonctionne comme une combinaison du dessin la main et des lignes relies. Si vous maintenez le bouton de la souris press, vous dessinerez comme si vous tiez en mode de dessin la main. Et, si vous relchez le bouton de la souris, cela fonctionnera comme les lignes relies. Cliquez sur le bouton de la souris oppos (i.e.: cliquez droite si vous avez commenc dessiner avec le bouton gauche de la souris, et vice versa) pour terminer l'opration. Les deux extrmits seront relies automatiquement. 9 - Polygones/Polyformes plein(e)s: Fonctionnent exactement de la mme manire que les polygnes et poly- formes ci-dessus, mais remplissent l'intrieur des formes ainsi dfinies. 10 - Rectangles vides: N'importe quel clic: ====================> Selectionne les rectangles vides comme outil de dessin actif. Placez le coin d'un rectangle. Maintenez le clic pour dplacer le coin oppos et relachez le bouton de la souris pour le placer dfinitivement. 11 - Rectangles pleins: N'importe quel clic: ====================> Slectionne les rectangles pleins comme outil de dessin actif. Fonctionne comme un rectangle vide. 12 - Cercles/Ellipses vides: Clic gauche: ============> Slectionne les cercles vides comme outil de dessin actif. Positionnez le centre du cercle et maintenez le bouton de la souris pour choisir son rayon. Clic droit: ============> Slectionne les ellipses vides comme outil de dessin actif. Positionnez le centre du cercle et maintenez le bouton de la souris pour choisir ses dimensions. 13 - Cercles/Ellipses plein(e)s: Fonctionne comme les cercles et les ellipses vides. 14 - Rectangles avec dgrad: *** Pas encore implment *** 15 - Menu de dgrad: N'importe quel clic: ====================> Ouvre une fentre dans laquelle vous pouvez dfinir la faon dont les dgrads sont traits. Les diffrentes sections de ce menu sont: - Direction (flche): Change le sens du dgrad. - Mthode de transition: Permute parmi les trois mthodes suivantes: - Pas de transition - Transition de base - Transition amliore - Mix (Mlange): Mlange le dgrad avec un facteur alatoire plus ou moins important. - Palette: Selectionnez un intervale de couleurs pour constituer un dgrad. - Ascenseur d'index: Dfinit le dgrad courant parmi un ensemble de 16 mmoriss. 16 - Sphres / Ellipses avec dgrad: Clic gauche: ============> Slectionne les sphres comme outil de dessin actif. Positionnez le centre de la sphre et maintenez le bouton de la souris pour choisir son rayon. Ensuite placez la source de l'clairage. Clic droit: ============> Slectionne les ellipses avec dgrad comme outil de dessin actif. *** La version actuelle de cet outil n'est pas la bonne, donc *** *** nous expliquerons son fonctionnement quand elle sera acheve. *** Si vous tracez une sphre ou une ellipse dgrade avec le bouton droit de la souris, le rsultat sera la mme figure remplie avec la couleur de fond. 17 - Prise de brosse / Restauration: Clic gauche: ============> Dmarre une prise de brosse. Cliquez sur un coin du rectangle contenant la brosse puis maintenez le clic pour dfinir le coin oppos du rectangle. Relachez le bouton de la souris pour prendre la brosse. Effectuer cette opration avec le bouton droit de la souris effacera la zone dans laquelle la brosse a t prise avec la couleur de fond. Clic droit: ============> Restaure l'ancienne brosse. 18 - Prise de brosse par polyforme / Restauration: Clic gauche: ============> Capture une brosse de forme quelconque en dfinissant un "polyforme" (veuillez vous rferer la section 8 pour plus d'explications). Clic droit: ============> Restaure l'ancienne brosse (pareil que ci-dessus). 19 - Effets sur la brosse: N'importe quel clic: ====================> Affiche un menu dans lequel les options suivantes sont disponibles: - X: Inversion selon X (symtrie par rapport (Oy)). - Y: Inversion selon Y (symtrie par rapport (Ox)). - Rotate by 90: Effectue sur la brosse une rotation de 90 degrs. - Rotate by 180: Effectue sur la brosse une rotation de 180 degrs. - Rotate by any angle (Rotation de n'importe quel angle): Engendre une opration interactive qui permet de faire tourner la brosse. Pour cela, commencez par placer le centre de rotation avec le bouton gauche de la souris (si, ce moment-l, vous appuyez sur le bouton droit, l'opration sera annule). Ensuite vous pouvez dfinir l'angle de rotation autant de fois que vous le voulez en dplaant la souris et en cliquant avec le bouton gauche. Puis vous validerez avec le bouton droit lorsque vous serez satisfait. Pendant ce temps, vous pouvez appuyer sur les 8 chiffres extrieurs du pav numrique pour dfinir des angles multiples de 45: 135 90 45 \ | / '7' '8' '9' 180 -'4' '6'- 0 '1' '2' '3' / | \ 225 270 315 - Stretch (Etirement): Engendre une opration interactive qui permet d'tirer la brosse. Pour cela, commencez par placer le coin haut- gauche de la brosse avec le bouton gauche de la souris (si, ce moment-l, vous appuyez sur le bouton droit, l'opration sera annule). Ensuite vous pouvez placer le coin oppos autant de fois que vous le voulez, puis vous validerez avec le bouton droit lorsque vous serez satisfait. Si vous placez ce point des coordonnes infrieures celles du point de dpart, la brosse sera inverse. Pendant ce temps, vous pouvez appuyer sur les touches suivantes dont voici les effets: 'D' : double la brosse en X et en Y 'H' : rduit la brosse de moiti en X et en Y 'X' : double la brosse en X 'Shift+X': rduit la brosse de moiti en X 'Y' : double la brosse en Y 'Shift+Y': rduit la brosse de moiti en Y 'N' : restaure la taille normale de la brosse (peut se rvler utile car c'est le seul moyen d'annuler) - Distort (Dformation): *** Pas encore implment *** - Outline (Contours): Cette option permet de dessiner les contours de la brosse avec la couleur principale (Fore-color). - Nibble (Grignotter): Cette option "grignotte" les contours de la brosse. C'est en quelque sorte l'effet inverse de l'option Outline. - Recolorize: Modifie la brosse de faon ce qu'elle ressemble l'aspect qu'elle aurait dans la page de brouillon, en utilisant la palette courante. - Get brush colors: Transfre les couleurs de la page de brouillon utilises par la brosse, dans la palette courante. - Brush handle: Vous permet de choisir o placer la prise (poigne) de la brosse. - Load / Save: charger ou sauvegarder une brosse. 20 - Modes de dessin: Ce bouton ouvre un menu dans lequel vous pouvez activer/dsactiver les diffrents modes de dessin. (Les touches [F1]-[F9] correspondent aux 9 boutons) Dans ce menu, le bouton "All off" (tout teint) dsactive tous les modes de dessin. La touche [Suppr] est le raccourci clavier pour ce bouton. Le bouton "Feedback" sert uniquement pour les modes "Shade", "Quick- shade", "Smooth" et "Transparence". Lorsqu'il est activ, il indique que l'tat _actuel_ de l'image doit tre pris en compte pour l'effet au lieu de l'tat dans lequel tait l'image lorsqu'on a click pour commencer tracer. Le mieux, comme bien souvent, est que vous testiez par vous-mme avec et sans Feedback pour constater la diffrence. Les autres boutons sont les suivants: * Mode Shade (Ombrage) / Menu: ------------------------------ Cet effet consiste incrmenter ou dcrmenter le numro de la couleur dans un ensemble dfini par l'utilisateur. Cela montre sa vraie dimension lorsque l'ensemble de couleurs est un dgrad. Alors, vous pouvez travailler sur une partie de l'image o les couleurs appartiennent ce mme ensemble sans avoir changer la couleur de votre pinceau systmatiquement. Vous pouvez choisir d'incrmenter ou de dcrmenter la couleur en cliquant sur le bouton gauche ou droit de la souris lorsque vous dessinez. Si vous cliquez sur une couleur qui n'appartient pas l'ensemble de couleurs, elle restera inchange. Clic gauche: ============> Active/Dsactive le mode Shade. Clic droit: ============> Ouvre un menu dans lequel vous pouvez dfinir une table de shades parmi les 8 mmorises par le programme. Les diffrentes sections de ce menu sont: - Palette: Vous pouvez dfinir dans celle-ci les blocs de couleurs insrer dans la table des shades. - Scroller: Sert changer de table de shades. - Zone de dfinition de table de Shades: Les 512 cases fournies sont largement suffisantes pour dfinir les diffrents shades puisque chacune des 256 couleurs de la palette ne peut tre prsente qu'une seule fois dans chaque table. - Une fentre (celle situe en haut droite) qui vous permet de visualiser les diffrents shades dfinis dans la table actuelle. - Copy (copier): Copie le contenu actuel de la table dans un buffer. (Lors de l'ouverture du menu, la table courante est automatiquement range dans le buffer). - Paste (coller): Copie le contenu du buffer ci-dessus dans la table actuelle. - Clear (tout effacer): Permet de rinitialiser la table de "shades". - Insert (insrer): Sert insrer le bloc slectionn dans la palette la position du curseur dans la table des shades. SI vous clickez avec le bouton gauche de la souris sur ce bouton ALORS SI un bloc de plus d'une case est slectionn dans la table ALORS Il est effac puis on insre le bloc dfini dans la palette. SINON On insre le bloc dfini dans la palette juste avant la case slectionne. FIN SI SINON Le bloc dfini dans la palette est insr en crasant les couleurs suivant le dbut du bloc slectionn dans la table. FIN SI - Delete (effacer): Supprime le bloc slectionn dans la table. - Blank (vide): Suit l'algorithme suivant: SI vous clickez avec le bouton gauche de la souris sur ce bouton ALORS On remplace le bloc slectionn dans la table par des cases vides SINON SI un bloc de plus d'une case est slectionn dans la table ALORS Insrer une case vide gauche et une case vide droite du bloc (ceci sert isoler un shade rapidement) SINON Insrer une case vide gauche de la case slectionne FIN SI FIN SI - Invert (inverser): Inverse l'ordre du bloc slectionn dans la table. - Swap (changer): Permet de dplacer un bloc (cela l'change avec ce qu'il y a l ou veut le dplacer). - Undo (dfaire): Permet d'annuler la dernire modification de la table. - Les 2 numros qui s'affichent droite de ces boutons sont: (en haut)- le numro de la couleur slectionne dans la palette si une seule est slectionne. (en bas) - le numro de la couleur contenue dans la case de la table de shades si cette case est la seule slectionne. - Le bouton de "mode" affiche 3 tats diffrents: "Normal": Opre l'intrieur de l'intervalle de couleurs et sature ses bordures. "Loop" (Boucle): Boucle lorsque les bornes de l'intervalle sont dpasses. "No saturation": Ne sature pas aux bornes de l'intervalle si elles sont dpasses. Si le Pas (voir plus bas) est de 1, cette option fait exactement la mme chose que le mode Normal. - Set/Disable (placer un masque): Si vous voulez dfinir plusieurs shades dans une mme table mais que vous souhaiteriez qu'ils ne soient pas tous effectifs en mme temps, vous pouvez en masquer certains ce qui aura pour effet qu'ils seront interprts comme des cases vides. Pour ce faire, slectionnez un bloc dans la table des shades et clickez sur "Set". Le bloc sera alors soulign d'un trait blanc; ce qui signifie qu'il est dsactiv. - Clear/Enable (enlever le masque): fait exactement l'inverse du bouton prcdent. - Step (pas): Dfinit un pas d'incrmentation du shade. Plus le pas est grand et plus vous parcourerez rapidement les couleurs du shade. Par exemple: si le pas est de 2 et que vous avez dfini un shade avec les couleurs 0,1,4,5,9 et que vous clickez sur un pixel de couleur 1, il prendra alors la couleur 5 qui est 2 cases plus loin dans la table. (Nous sommes dsols pour ces considrations techniques assez lointaines d'une vision prement artistique; mais sachez que cet effet est vraiment trs utile et qu'il est prfrable que vous compreniez son fonctionnement si vous voulez en profiter pleinement). * Mode Quick-shade (Ombrage) / Menu: ------------------------------------ Ce mode de dessin a peu prs le mme effet que le mode Shade si ce n'est qu'il est beaucoup plus rapide configurer mais un peu moins puissant. Lorsque vous dessinez sur une couleur de l'image qui se situe entre la couleur principale (fore-color) et la couleur de fond (back-color) dans la palette, la couleur tend se rapprocher de la fore-color (suivant le pas dfini) si l'on dessine avec le bouton gauche de la souris, ou bien tend vers la back-color si l'on dessine avec le bouton droit. Clic gauche: ============> Active/Dsactive le mode Quick-shade. Clic droit: ============> Ouvre un menu avec quelques paramtres qui reprsentent exactement la mme chose que dans le menu du mode Shade. Ces paramtres sont le pas et le mode de bouclage/saturation (normal, loop, no saturation). * Mode Stencil (Pochoir) / Menu: -------------------------------- C'est utilis pour empcher la modification de certaines couleurs si vous essayez de dessiner sur elles. L'application principale du stencil est lorsque vous voulez remplacer une ou plusieurs couleurs par une autre. Clic gauche: ============> Active/Dsactive le mode Stencil. Clic droit: ============> Ouvre un menu dans lequel vous pouvez dfinir un stencil. Les diffrentes sections de ce menu sont: - Clear (Effacer): Dprotge toutes les couleurs. - Invert (Inverser): Les couleurs qui taient protges ne le sont plus et vice versa. - Palette: Selectionnez les couleurs qui doivent tre protges avec le bouton gauche de la souris ou dprotgez-les avec le bouton droit. * Mode Masque / Menu: --------------------- Cet effet aurait pu tre appel "True stencil" (vrai pochoir) car il protge des parties de l'image au lieu de protger des couleurs. Les couleurs que vous slectionnez reprsentent les pixels dans la page de brouillon, correspondant aux pixels dans la page actuelle, que vous ne voulez pas modifier. Par exemple, dessinez une simple figure blanche sur un fond noir dans la page de brouillon. Puis, slectionnez la couleur noire dans le menu du mode Masque. Lorsque vous dessinerez dans la page actuelle, seulement les pixels correspondant aux pixels blancs (non-noirs) dans la page de brouillon seront modifis. Clic gauche: ============> Active/Dsactive le mode Masque. Clic droit: ============> Ouvre un menu dans lequel vous pouvez dfinir les couleurs du masque. Ce menu fonctionne de la mme faon que celui du Stencil. Veuillez donc vous rfrer au paragraphe consacr au Stencil pour savoir comment utiliser ce menu. * Mode Grille / Menu: --------------------- C'est utile pour accrocher le curseur aux points de croisement d'une grille. C'est gnralement utilis pour dessiner une grille avant de dessiner des sprites de la mme taille tels que des "tiles" ou une fonte, ou bien pour dessiner des figures ou prendre des brosses avec des dimensions multiples du pas de la grille.'); Clic gauche: ============> Active/Dsactive le mode Grille. Clic droit: ============> Ouvre un menu dans lequel vous pouvez dfinir les paramtres de la grille. Ces paramtres sont: - X,Y: Pas de la grille. - dX,dY: Dcalages de la grille. * Mode Trame (Passoire) / Menu: ------------------------------- Cet effect permet, en dfinissant un motif, de dessiner seulement sur des points particuliers de l'image. Si vous tes un dessinateur Manga, vous pourriez trouver a utile pour dessiner des ombres avec diffrentes trames ou bien des transitions de couleurs. Clic gauche: ============> Active/Dsactive le mode Trame. Clic droit: ============> Ouvre un menu dans lequel vous pouvez dfinir les paramtres des trames. Ce menu est constitu de: - Zone de dessin 16x16: Vous pouvez dfinir une trame dedans (clic gauche => pixel blanc / clic droit => pixel noir). Tous les pixel blancs indiquent que lorsque vous dessinerez, des pixels seront appliques sur l'image aux positions correspondantes tandis que des pixels noirs n'entrneront aucun affichage: les points blancs correspondent aux "trous de la passoire". - 12 trames par dfaut: Elles peuvent tres recopies vers la zone de dessin (16x16). - "Transfer to brush" (transfrer vers la brosse): Copie la trame vers la brosse (pixels blancs => couleur principale / pixels noirs => couleur de fond). - "Get from brush" (rcuprer partir de la brosse): Place la brosse dans la zone de dessin (couleur de fond => pixels noirs / les autres => pixels blancs). - 4 flches de dplacement (scrolling): Dplacent la trame dans la zone de dessin. - 4 flches de dimensionnement: Dfinissent les dimensions de la trame. - Valeur par dfaut (carr noir ou blanc): Indique quelle couleur doit tre insre quand vous augmentez les dimensions de la trame. - "Clear" (Effacer): Remplit toute la trame avec la valeur par dfaut (voir ci-dessus). - "Invert" (Inversion): Il ... inverse :) ... les pixels noirs et blancs. * Mode Transparence (Colorize) / Menu: -------------------------------------- Cela permet de mlanger les couleur(s) du pinceau (brosse) avec les couleurs de l'image. C'est utilis pour faire des effets de transparence comme avec de l'aquarelle. Clic gauche: ============> Active/Dsactive le mode Transparence. Clic droit: ============> Ouvre un menu dans lequel vous pouvez dfinir les paramtres de transparence. Ces paramtres sont: - Taux d'interpolation: Indique le pourcentage de la couleur applique qui sera considre sur la couleur remplace. - Mthode par interpolation: Utilise une mthode de moyenne pondre pour calculer la couleur, selon le taux d'interpolation. - Mthode additive: Utilise les teintes les plus claires pour choisir la couleur appliquer. Par exemple: si vous voulez appliquer une couleur ayant les teintes 30,20,40 sur une couleur 10,50,20, la couleur qui sera applique sera celle qui, dans la palette, sera la plus proche de la couleur thorique 30,50,40. - Mthode soustractive: Utilise les teintes les plus sombres pour choisir la couleur appliquer. Par exemple: si vous voulez appliquer une couleur ayant les teintes 30,20,40 sur une couleur 10,50,20, la couleur qui sera applique sera celle qui, dans la palette, sera la plus proche de la couleur thorique 10,20,20. * Mode Smooth (adouci) / Menu: ------------------------------ Cela permet d'obtenit un effet d'anti-aliasing primaire mais ce n'est vraiment pas aussi efficace que si c'tait fait par un artiste. De toutes faon, cet effet est surtout utile pour donner un aspect flou. Click gauche: =============> Active/Dsactive le mode Smooth. Clic droit: ============> Ouvre un menu dans lequel vous pouvez dfinir la matrice du Smooth ou bien en choisir une parmi les 4 prdfinies. La case du milieu reprsente le pixel sur lequel on dessine et les 8 cases qui l'entourent reprsentent les pixels voisins. Le point sur lequel on dessine sera alors remplac par la moyenne pondre (suivant les valeurs de chaque case) des 9 points dfinis. * Mode Smear (taler) / Menu: ------------------------------ Cet effet tale les pixels dans la direction dans laquelle vous bougez votre pinceau, comme si vous vouliez taler de la peinture fraiche avec le doigt. Vous pouvez combiner cet effet avec l'effet de transparence. N'importe quel clic: ====================> Active/Dsactive le mode Smear. * Mode Tiling (Dallage) / Menu: ------------------------------- Cela consiste appliquer des parties de la brosse ajustes sur une sorte de carrelage lorsque vous dessinez. C'est principalement utilis pour dessiner rapidement un fond avec un certain motif, mais un grand nombre d'autres utilisations est possible. Clic gauche: ============> Active/Dsactive le mode Tiling. Clic droit: ============> Ouvre un menu dans lequel vous pouvez choisir les paramtres de Tiling. Ces paramtres sont les dcalages du dallage. (Daaaallaaaage... Ton univers impitoyaaable... :) Je suis vraiment dsol... j'ai pas pu m'en empcher :)) 21 - Texte: *** Pas encore implment *** 22 - Mode Loupe / Menu: Clic gauche: ============> Dmarre/Annule le choix de la partie zoome. Si vous tes dj en mode Loupe, vous retournerez en mode normal. Clic droit: ============> Affiche un menu dans lequel vous pouvez choisir le facteur de loupe. Note: Lorsque vous tes en mode Loupe, vous pouvez dplacer la barre de sparation ("split") en cliquant dessus et en dplaant la souris vers la gauche ou vers la droite en maintenant enfonc le bouton de la souris. 23 - Pipette / Inverser les couleurs: Clic gauche: ============> Dmarre une prise de couleur. Cliquez sur l'image pour rcuprer la couleur du pixel sur lequel vous tes. Vous pouvez prendre indiffrement une nouvelle couleur principale ou couleur de fond en utilisant respectivement le bouton gauche ou droit de la souris. Clic droit: ============> Echange la couleur principale et la couleur de fond. La couleur sur laquelle vous pointez actuellement sera affiche dans la barre d'outils la suite des coordonnes. Si vous clickez en dehors de l'image, la couleur 0 vous sera renvoye. 24 - Taille de l'cran / Rsolution de scurit: Clic gauche: ============> Affiche un menu dans lequel vous pouvez dfinir la taille de votre image (jusqu' 1024x768) en cliquant dans les botes nommes "Width" (Largeur) et "Height" (Hauteur); et la rsolution (dans la liste) dans laquelle vous souhaitez dessiner. Cliquer sur une rsolution avec le bouton droit de la souris ne changera pas seulement la rsolution de l'cran, mais changera aussi les dimensions de l'image par celles de l'cran. Les rsolutions affiches en gris fonc sont des modes VESA qui ne sont pas supports par votre carte vido. Si vous avez des modes comme cela, vous devriez essayer de lancer un driver VESA tel que Univesa ou Univbe avant de lancer le programme. Si ces modes restent indisponibles, alors cela signifie que votre carte vido ne les supporte vraiment pas. Les petits boutons sur le ct gauche des lignes dans la liste des modes ont t conus pour vous permettre d'inhiber certains modes qui ne sont pas supports par votre carte. Lorsque vous clickez sur l'un de ces boutons, sa couleur change vers l'une des 4 suivantes. La signification de chacune de ces couleurs est: - Gris clair: Le mode vido est correct. Il peut tre utilis par l'option de changement de rsolution automatique lorsque vous chargez une image, et vous pouvez le slectionner dans le menu des rsolutions. - Blanc: Cela fonctionne exactement comme ci-dessus. De plus, cela vous permet de cocher vos modes prfrs. En effet, le nombre impressionnant de modes vido rendant difficile la recherche d'un mode en particulier dans la liste, aussi vous pouvez mettre ceux que vous utilisez frquemment en blanc afin qu'ils soient plus facile localiser ultrieurement. (Note: vous ne pouvez pas inhiber le mode 320x200 standard) - Gris fonc: Il vous permet d'indiquer quels modes ne sont pas parfaits (clignotements, dcentrage, surbrillance, etc...) mais qui peuvent tout de mme tres utiliss par "l'auto-rsolution". La diffrence avec les boutons gris clair est que ces modes ne seront pas utiliss par l'option de changement de rsolution automatique. - Black: Utilisez cette couleur pour les modes qui ne fonctionnent vraiment pas. Ainsi, ces modes ne seront pas utiliss par l'option "auto-set res." et le programme vous empchera de les slectionner partir du menu des rsolutions. Clic droit: ============> Passe automatiquement au mode 320x200 MCGA. 25 - Page de brouillon / Copier vers le brouillon: Clic gauche: ============> Passe la page de brouillon. La page courante est alors considre comme la nouvelle page de brouillon, et la page de brouillon comme la nouvelle page courante. Clic droit: ============> Ouvre un menu dans lequel vous pouvez choisir si vous voulez copier toute l'image (touche de raccourci dans ce menu: [Return]), seulement les pixels, seulement la palette, ou seulement quelques couleurs. Dans ce dernier cas, un second menu (genre stencil) vous proposera de slectionner les couleurs copier (par dfaut, elles sont toutes slectionnes). Veuillez vous reporter la section "18 - Stencil" pour savoir comment utiliser ce dernier menu. La dernire option du menu ("Copier palette et remapper"), adapte la page de brouillon avec la palette actelle puis recopie cette palette sur la page de brouillon. Cette option est utile pour remapper rapidement une image avec la palette d'une autre. 26 - Sauver l'image / Sauvegarde automatique: Clic gauche: ============> Affiche un selecteur de fichier dans lequel les options suivantes sont disponibles: - Lecteurs: Vous permettent de changer le lecteur courant. Vous pouvez aussi utiliser + pour changer de lecteur. - Format: Vous permet de choisir le format de fichier que vous voulez (les formats PAL et KCF sont des formats de palette). - Filename (Nom de fichier): Vous permet de donner un nouveau nom l'image. Si aucune extension n'est donne, une par dfaut (dpendant du format) sera utilise. - Liste de fichiers: Vous permet de parcourir l'arborescence du disque ou de remplacer un fichier dj existant. - Delete (Supprimer): Permet d'effacer le fichier ou le rpertoire (si celui-ci est vide) se trouvant sous la barre de slection. - Save (Sauver): Sauve l'image avec le nom de fichier courant, le format choisi et le commentaire courant (pour les fichiers PKM). Si le nom de fichier courant reprsente un rpertoire, vous entrerez dedans. - Commentaire (Txt): Si vous utilisez le format PKM, vous pouvez saisir un commentaire de votre image. Note: La touche Backspace vous amne directement au rpertoire parent. Tapez les 1res lettres d'un nom de fichier que vous recherchez pour y accder plus rapidement. Clic droit: ============> Sauve l'image courante avec son nom de fichier, son format et son commentaire actuels. Si le nom de fichier utilis pour sauver l'image existe dj, une demande de confirmation apparatra. 27 - Charger une image / Recharger: Clic gauche: ============> Cela fonctionne de la mme faon que la sauvegarde. Vous aurez accs dans le selecteur de format un filtre "*.*". Et bien videmment, vous ne pourrez pas saisir de commentaire. Clic droit: ============> Recharge l'image. Si vous voulez charger une image et que vous n'avez pas sauv les dernires modifications de l'image courante, une demande de confimation apparatra. 28 - Paramtres gnraux (Settings): N'importe quel clic: ====================> Affiche un menu dans lequel vous pouvez configurer divers lments du programme: - Nombre de pages d'UNDO: Indique le nombre total de pages que GrafX2 mmorisera. Chaque fois que vous modifiez l'image, son tat courant est mmoris dans l'une de ces pages. Pour parcourir ces pages, utilisez le bouton Oops(Undo/Redo). - Fonte: Dtermine si vous voulez utiliser GrafX2 avec une police de caractres classique ou une autre un peu plus amusante. - Sensibilit de la souris: Modifie la vitesse de la souris. - Montrer/Cacher les fichiers dans les listes: Dfinit si certains fichiers/rpertoires aux attributs particuliers doivent apparatre ou non dans les slecteurs de fichiers. - Montrer/Cacher les limites de l'image: Indique si les limites de l'image doivent tre affiches lorsque vous tes dans une rsolution plus grande que l'image. - Ecraser la palette: Indique si le chargement d'un fichier dont la palette fait moins de 256 couleurs doit craser le reste de la palette actuelle (remplacer par du noir). - Maximiser la preview: Maximise la preview des images de faon ce qu'elle prenne le plus de place. Si vous n'tes pas dans la mme rsolution que celle utilise par l'image, cela peut corriger l'aspect ratio, mais si l'image ne remplit pas tout l'cran, cela peut tre pire. - Backup: Lorsque vous sauverez une image sur un fichier existant, le programme renommera ce fichier en "*.BAK" o * est le nom de l'image sans son extension. Si le fichier de backup existe dj dans le rpertoire, il sera remplac. Si vous sauvez une image avec le nom du fichier de backup, aucun fichier de backup ne sera cr (bien videmment!) ;). - Curseur: Vous permet de choisir un curseur solide (sprite) ou transparent. - Couleurs de sret: Remet les 4 couleurs par dfaut des menus si vous effectuez une opration qui passe l'image en moins de quatre couleurs dans l'diteur de palette. - Adjust brush pick (ajuster la prise de brosse): Cette option est utilise lorsque vous capturez une brosse en mode Grille. Alors, les pixels en bas et droite ne seront pas pris avec le rest de la brosse. Cette option t faite car, si les gens rcuprent des brosses en mode Grille, c'est principalement lorsqu'ils veulent rcuprer des sprites. Par exemple: si vous avez des sprites 16x16 sur votre page, vous dfinirez une grille de 16x16. Mais le curseur se positionnera sur des points tels que (0,0), (16,0), (16,16) etc... Et le problme est que, de (0,0) (16,16), il y a 17 pixels! Mais si vous slectionnez l'option adjust-brush-pick, les pixels indsirables seront ignors. De plus, cette option ajuste la "poigne" de la brosse de faon ce que la brosse concide toujours avec la grille, au lieu de placer systmatiquement l'attache au centre de la brosse. - Sparer les couleurs: Dessiner un quadrillage autour des couleurs de la barre d'outil. - Changer automatiquement de rsolution: Passe dans la meilleure rsolution pour l'image charge. - Coordonnes: Choisissez si vous souhaitez afficher des coordonnes relatives ou absolues lorsque vous utilisez des outils tels que les cercles, les rectangles, etc... Par exemple, si vous dessinez un cercle: si les coordonnes sont relatives, le rayon du cercle sera affich, tandis qu'en coordonnes absolues coords, ce sont les coordonnes du curseur qui seront affiches. - Reload (Recharger): Charge la configuration prcdemment sauve. - Auto-save (Sauvegarde automatique): Signifie que la configuration sera automatiquement sauve quand vous quitterez le programme. - Save (Sauver): Sauve la configuration tout de suite. Toutes les modifications prennent effet juste aprs avoir ferm le menu des paramtres gnraux. 29 - Effacer l'image: Clic gauche: ============> Efface l'image avec la couleur numro 0. Clic droit: ============> Efface l'image avec la couleur de fond. 30 - Aide / Statistiques: Clic gauche: ============> Affiche une fentre d'information o vous trouverez quelques crdits, de l'aide sur les diffrents effets, des greetings, des information sur l'enregistrement, etc... Clic droit: ============> Affiche une fentre d'informations o vous trouverez diverses informations sur le systme. Note: pour assurer le bon fonctionnement du programme, il est conseill de disposer de plus de 128 Ko de libres. 31 - Oops (Dfaire/Refaire): Clic gauche: ============> Vous permet d'annuler la dernire modification sur l'image. Clic droit: ============> Vous permet de refaire la dernire modification annule sur l'image. Le nombre maximum d'annulations (UNDO) que vous pouvez effectuer peut tre dfini dans le menu des paramtres gnraux. Dfaire/Refaire une modification est impossible aprs un changement de page, une chargement d'image ou la modification de la taille de l'image. 32 - Dtruire la page courante (Kill): N'importe quel clic: ====================> Supprime la page courante de la liste des pages "Undo". Cela vous permet de librer un peu de mmoire si le besoin s'en fait sentir. Cela permet notamment d'effacer de la mmoire la page de dmarrage aprs avoir charg une image. Un message s'affichera lorsque vous aurez supprim toutes les pages sauf la dernire. Note: Un autre moyen de librer de la mmoire est de rduire le nombre de pages "Undo". Ou encore, si vous avez rcemment captur une trs grosse brosse dont vous ne vous servez plus, vous pouvez en prendre une plus petite. La mmoire alloue pas la grosse brosse sera alors libre. 33 - Quitter le programme: N'importe quel clic: ====================> Vous permet de quitter GrafX2. S'il y a des modifications non sauves dans la page courante ou de brouillon, une boite de confirmation vous demandera si vous dsirez rellement quitter GrafX2, si vous voulez sauver (sauvegarde automatique, pas de slecteur de fichier) ou si vous voulez rester dans GrafX2. 34 - Menu de palette: Clic gauche: ============> Affiche un menu dans lequel les options suivantes sont disponibles: - Palette: Vous permet de choisir un bloc de couleurs diter. Si vous cliquez avec le bouton droit de la souris, vous dfinirez une nouvelle couleur de fond. - Jauges RGB: Vous permettent de modifier la slection courante. - "+" et "-": Vous permettent d'claircir ou d'assombrir la slection courante. - Default (Palette par dfaut): Restaure la palette prdfinie de GrafX2. - Gray (Gris): Transforme la slection courante en son quivalent en niveaux de gris. - Negative (Ngatif): Transforme la slection courante en son quivalent en vido inverse. - Invert (Invertion): Echange les couleurs de la slection courante de faon ce que les premires couleurs deviennent les dernires. - X-Invert (Inverser de faon tendue): Fonctionne comme ci-dessus mais modifie l'image de faon ce qu'elle semble inchange. - Swap (Echanger): Echange la slection courante avec un autre bloc de couleurs. Cliquez sur le dbut du nouveau bloc de couleur. - X-Swap (Echanger de faon tendue): Fonctionne comme ci-dessus mais modifie l'image de faon ce qu'elle semble inchange. Cela peut tre utile si vous voulez rordonner votre palette. - Copy (Copier): Copie la slection courante vers un autre bloc de couleurs. Cliquez sur le dbut du nouveau bloc de couleurs. - Spread (Dgrad): Calcule un dgrad entre deux couleurs. Si votre slection n'est faite que d'une seule couleur, slectionnez la deuxime couleur dans la palette. Sinon, les deux couleurs seront les extrmits de la slection. - Used (Comptage): Indique le nombre de couleurs utilises dans l'image. - Zap unused (Supprimer les couleurs inutilises): crase les couleurs inutilises avec des copies de la slection courante. (La touche de raccourci de ce bouton est ). - Reduce (Rduire): Vous permet de rduire la palette au nombre de couleurs que vous dsirez (modifie l'image). - Undo (Dfaire): Vous permet d'annuler la dernire opration faite sur la palette. Si la dernire opration a modifi l'image, cela n'annulera pas les modifications de l'image: vous devrez cliquer sur Cancel pour cela. Si vous appuyez sur , le programme insrera au mieux les quatre couleurs par dfaut du menu la place de couleurs peu ou pas utilises. L'image ne paratra pas altre car les couleurs modifies (dans le cas o elles taient utilises) seront remplaces par les plus proches couleurs dans le reste de la palette. Cette option se rvle fort utile lorsque vous passez la palette dans un tat ou aucune couleur ne convient pour le menu (ex: "Zap unused" alors que trs peu de couleurs sont utilises dans l'image; ou encore "Reduce" avec un trs faible nombre de couleurs). Si vous appuyez sur la touche en dessous de ou <,> (QWERTY), le menu disparatra et vous pourrez ainsi piocher aisment une couleur de l'image. Appuyez sur Pour annuler. Si une seule couleur est slectionne (pas un bloc), les touches <[> et <]> (<^> et <$> en AZERTY) peuvent tre utilises pour passer la couleur principale prcdente ou suivante (couleur de fond si vous appuyez sur en mme temps). Attention! Si vous appuyez sur Undo aprs une action qui modifie l'image (X-Swap, X-Invert et Reduce colors), l'image ne sera pas remappe comme elle tait juste avant cette action. Elle le sera uniquement avec Cancel (Annuler). Clic droit: ============> Ouvre un menu permettant d'accder aux menus suivants: - Menu dans lequel on slectionne les couleurs qui ne doivent pas tre employes pour le Smooth, le mode de transparence et le remappage. - Un menu dans lequel on peut dfinir des suites de couleurs. *** Pas encore implment *** 35 - Dplacer la palette gauche / droite: Clic gauche: ============> Dplace la fentre de palette ( la droite du menu). Clic droit: ============> Idem, mais plus rapidement. 36 - Fentre de palette: Clic gauche: ============> Dfinit la couleur principale. Clic droit: ============> Dfinit la couleur de fond. 37 - Cacher le menu: N'importe quel clic: ====================> Vous permet de cacher le menu. Si vous faites cela, prenez soin de regarder pralablement la touche presser pour rafficher le menu (la touche par dfaut est ). Let's talk about $$$, baby: Veuillez vous rfrer la section "Register?" de l'aide interne de GrafX2. Pour rsumer cette section, disons que GrafX2 est freeware. Mais vous pouvez quand mme nous envoyer de l'argent, des dessins, ou simplement une carte postale pour nous montrer que nous avons fait un programme qui vous est utile. Nous attirons votre attention sur le fait que la version que vous avez entre les mains est dj la version "complte" (la mme que la version enregistre) aussi nous ne vous enverrons pas d'autre copie de GrafX2. Mais si vous vous enregistrez pour une version, nous considererons que vous n'avez pas vous enregistrer pour les suivantes. Astuces de dessin: Cette section parle des astuces qui permettent d'obtenir des effets sympathiques, ou qui servent simplement dessiner plus vite. Notez que, dans la plupart des cas, ces astuces ne permettent que de faire une grosse partie du travail et qu'il vous faudra bien sr fignoler la loupe si vous souhaitez faire un dessin digne de ce nom! ;) De plus, si vous avez vous aussi des astuces sympa et que vous souhaitez en faire profiter les autres, n'hsitez pas on nous les signaler. Anti-aliasing: Ce n'est pas un effet propos par GrafX2 mais une mthode de dessin. Cela consiste placer des pixels de couleur moyennes dans les angles forms par des pixels contrasts pour adoucir de faon esthtique leur aspect. A notre avis, c'est essential pour dessiner des images vraiment belles. Une mthode facile mais fatigante (la meilleure mthode!) est de commencer par ajouter 1 couleur moyenne puis d'antialiaser les nouvelles couleurs "rcursivement" tant qu'il y a des couleurs intermdiaires dans votre palette. ۱ ۲ Mode "Smear" combin avec les lignes concentriques: En combinant cet effet et cet outil de dessin, vous pouvez arriver "parpiller" une zone partir d'un point central. Si vous n'tes pas en haute rsolution, il peut s'avrer utile d'en- clencher galement le mode de Transparence (cf. section suivante). Une application possible est de dessiner des poils sur une peluche. Pour cela, vous pouvez choisir un des pinceaux prdfinis qui ressemblent un ensemble alatoire de points. Selon la densit de poils que vous souhaitez donner votre peluche, vous pouvez choisir un pinceau contenant plus ou moins de points. Placez ensuite le centre des lignes concentriques environ au centre de la peluche, puis faites tourner la souris autour de la peluche en maintenant le bouton de la souris enfonc. Avec la mme mthode, mais en insistant plus longtemps, vous pouvez donner un effet d'explosion sur un objet. Vous pouvez galement crer facilement et rapidement des rayons de soleil avec cette mthode. Pour cela, aprs avoir plac la forme premire du soleil sur le ciel, choisissez un pinceau en fonction de la taille des rayons que vous voulez crer (mais un petit pinceau sera souvent prfrable), et placez le centre des lignes au centre du soleil. Puis tracez les rayons la longueur que vous voulez. Si vous n'avez pas pris un trop gros pinceau, vous pourrez dans un premier temps tracer rapidement une aurole autour du soleil en tournant rapidement autour et en maintenant le bouton de la souris enfonc, et dans un deuxime temps vous rajouterez des rayons plus importants avec prcision. Mode "Smear" combin avec l'effet de Transparence: Ces deux modes de dessin combins permettent d'taler des parties d'image comme de la peinture fraiche. Il est recommand d'utiliser la mthode de transparence qui consiste interpoler avec une opacit d'environ 60% et le "Feedback" des effets enclench. Tout comme dans la section prcdente, cela peut servir dessiner des poils et notamment des cils si vous avez une palette adapte (c'est--dire une palette contenant des dgrads de couleurs entre toutes les couleurs sur lesquelles vous dessinerez pendant cette opration. Pour dessiner des cils par exemple, aprs avoir dessin l'oeil et la paupire, tracez un trait noir assez pais reprsentant la base des cils (c'est ce noir que vous talerez sur la paupire). Puis, en mode smear+transparence, dessinez des traits la main (avec un petit pinceau: 1, 2 ou 3 pixels de large suivant que vous dessiniez un visage ou un oeil en gros plan) en partant de la base des cils et en donnant leur forme. Vous verrez petit-- petit votre barre noire s'effiler en forme de cils. On peut galement se servir de ces effets pour mlanger des couleurs l'cran et donner ainsi un aspect de peinture. Par exemple, si l'on souhaite raliser un fond comportant des formes abstraites composes de mlanges de couleurs, on peut procder comme suit: - Dfinir un palette comportant un dgrad entre les diffrentes teintes que vous souhaitez utiliser. - Dessiner trs vaguement l'aide d'un gros pinceau les diffrentes zones de couleurs (en mode normal). - Avec un plus petit pinceau, et l'aide du spray, appliquer ces mmes teintes mais en plus clair ou plus fonc sur les zones prcdemment dfinies. - Toujours avec le mme pinceau en spray, mais cette fois-ci en mode smear (pas forcment avec transparence... mais pourquoi pas?), mlangez un peu toutes les couleurs l'cran pour obtenir une "bouillie multicolore" tout en conservant vaguement les diffrentes zones de couleurs. - Enfin, en mode Smear+Transparence, avec un pinceau moyen arrondi, dessinez la main en faisant des tourbillons, des vagues, etc... en conservant a peu prs le mme mouvement pour viter les cassures. Ceci a pour but d'liminer la pixellisation opre par le spray et de donner l'aspect final de peinture mlange. - Maintenant, si c'est moche, c'est soit que j'explique mal, soit que vous n'avez pas de talent! :p Spray combin au mode shade: Si vous utilisez souvent le mode Shade, et que a vous fatigue de cliquer plein de fois sur une couleur pour atteindre celle que vous voulez, vous pouvez definir un spray avec "Size"=1, "Mono-flow"=1, et "Delay"=2 (ou plus, selon vos rflexes). Et vous n'aurez alors plus qu' cliquer quelques centimes de seconde pour modifier une couleur. Avec un diamtre plus large, cela permet de rajouter de la granularit une texture, car placer des petits pixels plus foncs ou plus clairs permet de crer des asprits. Diffrentes textures appropries cet effet sont: du sable, de la pierre, etc... Il faut bien sr que vous ayez un dgrad adapt la couleur de la texture. Vous pouvez galement raliser des textures - \ plus labores en employant un pinceau en forme \ \ de petite courbe ou ligne comme "tentent" de le ` \ montrer les figures ci-contre. ;) | \ Vous pourrez ainsi raliser des textures de paille, de cheveux, de pierres stries ou de marbre (le spray tant toutefois moins recommand que le dessin la main pour ce dernier). Mode shade pour remplacer les couleurs d'un dgrad par un autre: Si vous avec dessin quelque chose avec des couleurs appartenant un dgrad et que vous souhaitiez remplacer toutes ces couleurs par celles d'un autre dgrad (du mme nombre de couleurs), procdez comme suit: - Dfinissez dans le menu du mode shade les 2 dgrads en question sans les sparer par une case vide. - Passez le shade en mode "no saturation" - Dfinissez le pas du shade avec la taille des dgrads (ex: entrez 16 si vos dgrads comportent chacun 16 couleurs). - Et voil, vous n'avez plus qu' dessiner par dessus la zone qui doit changer de teinte (avec le bouton gauche de la souris si vous avez plac le dgrad remplacer en premier dans la table de shade, ou inversement). Sphres combines avec le mode de transparence additive: En partant d'un fond sombre (et si possible de couleur unie), tracez des sphres qui se chevauchent avec leur point d'clairage au centre. Vous obtiendrez rapidement un effet de "blobs". Comment dessiner une goutte: Voici une mthode rapide et efficace pour dessiner des gouttes. Dessinez simplement des pixels trs brillants sur le ct de la goutte d'o vient la lumire, et des pixels moins brillants sur le ct oppos. Enfin, dessinez les ombres suivant la position de la lumire. Voici des exemples avec une lumire venant du coin haut-gauche. (il est prfrable de les regarder ۰ en mode texte 80x50) ۰ ۲ Vous pouvez penser que la plus petite goutte ne ressemble pas a ۱ une goutte, mais dessinez-la en mode graphique et vous verrez qu'elle a bien l'air d'une goutte. Si vous n'avez pas confiance, dites-vous que c'est en observant les graphs de Lazur que j'ai trouv cette mthode. Et d'une faon gnrale, il est toujours bon de regarder le travail des artistes confirms pour apprendre de nouvelles techniques. Problmes/Astuces gnrales/Questions frquentes (FAQ): * Problmes de carte vido: - Les modes VESA sont rendus inaccessibles par Windows NT. Et il parait que a va tre pareil sous Windows 2000 (on n'a pas encore essay, mais on n'est pas presss!). - Si votre carte vido n'est pas compatible VESA matriellement, vous devriez essayer de lancer un driver VESA tel que Univesa ou Univbe. - Si votre carte est compatible VESA mais n'affiche pas correctement le contenu de l'cran dans les rsolutions VESA, c'est probablement parce qu'elle ne rpond pas tous les critres que nous attendons. L'explica- tion est que, pour une plus grande efficacit, nous avons d ngliger certaines spcificits de quelques cartes vidos. Cependant, nous tentons chaque nouvelle version d'augmenter la compatibilit avec toutes les formes du standard VESA. - Si vous possdez une carte vido ATI Mach 64 (e.g. ATI Xpert), vous devriez utiliser le programme rsident m64vbe fourni avec la carte pour supporter compltement nos modes XVESA en tapant: "m64vbe vga". * Problmes de mmoire: - Depuis la version 94.666%, nous utilisons le dos-extender EOS Copyright (c) 1996 Eclipse, au lieu du traditionnel DOS4GW. La raison en est qu'il est beaucoup plus petit en place disque (un zip plus petit, a devrait faire plaisir vos factures de tlphone) et en mmoire (vous pouvez donc lancer GrafX2 avec plus de gestionnaires utilisant la mmoire conventionnelle). De plus, ce dos-extender est intgr l'xcutable de GrafX2, ce qui diminue galement le nombre de fichiers (votre FAT vous en sera reconnaissante). L'inconvnient est que ce dos-extender ne gre pas de cache disque. Ainsi, si vous ne disposez pas d'au moins 4 Mgaoctets de RAM, vous devrez utiliser le fichier batch GFX2_MEM.BAT . Il est noter que: - vous devrez configurer ce fichier selon l'emplacement de certains fichiers dans l'arborescence de votre (vos) disque(s) dur(s) - vous devrez avoir quelque part dans l'arborescence de votre (vos) disque(s) dur(s) le fichier DOS4GW.EXE . - vous devrez disposer d'au moins 16 Mgaoctets de libre sur votre disque dur courant. Si vous avez rencontr des problmes dans l'utilisation de GrafX2 (avec au moins 4 Mgaoctets de mmoire) qui se seraient rsolus en utilisant GFX2_MEM, nous vous serions reconnaissant de nous en faire part. EOS est un dos-extender shareware, accompagn de bibliothques trs intressantes pour la musique, le graphisme, ... pour des applications Watcom, Tasm ou Masm. Si vous dsirez avoir plus d'informations sur ses fonctionnalits ou les bibliothques qui l'accompagne, n'hsitez pas nous contacter pour que nous vous mettions en relation avec ses auteurs. * Problmes de carte son: Q: Aucun son ne sort de ma Ultra-maxi-sound-blaster-galaxy-64-3D-pnp, alors que puis-je faire ? R: Et bien... Vous devez comprendre que ce programme n'est ni un soundtracker ni un player de musique :) ... Aussi, si vous voulez de la musique, vous devrez soit jouer des modules avec un bon player qui peut tourner en arrire-plan (avec une session DOS), soit allumer votre chaine Hi-Fi. * Divers: - Si vous avez foutu en l'air le fichier GFX2.CFG et que GrafX2 l'utilise tel quel, avec un comportement anormal, n'hsitez pas effacer GFX2.CFG et relancer GFXCFG pour en crer un nouveau, et correct. En effet les seuls tests de validit que nous faisons sur le fichier de configuration sont sa taille et son numro de version. - Il se peut que vous ayez rcupr une version de GrafX2 dj configure par un ami qui aurait pu utiliser des touches "Windows 95" alors que vous ne disposez pas vous-mme d'un clavier adapt. Dans ce cas, il vous faudra reconfigurer ces combinaisons l'aide de GFXCFG. * Questions frquemment poses: Q: Comment puis-je choisir les dimensions de l'image ? R: Nous pensions qu'il tait vident que vous deviez cliquer dans les zones o les dimensions sont affiches, dans le menu de rsolution (Width & Height) mais beaucoup de personnes nous ont pos cette question (?!). Alors, pour rsumer, partout o vous verrez une valeur ou un texte affich en noir dans une sorte de zone incruste, cela signifie qu'en cliquant dessus vous pourrez modifier cette valeur. De plus, si vous voulez que les dimensions de l'image soient celles de l'cran, il vous suffit de cliquer sur la rsolution dans la liste avec le bouton droit de la souris. Q: O puis-je obtenir la dernire version de GrafX2 ? R: Le seul endroit o vous puissiez tre sr de trouver la toute dernire version est sur notre site web: http://www-msi.ensil.unilim.fr/~maritaud/sunset Toutefois, il n'est pas impossible que GrafX2 se retrouve galement sur des sites FTP ddis la "demo-scene" (e.g. ftp://ftp.scene.org). Q: Comment puis-je passer la brosse en monochrome, et comment puis-je la rcuprer dans son tat normal? R: Vous pouvez le faire ( supposer que vous n'avez pas chang les touches par dfaut) avec les touches + pour rendre la brosse monochrome, et + pour rcuprer la brosse en couleur. Q: Pourquoi est-ce que la barre d'outil est en bas de l'cran et non pas sur le ct droit comme dans Deluxe Paint (Copyright Electronic Arts) ? R: Eh bien... GrafX2 N'EST PAS Deluxe Paint! Nous savons que vous tes habitus Deluxe Paint mais vous allez devoir vous habituer GrafX2! ;) Si vous ne supportez vraiment pas d'utiliser GrafX2 comme cela, vous devrez attendre GrafX3 mais nous ne le raliserons certainement pas avant l'an 2013! En fait, la principale raison pour laquelle nous avons conu la barre d'outil avec un aspect aussi basique est que cela facilitait (et acclrait) l'affichage de l'cran, en indiquant aux routines o s'arrter (l o commence la barre d'outil). De plus, l'un des meilleurs logiciels de dessin sur Amiga (Brilliance) affiche galement la barre du menu en bas de l'cran. Q: Pourquoi est-ce que la partie de l'image cache par le menu n'est pas remplie lorsque j'utilise l'outil "Flood-fill"? R: Pour la simple et "assez" bonne raison qu'il est prfrable que l'uti- lisateur contrle parfaitement ce qu'il dessine. Ainsi il ne pourra pas remarquer trop tard qu'il a saccag une partie de son dessin. Il en est de mme pour tous les autres outils. Et puis pour une moins bonne raison qui est que c'tait plus pratique pour nous. ;) Q: Y'a-t-il un moyen pour lancer le programme dans une autre rsolution que 320x200 ? R: Oui, il suffit de taper GFX2 sur la ligne de commande du DOS. Pour obtenir la liste de tous les modes vido, tapez: GFX2 /?. Q: Est-ce normal que certains boutons ne marchent pas (par exemple: le bouton Texte) ? R: Oui, c'est que nous n'avons pas encore eu le temps de les faire (je vous rappelle que GrafX2 en est encore au stade des Beta versions). Voici cependant la liste des boutons qui ne repondent pas dans GrafX2: - Rectangles dgrads (Grad. rectangles) - Texte - Effets sur l'image - et le bouton suivant dans le menu "Brush effects": Torsion (Distort) Q: Allez-vous sortir une version Windows? R: GrafX2 perdrait son me en tant adapt un systme fentr ou un systme qui ne supporte pas tous ses modes vidos. Et de toutes faons, il peut se lancer partir de Windows 9x (on ne sait pas pour Windows 2000 mais on s'en fiche). Alors c'est bien comme a. La seule chose intressante que pourrait apporter Windows est le presse-papier. Q: Allez-vous sortir une version Linux? R: Bien que ce soit peu prs le mme problme qu'avec la version Windows, Linux manque de programmes comme GrafX2; donc, mme une version limite serait intressante pour cet OS. Par consquent, nous aimerions sortir une version Linux. Mais nous n'avons aucune exprience de programmation Linux et notre code est compltement indechiffrable pour les autres. Alors vous devrez attendre... Q: Comment puis-je vous contacter ? R: En fait, ce n'est pas exactement cette question qu'on nous pose puisque ces gens arrivent nous contacter ;) mais... * Poste: GUILLAUME DORME (Robinson) KARL MARITAUD (X-Man) 15, rue de l'observatoire 10, rue de la Brasserie 87000 LIMOGES (FRANCE) 87000 LIMOGES (FRANCE) * E-mail: dorme@msi.unilim.fr maritaud@ensil.unilim.fr N'hsitez pas nous contacter; on adore a! :) Nous essaierons de rpondre tous les e-mails (s'il ncessitent une rponse), et certains courriers (Bah oui! On ne va pas se ruiner en timbres juste pour vous dire "merci d'avoir crit!" :)). grafx2_2.4+git20180105/doc/tech_eng.txt0000664000000000000000000007300613223665306016030 0ustar rootrootĿ Technical documentation for GrafX 2.00 - Version 1.08 (10/05/1997) ۲ This file deals with: - the PKM picture format - the values to send to the CRTC to access all the amazing video modes available in GrafX 2.00 Ŀ The PKM picture format - by Karl Maritaud ۲ First of all, I'd like to say that I made this file format some years ago when I didn't knew how to load any good format (eg. GIF) and wanted to have my own format. PKM format was designed to be very simple, easy to encode and decode. Its header is very simple (short) and evolutive. The only real default I can find in this format is that you can only save 256-color pictures. I know that you will think: "Oh no just another fucking format! I'll never use it! Its compression is too poor and I prefer GIF!". And I'll answer: "Yeah! You're right. But if you dunno how to load GIF and want a simple format with a quite good compression rate (on simple pictures at least), it could be useful." So, here comes the format documentation... The HEADER: The header is the following 780-byte-structure. (Don't worry about the size. That's just because the palette is considered as a part of the header). Ŀ Pos Field Type Size Description ͵ 0 Signature char 3 Constant string "PKM" (with NO size delimitation '\0' or so...) Ĵ 3 Version byte 1 For the moment, it can take only the value 0. Other packing methods may change this field but there is only one for now... Ĵ 4 Pack_byte byte 1 Value of the recognition byte for color repetitions that are coded on 1 byte. (See the picture packing section for a better explanation) Ĵ 5 Pack_word byte 1 Value of the recognition byte for color repetitions that are coded on 2 bytes. (See the picture packing section...) Ĵ 6 Width word 2 Picture width (in pixels) Ĵ 8 Height word 2 Picture height (in pixels) Ĵ 10 Palette byte 768 RGB palette (RGB RGB ... 256 times) with values from 0 to 63. I know the standard in picture files is 0 to 255 but I find it stupid! It is really easier to send the whole palette in port 3C9h with a REP OUTSB without palette convertion. Ĵ 778 PH_size word 2 Post-header size. This is the number of bytes between the header and the picture data. This value can be equal to 0. Data of type "word" are stored with Intel conventions: lower byte first. The POST-HEADER: The post-header has a variable size. It was designed to support new features for this file format without changing the whole format. It consists in field identifiers followed by their size and their value. A field identifier is coded with 1 byte and a field size also. These field identifiers are: (this list may be updated...) 0 : Comment on the picture 1 : Original screen dimensions 2 : Back color (transparent color) If you encounter a field that you don't know just jump over it. But if a field tells you to jump to a position that is over the beginning of the picture data, there is an error in the file. The fields: * Comment: With this field, artists will be able to comment their pictures. Note that GrafX 2 has a comment size limit of 32 chars. But you can comment a picture with up to 255 chars if you make your own viewer since GrafX 2 will just ignore extra characters. Example: [0],[16],[Picture by X-Man] This sequence means: - the field is a comment - the comment takes 16 characters (there is no end-of-string character since you know its size) - the comment is "Picture by X-Man" * Original screen dimensions: Since GrafX 2 supplies a huge range of resolutions, it seemed convenient to add a field that indicates what were the original screen dimensions. Example: [1],[4],[320],[256] This sequence means: - the field is a screen dimensions descriptor - the dimensions are 2 words (so this value must be always equal to 4) - the original screen width was 320 pixels - the original screen height was 256 pixels Note that words stored in fields are written Intel-like. The 90% BETA version did not respect this norm. I'm really sorry about this. This is not very serious but pictures saved with version 90% and loaded with a latest version (91% and more) won't set the right resolution. * Back color: Saving the back color (transparent color) is especially useful when you want to save a brush. The size of this field is 1 byte (index of the color between 0 and 255). Example: [2],[1],[255] This sequence means: - the field is a screen dimensions descriptor - the value takes 1 byte - the transparent color is 255 The PICTURE PACKING METHOD: The PKM compression method is some sort of Run-Length-Compression which is very efficient on pictures with long horizontal color repetitions. Actually, the compression is efficient if there are often more than 3 times the same color consecutively. I think that it would be better to give you the algorithm instead of swim- ming in incomprehensible explanations. BEGIN /* functions: Read_byte(File) reads and returns 1 byte from File Draw_pixel(X,Y,Color) draws a pixel of a certain Color at pos. (X,Y) File_length(File) returns the total length in bytes of File variables: type of Image_size is dword type of Data_size is dword type of Packed_data_counter is dword type of Pixels_counter is dword type of Color is byte type of Byte_read is byte type of Word_read is word type of Counter is word type of File is */ /* At this point you've already read the header and post-header. */ Image_size <- Header.Width * Header.Height Data_size <- File_length(File) - (780+Header.PH_size) Packed_data_counter <- 0 Pixels_counter <- 0 /* Depacking loop: */ WHILE ((Pixels_counterHeader.Pack_byte) AND (Byte_read<>Header.Pack_word)) THEN { Draw_pixel(Pixels_counter MOD Header.Width, Pixels_counter DIV Header.Width, Byte_read) Pixels_counter <- Pixels_counter + 1 Packed_data_counter <- Packed_data_counter + 1 } ELSE /* Is the number of pixels to repeat coded... */ { /* ... with 1 byte */ IF (Byte_read = Header.Pack_byte) THEN { Color <- Read_byte(File) Byte_read <- Read_byte(File) FOR Counter FROM 0 TO (Byte_read-1) STEP +1 Draw_pixel((Pixels_counter+Counter) MOD Header.Width, (Pixels_counter+Counter) DIV Header.Width, Color) Pixels_counter <- Pixels_counter + Byte_read Packed_data_counter <- Packed_data_counter + 3 } ELSE /* ... with 2 bytes */ { Color <- Read_byte(File) Word_read <- (word value) (Read_byte(File) SHL 8)+Read_byte(File) FOR Counter FROM 0 TO (Word_read-1) STEP +1 Draw_pixel((Pixels_counter+Counter) MOD Header.Width, (Pixels_counter+Counter) DIV Header.Width, Color) Pixels_counter <- Pixels_counter + Word_read Packed_data_counter <- Packed_data_counter + 4 } } } END For example, the following sequence: (we suppose that Pack_byte=01 and Pack_word=02) 04 03 01 05 06 03 02 00 01 2C will be decoded as: 04 03 05 05 05 05 05 05 03 00 00 00 ... (repeat 0 300 times (012Ch=300)) Repetitions that fit in a word must be written with their higher byte first. I know that it goes against Intel standard but since I read bytes from the file thru a buffer (really faster), I don't care about the order (Sorry :)). But words in the header and post-header must be written and read Intel-like! Packing advices: * As you can see, there could be a problem when you'd want to pack a raw pixel with a color equal to Pack_byte or Pack_word. These pixels should always be coded as a packet even if there is only one pixel. Example: (we suppose that Pack_byte=9) 9 will be encoded 9,9,1 (The 1st 9 in the encoded... 9,9 will be encoded 9,9,2 ... sequence is Pack_byte) etc... * It seems obvious to find values for Pack_byte and Pack_word that are (almost) never used. So a small routine that finds the 2 less used colors in the image should be called before starting to pack the picture. This can be done almost instantaneously in Assembler. * When you want to pack a 2-color-sequence, just write these 2 colors one after the other (Color,Color) because it only takes 2 bytes instead of 3 if you had to write a packet (Pack_byte,Color,2). * If you pack a very simple picture which has a sequence of more than 65535 same consecutive bytes, you must break the sequence and continue with a new packet. Example: you have to pack 65635 same consecutive bytes (eg. color 0) (we suppose that Pack_byte=01 and Pack_word=02) You'll write: 02 00 FF FF 01 00 64 (FFFFh=65535, 64h=100) Ŀ Setting GrafX 2.00 video modes ۲ All set-mode procs are in 386 ASM. Anyway, if you can't understand any line of ASM, I really can't see the use you'll have of these procedures. They are designed to be used in FLAT memory model. Anyway, it wouldn't take too much time for you to adapt them to the model you use since only memory indexations can be affected by this (so use DS:SI instead of ESI, ES:DI instead of EDI, and beware to the address 0A0000h that will become 0A000h:0000h). MCGA: (Standard VGA mode) Is there anybody in this world who still don't now how to set the MCGA 320x200 256 colors mode ??!? Well... I hope you are a novice if you read the 2 following lines :) mov ax,0013h int 10h X-Modes: (Extended VGA modes) Well... I think the original Mode X was 320x240 but now, many people call "X-Modes" (or Modes X, or Tweaked modes) all the VGA modes that use more that 64Kb of video memory with the "Unchained" structure. Setting a pixel in any X-Mode can be done by one same function (but I won't explain to you how to do that. You just have to tell the function what the plane width (screen_width/4) is). If you can't understand anything about what I say (unchained, planes...), just read any good documentation about Mode X. We'd like to thank the authors of XLIB2 for saving our time by having made this useful function. We slightly optimized it for our needs but the most important parts are here. mov ax,13h ; Yeah! The MCGA mode again! All X-Modes must start from int 10h ; the standard VGA mode, but many things change after. mov dx,3C6h ; During the initialization, we'll turn the palette into xor al,al ; black in order to avoid the user to see all our out dx,al ; manipulations. mov dx,3C4h ; We will inform the TIMING SEQUENCER register to switch mov ax,0604h ; in unchained mode (mode-X), without odd/even management out dx,ax ; and with an access to the 256Kb of the video card. mov ax,0100h ; Now we will engage the synchronous reset of the TS out dx,ax ; register because we're about to play with registers. mov al,01h ; Like with the palette, we ask the video card not to out dx,al ; peek the memory to display it anymore. Thus, it's inc dx ; one more way to avoid interferences in the display, in al,dx ; which happens until the mode is completely initialized mov ah,al ; and stable. In addition, we can expect that asking a mov al,01h ; memory reading interruption will turn the system push ax ; faster, and thus speed up the initialization of the mov al,ah ; graphic mode (hope makes you live :)) or al,20h ; out dx,al ; mov esi,X_ptr ; Pointer on the list of constants to send to the CRTC. cld lodsb ; This loads in AL a value that will tell what to do ; with the MISCELLANEOUS register, and increases ESI. ; The value is equal to ZERO => Nothing to do ; or ELSE => Send AL to MISCELLANEOUS or al,al ; Shall we modify the basic video mode? jz NoThankYou ; No?Ŀ Actually the answer is always "Yes". mov dx,3C2h ; Except for a few modes such as out dx,al ; 320x200 in Mode X NoThankYou: ; < (but our 320x200 is MCGA...) mov dx,3C4h ; Manipulations with MISCELLANEOUS register are over, we mov ax,0300h ; can now disengage the synchronous register of the TS. out dx,ax ; Now, what about teasing the CRTC? mov dx,3D4h ; In the 18th register of the CRTC, we will disengage the mov al,11h ; protection bit. Without this, the values we would have out dx,al ; sent to the CRTC registers would have been ignored. inc dx in al,dx and al,7Fh out dx,al dec dx ; DX points back to the CRTC register entry lodsb ; This loads in AL the number of CRTC registers to modify xor ecx,ecx ; You must clear ECX before... mov cl,al ; ... starting to repeat AL (CL) times OUTSW rep outsw ; Let's send all the CRTC parameters! ; Just in case the 20th CRTC register would have been forgotten in the ; initialisation table, we can compute it by ourselves (Yeah, we are good ; guys). mov ax,Screen_width ; You must tell the routine what the Screen width is shr ax,3 mov ah,al mov al,13h out dx,ax mov dx,3C4h ; Now you have the good resolution but there can be mov ax,0F02h ; shitty pixels on the screen coming from the uncleared out dx,ax ; memory areas. mov edi,0A0000h ; So we'll clean memory starting from 0A0000h with the xor eax,eax ; value 0 (which is the standard black) and on a range mov ecx,4000h ; of 4000h dwords (256Kb). rep stosd ; Let's wipe all this out. mov dx,3C4h ; We can ask the VGA to read again the memory to display pop ax ; it on the screen... out dx,ax ; mov dx,3C6h ; ... and turn on the palette so the picture appears to mov al,0FFh ; the user. out dx,al ; The table of constants you must send is one of these: (These are tables for C but they can be easily used in other languages) word X320Y224[] = { 0x0BA3, 0x6F06, 0xBA07, 0x0008, 0x4109, 0x0810, 0x8A11, 0xBF12, 0x0014, 0xC715, 0x0416, 0xE317 }; word X320Y240[] = { 0x0AE3, 0x0D06, 0x3E07, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0x0014, 0xE715, 0x0616, 0xE317 }; word X320Y256[] = { 0x0CE3, 0x2306, 0xB207, 0x0008, 0x6109, 0x0A10, 0xAC11, 0xFF12, 0x2013, 0x0014, 0x0715, 0x1A16, 0xE317 }; word X320Y270[] = { 0x0BE7, 0x3006, 0xF007, 0x0008, 0x6109, 0x2010, 0xA911, 0x1B12, 0x0014, 0x1F15, 0x2F16, 0xE317 }; word X320Y282[] = { 0x0CE3, 0x6206, 0xF007, 0x6109, 0x310F, 0x3710, 0x8911, 0x3312, 0x2F13, 0x0014, 0x3C15, 0x5C16, 0xE317 }; word X320Y300[] = { 0x0DE3, 0x4606, 0x1F07, 0x0008, 0x4009, 0x3110, 0x8011, 0x2B12, 0x2013, 0x0014, 0x2F15, 0x4416, 0xE317 }; word X320Y360[] = { 0x09E3, 0x4009, 0x8810, 0x8511, 0x6712, 0x2013, 0x0014, 0x6D15, 0xBA16, 0xE317 }; word X320Y400[] = { 0x03E3, 0x4009, 0x0014, 0xE317 }; word X320Y448[] = { 0x0BA3, 0x6F06, 0xBA07, 0x0008, 0x4009, 0x0810, 0x8A11, 0xBF12, 0x0014, 0xC715, 0x0416, 0xE317 }; word X320Y480[] = { 0x0AE3, 0x0D06, 0x3E07, 0x4009, 0xEA10, 0xAC11, 0xDF12, 0x0014, 0xE715, 0x0616 , 0xE317}; word X320Y512[] = { 0x0CE3, 0x2306, 0xB207, 0x0008, 0x6009, 0x0A10, 0xAC11, 0xFF12, 0x2013, 0x0014, 0x0715, 0x1A16, 0xE317 }; word X320Y540[] = { 0x0BE7, 0x3006, 0xF007, 0x0008, 0x6009, 0x2010, 0xA911, 0x1B12, 0x0014, 0x1F15, 0x2F16, 0xE317 }; word X320Y564[] = { 0x0CE7, 0x6206, 0xF007, 0x0008, 0x6009, 0x3E10, 0x8911, 0x3312, 0x2013, 0x0014, 0x3C15, 0x5C16, 0xE317 }; word X320Y600[] = { 0x0BE7, 0xBE06, 0xF007, 0x0008, 0x6009, 0x7C10, 0x8C11, 0x5712, 0x0014, 0x5815, 0x7016, 0xE317 }; word X360Y200[] = { 0x09E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x2D13, 0x0014, 0xE317 }; word X360Y224[] = { 0x12A7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x6F06, 0xBA07, 0x0008, 0x4109, 0x0810, 0x8A11, 0xBF12, 0x2D13, 0x0014, 0xC715, 0x0416, 0xE317 }; word X360Y240[] = { 0x11E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x0D06, 0x3E07, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0x2D13, 0x0014, 0xE715, 0x0616, 0xE317 }; word X360Y256[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x2B06, 0xB207, 0x0008, 0x6109, 0x0E10, 0xAC11, 0xFF12, 0x2D13, 0x0014, 0x0715, 0x1A16, 0xE317 }; word X360Y270[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x3006, 0xF007, 0x0008, 0x6109, 0x2010, 0xA911, 0x1B12, 0x2D13, 0x0014, 0x1F15, 0x2F16, 0xE317 }; word X360Y282[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x6206, 0xF007, 0x6109, 0x310F, 0x3710, 0x8911, 0x3312, 0x2D13, 0x0014, 0x3C15, 0x5C16, 0xE317 }; word X360Y300[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x4606, 0x1F07, 0x0008, 0x4009, 0x3110, 0x8011, 0x2B12, 0x2D13, 0x0014, 0x2F15, 0x4416, 0xE317 }; word X360Y360[] = { 0x0FE7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x4009, 0x8810, 0x8511, 0x6712, 0x2D13, 0x0014, 0x6D15, 0xBA16, 0xE317 }; word X360Y400[] = { 0x0AE7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x4009, 0x2D13, 0x0014, 0xE317 }; word X360Y448[] = { 0x12A7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x6F06, 0xBA07, 0x0008, 0x4009, 0x0810, 0x8A11, 0xBF12, 0x2D13, 0x0014, 0xC715, 0x0416, 0xE317 }; word X360Y480[] = { 0x11E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x0D06, 0x3E07, 0x4009, 0xEA10, 0xAC11, 0xDF12, 0x2D13, 0x0014, 0xE715, 0x0616, 0xE317 }; word X360Y512[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x2B06, 0xB207, 0x0008, 0x6009, 0x0E10, 0xAC11, 0xff12, 0x2D13, 0x0014, 0x0715, 0x1A16, 0xE317 }; word X360Y540[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x3006, 0xF007, 0x0008, 0x6009, 0x2010, 0xA911, 0x1B12, 0x2D13, 0x0014, 0x1F15, 0x2F16, 0xE317 }; word X360Y564[] = { 0x12EB, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0x6206, 0xF007, 0x0008, 0x6009, 0x3E10, 0x8911, 0x3312, 0x2D13, 0x0014, 0x3C15, 0x5C16, 0xE317 }; word X360Y600[] = { 0x12E7, 0x6B00, 0x5901, 0x5A02, 0x8E03, 0x5E04, 0x8A05, 0xBE06, 0xF007, 0x0008, 0x6009, 0x7C10, 0x8C11, 0x5712, 0x2D13, 0x0014, 0x5815, 0x7016, 0xE317 }; word X400Y200[] = { 0x09E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x3213, 0x0014, 0xE317 }; word X400Y224[] = { 0x12A7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x6F06, 0xBA07, 0x0008, 0x4109, 0x0810, 0x8A11, 0xBF12, 0x3213, 0x0014, 0xC715, 0x0416, 0xE317 }; word X400Y240[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x0D06, 0x3E07, 0x0008, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0x3213, 0x0014, 0xE715, 0x0616, 0xE317 }; word X400Y256[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x2B06, 0xB207, 0x0008, 0x6109, 0x1310, 0xAC11, 0xFF12, 0x3213, 0x0014, 0x0715, 0x1A16, 0xE317 }; word X400Y270[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x3006, 0xF007, 0x0008, 0x6109, 0x2010, 0xA911, 0x1B12, 0x3213, 0x0014, 0x1F15, 0x2F16, 0xE317 }; word X400Y282[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x6206, 0xF007, 0x6109, 0x310F, 0x3710, 0x8911, 0x3312, 0x3213, 0x0014, 0x3C15, 0x5C16, 0xE317 }; word X400Y300[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x4606, 0x1F07, 0x0008, 0x4009, 0x3110, 0x8011, 0x2B12, 0x3213, 0x0014, 0x2F15, 0x4416, 0xE317 }; word X400Y360[] = { 0x0FE7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x4009, 0x8810, 0x8511, 0x6712, 0x3213, 0x0014, 0x6D15, 0xBA16, 0xE317 }; word X400Y400[] = { 0x0AE7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x4009, 0x3213, 0x0014, 0xE317 }; word X400Y448[] = { 0x12A7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x6F06, 0xBA07, 0x0008, 0x4009, 0x0810, 0x8A11, 0xBF12, 0x3213, 0x0014, 0xC715, 0x0416, 0xE317 }; word X400Y480[] = { 0x11E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x0D06, 0x3E07, 0x4009, 0xEA10, 0xAC11, 0xDF12, 0x3213, 0x0014, 0xE715, 0x0616, 0xE317 }; word X400Y512[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x2B06, 0xB207, 0x0008, 0x6009, 0x1310, 0xAC11, 0xFF12, 0x3213, 0x0014, 0x0715, 0x1A16, 0xE317 }; word X400Y540[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x3006, 0xF007, 0x0008, 0x6009, 0x2010, 0xA911, 0x1B12, 0x3213, 0x0014, 0x1F15, 0x2F16, 0xE317 }; word X400Y564[] = { 0x12EB, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0x6206, 0xF007, 0x0008, 0x6009, 0x3E10, 0x8911, 0x3312, 0x3213, 0x0014, 0x3C15, 0x5C16, 0xE317 }; word X400Y600[] = { 0x12E7, 0x7100, 0x6301, 0x6402, 0x9203, 0x6604, 0x8205, 0xBE06, 0xF007, 0x0008, 0x6009, 0x7C10, 0x8C11, 0x5712, 0x3213, 0x0014, 0x5815, 0x7016, 0xE317 }; The structure: (example) This is the number of values to send to the CRTC registers. This is actually the number of words in the tables minus 1 (because the 1st word of the table is not sent to the CRTC but contains a value to send to the MISCELLANEOUS register and the number of values to send to the CRTC registers ;) ). This is the value to send to the MISCEALLANEOUS register (or ZERO if no value must be sent to it). This is a value to send to a register of the CRTC. This is the index of the CRTC register that will receive the value. ÿÿ ÿÿ { 0x0AE3, 0x0D06, 0x3E07, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0x0014, 0xE715, 0x0616, 0xE317 }; You can notice that CRTC registers 0 to 5 (and 13h) define the screen width while registers 6 to 17h (except 13h) define the screen height. We have more modes in our pocket than the "few" :) ones we included in GrafX 2.00, but they aren't really useful or stable. But we may decice to include them anyway in a next version. If some of your favourite modes are missing, just send us the list of constants we must shoot at the CRTC just following the structure we use above. IMPORTANT! The constant values listed above are not supported by every monitor or video card. We have tested GrafX2 with several different configurations and we constated that some modes don't work at all with some video cards while some others can be overscanned, out of center, dark, too bright, or shrunk. But they all work fine with our poor little Tseng Labs ET4000... If you already have a good knowledge about CRTC and have different values than ours for certain modes, please let us know. We'll use them if they work better with a majority of computers. VESA: (A "pseudo-standard" for Super-VGA modes) We use VESA for modes that require a width of 640, 800 or 1024 pixels. But there is a way to combine X-Modes height with VESA so it's possible to have modes as weird as in X-Mode. mov ax,4F02h mov bx,Video_mode int 10h 256-color-VESA video modes are: 100h : 640x400 101h : 640x480 103h : 800x600 105h : 1024x768 107h : 1280x1024 (not available in GrafX2 because only supported with video cards with 2 or more Megabytes of video memory) As with X-Modes, you can modify CRTC registers to access "Xtd-VESA" modes! (Note that some video cards don't support the modification of the VGA CRTC registers in VESA modes.) To enter these extended VESA modes, set a standard VESA mode with the right width, and then call Modify_CRTC_registers with the proper Height table. Example (640x512) : VESA_Set_mode(101h) /* Set a video mode with the same width */ Modify_CRTC_registers(Y512) /* Modify height */ * Height tables: word Y224[] = { 0x09A3, 0x6F06, 0xBA07, 0x0008, 0x4109, 0x0810, 0x8A11, 0xBF12, 0xC715, 0x0416 }; word Y240[] = { 0x09E3, 0x0D06, 0x3E07, 0x0008, 0x4109, 0xEA10, 0xAC11, 0xDF12, 0xE715, 0x0616 }; word Y256[] = { 0x0900, 0x2B06, 0xB207, 0x0008, 0x6109, 0x0A10, 0xAC11, 0xFF12, 0x0715, 0x1A16 }; word Y270[] = { 0x09E7, 0x3006, 0xF007, 0x0008, 0x6109, 0x2010, 0xA911, 0x1B12, 0x1F15, 0x2F16 }; word Y282[] = { 0x0AE3, 0x6206, 0xF007, 0x0008, 0x6109, 0x310F, 0x3710, 0x8911, 0x3312, 0x3C15, 0x5C16 }; word Y300[] = { 0x09E3, 0x4606, 0x1F07, 0x0008, 0x4009, 0x3110, 0x8011, 0x2B12, 0x2F15, 0x4416 }; word Y350[] = { 0x09A3, 0xBF06, 0x1F07, 0x0008, 0x4009, 0x8310, 0x8511, 0x5D12, 0x6315, 0xBA16 }; word Y360[] = { 0x07E3, 0x0008, 0x4009, 0x8810, 0x8511, 0x6712, 0x6D15, 0xBA16 }; word Y400[] = { 0x01E3, 0x4009 }; word Y448[] = { 0x09A3, 0x6F06, 0xBA07, 0x0008, 0x4009, 0x0810, 0x8A11, 0xBF12, 0xC715, 0x0416 }; word Y480[] = { 0x09E3, 0x0D06, 0x3E07, 0x0008, 0x4009, 0xEA10, 0xAC11, 0xDF12, 0xE715, 0x0616 }; word Y512[] = { 0x0900, 0x2B06, 0xB207, 0x0008, 0x6009, 0x0A10, 0xAC11, 0xFF12, 0x0715, 0x1A16 }; word Y540[] = { 0x09E7, 0x3006, 0xF007, 0x0008, 0x6009, 0x2010, 0xA911, 0x1B12, 0x1F15, 0x2F16 }; word Y564[] = { 0x09E7, 0x6206, 0xF007, 0x0008, 0x6009, 0x3E10, 0x8911, 0x3312, 0x3C15, 0x5C16 }; word Y600[] = { 0x09E7, 0xBE06, 0xF007, 0x0008, 0x6009, 0x7C10, 0x8C11, 0x5712, 0x5815, 0x7016 }; Modifying CRTC registers: (inspired by X-Modes init... See above for more details or comments) mov esi,XVESA_Ptr cld lodsb or al,al ; Shall we modify the basic video mode? jz NoThankYou ; No?Ŀ The answer can be "No" because initialisations mov dx,3C2h ; of certain VESA modes directly set the right out dx,al ; value for the Miscellaneous register. NoThankYou: ; < mov dx,3D4h mov al,11h out dx,al inc dx in al,dx and al,7Fh out dx,al dec dx lodsb xor ecx,ecx mov cl,al rep outsw If you are cunning enough, you'll be able to combine constants used in X-Modes to get more "Xtd-VESA" modes such as 640x200, 800x480, etc... (but I don't think this will work with 1024x??? because this mode is generally interlaced... But who knows?...) The most difficult is to find the right value for the MISCELLANEOUS register. grafx2_2.4+git20180105/doc/README-SDL.txt0000664000000000000000000000067113223665306015627 0ustar rootrootThe following file: SDL.dll is the runtime environment for the SDL library. The Simple DirectMedia Layer (SDL for short) is a cross-platfrom library designed to make it easy to write multi-media software, such as games and emulators. The Simple DirectMedia Layer library source code is available from: http://www.libsdl.org/ This library is distributed under the terms of the GNU LGPL license: http://www.gnu.org/copyleft/lesser.html grafx2_2.4+git20180105/doc/README.txt0000664000000000000000000001160213223665306015203 0ustar rootroot __/_/_/ __/_/ _/ _/ __/_/ _/ _/ __/_/ __/_/_/ _/ _/ _/ _/ _/ _/ _/_/ _/_/ _/ _/ _/_/_/_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/_/_/ _/ _/_/_/ _/ _/ _/ _/_/_/_/ GrafX2 - The Ultimate 256-color bitmap paint program Copyright (C)1996-2001 Sunset Design (G.Dorme & K.Maritaud) Copyright (C)2007-2012 the Grafx2 Project Team (A.Destugues & Y.Rizoud) ------------------------------------- === ABOUT === GrafX2 is a drawing program dedicated to pixelart and low-color graphics. This program is dedicated to everybody who knows what a single pixel is. Its layout is not very different from the famous Deluxe Paint or Brilliance, so it will be quite easy to handle it if you know at least one of these programs. If you aren't used to the art of drawing with up to 256 colors, it will be a little more difficult for you, but you should give it a try (or more, because most of the power of this program won't show up on the first try). Then, you might eventually like to draw the oldskool way ! Grafx2 was originally written for the MS-DOS operating system. The authors then released the sourcecode and we've modified it to run on your favorite platform (if we missed it, please tell us !). Check the homepage at http://pulkomandy.tk/projects/GrafX2 for latest news and bugfixed versions. === HELP === Remember that right-clicking and left-clicking often have different functions, even on menu buttons. If you are in trouble when using the program, press to get contextual help. You can also check the wiki at http://code.google.com/p/grafx2/wiki for some more information. === LICENSE === GrafX2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software foundation; version 2 of the License. See doc/gpl-v2.txt for details. GrafX2 uses the following libraries that are distributed according to their own licenses: - SDL: see doc/README-SDL.txt - SDL_image: see doc/README-SDL_image.txt - SDL_ttf: see doc/README-SDL_ttf.txt - zlib: (on Windows) see doc/README-zlib1.txt - Lua: see doc/README-lua.txt The font Tuffy.ttf included as a sample in the fonts directory is public domain. The source code of Grafx2 should always be distributed along with the executable; You can normally find it in a packed archive whose name begins by "src". The source code is also available on the web site, either by accessing the git repository: https://gitlab.com/GrafX2/grafX2.git or you can find the latest versions as packed archives: http://pulkomandy.tk/projects/GrafX2/downloads === COMPILING === See the file COMPILING.txt for compiling instructions. There's also a page on the wiki: http://code.google.com/p/grafx2/wiki/Compiling === AUTHORS AND SUPPORT === To watch the full credits list, in the program, click '?' then 'Credits'. Please report bugs and request features on the bugtracker: http://pulkomandy.tk/projects/GrafX2/query E-mail: grafx2@googlegroups.com It's a public mailing-list, so be aware that your message will be visible at: http://groups.google.com/group/grafx2 Sends greetings and glops to pouet.net : http://pouet.net/prod.php?which=51865 === HISTORY === Short revision history : * 10/2012 2.4 Animation * 04/2011 2.3 Further improvements * 03/2010 2.2 Layers, Lua scripting * 09/2009 2.1 GUI improvements and some new features. * 06/2009 2.0 Completed the features planned by Sunset Design. * 04/2009 2.0b99.0% Many new features and critical fixes. * 01/2009 2.0b98.0% Now running Linux, Windows, Mac OS X, BeOS, Haiku, AmigaOS 3.x and 4, MorphOS, SkyOS and gp2x. * 10/2008 2.0b97.0% Our first public beta release. * 07/2008 Our first public alpha release, Windows and Linux only * 04/2007 Start of this project and port to SDL. * 2001 Sunset Design releases the source under the GNU GPL. * 12/1999 2.0b96.5% Last release from Sunset Design. * 11/1996 2.0b90% First public release, at the Wired'96. * 09/1995 Project starts. Check http://pulkomandy.tk/projects/GrafX2/log/ for (very) detailed changelog. Check http://pulkomandy.tk/projects/GrafX2/wiki/History for an overview of the new features and bugfixes in each numbered version. === FINAL WORDS === We enjoy programming GrafX2, we hope you will enjoy drawing with it. If you like the program, here is a list of things you can do: * Register as an user at www.ohloh.net/p/grafx2 to improve our Karma * Port GrafX2 to your favourite platform * Report bugs or ask for features you miss (you'll get credited in the helpscreen !) * Make all your friends use GrafX2 * Send us your nice drawings, we'll put them in our online gallery Enjoy Pixelling with GrafX2, PulkoMandy & Yves, the great GrafX2 Project Team.- grafx2_2.4+git20180105/doc/PF_fonts.txt0000664000000000000000000000057413223665306015772 0ustar rootrootFonts by Yusuke Kamiyamane http://p.yusukekamiyamane.com/fonts/ License: "The fonts can be used free for any personal or commercial projects." - Arma Five - Ronda Seven - Easta Seven - Westa Seven - Tempesta Seven - Tempesta Five Converted to Sfont format by yrizoud Changed filenames for better sorting: for Compressed _ for Condensed __ for Normal ___ for Extended grafx2_2.4+git20180105/doc/README-zlib1.txt0000664000000000000000000000270313223665306016224 0ustar rootroot What's here =========== The official ZLIB1.DLL Source ====== zlib version 1.2.3 available at http://www.gzip.org/zlib/ Specification and rationale =========================== See the accompanying DLL_FAQ.txt Usage ===== See the accompanying USAGE.txt Build info ========== Contributed by Gilles Vollant Compiler: Microsoft Visual C++ Toolkit 2003 Library: Microsoft Visual C++ 6.0 (to link with MSVCRT.DLL) Copyright notice ================ (C) 1995-2005 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu grafx2_2.4+git20180105/doc/README-lua.txt0000664000000000000000000000224613223665306015766 0ustar rootrootThe Windows distribution of Grafx2 is compiled and statically linked with Lua v5.1.4 Lua is licensed with the MIT license: Copyright 1994-2008 Lua.org, PUC-Rio. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. grafx2_2.4+git20180105/src/0000775000000000000000000000000013223665307013530 5ustar rootrootgrafx2_2.4+git20180105/src/pages.h0000664000000000000000000001176313223665306015007 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file pages.h /// Handler for the Undo/Redo system. ////////////////////////////////////////////////////////////////////////////// #ifndef _PAGES_H_ #define _PAGES_H_ /// /// Pointer to the image to read, while drawing. It's either the last history /// layer page when FX feedback is on, or the history page before it /// when FX feedback is off. extern byte * FX_feedback_screen; ////////////////////////////////////////////////////////////////////////// /////////////////////////// BACKUP /////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// /// The pixels of visible layers, flattened copy. extern T_Bitmap Main_visible_image; /// The pixels of visible layers, flattened copy, used for no-feedback effects. extern T_Bitmap Main_visible_image_backup; /// The index of visible pixels from ::Main_visible_image. Points to the right layer. extern T_Bitmap Main_visible_image_depth_buffer; /// The pixels of visible layers for the spare page, flattened copy. extern T_Bitmap Spare_visible_image; /// /// INDIVIDUAL PAGES /// void Download_infos_page_main(T_Page * page); void Upload_infos_page_main(T_Page * page); /// Add a new layer to latest page of a list. Returns 0 on success. byte Add_layer(T_List_of_pages *list, int layer); /// Delete a layer from the latest page of a list. Returns 0 on success. byte Delete_layer(T_List_of_pages *list, int layer); /// Merges the current layer onto the one below it. byte Merge_layer(); /// Backs up a layer, unless it's already different from previous history step. int Dup_layer_if_shared(T_Page * page, int layer); // private T_Page * New_page(int nb_layers); void Download_infos_page_spare(T_Page * page); void Upload_infos_page_spare(T_Page * page); void Clear_page(T_Page * page); void Copy_S_page(T_Page * dest,T_Page * source); /// /// LISTS OF PAGES /// void Init_list_of_pages(T_List_of_pages * list); // private int Allocate_list_of_pages(T_List_of_pages * list); void Backward_in_list_of_pages(T_List_of_pages * list); void Advance_in_list_of_pages(T_List_of_pages * list); void Free_last_page_of_list(T_List_of_pages * list); int Create_new_page(T_Page * new_page,T_List_of_pages * current_list, int layer); void Change_page_number_of_list(T_List_of_pages * list,int number); void Free_page_of_a_list(T_List_of_pages * list); /// /// BACKUP HIGH-LEVEL FUNCTIONS /// static const int LAYER_NONE = -1; static const int LAYER_ALL = -2; int Init_all_backup_lists(enum IMAGE_MODES image_mode,int width,int height); void Set_number_of_backups(int nb_backups); int Backup_new_image(int layers,int width,int height); int Backup_with_new_dimensions(int width,int height); /// /// Resizes a backup step in-place (doesn't add a Undo/Redo step). /// Should only be called after an actual backup, because it loses the current. /// pixels. This function is meant to be used from within Lua scripts. int Backup_in_place(int width,int height); /// Backup the spare image, the one you don't see. void Backup_the_spare(int layer); int Backup_and_resize_the_spare(int width,int height); /// Backup with a new copy for the working layer, and references for all others. void Backup(void); /// Backup with a new copy of some layers (the others are references). void Backup_layers(int layer); void Undo(void); void Redo(void); void Free_current_page(void); // 'Kill' button void Exchange_main_and_spare(void); void End_of_modification(void); void Update_depth_buffer(void); void Redraw_layered_image(void); void Redraw_current_layer(void); void Update_screen_targets(void); /// Update all the special image buffers, if necessary. int Update_buffers(int width, int height); int Update_spare_buffers(int width, int height); void Redraw_spare_image(void); /// /// Must be called after changing the head of Main_backups list, or /// Main_current_layer void Update_FX_feedback(byte with_feedback); void Switch_layer_mode(enum IMAGE_MODES new_mode); /// /// STATISTICS /// /// Total number of unique bitmaps (layers, animation frames, backups) extern long Stats_pages_number; /// Total memory used by bitmaps (layers, animation frames, backups) extern long long Stats_pages_memory; #endif grafx2_2.4+git20180105/src/SFont.h0000664000000000000000000001002513223665306014727 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* SFont: a simple font-library that uses special bitmaps as fonts Copyright (C) 2003 Karl Bartel License: GPL or LGPL (at your choice) WWW: http://www.linux-games.com/sfont/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . Karl Bartel Cecilienstr. 14 12307 Berlin GERMANY karlb@gmx.net */ /************************************************************************ * SFONT - SDL Font Library by Karl Bartel * * * * All functions are explained below. For further information, take a * * look at the example files, the links at the SFont web site, or * * contact me, if you problem isn' addressed anywhere. * * * ************************************************************************/ ////////////////////////////////////////////////////////////////////////////// ///@file SFont.h /// Text rendering system, that uses bitmaps as fonts. /// Not specific to Grafx2, it writes to SDL_Surface. ////////////////////////////////////////////////////////////////////////////// #ifndef _SFONT_H_ #define _SFONT_H_ #include #ifdef __cplusplus extern "C" { #endif /// /// Declare one variable of this type for each font you are using. /// To load the fonts, load the font image into YourFont->Surface /// and call InitFont( YourFont ); typedef struct { SDL_Surface *Surface; int CharBegin[256]; int CharWidth[256]; int Space; unsigned char Transparent; } SFont_Font; /// /// Initializes the font. /// @param Font this contains the suface with the font. /// The Surface must be loaded before calling this function SFont_Font* SFont_InitFont (SDL_Surface *Font); /// /// Frees the font. /// @param Font The font to free /// The font must be loaded before using this function. void SFont_FreeFont(SFont_Font* Font); /// /// Blits a string to a surface. /// @param Surface The surface you want to blit to. /// @param Font The font to use. /// @param text A string containing the text you want to blit. /// @param x Coordinates to start drawing. /// @param y Coordinates to start drawing. void SFont_Write(SDL_Surface *Surface, const SFont_Font *Font, int x, int y, const char *text); /// Returns the width of "text" in pixels int SFont_TextWidth(const SFont_Font* Font, const char *text); /// Returns the height of "text" in pixels (which is always equal to Font->Surface->h) int SFont_TextHeight(const SFont_Font* Font, const char *text); /// Blits a string to Surface with centered x position void SFont_WriteCenter(SDL_Surface *Surface, const SFont_Font* Font, int y, const char *text); #ifdef __cplusplus } #endif #endif /* SFONT_H */ grafx2_2.4+git20180105/src/pxwide2.h0000664000000000000000000000631413223665306015266 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file pxwide2.h /// Renderer for double-wide pixels (4x2). ////////////////////////////////////////////////////////////////////////////// #include "struct.h" void Pixel_wide2 (word x,word y,byte color); byte Read_pixel_wide2 (word x,word y); void Block_wide2 (word start_x,word start_y,word width,word height,byte color); void Pixel_preview_normal_wide2 (word x,word y,byte color); void Pixel_preview_magnifier_wide2 (word x,word y,byte color); void Horizontal_XOR_line_wide2 (word x_pos,word y_pos,word width); void Vertical_XOR_line_wide2 (word x_pos,word y_pos,word height); void Display_brush_color_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_brush_mono_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); void Clear_brush_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); void Remap_screen_wide2 (word x_pos,word y_pos,word width,word height,byte * conversion_table); void Display_part_of_screen_wide2 (word width,word height,word image_width); void Display_line_on_screen_wide2 (word x_pos,word y_pos,word width,byte * line); void Read_line_screen_wide2 (word x_pos,word y_pos,word width,byte * line); void Display_part_of_screen_scaled_wide2(word width,word height,word image_width,byte * buffer); void Display_brush_color_zoom_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); void Display_brush_mono_zoom_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); void Clear_brush_scaled_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); void Display_brush_wide2 (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_line_on_screen_fast_wide2 (word x_pos,word y_pos,word width,byte * line); grafx2_2.4+git20180105/src/engine.c0000664000000000000000000034401413223665306015146 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ /// @file engine.c: Window engine and interface management #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "graph.h" #include "misc.h" #include "special.h" #include "buttons.h" #include "operatio.h" #include "shade.h" #include "errors.h" #include "sdlscreen.h" #include "windows.h" #include "brush.h" #include "input.h" #include "engine.h" #include "pages.h" #include "layers.h" #include "factory.h" #include "loadsave.h" #include "io.h" #include "pxsimple.h" #include "oldies.h" // we need this as global short Old_MX = -1; short Old_MY = -1; //---------- Annuler les effets des modes de dessin (sauf la grille) --------- // Variables mmorisants les anciens effets byte Shade_mode_before_cancel; byte Quick_shade_mode_before_cancel; byte Stencil_mode_before_cancel; byte Sieve_mode_before_cancel; byte Colorize_mode_before_cancel; byte Smooth_mode_before_cancel; byte Tiling_mode_before_cancel; Func_effect Effect_function_before_cancel; ///This table holds pointers to the saved window backgrounds. We can have up to 8 windows open at a time. byte* Window_background[8]; ///Save a screen block (usually before erasing it with a new window or a dropdown menu) void Save_background(byte **buffer, int x_pos, int y_pos, int width, int height) { int index; if(*buffer != NULL) DEBUG("WARNING : buffer already allocated !!!",0); *buffer=(byte *) malloc(width*Menu_factor_X*height*Menu_factor_Y*Pixel_width); if(*buffer==NULL) Error(0); for (index=0; index<(height*Menu_factor_Y); index++) Read_line(x_pos,y_pos+index,width*Menu_factor_X,(*buffer)+((int)index*width*Menu_factor_X*Pixel_width)); } ///Restores a screen block void Restore_background(byte *buffer, int x_pos, int y_pos, int width, int height) { int index; for (index=0; index= Menu_Y+Menu_factor_Y*(Menu_bars[current_menu].Top) && Mouse_Y < Menu_Y+Menu_factor_Y*(Menu_bars[current_menu].Top + Menu_bars[current_menu].Height)) break; } } if (current_menu==MENUBAR_COUNT) return -1; y_pos=(Mouse_Y - Menu_Y)/Menu_factor_Y - Menu_bars[current_menu].Top; if (current_menu == 0) first_button = 0; else first_button = Menu_bars[current_menu - 1].Last_button_index + 1; for (btn_number=first_button;btn_number<=Menu_bars[current_menu].Last_button_index;btn_number++) { switch(Buttons_Pool[btn_number].Shape) { case BUTTON_SHAPE_NO_FRAME : case BUTTON_SHAPE_RECTANGLE : if ((x_pos>=Buttons_Pool[btn_number].X_offset) && (y_pos>=Buttons_Pool[btn_number].Y_offset) && (x_pos<=Buttons_Pool[btn_number].X_offset+Buttons_Pool[btn_number].Width) && (y_pos<=Buttons_Pool[btn_number].Y_offset+Buttons_Pool[btn_number].Height)) return btn_number; break; case BUTTON_SHAPE_TRIANGLE_TOP_LEFT: if ((x_pos>=Buttons_Pool[btn_number].X_offset) && (y_pos>=Buttons_Pool[btn_number].Y_offset) && (x_pos+y_pos-(short)Buttons_Pool[btn_number].Y_offset-(short)Buttons_Pool[btn_number].X_offset<=Buttons_Pool[btn_number].Width)) return btn_number; break; case BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT: if ((x_pos<=Buttons_Pool[btn_number].X_offset+Buttons_Pool[btn_number].Width) && (y_pos<=Buttons_Pool[btn_number].Y_offset+Buttons_Pool[btn_number].Height) && (x_pos+y_pos-(short)Buttons_Pool[btn_number].Y_offset-(short)Buttons_Pool[btn_number].X_offset>=Buttons_Pool[btn_number].Width)) return btn_number; break; } } return -1; } ///Draw a menu button, selected or not void Draw_menu_button(byte btn_number,byte pressed) { word start_x; word start_y; word width; word height; byte * bitmap; word bitmap_width; word x_pos; word y_pos; byte current_menu; byte color; signed char icon; // Find in which menu the button is for (current_menu = 0; current_menu < MENUBAR_COUNT; current_menu++) { // We found the right bar ! if (Menu_bars[current_menu].Last_button_index >= btn_number && (current_menu==0 || Menu_bars[current_menu -1].Last_button_index < btn_number)) { break; } } start_x = Buttons_Pool[btn_number].X_offset; start_y = Buttons_Pool[btn_number].Y_offset; width = Buttons_Pool[btn_number].Width+1; height = Buttons_Pool[btn_number].Height+1; icon = Buttons_Pool[btn_number].Icon; if (icon==-1) { // Standard button bitmap_width = Menu_bars[current_menu].Skin_width; bitmap=&(Menu_bars[current_menu].Skin[pressed][start_y*Menu_bars[current_menu].Skin_width+start_x]); } else { // From Menu_buttons bitmap_width = MENU_SPRITE_WIDTH; bitmap=Gfx->Menu_sprite[pressed][(byte)icon][0]; // For bottom right: offset +1,+1 if (Buttons_Pool[btn_number].Shape==BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT) bitmap += MENU_SPRITE_WIDTH+1; } switch(Buttons_Pool[btn_number].Shape) { case BUTTON_SHAPE_NO_FRAME : break; case BUTTON_SHAPE_RECTANGLE : for (y_pos=0;y_posPages->Nb_layers; static int previewW=0, previewH=0; if (! *preview_is_visible && layercount>1) { previewW = Min(Main_image_width/Menu_factor_X,Layer_button_width); previewH = previewW * Main_image_height / Main_image_width * Menu_factor_X / Menu_factor_Y; if (previewH > Screen_height/4) { previewH = Screen_height/4; previewW = Main_image_width*previewH/Main_image_height*Menu_factor_Y/Menu_factor_X; } Open_popup((Buttons_Pool[BUTTON_LAYER_SELECT].X_offset + 2)*Menu_factor_X, Menu_Y - previewH * Menu_factor_Y, Buttons_Pool[BUTTON_LAYER_SELECT].Width, previewH); *preview_is_visible = 1; // Make the system think the menu is visible (Open_popup hides it) // so Button_under_mouse still works Menu_is_visible=Menu_is_visible_before_window; Menu_Y=Menu_Y_before_window; Window_rectangle(0, 0, Window_width, Window_height, MC_Dark); for(layer = 0; layer < layercount; ++layer) { int offset; // Stop if the window is too small to show the // layer button (ex: 320x200 can only display 12 layers) if (layer*Layer_button_width+previewW > Window_width) break; offset=(Layer_button_width-previewW)/2; for (y = 0; y < previewH*Pixel_height*Menu_factor_Y-1; y++) for (x = 0; x < previewW*Pixel_width*Menu_factor_X-1; x++) { int imgx = x * Main_image_width / (previewW*Pixel_width*Menu_factor_X-1); int imgy = y * Main_image_height / (previewH*Pixel_height*Menu_factor_Y-1); // Use Pixel_simple() in order to get highest resolution Pixel_simple(x+((layer*Layer_button_width+offset)*Menu_factor_X+Window_pos_X)*Pixel_width, y+Window_pos_Y*Pixel_height+1, *(Main_backups->Pages->Image[layer].Pixels + imgx + imgy * Main_image_width)); } } Update_window_area(0,0,Window_width, Window_height); } } void Layer_preview_off(int * preview_is_visible) { if (*preview_is_visible) { int x = Mouse_K; Close_popup(); Display_cursor(); Mouse_K = x; // Close_popup waits for end of click and resets Mouse_K... *preview_is_visible = 0; } } ///Main handler for everything. This is the main loop of the program void Main_handler(void) { static byte temp_color; int button_index; // Numro de bouton de menu en cours int prev_button_number=0; // Numro de bouton de menu sur lequel on tait prcdemment byte blink; // L'opration demande un effacement du curseur int key_index; // index du tableau de touches spciales correspondant la touche enfonce byte temp; byte effect_modified; byte action; dword key_pressed; int preview_is_visible=0; // This is used for the layer preview do { // Resize requested if (Resize_width || Resize_height) { Hide_cursor(); Init_mode_video(Resize_width, Resize_height, 0, Pixel_ratio); // Reset the variables that indicate a resize was requested. Display_menu(); Reposition_palette(); Display_all_screen(); Display_cursor(); } else if (Drop_file_name) { // A file was dragged into Grafx2's window if (Main_image_is_modified && !Confirmation_box("Discard unsaved changes ?")) { // do nothing } else { T_IO_Context context; char* flimit; byte old_cursor_shape; Upload_infos_page_main(Main_backups->Pages); flimit = Find_last_separator(Drop_file_name); *(flimit++) = '\0'; Hide_cursor(); old_cursor_shape=Cursor_shape; Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Init_context_layered_image(&context, flimit, Drop_file_name); Load_image(&context); if (File_error!=1) { Compute_limits(); Compute_paintbrush_coordinates(); Redraw_layered_image(); End_of_modification(); Main_image_is_modified=0; } Destroy_context(&context); Compute_optimal_menu_colors(Main_palette); Check_menu_mode(); Display_menu(); if (Config.Display_image_limits) Display_image_limits(); Hide_cursor(); Cursor_shape=old_cursor_shape; Display_all_screen(); Display_cursor(); } free(Drop_file_name); Drop_file_name=NULL; } if(Get_input(0)) { action = 0; // Inhibit all keys if a drawing operation is in progress. // We make an exception for the freehand operations, but these will // only accept a very limited number of shortcuts. if (Operation_stack_size!=0 && !Allow_color_change_during_operation) Key=0; // Evenement de fermeture if (Quit_is_required) { Quit_is_required=0; Button_Quit(); } if (Pan_shortcut_pressed && Current_operation!=OPERATION_PAN_VIEW) { Hide_cursor(); Start_operation_stack(OPERATION_PAN_VIEW); Display_cursor(); action++; } else if (Key) { effect_modified = 0; for (key_index=SPECIAL_CLICK_RIGHT+1;key_index>2)); else Scroll_screen(0,-(Screen_height>>3)); action++; break; case SPECIAL_SCROLL_DOWN : // Scroll down if (Main_magnifier_mode) Scroll_magnifier(0,(Main_magnifier_height>>2)); else Scroll_screen(0,(Screen_height>>3)); action++; break; case SPECIAL_SCROLL_LEFT : // Scroll left if (Main_magnifier_mode) Scroll_magnifier(-(Main_magnifier_width>>2),0); else Scroll_screen(-(Screen_width>>3),0); action++; break; case SPECIAL_SCROLL_RIGHT : // Scroll right if (Main_magnifier_mode) Scroll_magnifier((Main_magnifier_width>>2),0); else Scroll_screen((Screen_width>>3),0); action++; break; case SPECIAL_SCROLL_UP_FAST : // Scroll up faster if (Main_magnifier_mode) Scroll_magnifier(0,-(Main_magnifier_height>>1)); else Scroll_screen(0,-(Screen_height>>2)); action++; break; case SPECIAL_SCROLL_DOWN_FAST : // Scroll down faster if (Main_magnifier_mode) Scroll_magnifier(0,(Main_magnifier_height>>1)); else Scroll_screen(0,(Screen_height>>2)); action++; break; case SPECIAL_SCROLL_LEFT_FAST : // Scroll left faster if (Main_magnifier_mode) Scroll_magnifier(-(Main_magnifier_width>>1),0); else Scroll_screen(-(Screen_width>>2),0); action++; break; case SPECIAL_SCROLL_RIGHT_FAST : // Scroll right faster if (Main_magnifier_mode) Scroll_magnifier((Main_magnifier_width>>1),0); else Scroll_screen((Screen_width>>2),0); action++; break; case SPECIAL_SCROLL_UP_SLOW : // Scroll up slower if (Main_magnifier_mode) Scroll_magnifier(0,-1); else Scroll_screen(0,-1); action++; break; case SPECIAL_SCROLL_DOWN_SLOW : // Scroll down slower if (Main_magnifier_mode) Scroll_magnifier(0,1); else Scroll_screen(0,1); action++; break; case SPECIAL_SCROLL_LEFT_SLOW : // Scroll left slower if (Main_magnifier_mode) Scroll_magnifier(-1,0); else Scroll_screen(-1,0); action++; break; case SPECIAL_SCROLL_RIGHT_SLOW : // Scroll right slower if (Main_magnifier_mode) Scroll_magnifier(1,0); else Scroll_screen(1,0); action++; break; case SPECIAL_SHOW_HIDE_CURSOR : // Show / Hide cursor Hide_cursor(); Cursor_hidden=!Cursor_hidden; Display_cursor(); action++; break; case SPECIAL_DOT_PAINTBRUSH : // Paintbrush = "." Hide_cursor(); Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND; Set_paintbrush_size(1,1); Change_paintbrush_shape(PAINTBRUSH_SHAPE_ROUND); Display_cursor(); action++; break; case SPECIAL_CONTINUOUS_DRAW : // Continuous freehand drawing Select_button(BUTTON_DRAW,LEFT_SIDE); // ATTENTION CE TRUC EST MOCHE ET VA MERDER SI ON SE MET A UTILISER DES BOUTONS POPUPS while (Current_operation!=OPERATION_CONTINUOUS_DRAW) Select_button(BUTTON_DRAW,RIGHT_SIDE); action++; break; case SPECIAL_FLIP_X : // Flip X Hide_cursor(); Flip_X_lowlevel(Brush_original_pixels, Brush_width, Brush_height); // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Display_cursor(); action++; break; case SPECIAL_FLIP_Y : // Flip Y Hide_cursor(); Flip_Y_lowlevel(Brush_original_pixels, Brush_width, Brush_height); // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Display_cursor(); action++; break; case SPECIAL_ROTATE_90 : // 90 brush rotation Hide_cursor(); Rotate_90_deg(); Display_cursor(); action++; break; case SPECIAL_ROTATE_180 : // 180 brush rotation Hide_cursor(); Rotate_180_deg_lowlevel(Brush_original_pixels, Brush_width, Brush_height); // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); Display_cursor(); action++; break; case SPECIAL_STRETCH : // Stretch brush Hide_cursor(); Start_operation_stack(OPERATION_STRETCH_BRUSH); Display_cursor(); action++; break; case SPECIAL_DISTORT : // Distort brush Hide_cursor(); Start_operation_stack(OPERATION_DISTORT_BRUSH); Display_cursor(); action++; break; case SPECIAL_ROTATE_ANY_ANGLE : // Rotate brush by any angle Hide_cursor(); Start_operation_stack(OPERATION_ROTATE_BRUSH); Display_cursor(); action++; break; case SPECIAL_BRUSH_DOUBLE: if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) { Hide_cursor(); Stretch_brush(1,1,Brush_width*2,Brush_height*2); Display_cursor(); } action++; break; case SPECIAL_BRUSH_DOUBLE_WIDTH: if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) { Hide_cursor(); Stretch_brush(1,1,Brush_width*2,Brush_height); Display_cursor(); } action++; break; case SPECIAL_BRUSH_DOUBLE_HEIGHT: if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) { Hide_cursor(); Stretch_brush(1,1,Brush_width,Brush_height*2); Display_cursor(); } action++; break; case SPECIAL_BRUSH_HALVE: if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) { Hide_cursor(); Stretch_brush(1,1,Brush_width/2,Brush_height/2); Display_cursor(); } action++; break; case SPECIAL_OUTLINE : // Outline brush Hide_cursor(); Outline_brush(); Display_cursor(); action++; break; case SPECIAL_NIBBLE : // Nibble brush Hide_cursor(); Nibble_brush(); Display_cursor(); action++; break; case SPECIAL_GET_BRUSH_COLORS : // Get colors from brush Get_colors_from_brush(); action++; break; case SPECIAL_RECOLORIZE_BRUSH : // Recolorize brush Hide_cursor(); Remap_brush(); Display_cursor(); action++; break; case SPECIAL_LOAD_BRUSH : Load_picture(0); action++; break; case SPECIAL_SAVE_BRUSH : Save_picture(CONTEXT_BRUSH); action++; break; case SPECIAL_ZOOM_IN : // Zoom in Zoom(+1); action++; break; case SPECIAL_ZOOM_OUT : // Zoom out Zoom(-1); action++; break; case SPECIAL_CENTER_ATTACHMENT : // Center brush attachment Hide_cursor(); Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); Display_cursor(); action++; break; case SPECIAL_TOP_LEFT_ATTACHMENT : // Top-left brush attachment Hide_cursor(); Brush_offset_X=0; Brush_offset_Y=0; Display_cursor(); action++; break; case SPECIAL_TOP_RIGHT_ATTACHMENT : // Top-right brush attachment Hide_cursor(); Brush_offset_X=(Brush_width-1); Brush_offset_Y=0; Display_cursor(); action++; break; case SPECIAL_BOTTOM_LEFT_ATTACHMENT : // Bottom-left brush attachment Hide_cursor(); Brush_offset_X=0; Brush_offset_Y=(Brush_height-1); Display_cursor(); action++; break; case SPECIAL_BOTTOM_RIGHT_ATTACHMENT : // Bottom right brush attachment Hide_cursor(); Brush_offset_X=(Brush_width-1); Brush_offset_Y=(Brush_height-1); Display_cursor(); action++; break; case SPECIAL_EXCLUDE_COLORS_MENU : // Exclude colors menu Menu_tag_colors("Tag colors to exclude",Exclude_color,&temp,1, NULL, SPECIAL_EXCLUDE_COLORS_MENU); action++; break; case SPECIAL_INVERT_SIEVE : Invert_trame(); action++; break; case SPECIAL_SHADE_MODE : Button_Shade_mode(); effect_modified = 1; action++; break; case SPECIAL_SHADE_MENU : Button_Shade_menu(); effect_modified = 1; action++; break; case SPECIAL_QUICK_SHADE_MODE : Button_Quick_shade_mode(); effect_modified = 1; action++; break; case SPECIAL_QUICK_SHADE_MENU : Button_Quick_shade_menu(); effect_modified = 1; action++; break; case SPECIAL_STENCIL_MODE : Button_Stencil_mode(); effect_modified = 1; action++; break; case SPECIAL_STENCIL_MENU : Button_Stencil_menu(); effect_modified = 1; action++; break; case SPECIAL_MASK_MODE : Button_Mask_mode(); effect_modified = 1; action++; break; case SPECIAL_MASK_MENU : Button_Mask_menu(); effect_modified = 1; action++; break; case SPECIAL_GRID_MODE : Button_Snap_mode(); effect_modified = 1; action++; break; case SPECIAL_GRID_MENU : Button_Grid_menu(); effect_modified = 1; action++; break; case SPECIAL_SHOW_GRID : Button_Show_grid(); effect_modified = 1; action++; break; case SPECIAL_SIEVE_MODE : Button_Sieve_mode(); effect_modified = 1; action++; break; case SPECIAL_SIEVE_MENU : Button_Sieve_menu(); effect_modified = 1; action++; break; case SPECIAL_COLORIZE_MODE : Button_Colorize_mode(); effect_modified = 1; action++; break; case SPECIAL_COLORIZE_MENU : Button_Colorize_menu(); effect_modified = 1; action++; break; case SPECIAL_SMOOTH_MODE : Button_Smooth_mode(); effect_modified = 1; action++; break; case SPECIAL_SMOOTH_MENU : Button_Smooth_menu(); effect_modified = 1; action++; break; case SPECIAL_SMEAR_MODE : Button_Smear_mode(); effect_modified = 1; action++; break; case SPECIAL_TILING_MODE : Button_Tiling_mode(); effect_modified = 1; action++; break; case SPECIAL_TILING_MENU : effect_modified = 1; Button_Tiling_menu(); action++; break; case SPECIAL_TILEMAP_MODE : Button_Tilemap_mode(); effect_modified = 1; action++; break; case SPECIAL_TILEMAP_MENU : effect_modified = 1; Button_Tilemap_menu(); action++; break; case SPECIAL_EFFECTS_OFF : Effects_off(); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_1 : Transparency_set(1); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_2 : Transparency_set(2); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_3 : Transparency_set(3); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_4 : Transparency_set(4); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_5 : Transparency_set(5); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_6 : Transparency_set(6); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_7 : Transparency_set(7); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_8 : Transparency_set(8); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_9 : Transparency_set(9); effect_modified = 1; action++; break; case SPECIAL_TRANSPARENCY_0 : Transparency_set(0); effect_modified = 1; action++; break; case SPECIAL_ZOOM_1 : Zoom_set(-1); action++; break; case SPECIAL_ZOOM_2 : Zoom_set(0); action++; break; case SPECIAL_ZOOM_3 : Zoom_set(1); action++; break; case SPECIAL_ZOOM_4 : Zoom_set(2); action++; break; case SPECIAL_ZOOM_5 : Zoom_set(3); action++; break; case SPECIAL_ZOOM_6 : Zoom_set(4); action++; break; case SPECIAL_ZOOM_8 : Zoom_set(5); action++; break; case SPECIAL_ZOOM_10 : Zoom_set(6); action++; break; case SPECIAL_ZOOM_12 : Zoom_set(7); action++; break; case SPECIAL_ZOOM_14 : Zoom_set(8); action++; break; case SPECIAL_ZOOM_16 : Zoom_set(9); action++; break; case SPECIAL_ZOOM_18 : Zoom_set(10); action++; break; case SPECIAL_ZOOM_20 : Zoom_set(11); action++; break; case SPECIAL_LAYER1_SELECT: case SPECIAL_LAYER2_SELECT: case SPECIAL_LAYER3_SELECT: case SPECIAL_LAYER4_SELECT: case SPECIAL_LAYER5_SELECT: case SPECIAL_LAYER6_SELECT: case SPECIAL_LAYER7_SELECT: case SPECIAL_LAYER8_SELECT: Layer_activate((key_index-SPECIAL_LAYER1_SELECT)/2, LEFT_SIDE); action++; break; case SPECIAL_LAYER1_TOGGLE: case SPECIAL_LAYER2_TOGGLE: case SPECIAL_LAYER3_TOGGLE: case SPECIAL_LAYER4_TOGGLE: case SPECIAL_LAYER5_TOGGLE: case SPECIAL_LAYER6_TOGGLE: case SPECIAL_LAYER7_TOGGLE: case SPECIAL_LAYER8_TOGGLE: Layer_activate((key_index-SPECIAL_LAYER1_TOGGLE)/2, RIGHT_SIDE); action++; break; case SPECIAL_FORMAT_CHECKER: C64_FLI_enforcer(); action++; break; case SPECIAL_REPEAT_SCRIPT: #ifdef __ENABLE_LUA__ Repeat_script(); action++; #endif break; case SPECIAL_RUN_SCRIPT_1: case SPECIAL_RUN_SCRIPT_2: case SPECIAL_RUN_SCRIPT_3: case SPECIAL_RUN_SCRIPT_4: case SPECIAL_RUN_SCRIPT_5: case SPECIAL_RUN_SCRIPT_6: case SPECIAL_RUN_SCRIPT_7: case SPECIAL_RUN_SCRIPT_8: case SPECIAL_RUN_SCRIPT_9: case SPECIAL_RUN_SCRIPT_10: #ifdef __ENABLE_LUA__ Run_numbered_script(key_index-SPECIAL_RUN_SCRIPT_1); action++; #endif break; case SPECIAL_CYCLE_MODE: Cycling_mode= !Cycling_mode; // Restore palette if (!Cycling_mode) Set_palette(Main_palette); action++; break; case SPECIAL_HOLD_PAN: // already handled by Pan_shortcut_pressed break; } } } // End of special keys // Shortcut for clicks of Menu buttons. // Disable all of them when an operation is in progress if (Operation_stack_size==0) { // Some functions open windows that clear the Key variable, // so we need to use a temporary replacement. key_pressed = Key; for (button_index=0;button_index=Menu_Y) || ( (Main_magnifier_mode) && (Mouse_X>=Main_separator_position) && (Mouse_XHover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed) Draw_menu_button(prev_button_number, BUTTON_RELEASED); */ Block(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,Menu_factor_Y<<3,MC_Light); Update_rect(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,Menu_factor_Y<<3); Display_cursor(); } } else { if ( (prev_button_number!=BUTTON_CHOOSE_COL) || (temp_color!=First_color_in_palette) || (Old_MX!=Mouse_X) || (Old_MY!=Mouse_Y) ) { // Le curseur est sur un nouveau bouton if (button_index!=BUTTON_CHOOSE_COL) { Hide_cursor(); /*if (Gfx->Hover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed) Draw_menu_button(prev_button_number, BUTTON_RELEASED); */ Print_in_menu(Buttons_Pool[button_index].Tooltip,0); /*if (Gfx->Hover_effect && !Buttons_Pool[button_index].Pressed) Draw_menu_button(button_index, BUTTON_HIGHLIGHTED); */ Display_cursor(); } else { // Le curseur est-il sur une couleur de la palette? int color; if ((color=Pick_color_in_palette())!=-1) { Hide_cursor(); Status_print_palette_color(color); Display_cursor(); } else { if ( (Old_MX!=Mouse_X) || (Old_MY!=Mouse_Y) ) { Hide_cursor(); Block(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,Menu_factor_Y<<3,MC_Light); Update_rect(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,8*Menu_factor_Y); Display_cursor(); } } } } } } prev_button_number=button_index; // Gestion des clicks if (Mouse_K) { if (Mouse_Y>=Menu_Y) { if (button_index>=0) { Layer_preview_off(&preview_is_visible); Select_button(button_index,Mouse_K); prev_button_number=-1; } } else if (Main_magnifier_mode) Move_separator(); } if (button_index == BUTTON_LAYER_SELECT) Layer_preview_on(&preview_is_visible); else Layer_preview_off(&preview_is_visible); } else // if (!Cursor_in_menu) { Layer_preview_off(&preview_is_visible); } // we need to refresh that one as we may come from a sub window Cursor_in_menu=(Mouse_Y>=Menu_Y) || ( (Main_magnifier_mode) && (Mouse_X>=Main_separator_position) && (Mouse_XHover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed) Draw_menu_button(prev_button_number, BUTTON_RELEASED); */ if ( (Current_operation!=OPERATION_COLORPICK) && (Current_operation!=OPERATION_REPLACE) ) { Print_in_menu("X: Y: ",0); } else { Print_in_menu("X: Y: ( )",0); } Display_cursor(); Cursor_in_menu_previous = 0; } } if(Cursor_in_menu) { Cursor_in_menu_previous = 1; } else { blink=Operation[Current_operation][Mouse_K_unique][Operation_stack_size].Hide_cursor; if (blink) Hide_cursor(); Operation[Current_operation][Mouse_K_unique][Operation_stack_size].Action(); if (blink) Display_cursor(); } Old_MX=Mouse_X; Old_MY=Mouse_Y; } while (!Quitting); } ////////////////////////////////////////////////////////////////////////////// // diffrentes fonctions d'affichage utilises dans les fentres // ////////////////////////////////////////////////////////////////////////////// //----------------------- Tracer une fentre d'options ----------------------- void Open_window(word width,word height, const char * title) // Lors de l'appel cette procdure, la souris doit tre affiche. // En sortie de cette procedure, la souris est efface. { //word i,j; size_t title_length; Hide_cursor(); /*if (Windows_open == 0 && Gfx->Hover_effect) { if (Cursor_in_menu) { int button_index=Button_under_mouse(); if (button_index > -1 && !Buttons_Pool[button_index].Pressed) Draw_menu_button(button_index, BUTTON_RELEASED); } }*/ Windows_open++; Window_width=width; Window_height=height; // Positionnement de la fentre Window_pos_X=(Screen_width-(width*Menu_factor_X))>>1; Window_pos_Y=(Screen_height-(height*Menu_factor_Y))>>1; Window_draggable=1; // Sauvegarde de ce que la fentre remplace Save_background(&(Window_background[Windows_open-1]), Window_pos_X, Window_pos_Y, width, height); // Fentre grise Window_rectangle(2,2,width-4,height-4,MC_Window); // -- Frame de la fentre ----- --- -- - - // Frame noir puis en relief Window_display_frame_mono(0,0,width,height,MC_Black); Window_display_frame_out(1,1,width-2,height-2); // Barre sous le titre Window_rectangle(3,3,width-6,10,MC_White); Window_rectangle(2,12,width-4,1,MC_Dark); title_length = strlen(title); if (title_length+2 > (size_t)(width/8)) title_length = width/8-2; Print_in_window_limited((width-(title_length<<3))>>1,4,title,title_length,MC_Black,MC_White); if (Windows_open == 1) { Menu_is_visible_before_window=Menu_is_visible; Menu_is_visible=0; Menu_Y_before_window=Menu_Y; Menu_Y=Screen_height; Cursor_shape_before_window=Cursor_shape; Cursor_shape=CURSOR_SHAPE_ARROW; Paintbrush_hidden_before_window=Paintbrush_hidden; Paintbrush_hidden=1; if (Allow_colorcycling) { Allow_colorcycling=0; // Restore palette Set_palette(Main_palette); } Allow_drag_and_drop(0); } // Initialisation des listes de boutons de la fentre Window_normal_button_list =NULL; Window_palette_button_list =NULL; Window_scroller_button_list=NULL; Window_special_button_list =NULL; Window_dropdown_button_list=NULL; Window_nb_buttons =0; } //----------------------- Fermer une fentre d'options ----------------------- void Close_window(void) // Lors de l'appel cette procedure, la souris doit tre affiche. // En sortie de cette procedure, la souris est efface. { T_Normal_button * temp1; T_Palette_button * temp2; T_Scroller_button * temp3; T_Special_button * temp4; T_Dropdown_button * temp5; T_List_button * temp6; Hide_cursor(); while (Window_normal_button_list) { temp1=Window_normal_button_list->Next; free(Window_normal_button_list); Window_normal_button_list=temp1; } while (Window_palette_button_list) { temp2=Window_palette_button_list->Next; free(Window_palette_button_list); Window_palette_button_list=temp2; } while (Window_scroller_button_list) { temp3=Window_scroller_button_list->Next; free(Window_scroller_button_list); Window_scroller_button_list=temp3; } while (Window_special_button_list) { temp4=Window_special_button_list->Next; free(Window_special_button_list); Window_special_button_list=temp4; } while (Window_dropdown_button_list) { temp5=Window_dropdown_button_list->Next; Window_dropdown_clear_items(Window_dropdown_button_list); free(Window_dropdown_button_list); Window_dropdown_button_list=temp5; } while (Window_list_button_list) { temp6=Window_list_button_list->Next; free(Window_list_button_list); Window_list_button_list=temp6; } if (Windows_open != 1) { // Restore de ce que la fentre cachait Restore_background(Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height); Window_background[Windows_open-1]=NULL; Update_window_area(0,0,Window_width,Window_height); Windows_open--; } else { free(Window_background[Windows_open-1]); Window_background[Windows_open-1]=NULL; Windows_open--; Paintbrush_hidden=Paintbrush_hidden_before_window; Compute_paintbrush_coordinates(); Menu_Y=Menu_Y_before_window; Menu_is_visible=Menu_is_visible_before_window; Cursor_shape=Cursor_shape_before_window; Check_menu_mode(); Display_all_screen(); Display_menu(); Allow_colorcycling=1; Allow_drag_and_drop(1); } Key=0; Mouse_K=0; Old_MX = -1; Old_MY = -1; } //---------------- Dessiner un bouton normal dans une fentre ---------------- void Window_draw_normal_bouton(word x_pos,word y_pos,word width,word height, const char * title,byte undersc_letter,byte clickable) { byte title_color; word text_x_pos,text_y_pos; if (clickable) { Window_display_frame_out(x_pos,y_pos,width,height); Window_display_frame_generic(x_pos-1,y_pos-1,width+2,height+2,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark); title_color=MC_Black; } else { Window_display_frame_out(x_pos,y_pos,width,height); Window_display_frame_mono(x_pos-1,y_pos-1,width+2,height+2,MC_Light); title_color=MC_Dark; } text_x_pos=x_pos+( (width-(strlen(title)<<3)+1) >>1 ); text_y_pos=y_pos+((height-7)>>1); Print_in_window(text_x_pos,text_y_pos,title,title_color,MC_Light); if (undersc_letter) Window_rectangle(text_x_pos+((undersc_letter-1)<<3), text_y_pos+8,8,1,MC_Dark); } // -- Button normal enfonc dans la fentre -- void Window_select_normal_button(word x_pos,word y_pos,word width,word height) { Window_display_frame_generic(x_pos,y_pos,width,height,MC_Dark,MC_Black,MC_Dark,MC_Dark,MC_Black); Update_window_area(x_pos, y_pos, width, height); } // -- Button normal dsenfonc dans la fentre -- void Window_unselect_normal_button(word x_pos,word y_pos,word width,word height) { Window_display_frame_out(x_pos,y_pos,width,height); Update_window_area(x_pos, y_pos, width, height); } //--------------- Dessiner un bouton palette dans une fentre ---------------- void Window_draw_palette_bouton(word x_pos,word y_pos) { word color; for (color=0; color<=255; color++) Window_rectangle( ((color >> 4)*10)+x_pos+6,((color & 15)*5)+y_pos+3,5,5,color); Window_display_frame(x_pos,y_pos,164,86); } // -------------------- Effacer les TAGs sur les palette --------------------- // Cette fonct ne sert plus que lorsqu'on efface les tags dans le menu Spray. void Window_clear_tags(void) { word origin_x; word origin_y; word x_pos; word window_x_pos; //word window_y_pos; origin_x=Window_palette_button_list->Pos_X+3; origin_y=Window_palette_button_list->Pos_Y+3; for (x_pos=0,window_x_pos=origin_x;x_pos<16;x_pos++,window_x_pos+=10) Window_rectangle(window_x_pos,origin_y,3,80,MC_Light); Update_window_area(origin_x,origin_y,160,80); } // ---- Tracer les TAGs sur les palettes du menu Palette ou du menu Shade ---- void Tag_color_range(byte start,byte end) { word origin_x; word origin_y; //word x_pos; word y_pos; //word window_x_pos; word window_y_pos; word index; // On efface les anciens TAGs for (index=0;index<=start;index++) Window_rectangle(Window_palette_button_list->Pos_X+3+((index>>4)*10), Window_palette_button_list->Pos_Y+3+((index&15)* 5), 3,5,MC_Light); for (index=end;index<256;index++) Window_rectangle(Window_palette_button_list->Pos_X+3+((index>>4)*10), Window_palette_button_list->Pos_Y+3+((index&15)* 5), 3,5,MC_Light); // On affiche le 1er TAG origin_x=(Window_palette_button_list->Pos_X+3)+(start>>4)*10; origin_y=(Window_palette_button_list->Pos_Y+3)+(start&15)* 5; for (y_pos=0,window_y_pos=origin_y ;y_pos<5;y_pos++,window_y_pos++) Pixel_in_window(origin_x ,window_y_pos,MC_Black); for (y_pos=0,window_y_pos=origin_y+1;y_pos<3;y_pos++,window_y_pos++) Pixel_in_window(origin_x+1,window_y_pos,MC_Black); Pixel_in_window(origin_x+2,origin_y+2,MC_Black); if (start!=end) { // On complte le 1er TAG Pixel_in_window(origin_x+1,origin_y+4,MC_Black); // On affiche le 2me TAG origin_x=(Window_palette_button_list->Pos_X+3)+(end>>4)*10; origin_y=(Window_palette_button_list->Pos_Y+3)+(end&15)* 5; for (y_pos=0,window_y_pos=origin_y; y_pos<5; y_pos++,window_y_pos++) Pixel_in_window(origin_x ,window_y_pos,MC_Black); for (y_pos=0,window_y_pos=origin_y; y_pos<4; y_pos++,window_y_pos++) Pixel_in_window(origin_x+1,window_y_pos,MC_Black); Pixel_in_window(origin_x+2,origin_y+2,MC_Black); // On TAG toutes les couleurs intermdiaires for (index=start+1;indexPos_X+3+((index>>4)*10), Window_palette_button_list->Pos_Y+3+((index&15)* 5), 2,5,MC_Black); // On efface l'ventuelle pointe d'une ancienne extrmit de l'intervalle Pixel_in_window(Window_palette_button_list->Pos_X+5+((index>>4)*10), Window_palette_button_list->Pos_Y+5+((index&15)* 5), MC_Light); } } Update_window_area(Window_palette_button_list->Pos_X+3,Window_palette_button_list->Pos_Y+3,12*16,5*16); } //------------------ Dessiner un scroller dans une fentre ------------------- void Compute_slider_cursor_length(T_Scroller_button * button) { if (button->Nb_elements>button->Nb_visibles) { button->Cursor_length=(button->Nb_visibles*(button->Length-24))/button->Nb_elements; if (!(button->Cursor_length)) button->Cursor_length=1; } else { button->Cursor_length=button->Length-24; } } void Window_draw_slider(T_Scroller_button * button) { word slider_position; if (button->Is_horizontal) { slider_position=button->Pos_X+12; Window_rectangle(slider_position, button->Pos_Y, button->Length-24,11,MC_Black/*MC_Dark*/); if (button->Nb_elements>button->Nb_visibles) slider_position+= ((button->Length-24-button->Cursor_length)*(button->Position)+(button->Nb_elements-button->Nb_visibles)/2)/(button->Nb_elements-button->Nb_visibles); Window_rectangle(slider_position, button->Pos_Y, button->Cursor_length,11,MC_OnBlack/*MC_White*/); Update_window_area(button->Pos_X, button->Pos_Y, button->Length,11); } else { slider_position=button->Pos_Y+12; Window_rectangle(button->Pos_X, slider_position, 11,button->Length-24,MC_Black/*MC_Dark*/); if (button->Nb_elements>button->Nb_visibles) slider_position+= ((button->Length-24-button->Cursor_length)*(button->Position)+(button->Nb_elements-button->Nb_visibles)/2)/(button->Nb_elements-button->Nb_visibles); // //(button->Position*) / (button->Nb_elements-button->Nb_visibles)); Window_rectangle(button->Pos_X, slider_position, 11,button->Cursor_length,MC_OnBlack/*MC_White*/); Update_window_area(button->Pos_X, button->Pos_Y, 11,button->Length); } } void Window_draw_scroller_button(T_Scroller_button * button) { if (button->Is_horizontal) { Window_display_frame_generic(button->Pos_X-1,button->Pos_Y-1,button->Length+2,13,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark); Window_display_frame_mono(button->Pos_X+11,button->Pos_Y-1,button->Length-22,13,MC_Black); Window_display_frame_out(button->Pos_X,button->Pos_Y,11,11); Window_display_frame_out(button->Pos_X+button->Length-11,button->Pos_Y,11,11); Print_in_window(button->Pos_X+2,button->Pos_Y+2,"\033",MC_Black,MC_Light); Print_in_window(button->Pos_X+button->Length-9,button->Pos_Y+2,"\032",MC_Black,MC_Light); } else { Window_display_frame_generic(button->Pos_X-1,button->Pos_Y-1,13,button->Length+2,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark); Window_display_frame_mono(button->Pos_X-1,button->Pos_Y+11,13,button->Length-22,MC_Black); Window_display_frame_out(button->Pos_X,button->Pos_Y,11,11); Window_display_frame_out(button->Pos_X,button->Pos_Y+button->Length-11,11,11); Print_in_window(button->Pos_X+2,button->Pos_Y+2,"\030",MC_Black,MC_Light); Print_in_window(button->Pos_X+2,button->Pos_Y+button->Length-9,"\031",MC_Black,MC_Light); } Window_draw_slider(button); } //--------------- Dessiner une zone de saisie dans une fentre --------------- void Window_draw_input_bouton(word x_pos,word y_pos,word width_in_characters) { Window_display_frame_in(x_pos,y_pos,(width_in_characters<<3)+3,11); } //------------ Modifier le contenu (caption) d'une zone de saisie ------------ void Window_input_content(T_Special_button * button, const char * content) { Print_in_window_limited(button->Pos_X+2,button->Pos_Y+2,content,button->Width/8,MC_Black,MC_Light); } //------------ Effacer le contenu (caption) d'une zone de saisie ------------ void Window_clear_input_button(T_Special_button * button) { Window_rectangle(button->Pos_X+2,button->Pos_Y+2,(button->Width/8)*8,8,MC_Light); Update_window_area(button->Pos_X+2,button->Pos_Y+2,button->Width/8*8,8); } //------ Rajout d'un bouton la liste de ceux prsents dans la fentre ------ T_Normal_button * Window_set_normal_button(word x_pos, word y_pos, word width, word height, const char * title, byte undersc_letter, byte clickable, word shortcut) { T_Normal_button * temp=NULL; Window_nb_buttons++; if (clickable) { temp=(T_Normal_button *)malloc(sizeof(T_Normal_button)); temp->Number =Window_nb_buttons; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Width =width; temp->Height =height; temp->Clickable=clickable; temp->Shortcut =shortcut; temp->Repeatable=0; temp->Next=Window_normal_button_list; Window_normal_button_list=temp; } Window_draw_normal_bouton(x_pos,y_pos,width,height,title,undersc_letter,clickable); return temp; } //------ Rajout d'un bouton la liste de ceux prsents dans la fentre ------ T_Normal_button * Window_set_repeatable_button(word x_pos, word y_pos, word width, word height, const char * title, byte undersc_letter, byte clickable, word shortcut) { T_Normal_button * temp=NULL; Window_nb_buttons++; if (clickable) { temp=(T_Normal_button *)malloc(sizeof(T_Normal_button)); temp->Number =Window_nb_buttons; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Width =width; temp->Height =height; temp->Shortcut=shortcut; temp->Repeatable=1; temp->Next=Window_normal_button_list; Window_normal_button_list=temp; } Window_draw_normal_bouton(x_pos,y_pos,width,height,title,undersc_letter,clickable); return temp; } T_Palette_button * Window_set_palette_button(word x_pos, word y_pos) { T_Palette_button * temp; temp=(T_Palette_button *)malloc(sizeof(T_Palette_button)); temp->Number =++Window_nb_buttons; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Next=Window_palette_button_list; Window_palette_button_list=temp; Window_draw_palette_bouton(x_pos,y_pos); return temp; } T_Scroller_button * Window_set_scroller_button(word x_pos, word y_pos, word height, word nb_elements, word nb_elements_visible, word initial_position) { T_Scroller_button * temp; temp=(T_Scroller_button *)malloc(sizeof(T_Scroller_button)); temp->Number =++Window_nb_buttons; temp->Is_horizontal =0; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Length =height; temp->Nb_elements =nb_elements; temp->Nb_visibles =nb_elements_visible; temp->Position =initial_position; Compute_slider_cursor_length(temp); temp->Next=Window_scroller_button_list; Window_scroller_button_list=temp; Window_draw_scroller_button(temp); return temp; } T_Scroller_button * Window_set_horizontal_scroller_button(word x_pos, word y_pos, word width, word nb_elements, word nb_elements_visible, word initial_position) { T_Scroller_button * temp; temp=(T_Scroller_button *)malloc(sizeof(T_Scroller_button)); temp->Number =++Window_nb_buttons; temp->Is_horizontal =1; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Length =width; temp->Nb_elements =nb_elements; temp->Nb_visibles =nb_elements_visible; temp->Position =initial_position; Compute_slider_cursor_length(temp); temp->Next=Window_scroller_button_list; Window_scroller_button_list=temp; Window_draw_scroller_button(temp); return temp; } T_Special_button * Window_set_special_button(word x_pos,word y_pos,word width,word height) { T_Special_button * temp; temp=(T_Special_button *)malloc(sizeof(T_Special_button)); temp->Number =++Window_nb_buttons; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Width =width; temp->Height =height; temp->Next=Window_special_button_list; Window_special_button_list=temp; return temp; } T_Special_button * Window_set_input_button(word x_pos,word y_pos,word width_in_characters) { T_Special_button *temp; temp=Window_set_special_button(x_pos,y_pos,(width_in_characters<<3)+3,11); Window_draw_input_bouton(x_pos,y_pos,width_in_characters); return temp; } T_Dropdown_button * Window_set_dropdown_button(word x_pos,word y_pos,word width,word height,word dropdown_width,const char *label,byte display_choice,byte display_centered,byte display_arrow,byte active_button, byte bottom_up) { T_Dropdown_button *temp; temp=(T_Dropdown_button *)malloc(sizeof(T_Dropdown_button)); temp->Number =++Window_nb_buttons; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; temp->Width =width; temp->Height =height; temp->Display_choice =display_choice; temp->First_item=NULL; temp->Dropdown_width=dropdown_width?dropdown_width:width; temp->Display_centered=display_centered; temp->Display_arrow=display_arrow; temp->Active_button=active_button; temp->Bottom_up=bottom_up; temp->Next=Window_dropdown_button_list; Window_dropdown_button_list=temp; Window_draw_normal_bouton(x_pos,y_pos,width,height,"",0,1); if (label && label[0]) Print_in_window(temp->Pos_X+2,temp->Pos_Y+(temp->Height-7)/2,label,MC_Black,MC_Light); if (display_arrow) Window_display_icon_sprite(temp->Pos_X+temp->Width-10,temp->Pos_Y+(temp->Height-7)/2,ICON_DROPDOWN); return temp; } // Ajoute un choix une dropdown. Le libell est seulement rfrenc, // il doit pointer sur une zone qui doit tre encore valide la fermeture // de la fentre (comprise). void Window_dropdown_add_item(T_Dropdown_button * dropdown, word btn_number, const char *label) { T_Dropdown_choice *temp; T_Dropdown_choice *last; temp=(T_Dropdown_choice *)malloc(sizeof(T_Dropdown_choice)); temp->Number =btn_number; temp->Label=label; temp->Next=NULL; last=dropdown->First_item; if (last) { // On cherche le dernier lment for (;last->Next;last=last->Next) ; last->Next=temp; } else { dropdown->First_item=temp; } } // ------------- Suppression de tous les choix d'une dropdown --------- void Window_dropdown_clear_items(T_Dropdown_button * dropdown) { T_Dropdown_choice * next_choice; while (dropdown->First_item) { next_choice=dropdown->First_item->Next; free(dropdown->First_item); dropdown->First_item=next_choice; } } //----------------------- Create a List control ----------------------- // These controls are special. They work over two controls previously created: // - entry_button is the textual area where the list values will be printed. // - scroller is a scroller button attached to it T_List_button * Window_set_list_button(T_Special_button * entry_button, T_Scroller_button * scroller, Func_draw_list_item draw_list_item, byte color_index) { T_List_button *temp; temp=(T_List_button *)malloc(sizeof(T_List_button)); temp->Number =++Window_nb_buttons; temp->List_start = 0; temp->Cursor_position = 0; temp->Entry_button = entry_button; temp->Scroller = scroller; temp->Draw_list_item = draw_list_item; temp->Color_index = color_index; temp->Next=Window_list_button_list; Window_list_button_list=temp; return temp; } void Window_redraw_list(T_List_button * list) { int i; for (i=Min(list->Scroller->Nb_visibles-1, list->Scroller->Nb_elements-1); i>=0; i--) { list->Draw_list_item( list->Entry_button->Pos_X, list->Entry_button->Pos_Y + i * 8, list->List_start + i, i == list->Cursor_position); } // Remaining rectangle under list i=list->Scroller->Nb_visibles-list->Scroller->Nb_elements; if (i>0) { byte color; color = list->Color_index == 0 ? MC_Black : (list->Color_index == 1 ? MC_Dark : (list->Color_index == 2 ? MC_Light : MC_White)); Window_rectangle( list->Entry_button->Pos_X, list->Entry_button->Pos_Y+list->Scroller->Nb_elements*8, list->Entry_button->Width, i*8, color); } } //----------------------- Ouverture d'un pop-up ----------------------- void Open_popup(word x_pos, word y_pos, word width,word height) // Lors de l'appel cette procdure, la souris doit tre affiche. // En sortie de cette procedure, la souris est efface. // Note : les pop-ups sont grs comme s'ils taient des sous-fentres, ils ont donc leur propre boucle d'vnements et tout, on peut ajouter des widgets dedans, ... // Les diffrences sont surtout graphiques : // -Possibilit de prciser la position XY // -Pas de titre // -Pas de cadre en relief mais seulement un plat, et il est blanc au lieu de noir. { Windows_open++; Window_width=width; Window_height=height; Window_pos_X=x_pos; Window_pos_Y=y_pos; Window_draggable=0; // Sauvegarde de ce que la fentre remplace Save_background(&(Window_background[Windows_open-1]), Window_pos_X, Window_pos_Y, width, height); /* // Fentre grise Window_rectangle(1,1,width-2,height-2,MC_Light); // Frame noir puis en relief Window_display_frame_mono(0,0,width,height,MC_White); */ if (Windows_open == 1) { Menu_is_visible_before_window=Menu_is_visible; Menu_is_visible=0; Menu_Y_before_window=Menu_Y; Menu_Y=Screen_height; Cursor_shape_before_window=Cursor_shape; Cursor_shape=CURSOR_SHAPE_ARROW; Paintbrush_hidden_before_window=Paintbrush_hidden; Paintbrush_hidden=1; } // Initialisation des listes de boutons de la fentre Window_normal_button_list =NULL; Window_palette_button_list =NULL; Window_scroller_button_list=NULL; Window_special_button_list =NULL; Window_dropdown_button_list =NULL; Window_nb_buttons =0; } //----------------------- Fermer une fentre d'options ----------------------- void Close_popup(void) // Lors de l'appel cette procedure, la souris doit tre affiche. // En sortie de cette procedure, la souris est efface. { T_Normal_button * temp1; T_Palette_button * temp2; T_Scroller_button * temp3; T_Special_button * temp4; T_Dropdown_button * temp5; T_List_button * temp6; Hide_cursor(); while (Window_normal_button_list) { temp1=Window_normal_button_list->Next; free(Window_normal_button_list); Window_normal_button_list=temp1; } while (Window_palette_button_list) { temp2=Window_palette_button_list->Next; free(Window_palette_button_list); Window_palette_button_list=temp2; } while (Window_scroller_button_list) { temp3=Window_scroller_button_list->Next; free(Window_scroller_button_list); Window_scroller_button_list=temp3; } while (Window_special_button_list) { temp4=Window_special_button_list->Next; free(Window_special_button_list); Window_special_button_list=temp4; } while (Window_dropdown_button_list) { Window_dropdown_clear_items(Window_dropdown_button_list); temp5=Window_dropdown_button_list->Next; free(Window_dropdown_button_list); Window_dropdown_button_list=temp5; } while (Window_list_button_list) { temp6=Window_list_button_list->Next; free(Window_list_button_list); Window_list_button_list=temp6; } if (Windows_open != 1) { // Restore de ce que la fentre cachait Restore_background(Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height); Window_background[Windows_open-1]=NULL; Update_window_area(0,0,Window_width,Window_height); Windows_open--; } else { free(Window_background[Windows_open-1]); Window_background[Windows_open-1] = NULL; Windows_open--; Paintbrush_hidden=Paintbrush_hidden_before_window; Compute_paintbrush_coordinates(); Menu_Y=Menu_Y_before_window; Menu_is_visible=Menu_is_visible_before_window; Cursor_shape=Cursor_shape_before_window; Display_all_screen(); Display_menu(); } Key=0; Mouse_K=0; Old_MX = -1; Old_MY = -1; } ////////////////////////////////////////////////////////////////////////////// // // // Mini-MOTEUR utilis dans les fentres (menus des boutons...) // // // ////////////////////////////////////////////////////////////////////////////// // -- Indique si on a cliqu dans une zone dfinie par deux points extremes -- byte Window_click_in_rectangle(short start_x,short start_y,short end_x,short end_y) { short x_pos,y_pos; x_pos=((short)Mouse_X-Window_pos_X)/Menu_factor_X; y_pos=((short)Mouse_Y-Window_pos_Y)/Menu_factor_Y; return ((x_pos>=start_x) && (y_pos>=start_y) && (x_pos<=end_x) && (y_pos<=end_y)); } // --- Attend que l'on clique dans la palette pour renvoyer la couleur choisie // ou bien renvoie -1 si on a annul l'action pas click-droit ou Escape ------ short Wait_click_in_palette(T_Palette_button * button) { short start_x=button->Pos_X+5; short start_y=button->Pos_Y+3; short end_x =button->Pos_X+160; short end_y =button->Pos_Y+82; byte selected_color; byte old_hide_cursor; byte old_main_magnifier_mode; Hide_cursor(); old_hide_cursor=Cursor_hidden; old_main_magnifier_mode=Main_magnifier_mode; Main_magnifier_mode=0; Cursor_hidden=0; Cursor_shape=CURSOR_SHAPE_TARGET; Display_cursor(); for (;;) { while (Get_input(20)) ; if (Mouse_K==LEFT_SIDE) { if (Window_click_in_rectangle(start_x,start_y,end_x,end_y)) { Hide_cursor(); selected_color=(((Mouse_X-Window_pos_X)/Menu_factor_X)-(button->Pos_X+2)) / 10 * 16 + (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-(button->Pos_Y+3)) / 5; Cursor_shape=CURSOR_SHAPE_ARROW; Cursor_hidden=old_hide_cursor; Main_magnifier_mode=old_main_magnifier_mode; Display_cursor(); return selected_color; } if ((Mouse_X=Window_pos_X+(Window_width*Menu_factor_X)) || (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y)) ) { Hide_cursor(); selected_color=Read_pixel(Mouse_X,Mouse_Y); Cursor_shape=CURSOR_SHAPE_ARROW; Cursor_hidden=old_hide_cursor; Main_magnifier_mode=old_main_magnifier_mode; Display_cursor(); return selected_color; } } if ((Mouse_K==RIGHT_SIDE) || (Key==KEY_ESC)) { Hide_cursor(); Cursor_shape=CURSOR_SHAPE_ARROW; Cursor_hidden=old_hide_cursor; Main_magnifier_mode=old_main_magnifier_mode; Display_cursor(); return -1; } } } // -------------- Rcupration d'une couleur derrire un menu ---------------- void Get_color_behind_window(byte * color, byte * click) { short old_x=-1; short old_y=-1; short index; short a,b,c,d; // Variables temporaires et multitches... byte * buffer = NULL; char str[25]; byte cursor_was_hidden; Hide_cursor(); cursor_was_hidden=Cursor_hidden; Cursor_hidden=0; Save_background(&buffer,Window_pos_X,Window_pos_Y,Window_width,Window_height); a=Menu_Y; Menu_Y=Menu_Y_before_window; b=Menu_is_visible; Menu_is_visible=Menu_is_visible_before_window; Display_all_screen(); Display_menu(); Menu_Y=a; Menu_is_visible=b; Cursor_shape=CURSOR_SHAPE_COLORPICKER; b=Paintbrush_hidden; Paintbrush_hidden=1; c=-1; // color pointe: au dbut aucune, comme a on initialise tout if (Menu_is_visible_before_window) Print_in_menu(Buttons_Pool[BUTTON_CHOOSE_COL].Tooltip,0); Display_cursor(); do { Get_input(20); if ((Mouse_X!=old_x) || (Mouse_Y!=old_y)) { Hide_cursor(); a=Read_pixel(Mouse_X,Mouse_Y); if (a!=c) { c=a; // Mise jour de la couleur pointe if (Menu_is_visible_before_window) { sprintf(str,"%d",a); d=strlen(str); strcat(str," ("); sprintf(str+strlen(str),"%d",Main_palette[a].R); strcat(str,","); sprintf(str+strlen(str),"%d",Main_palette[a].G); strcat(str,","); sprintf(str+strlen(str),"%d",Main_palette[a].B); strcat(str,")"); a=24-d; for (index=strlen(str); indexScreen_width-width) { new_x=Screen_width-width; dx = Mouse_X - new_x; } new_y=Mouse_Y-dy; if (new_y<0) { new_y=0; dy = Mouse_Y; } if (new_y>Screen_height-height) { new_y=Screen_height-height; dy = Mouse_Y - new_y; } if ((new_x!=old_x) || (new_y!=old_y)) { Hide_cursor(); Horizontal_XOR_line(old_x,old_y,width); Vertical_XOR_line(old_x,old_y+1,height-2); Vertical_XOR_line(old_x+width-1,old_y+1,height-2); Horizontal_XOR_line(old_x,old_y+height-1,width); Horizontal_XOR_line(new_x,new_y,width); Vertical_XOR_line(new_x,new_y+1,height-2); Vertical_XOR_line(new_x+width-1,new_y+1,height-2); Horizontal_XOR_line(new_x,new_y+height-1,width); Display_cursor(); Update_rect(old_x,old_y,width,height); Update_rect(new_x,new_y,width,height); } } Hide_cursor(); Horizontal_XOR_line(new_x,new_y,width); Vertical_XOR_line(new_x,new_y+1,height-2); Vertical_XOR_line(new_x+width-1,new_y+1,height-2); Horizontal_XOR_line(new_x,new_y+height-1,width); if ((new_x!=Window_pos_X) || (new_y!=Window_pos_Y)) { a=Menu_Y; Menu_Y=Menu_Y_before_window; b=Menu_is_visible; Menu_is_visible=Menu_is_visible_before_window; //Display_all_screen(); //Display_menu(); Menu_Y=a; Menu_is_visible=b; // Sauvegarde du contenu actuel de la fentre Save_background(&buffer, Window_pos_X, Window_pos_Y, Window_width, Window_height); // Restore de ce que la fentre cachait Restore_background(Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height); Window_background[Windows_open-1] = NULL; // Sauvegarde de ce que la fentre remplace Save_background(&(Window_background[Windows_open-1]), new_x, new_y, Window_width, Window_height); // Raffichage de la fentre Restore_background(buffer, new_x, new_y, Window_width, Window_height); buffer = NULL; // Mise jour du rectangle englobant Update_rect( (new_x>Window_pos_X)?Window_pos_X:new_x, (new_y>Window_pos_Y)?Window_pos_Y:new_y, ((new_x>Window_pos_X)?(new_x-Window_pos_X):(Window_pos_X-new_x)) + Window_width*Menu_factor_X, ((new_y>Window_pos_Y)?(new_y-Window_pos_Y):(Window_pos_Y-new_y)) + Window_height*Menu_factor_Y); Window_pos_X=new_x; Window_pos_Y=new_y; } else { // Update pour effacer le rectangle XOR Update_window_area(0, 0, Window_width, Window_height); } Cursor_shape=CURSOR_SHAPE_ARROW; Display_cursor(); } /// /// Displays a dropped-down menu and handles the UI logic until the user /// releases a mouse button. /// This function then clears the dropdown and returns the selected item, /// or NULL if the user wasn't highlighting an item when he closed. T_Dropdown_choice * Dropdown_activate(T_Dropdown_button *button, short off_x, short off_y) { short nb_choices; short choice_index; short selected_index; short old_selected_index; short box_height; T_Dropdown_choice *item; // Taille de l'ombre porte (en plus des dimensions normales) #define SHADOW_RIGHT 3 #define SHADOW_BOTTOM 4 // Comptage des items pour calculer la taille nb_choices=0; for (item=button->First_item; item!=NULL; item=item->Next) { nb_choices++; } box_height=3+nb_choices*8+1; // Open a new stacked "window" to serve as drawing area. Open_popup( off_x+(button->Pos_X)*Menu_factor_X, off_y+(button->Pos_Y+(button->Bottom_up?-box_height:button->Height))*Menu_factor_Y, button->Dropdown_width+SHADOW_RIGHT, box_height+SHADOW_BOTTOM); // Dessin de la boite // Bord gauche Window_rectangle(0,0,1,box_height,MC_Black); // Frame fonce et blanc Window_display_frame_out(1,0,button->Dropdown_width-1,box_height); // Ombre porte if (SHADOW_BOTTOM) { Window_rectangle(SHADOW_RIGHT, box_height, button->Dropdown_width, SHADOW_BOTTOM, MC_Black); Window_rectangle(0, box_height, SHADOW_RIGHT, 1, MC_Black); } if (SHADOW_RIGHT) { Window_rectangle(button->Dropdown_width, SHADOW_BOTTOM, SHADOW_RIGHT, box_height-SHADOW_BOTTOM, MC_Black); Window_rectangle(button->Dropdown_width, 1, 1, SHADOW_BOTTOM, MC_Black); } selected_index=-1; while (1) { old_selected_index = selected_index; // Fentre grise Window_rectangle(2,1,button->Dropdown_width-3,box_height-2,MC_Light); // Affichage des items for(item=button->First_item,choice_index=0; item!=NULL; item=item->Next,choice_index++) { byte color_1; byte color_2; if (choice_index==selected_index) { color_1=MC_White; color_2=MC_Dark; Window_rectangle(3,2+choice_index*8, (button->Dropdown_width-5),8,MC_Dark); } else { color_1=MC_Black; color_2=MC_Light; } Print_in_window(3,2+choice_index*8,item->Label,color_1,color_2); } Update_window_area(0,0,Window_width,Window_height); Display_cursor(); do { // Attente Get_input(20); // Mise jour du survol selected_index=Window_click_in_rectangle(2,2,button->Dropdown_width-2,box_height-1)? (((Mouse_Y-Window_pos_Y)/Menu_factor_Y-2)>>3) : -1; } while (Mouse_K && selected_index==old_selected_index); if (!Mouse_K) break; Hide_cursor(); } Close_popup(); if (selected_index>=0 && selected_indexFirst_item; selected_index; item=item->Next,selected_index--) ; return item; } return NULL; } // Gestion des dropdown short Window_dropdown_on_click(T_Dropdown_button *button) { T_Dropdown_choice * item; // Highlight the button Hide_cursor(); Window_select_normal_button(button->Pos_X,button->Pos_Y,button->Width,button->Height); // Handle the dropdown's logic item = Dropdown_activate(button, Window_pos_X, Window_pos_Y); // Unhighlight the button Window_unselect_normal_button(button->Pos_X,button->Pos_Y,button->Width,button->Height); Display_cursor(); if (item == NULL) { Window_attribute2=-1; return 0; } if (button->Display_choice) { // Automatically update the label of the dropdown list. int text_length = (button->Width-4-(button->Display_arrow?8:0))/8; // Clear original label area Window_rectangle(button->Pos_X+2,button->Pos_Y+(button->Height-7)/2,text_length*8,8,MC_Light); Print_in_window_limited(button->Pos_X+2,button->Pos_Y+(button->Height-7)/2,item->Label,text_length ,MC_Black,MC_Light); } Window_attribute2=item->Number; return button->Number; } // --- Fonction de clic sur un bouton a peu prs ordinaire: // Attend que l'on relache le bouton, et renvoie le numero du bouton si on // est rest dessus, 0 si on a annul en sortant du bouton. short Window_normal_button_onclick(word x_pos, word y_pos, word width, word height, short btn_number) { while(1) { Hide_cursor(); Window_select_normal_button(x_pos,y_pos,width,height); Display_cursor(); while (Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1)) { Get_input(20); if (!Mouse_K) { Hide_cursor(); Window_unselect_normal_button(x_pos,y_pos,width,height); Display_cursor(); return btn_number; } } Hide_cursor(); Window_unselect_normal_button(x_pos,y_pos,width,height); Display_cursor(); while (!(Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1))) { Get_input(20); if (!Mouse_K) return 0; } } } // --- Returns the number of the clicked button (-1:out of the window, 0:none) --- short Window_get_clicked_button(void) { T_Normal_button * temp1; T_Palette_button * temp2; T_Scroller_button * temp3; T_Special_button * temp4; T_Dropdown_button * temp5; Window_attribute1=Mouse_K; // Test click on normal buttons for (temp1=Window_normal_button_list; temp1; temp1=temp1->Next) { if ((Input_sticky_control == 0 || Input_sticky_control == temp1->Number) && Window_click_in_rectangle(temp1->Pos_X,temp1->Pos_Y,temp1->Pos_X+temp1->Width-1,temp1->Pos_Y+temp1->Height-1)) { Input_sticky_control = temp1->Number; if (temp1->Repeatable) { Hide_cursor(); Window_select_normal_button(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height); Display_cursor(); Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); Hide_cursor(); Window_unselect_normal_button(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height); Display_cursor(); return temp1->Number; } return Window_normal_button_onclick(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height,temp1->Number); } } // Test click on "Palette" buttons for (temp2=Window_palette_button_list; temp2; temp2=temp2->Next) { if ((Input_sticky_control == 0 || Input_sticky_control == temp2->Number) && Window_click_in_rectangle(temp2->Pos_X+5,temp2->Pos_Y+3,temp2->Pos_X+160,temp2->Pos_Y+82)) { Input_sticky_control = temp2->Number; // We store the clicked color in Attribute2 Window_attribute2 = (((Mouse_X-Window_pos_X)/Menu_factor_X)-(temp2->Pos_X+2)) / 10 * 16 + (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-(temp2->Pos_Y+3)) / 5; return temp2->Number; } } // Test click on slider/scroller bars for (temp3=Window_scroller_button_list; temp3; temp3=temp3->Next) { // Button Up arrow if ((Input_sticky_control == 0 || Input_sticky_control == (temp3->Number|1024)) && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y,temp3->Pos_X+10,temp3->Pos_Y+10)) { Input_sticky_control = temp3->Number | 1024; Hide_cursor(); Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11); if (temp3->Position) { temp3->Position--; Window_attribute1=1; Window_attribute2=temp3->Position; Window_draw_slider(temp3); } else Window_attribute1=0; Display_cursor(); Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); Hide_cursor(); Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11); Display_cursor(); return (Window_attribute1)? temp3->Number : 0; } // Button Down arrow if ((Input_sticky_control == 0 || Input_sticky_control == (temp3->Number|2048)) && ((temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,temp3->Pos_X+temp3->Length-1,temp3->Pos_Y+10)) || (!temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,temp3->Pos_X+10,temp3->Pos_Y+temp3->Length-1)))) { Input_sticky_control = temp3->Number | 2048; Hide_cursor(); if (temp3->Is_horizontal) Window_select_normal_button(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,11,11); else Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,11,11); if (temp3->Position+temp3->Nb_visiblesNb_elements) { temp3->Position++; Window_attribute1=2; Window_attribute2=temp3->Position; Window_draw_slider(temp3); } else Window_attribute1=0; Display_cursor(); Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); Hide_cursor(); if (temp3->Is_horizontal) Window_unselect_normal_button(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,11,11); else Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,11,11); Display_cursor(); return (Window_attribute1)? temp3->Number : 0; } // Middle slider if ((Input_sticky_control == temp3->Number) || (Input_sticky_control==0 && ((!temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+12,temp3->Pos_X+10,temp3->Pos_Y+temp3->Length-13)) ||(temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X+12,temp3->Pos_Y,temp3->Pos_X+temp3->Length-13,temp3->Pos_Y+10))))) { Input_sticky_control = temp3->Number; if (temp3->Nb_elements>temp3->Nb_visibles) { // If there is enough room to make the cursor move: long mouse_pos; long origin; // Window_attribute2 receives the position of the cursor. if (temp3->Is_horizontal) mouse_pos =(Mouse_X-Window_pos_X) / Menu_factor_X - (temp3->Pos_X+12); else mouse_pos =(Mouse_Y-Window_pos_Y) / Menu_factor_Y - (temp3->Pos_Y+12); // The following formula is wicked. The issue is that you want two // different behaviors: // *) If the range is bigger than the pixel precision, the last pixel // should map to max value, exactly. // *) Otherwise, the possible cursor positions are separated by // at least one full pixel, so we should find the valid position // closest to the center of the mouse cursor position pixel. origin = (temp3->Nb_visibles-1)*(temp3->Length-24)/temp3->Nb_elements/2; Window_attribute2 = (mouse_pos - origin) * (temp3->Nb_elements-(temp3->Cursor_length>1?0:1)) / (temp3->Length-24-1); if (Window_attribute2<0) Window_attribute2=0; else if (Window_attribute2+temp3->Nb_visibles>temp3->Nb_elements) Window_attribute2=temp3->Nb_elements-temp3->Nb_visibles; // If the cursor moved if (temp3->Position!=Window_attribute2) { temp3->Position=Window_attribute2; Window_attribute1=3; Hide_cursor(); Window_draw_slider(temp3); Display_cursor(); } else // If the cursor moved Window_attribute1=0; } else // If there's not enough room to make the cursor move: Window_attribute1=0; return (Window_attribute1)? temp3->Number : 0; } } // Test click on a special button for (temp4=Window_special_button_list; temp4; temp4=temp4->Next) { if ((Input_sticky_control == 0 || Input_sticky_control == temp4->Number) && Window_click_in_rectangle(temp4->Pos_X,temp4->Pos_Y,temp4->Pos_X+temp4->Width-1,temp4->Pos_Y+temp4->Height-1)) { Input_sticky_control = temp4->Number; return temp4->Number; } } // Test click on a dropdown box for (temp5=Window_dropdown_button_list; temp5; temp5=temp5->Next) { if ((Input_sticky_control == 0 || Input_sticky_control == temp5->Number) && Window_click_in_rectangle(temp5->Pos_X,temp5->Pos_Y,temp5->Pos_X+temp5->Width-1,temp5->Pos_Y+temp5->Height-1)) { Input_sticky_control = temp5->Number; if (Mouse_K & temp5->Active_button) return Window_dropdown_on_click(temp5); else { Window_attribute2=-1; return Window_normal_button_onclick(temp5->Pos_X,temp5->Pos_Y,temp5->Width,temp5->Height,temp5->Number); } } } return 0; } short Window_get_button_shortcut(void) { T_Normal_button * temp; if (Key & MOD_SHIFT) Window_attribute1=RIGHT_SIDE; else Window_attribute1=LEFT_SIDE; // On fait une premire recherche temp=Window_normal_button_list; while (temp!=NULL) { if (temp->Shortcut==Key) { Hide_cursor(); Window_select_normal_button(temp->Pos_X,temp->Pos_Y,temp->Width,temp->Height); Display_cursor(); Delay_with_active_mouse(Config.Delay_right_click_on_slider); Hide_cursor(); Window_unselect_normal_button(temp->Pos_X,temp->Pos_Y,temp->Width,temp->Height); Display_cursor(); return temp->Number; } temp=temp->Next; } // Si la recherche n'a pas t fructueuse ET que l'utilisateur appuyait sur // , on regarde si un bouton ne pourrait pas ragir comme si // n'tait pas appuy. if (Window_attribute1==RIGHT_SIDE) { temp=Window_normal_button_list; while (temp!=NULL) { if (temp->Shortcut==(Key&0x0FFF)) return temp->Number; temp=temp->Next; } } // Handle arrow keys, end/home, and mouse wheel that have // a certain behavior if a list control is present. if (Window_list_button_list) { T_List_button *list = Window_list_button_list; // If there's more than one of such control, only capture // events if the mouse cursor is over it. if (list->Next) { // to do } } return 0; } short Window_clicked_button(void) { short Button; byte old_mouse_k; old_mouse_k=Mouse_K; Get_input(20); // Handle clicks if (Mouse_K) { if ((Mouse_X=Window_pos_X+(Window_width*Menu_factor_X)) || (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y))) { if (Input_sticky_control == 0 || Input_sticky_control == -1) { Input_sticky_control = -1; return -1; } else { return 0; } } if (!Input_sticky_control && Window_draggable && Mouse_Y < Window_pos_Y+(12*Menu_factor_Y)) { Move_window(Mouse_X-Window_pos_X,Mouse_Y-Window_pos_Y); } else { short clicked_button; T_List_button * list; static Uint32 time_last_click = 0; static int last_list_number = -1; Uint32 time_now; // Check which controls was clicked (by rectangular area) clicked_button = Window_get_clicked_button(); // Check if it's part of a list control for (list=Window_list_button_list; list!=NULL; list=list->Next) { if (list->Entry_button->Number == clicked_button) { // Click in the textual part of a list. short clicked_line; clicked_line = (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-list->Entry_button->Pos_Y)>>3; if (clicked_line >= list->Scroller->Nb_elements) // Below last line return 0; time_now = SDL_GetTicks(); if (clicked_line == list->Cursor_position) { // Double click check if (old_mouse_k==0 && last_list_number==list->Number && time_now - time_last_click < Config.Double_click_speed) { time_last_click = time_now; Input_sticky_control=0; // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the "special button" that covers the list. return list->Entry_button->Number; } time_last_click = time_now; last_list_number=list->Number; // Already selected : don't activate anything return 0; } Hide_cursor(); // Redraw one item as disabled if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) list->Draw_list_item( list->Entry_button->Pos_X, list->Entry_button->Pos_Y + list->Cursor_position * 8, list->List_start + list->Cursor_position, 0); list->Cursor_position = clicked_line; // Redraw one item as enabled if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) list->Draw_list_item( list->Entry_button->Pos_X, list->Entry_button->Pos_Y + list->Cursor_position * 8, list->List_start + list->Cursor_position, 1); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } else if (list->Scroller->Number == clicked_button) { // Click in the scroller part of a list if (list->List_start == list->Scroller->Position) return 0; // Didn't actually move // Update scroller indices list->Cursor_position += list->List_start; list->List_start = list->Scroller->Position; list->Cursor_position -= list->List_start; // Need to redraw all Hide_cursor(); Window_redraw_list(list); Display_cursor(); } } return clicked_button; } } // Intercept keys if (Key) { T_List_button * list; Button=Window_get_button_shortcut(); if (Button) { Key=0; return Button; } // Check if there's a list control and the keys can control it for (list=Window_list_button_list; list!=NULL; list=list->Next) { // FIXME: Make only one list have the keyboard focus. if (1) { if (Key==SDLK_UP && (list->Cursor_position+list->List_start)>0) { Key=0; Hide_cursor(); list->Cursor_position--; if (list->Cursor_position<0) { list->List_start=list->List_start+list->Cursor_position; list->Cursor_position=0; // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } if (Key==SDLK_DOWN && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1)) { Key=0; Hide_cursor(); list->Cursor_position++; if (list->Cursor_position>(list->Scroller->Nb_visibles-1)) { list->List_start=list->List_start+list->Cursor_position-(list->Scroller->Nb_visibles-1); list->Cursor_position=(list->Scroller->Nb_visibles-1); // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } if (Key==SDLK_HOME && (list->Cursor_position!=0 || list->List_start!=0)) { Key=0; Hide_cursor(); list->Cursor_position=0; list->List_start=0; // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } if (Key==SDLK_END && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1)) { Key=0; Hide_cursor(); list->Cursor_position=(list->Scroller->Nb_elements-1)-list->List_start; if (list->Cursor_position>(list->Scroller->Nb_visibles-1)) { list->List_start=list->List_start+list->Cursor_position-(list->Scroller->Nb_visibles-1); list->Cursor_position=(list->Scroller->Nb_visibles-1); // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } if (Key==SDLK_PAGEDOWN && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1)) { Key=0; Hide_cursor(); if (list->Scroller->Nb_elementsScroller->Nb_visibles) { list->Cursor_position=list->Scroller->Nb_elements-1; } else if(list->Cursor_position!=list->Scroller->Nb_visibles-1) { list->Cursor_position=list->Scroller->Nb_visibles-1; } else { list->List_start+=list->Scroller->Nb_visibles; if (list->List_start+list->Scroller->Nb_visibles>list->Scroller->Nb_elements) { list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; } // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } if (Key==SDLK_PAGEUP && (list->Cursor_position+list->List_start)>0) { Key=0; Hide_cursor(); if(list->Cursor_position!=0) { list->Cursor_position=0; } else { list->List_start-=list->Scroller->Nb_visibles; if (list->List_start<0) { list->List_start=0; } // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } if (Key == KEY_MOUSEWHEELUP && list->List_start>0) { list->Cursor_position+=list->List_start; if (list->List_start>=3) list->List_start-=3; else list->List_start=0; list->Cursor_position-=list->List_start; // On affiche nouveau la liste Hide_cursor(); Window_redraw_list(list); // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); Display_cursor(); } if (Key==KEY_MOUSEWHEELDOWN && list->List_startScroller->Nb_elements-list->Scroller->Nb_visibles) { list->Cursor_position+=list->List_start; list->List_start+=3; if (list->List_start+list->Scroller->Nb_visibles>list->Scroller->Nb_elements) { list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; } list->Cursor_position-=list->List_start; // On affiche nouveau la liste Hide_cursor(); Window_redraw_list(list); // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); Display_cursor(); } } } } return 0; } // Fonction qui sert remapper les parties sauvegardes derriere les // fenetres ouvertes. C'est utilis par exemple par la fenetre de palette // Qui remappe des couleurs, afin de propager les changements. void Remap_window_backgrounds(byte * conversion_table, int Min_Y, int Max_Y) { int window_index; byte* EDI; int dx,cx; for (window_index=0; window_indexMax_Y) return; if (dx+Window_stack[window_index].Pos_Y0;cx--) { *EDI = conversion_table[*EDI]; EDI ++; } } } } void Delay_with_active_mouse(int speed) { Uint32 end; byte original_mouse_k = Mouse_K; end = SDL_GetTicks()+speed*10; do { Get_input(20); } while (Mouse_K == original_mouse_k && SDL_GetTicks()=0; i--) { Menu_bars[i].Top = offset; if(Menu_bars[i].Visible) { offset += Menu_bars[i].Height; Menu_height += Menu_bars[i].Height; } } // Update global menu coordinates Menu_Y = Screen_height - Menu_height * Menu_factor_Y; } /// /// Shows or hides a tolbar from the menu. /// If with_redraw is set to zero, the caller should /// redraw itself using Display_menu() and Display_all_screen(). void Set_bar_visibility(word bar, int visible, int with_redraw) { if (!visible && Menu_bars[bar].Visible) { // Hide it Menu_bars[bar].Visible=0; Compute_menu_offsets(); if (Main_magnifier_mode) { Compute_magnifier_data(); } // On repositionne le dcalage de l'image pour qu'il n'y ait pas d'in- // -cohrences lorsqu'on sortira du mode Loupe. if (Main_offset_Y+Screen_height>Main_image_height) { if (Screen_height>Main_image_height) Main_offset_Y=0; else Main_offset_Y=Main_image_height-Screen_height; } // On fait pareil pour le brouillon if (Spare_offset_Y+Screen_height>Spare_image_height) { if (Screen_height>Spare_image_height) Spare_offset_Y=0; else Spare_offset_Y=Spare_image_height-Screen_height; } Compute_magnifier_data(); if (Main_magnifier_mode) Position_screen_according_to_zoom(); Compute_limits(); Compute_paintbrush_coordinates(); if (with_redraw) { Display_menu(); Display_all_screen(); } } else if (visible && !Menu_bars[bar].Visible) { // Show it Menu_bars[bar].Visible = 1; Compute_menu_offsets(); Compute_magnifier_data(); if (Main_magnifier_mode) Position_screen_according_to_zoom(); Compute_limits(); Compute_paintbrush_coordinates(); if (with_redraw) { Display_menu(); if (Main_magnifier_mode) Display_all_screen(); } } } /// /// Checks if the current menu toolbars suit the current image type : /// layered vs anim. If they don't fit, swap the toolbars and return 1: /// The caller is then responsible for refreshing the screen by calling /// Display_menu() and Display_all_screen() int Check_menu_mode(void) { if (Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION) { if (Menu_bars[MENUBAR_LAYERS].Visible) { Set_bar_visibility(MENUBAR_LAYERS, 0, 0); Set_bar_visibility(MENUBAR_ANIMATION, 1, 0); return 1; } } else { if (Menu_bars[MENUBAR_ANIMATION].Visible) { Set_bar_visibility(MENUBAR_ANIMATION, 0, 0); Set_bar_visibility(MENUBAR_LAYERS, 1, 0); return 1; } } return 0; } grafx2_2.4+git20180105/src/Makefile.dep0000664000000000000000000001536413223665306015747 0ustar rootroot$(OBJDIR)/SFont.o: SFont.c SFont.h $(OBJDIR)/brush.o: brush.c global.h struct.h const.h graph.h misc.h errors.h \ windows.h sdlscreen.h brush.h tiles.h $(OBJDIR)/brush_ops.o: brush_ops.c brush.h struct.h const.h buttons.h engine.h \ global.h graph.h misc.h operatio.h pages.h sdlscreen.h windows.h $(OBJDIR)/buttons.o: buttons.c const.h struct.h global.h misc.h graph.h engine.h \ readline.h filesel.h loadsave.h init.h buttons.h operatio.h pages.h \ palette.h errors.h readini.h saveini.h shade.h io.h help.h text.h \ sdlscreen.h windows.h brush.h input.h special.h tiles.h setup.h $(OBJDIR)/buttons_effects.o: buttons_effects.c brush.h struct.h const.h buttons.h \ engine.h global.h graph.h help.h input.h misc.h pages.h readline.h \ sdlscreen.h windows.h tiles.h $(OBJDIR)/colorred.o: colorred.c colorred.h struct.h const.h $(OBJDIR)/engine.o: engine.c const.h struct.h global.h graph.h misc.h special.h \ buttons.h operatio.h shade.h errors.h sdlscreen.h windows.h brush.h \ input.h engine.h pages.h layers.h factory.h loadsave.h io.h pxsimple.h \ oldies.h $(OBJDIR)/factory.o: factory.c brush.h struct.h const.h buttons.h engine.h errors.h \ filesel.h loadsave.h global.h graph.h io.h misc.h pages.h readline.h \ sdlscreen.h windows.h palette.h input.h help.h realpath.h setup.h \ tiles.h $(OBJDIR)/factory_m.o: factory_m.c brush.h struct.h const.h buttons.h engine.h \ errors.h filesel.h loadsave.h global.h graph.h io.h misc.h pages.h \ readline.h sdlscreen.h windows.h palette.h input.h help.h realpath.h \ setup.h tiles.h $(OBJDIR)/fileformats.o: fileformats.c errors.h global.h struct.h const.h \ loadsave.h misc.h io.h pages.h windows.h $(OBJDIR)/filesel.o: filesel.c const.h struct.h global.h misc.h errors.h io.h \ windows.h sdlscreen.h loadsave.h mountlist.h engine.h readline.h input.h \ help.h filesel.h $(OBJDIR)/graph.o: graph.c global.h struct.h const.h engine.h buttons.h pages.h \ errors.h sdlscreen.h graph.h misc.h pxsimple.h pxtall.h pxwide.h \ pxdouble.h pxtriple.h pxwide2.h pxtall2.h pxtall3.h pxquad.h windows.h \ input.h brush.h tiles.h $(OBJDIR)/help.o: help.c const.h struct.h global.h misc.h engine.h helpfile.h \ help.h sdlscreen.h text.h keyboard.h windows.h input.h hotkeys.h \ errors.h pages.h factory.h $(OBJDIR)/hotkeys.o: hotkeys.c struct.h const.h global.h hotkeys.h $(OBJDIR)/init.o: init.c buttons.h struct.h const.h errors.h global.h graph.h \ init.h io.h factory.h help.h hotkeys.h keyboard.h loadsave.h misc.h \ mountlist.h operatio.h palette.h sdlscreen.h setup.h transform.h \ windows.h layers.h special.h $(OBJDIR)/input.o: input.c global.h struct.h const.h keyboard.h sdlscreen.h \ windows.h errors.h misc.h buttons.h input.h loadsave.h $(OBJDIR)/io.o: io.c struct.h const.h io.h realpath.h $(OBJDIR)/keyboard.o: keyboard.c global.h struct.h const.h keyboard.h $(OBJDIR)/layers.o: layers.c const.h struct.h global.h windows.h engine.h pages.h \ sdlscreen.h input.h help.h misc.h readline.h graph.h $(OBJDIR)/libraw2crtc.o: libraw2crtc.c const.h global.h struct.h loadsave.h $(OBJDIR)/loadsave.o: loadsave.c buttons.h struct.h const.h errors.h global.h io.h \ loadsave.h misc.h graph.h op_c.h colorred.h pages.h palette.h \ sdlscreen.h windows.h engine.h brush.h setup.h filesel.h $(OBJDIR)/main.o: main.c const.h struct.h global.h graph.h misc.h init.h buttons.h \ engine.h pages.h loadsave.h sdlscreen.h errors.h readini.h saveini.h \ io.h text.h setup.h windows.h brush.h palette.h realpath.h input.h \ help.h filesel.h $(OBJDIR)/misc.o: misc.c struct.h const.h sdlscreen.h global.h errors.h buttons.h \ engine.h misc.h keyboard.h windows.h palette.h input.h graph.h pages.h $(OBJDIR)/miscfileformats.o: miscfileformats.c engine.h struct.h const.h errors.h \ global.h io.h libraw2crtc.h loadsave.h misc.h sdlscreen.h windows.h \ oldies.h $(OBJDIR)/mountlist.o: mountlist.c $(OBJDIR)/oldies.o: oldies.c struct.h const.h global.h errors.h misc.h palette.h \ pages.h windows.h layers.h $(OBJDIR)/op_c.o: op_c.c op_c.h struct.h const.h colorred.h errors.h global.h \ engine.h windows.h $(OBJDIR)/operatio.o: operatio.c const.h struct.h global.h misc.h engine.h graph.h \ operatio.h buttons.h pages.h errors.h sdlscreen.h brush.h windows.h \ input.h special.h tiles.h $(OBJDIR)/pages.o: pages.c global.h struct.h const.h pages.h errors.h loadsave.h \ misc.h windows.h tiles.h graph.h $(OBJDIR)/palette.o: palette.c const.h struct.h global.h misc.h engine.h readline.h \ buttons.h pages.h help.h sdlscreen.h errors.h op_c.h colorred.h \ windows.h input.h palette.h shade.h $(OBJDIR)/pversion.o: pversion.c $(OBJDIR)/pxdouble.o: pxdouble.c global.h struct.h const.h sdlscreen.h misc.h \ graph.h pxdouble.h pxwide.h $(OBJDIR)/pxquad.o: pxquad.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxquad.h $(OBJDIR)/pxsimple.o: pxsimple.c global.h struct.h const.h sdlscreen.h misc.h \ graph.h pxsimple.h $(OBJDIR)/pxtall.o: pxtall.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxtall.h pxsimple.h $(OBJDIR)/pxtall2.o: pxtall2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxtall2.h $(OBJDIR)/pxtall3.o: pxtall3.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxtall3.h $(OBJDIR)/pxtriple.o: pxtriple.c global.h struct.h const.h sdlscreen.h misc.h \ graph.h pxtriple.h $(OBJDIR)/pxwide.o: pxwide.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxwide.h $(OBJDIR)/pxwide2.o: pxwide2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxwide2.h $(OBJDIR)/readini.o: readini.c const.h errors.h global.h struct.h misc.h readini.h \ setup.h realpath.h io.h windows.h $(OBJDIR)/readline.o: readline.c const.h struct.h global.h misc.h errors.h \ sdlscreen.h readline.h windows.h input.h engine.h $(OBJDIR)/realpath.o: realpath.c $(OBJDIR)/saveini.o: saveini.c const.h global.h struct.h readini.h io.h errors.h \ misc.h saveini.h setup.h windows.h $(OBJDIR)/sdlscreen.o: sdlscreen.c global.h struct.h const.h sdlscreen.h errors.h \ misc.h $(OBJDIR)/setup.o: setup.c struct.h const.h io.h setup.h $(OBJDIR)/shade.o: shade.c global.h struct.h const.h graph.h engine.h errors.h \ misc.h readline.h help.h sdlscreen.h windows.h input.h shade.h $(OBJDIR)/special.o: special.c const.h struct.h global.h graph.h engine.h windows.h \ special.h pages.h misc.h buttons.h $(OBJDIR)/text.o: text.c SFont.h struct.h const.h global.h sdlscreen.h io.h \ errors.h windows.h misc.h setup.h $(OBJDIR)/tiles.o: tiles.c struct.h const.h global.h graph.h sdlscreen.h engine.h \ windows.h input.h misc.h tiles.h $(OBJDIR)/transform.o: transform.c global.h struct.h const.h transform.h engine.h \ sdlscreen.h windows.h input.h help.h misc.h readline.h buttons.h pages.h \ tiles.h $(OBJDIR)/version.o: version.c $(OBJDIR)/windows.o: windows.c windows.h struct.h const.h engine.h errors.h \ global.h graph.h input.h misc.h op_c.h colorred.h readline.h sdlscreen.h \ palette.h grafx2_2.4+git20180105/src/layers.h0000664000000000000000000000305313223665306015200 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2009 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ void Button_Layer_add(void); void Button_Layer_duplicate(void); void Button_Layer_remove(void); void Button_Layer_menu(void); void Button_Layer_set_transparent(void); void Button_Layer_get_transparent(void); void Button_Layer_merge(void); void Button_Layer_up(void); void Button_Layer_down(void); void Button_Layer_select(void); void Button_Layer_toggle(void); void Layer_activate(int layer, short side); void Button_Anim_time(void); void Button_Anim_first_frame(void); void Button_Anim_prev_frame(void); void Button_Anim_next_frame(void); void Button_Anim_last_frame(void); void Button_Anim_play(void); void Button_Anim_continuous_prev(void); void Button_Anim_continuous_next(void); short Layer_under_mouse(void); grafx2_2.4+git20180105/src/colorred.h0000664000000000000000000000425013223665306015512 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Adrien Destugues Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see ******************************************************************************** 24bit RGB to 8bit indexed functions */ #include "struct.h" /* Octree for mapping RGB to color. A bit slower than a plain conversion table in theory, but : * Faster than running a search in the palette * Takes less memory than the huge conversion table * No loss of precision */ #ifndef __COLORRED_H #define __COLORRED_H typedef struct CT_Node_s { // min byte Rmin; byte Gmin; byte Bmin; // max byte Rmax; byte Gmax; byte Bmax; // possible optimization: a cluster has either two childs or a color index. // if the first child is NULL, then the other can be used to store the index // when the tree is being built, a node may have child0 set and not child1, but not the reverse) // possible optimization: there can't be more than 511 clusters in the tree // for a 256 color picture, so use int16 as pointers and store everything in a table : // * makes them smaller // * helps with cache locality // Child nodes : // Either two indices in the colorTree array, or // 0 and a palette index // 0 is not a valid array index, because no node points to the root ! word children[2]; } CT_Node; typedef struct ColorTree_S { short nodecount; CT_Node nodes[511]; } CT_Tree; CT_Tree* CT_new(); void CT_delete(CT_Tree* t); byte CT_get(CT_Tree* t,byte r,byte g,byte b); void CT_set(CT_Tree* colorTree, byte Rmin, byte Gmin, byte Bmin, byte Rmax, byte Gmax, byte Bmax, byte index); #endif grafx2_2.4+git20180105/src/tiles.h0000664000000000000000000000420513223665307015022 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Yves Rizoud Copyright 2011 Adrien Destugues Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file tiles.h /// Functions for tilemap effect ////////////////////////////////////////////////////////////////////////////// /// Create or update a tilemap based on current screen pixels. void Tilemap_update(void); /// /// Draw a pixel while Tilemap mode is active : This will paint on all /// similar tiles of the layer, visible on the screen or not. void Tilemap_draw(word x, word y, byte color); /// /// This exchanges the tilemap settings of the main and spare, it should /// be called when swapping pages. void Swap_tilemap(void); /// /// Clears all tilemap data and settings for the main page. /// Safe to call again. void Disable_main_tilemap(void); /// /// Clears all tilemap data and settings for the spare. /// Safe to call again. void Disable_spare_tilemap(void); /// Tilemap for the main screen extern T_Tile * Main_tilemap; /// Number of tiles (horizontally) for the main page's tilemap extern short Main_tilemap_width; /// Number of tiles (vertically) for the main page's tilemap extern short Main_tilemap_height; /// Tilemap for the spare extern T_Tile * Spare_tilemap; /// Number of tiles (horizontally) for the spare page's tilemap extern short Spare_tilemap_width; /// Number of tiles (vertically) for the spare page's tilemap extern short Spare_tilemap_height; grafx2_2.4+git20180105/src/pxquad.c0000664000000000000000000004530613223665306015205 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxquad.h" #define ZOOMX 4 #define ZOOMY 4 void Pixel_quad (word x,word y,byte color) /* Affiche un pixel de la color aux coords x;y l'cran */ { *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 3)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 3)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 2)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 3)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 2)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 3)=color; } byte Read_pixel_quad (word x,word y) /* On retourne la couleur du pixel aux coords donnes */ { return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); } void Block_quad (word start_x,word start_y,word width,word height,byte color) /* On affiche un rectangle de la couleur donne */ { SDL_Rect rectangle; rectangle.x=start_x*ZOOMX; rectangle.y=start_y*ZOOMY; rectangle.w=width*ZOOMX; rectangle.h=height*ZOOMY; SDL_FillRect(Screen_SDL,&rectangle,color); } void Display_part_of_screen_quad (word width,word height,word image_width) /* Afficher une partie de l'image telle quelle sur l'cran */ { byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'cran (dest) byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de dpart ds la source (src) int y; int dy; for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne for (dy=width;dy>0;dy--) { *(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; src++; dest+=ZOOMX; } // On double la ligne qu'on vient de copier memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On la triple memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On la quadruple memcpy(dest-width*ZOOMX+3*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } //Update_rect(0,0,width,height); } void Pixel_preview_normal_quad (word x,word y,byte color) /* Affichage d'un pixel dans l'cran, par rapport au dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure Pixel_Preview_Loupe_SDL. */ { // if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) Pixel_quad(x-Main_offset_X,y-Main_offset_Y,color); } void Pixel_preview_magnifier_quad (word x,word y,byte color) { // Affiche le pixel dans la partie non zoome Pixel_quad(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) { // On est dedans int height; int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_quad( Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, y_zoom, Main_magnifier_factor, height, color ); } } void Horizontal_XOR_line_quad(word x_pos,word y_pos,word width) { //On calcule la valeur initiale de dest: byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; int x; for (x=0;x0;i--) { *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=xor_lut[*(dest)]; dest+=VIDEO_LINE_WIDTH*ZOOMY; } } void Display_brush_color_quad(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = Brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+3*VIDEO_LINE_WIDTH+3) = *(dest+3*VIDEO_LINE_WIDTH+2) = *(dest+3*VIDEO_LINE_WIDTH+1) = *(dest+3*VIDEO_LINE_WIDTH) = *(dest+2*VIDEO_LINE_WIDTH+3) = *(dest+2*VIDEO_LINE_WIDTH+2) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+3) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+3) = *(dest+2) = *(dest+1) = *dest = *src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } Update_rect(x_pos,y_pos,width,height); } void Display_brush_mono_quad(word x_pos, word y_pos, word x_offset, word y_offset, word width, word height, byte transp_color, byte color, word brush_width) /* On affiche la brosse en monochrome */ { byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination // l'cran byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds // la brosse int x,y; for(y=height;y!=0;y--) //Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { if (*src!=transp_color) *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=color; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=brush_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Clear_brush_quad(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width) { byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'cran (dest) byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de dpart ds la source (src) int y; int x; (void)x_offset; // unused (void)y_offset; // unused (void)transp_color; // unused for(y=height;y!=0;y--) // Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } // Affiche une brosse (arbitraire) l'cran void Display_brush_quad(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } } void Remap_screen_quad(word x_pos,word y_pos,word width,word height,byte * conversion_table) { // dest = coords a l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; int x,y; // Pour chaque ligne for(y=height;y>0;y--) { // Pour chaque pixel for(x=width;x>0;x--) { *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest= conversion_table[*dest]; dest +=ZOOMX; } dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Display_line_on_screen_fast_quad(word x_pos,word y_pos,word width,byte * line) /* On affiche toute une ligne de pixels telle quelle. */ /* Utilise si le buffer contient dja des pixel doubls. */ { memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+3)*VIDEO_LINE_WIDTH,line,width*ZOOMX); } void Display_line_on_screen_quad(word x_pos,word y_pos,word width,byte * line) /* On affiche une ligne de pixels en les doublant. */ { int x; byte *dest; dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; for(x=width;x>0;x--) { *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*line; dest+=ZOOMX; line++; } } void Display_transparent_mono_line_on_screen_quad( word x_pos, word y_pos, word width, byte* line, byte transp_color, byte color) // Affiche une ligne l'cran avec une couleur + transparence. // Utilis par les brosses en mode zoom { byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; int x; // Pour chaque pixel for(x=0;x 0); src += image_width; } // ATTENTION on n'arrive jamais ici ! } // Affiche une partie de la brosse couleur zoome void Display_brush_color_zoom_quad(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle de la brosse byte * buffer) { byte* src = Brush+y_offset*brush_width + x_offset; word y = y_pos; byte bx; // Pour chaque ligne while(1) { Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche facteur fois la ligne zoome for(bx=Main_magnifier_factor;bx>0;bx--) { byte* line_src = buffer; byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; word x; // Pour chaque pixel de la ligne for(x = width*Main_magnifier_factor;x > 0;x--) { if(*line_src!=transp_color) { *(dest+3)=*(dest+2)=*(dest+1)=*dest = *line_src; } line_src++; dest+=ZOOMX; } // Double the line memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); // Triple the line memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); // Quadruple it memcpy(Screen_pixels + (y*ZOOMY+3)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); y++; if(y==end_y_pos) { return; } } src += brush_width; } // ATTENTION zone jamais atteinte } void Display_brush_mono_zoom_quad(word x_pos, word y_pos, word x_offset, word y_offset, word width, // width non zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle de la brosse byte * buffer ) { byte* src = Brush + y_offset * brush_width + x_offset; int y=y_pos*ZOOMY; //Pour chaque ligne zoomer : while(1) { int bx; // src = Ligne originale // On clate la ligne Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche la ligne Facteur fois l'cran (sur des // lignes conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome Display_transparent_mono_line_on_screen_quad( x_pos, y, width * Main_magnifier_factor, buffer, transp_color, color ); // On passe la ligne suivante y++; // On vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); Update_rect( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); return; } bx --; } while (bx > 0); // Passage la ligne suivante dans la brosse aussi src+=brush_width; } } void Clear_brush_scaled_quad(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer) { // En fait on va recopier l'image non zoome dans la partie zoome ! byte* src = Main_screen + y_offset * image_width + x_offset; int y = y_pos; int bx; (void)transp_color; // unused // Pour chaque ligne zoomer while(1){ Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); bx=Main_magnifier_factor; // Pour chaque ligne do{ // TODO a verifier Display_line_on_screen_fast_quad(x_pos,y, width * Main_magnifier_factor,buffer); // Ligne suivante y++; if(y==end_y_pos) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); Update_rect(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); return; } bx--; }while(bx!=0); src+= image_width; } } grafx2_2.4+git20180105/src/libraw2crtc.h0000664000000000000000000000061113223665306016114 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* GFX2CRTC - libraw2crtc.h * CloudStrife - 20080921 * Diffus sous licence libre CeCILL v2 * Voire LICENCE */ #ifndef LIBRAW2CRTC_H #define LIBRAW2CRTC_H 1 #include "loadsave.h" unsigned char * raw2crtc(T_IO_Context* context, unsigned char mode, unsigned char r9, unsigned long *outSize, unsigned char *r1, unsigned char r12, unsigned char r13); #endif grafx2_2.4+git20180105/src/Grafx2_Prefix.pch0000664000000000000000000000024113223665306016666 0ustar rootroot// // Prefix header for all source files of the 'Grafx2' target in the 'Grafx2' project // #include "SDL.h" #ifdef __OBJC__ #import #endif grafx2_2.4+git20180105/src/English.lproj/0000775000000000000000000000000013223665306016245 5ustar rootrootgrafx2_2.4+git20180105/src/English.lproj/InfoPlist.strings0000664000000000000000000000121613223665306021567 0ustar rootroot/* Localized versions of Info.plist keys */ CFBundleName = "Grafx2"; CFBundleShortVersionString = "Grafx2 version 2.2.2"; CFBundleGetInfoString = "Grafx2 version 2.0, Copyright 2008-2011 the Grafx2 project team."; NSHumanReadableCopyright = "Copyright 2008-2011 the Grafx2 project team.\nMacOS X version by Franck Charlet."; grafx2_2.4+git20180105/src/pxwide2.c0000664000000000000000000003714413223665306015266 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxwide2.h" #define ZOOMX 4 #define ZOOMY 2 void Pixel_wide2 (word x,word y,byte color) /* Affiche un pixel de la color aux coords x;y l'cran */ { *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 3)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 3)=color; } byte Read_pixel_wide2 (word x,word y) /* On retourne la couleur du pixel aux coords donnes */ { return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); } void Block_wide2 (word start_x,word start_y,word width,word height,byte color) /* On affiche un rectangle de la couleur donne */ { SDL_Rect rectangle; rectangle.x=start_x*ZOOMX; rectangle.y=start_y*ZOOMY; rectangle.w=width*ZOOMX; rectangle.h=height*ZOOMY; SDL_FillRect(Screen_SDL,&rectangle,color); } void Display_part_of_screen_wide2 (word width,word height,word image_width) /* Afficher une partie de l'image telle quelle sur l'cran */ { byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'cran (dest) byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de dpart ds la source (src) int y; int dy; for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne for (dy=width;dy>0;dy--) { *(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; src++; dest+=ZOOMX; } // On double la ligne qu'on vient de copier memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } //Update_rect(0,0,width,height); } void Pixel_preview_normal_wide2 (word x,word y,byte color) /* Affichage d'un pixel dans l'cran, par rapport au dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure Pixel_Preview_Loupe_SDL. */ { // if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) Pixel_wide2(x-Main_offset_X,y-Main_offset_Y,color); } void Pixel_preview_magnifier_wide2 (word x,word y,byte color) { // Affiche le pixel dans la partie non zoome Pixel_wide2(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) { // On est dedans int height; int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_wide2( Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, y_zoom, Main_magnifier_factor, height, color ); } } void Horizontal_XOR_line_wide2(word x_pos,word y_pos,word width) { //On calcule la valeur initiale de dest: byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; int x; for (x=0;x0;i--) { *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=xor_lut[*(dest)]; dest+=VIDEO_LINE_WIDTH*ZOOMY; } } void Display_brush_color_wide2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = Brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+VIDEO_LINE_WIDTH+3) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+3) = *(dest+2) = *(dest+1) = *dest = *src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } Update_rect(x_pos,y_pos,width,height); } void Display_brush_mono_wide2(word x_pos, word y_pos, word x_offset, word y_offset, word width, word height, byte transp_color, byte color, word brush_width) /* On affiche la brosse en monochrome */ { byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination // l'cran byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds // la brosse int x,y; for(y=height;y!=0;y--) //Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { if (*src!=transp_color) *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=color; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=brush_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Clear_brush_wide2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width) { byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'cran (dest) byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de dpart ds la source (src) int y; int x; (void)x_offset; // unused (void)y_offset; // unused (void)transp_color; // unused for(y=height;y!=0;y--) // Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } // Affiche une brosse (arbitraire) l'cran void Display_brush_wide2(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } } void Remap_screen_wide2(word x_pos,word y_pos,word width,word height,byte * conversion_table) { // dest = coords a l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; int x,y; // Pour chaque ligne for(y=height;y>0;y--) { // Pour chaque pixel for(x=width;x>0;x--) { *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest= conversion_table[*dest]; dest +=ZOOMX; } dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Display_line_on_screen_fast_wide2(word x_pos,word y_pos,word width,byte * line) /* On affiche toute une ligne de pixels telle quelle. */ /* Utilise si le buffer contient dja des pixel doubls. */ { memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); } void Display_line_on_screen_wide2(word x_pos,word y_pos,word width,byte * line) /* On affiche une ligne de pixels en les doublant. */ { int x; byte *dest; dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; for(x=width;x>0;x--) { *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*line; dest+=ZOOMX; line++; } } void Display_transparent_mono_line_on_screen_wide2( word x_pos, word y_pos, word width, byte* line, byte transp_color, byte color) // Affiche une ligne l'cran avec une couleur + transparence. // Utilis par les brosses en mode zoom { byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; int x; // Pour chaque pixel for(x=0;x 0); src += image_width; } // ATTENTION on n'arrive jamais ici ! } // Affiche une partie de la brosse couleur zoome void Display_brush_color_zoom_wide2(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle de la brosse byte * buffer) { byte* src = Brush+y_offset*brush_width + x_offset; word y = y_pos; byte bx; // Pour chaque ligne while(1) { Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche facteur fois la ligne zoome for(bx=Main_magnifier_factor;bx>0;bx--) { byte* line_src = buffer; byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; word x; // Pour chaque pixel de la ligne for(x = width*Main_magnifier_factor;x > 0;x--) { if(*line_src!=transp_color) { *(dest+3)=*(dest+2)=*(dest+1)=*dest = *line_src; } line_src++; dest+=ZOOMX; } // Double the line memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); y++; if(y==end_y_pos) { return; } } src += brush_width; } // ATTENTION zone jamais atteinte } void Display_brush_mono_zoom_wide2(word x_pos, word y_pos, word x_offset, word y_offset, word width, // width non zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle de la brosse byte * buffer ) { byte* src = Brush + y_offset * brush_width + x_offset; int y=y_pos*ZOOMY; //Pour chaque ligne zoomer : while(1) { int bx; // src = Ligne originale // On clate la ligne Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche la ligne Facteur fois l'cran (sur des // lignes conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome Display_transparent_mono_line_on_screen_wide2( x_pos, y, width * Main_magnifier_factor, buffer, transp_color, color ); // On passe la ligne suivante y++; // On vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); Update_rect( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); return; } bx --; } while (bx > 0); // Passage la ligne suivante dans la brosse aussi src+=brush_width; } } void Clear_brush_scaled_wide2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer) { // En fait on va recopier l'image non zoome dans la partie zoome ! byte* src = Main_screen + y_offset * image_width + x_offset; int y = y_pos; int bx; (void)transp_color; // unused // Pour chaque ligne zoomer while(1){ Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); bx=Main_magnifier_factor; // Pour chaque ligne do{ // TODO a verifier Display_line_on_screen_fast_wide2(x_pos,y, width * Main_magnifier_factor,buffer); // Ligne suivante y++; if(y==end_y_pos) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); Update_rect(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); return; } bx--; }while(bx!=0); src+= image_width; } } grafx2_2.4+git20180105/src/input.h0000664000000000000000000000637513223665306015052 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file input.h /// Functions for mouse, keyboard and joystick input. /// Joystick input is used to emulate mouse on platforms that don't have a /// pointing device, ie: the GP2X. ////////////////////////////////////////////////////////////////////////////// /// /// This is the keyboard/mouse/joystick input polling function. /// Returns 1 if a significant changed occurred, such as a mouse button pressed /// or depressed, or a new keypress was in the keyboard buffer. /// The latest input variables are held in ::Key, ::Key_ANSI, ::Mouse_X, ::Mouse_Y, ::Mouse_K. /// Note that ::Key and ::Key_ANSI are not persistent, they will be reset to 0 /// on subsequent calls to ::Get_input(). int Get_input(int sleep_time); /// Returns true if the keycode has been set as a keyboard shortcut for the function. int Is_shortcut(word key, word function); /// Returns true if the function has any shortcut key. int Has_shortcut(word function); /// Adjust mouse sensitivity (and actual mouse input mode) void Adjust_mouse_sensitivity(word fullscreen); void Set_mouse_position(void); /// /// This holds the ID of the GUI control that the mouse /// is manipulating. The input system will reset it to zero /// when mouse button is released, but it's the engine /// that will record and retrieve a real control ID. extern int Input_sticky_control; /// /// State of the shortcut for panning (SPECIAL_HOLD_PAN) : pressed or not. extern byte Pan_shortcut_pressed; /// Allows locking movement to X or Y axis: 0=normal, 1=lock on next move, 2=locked horizontally, 3=locked vertically. extern int Snap_axis; /// For the :Snap_axis mode, sets the origin's point (in image coordinates) extern int Snap_axis_origin_X; /// For the :Snap_axis mode, sets the origin's point (in image coordinates) extern int Snap_axis_origin_Y; /// /// This malloced string is set when a drag-and-drop event /// brings a file to Grafx2's window. extern char * Drop_file_name; #if defined __HAIKU__ #define SHORTCUT_COPY (SDLK_c|MOD_ALT) #elif defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #define SHORTCUT_COPY (SDLK_c|MOD_META) #else #define SHORTCUT_COPY (SDLK_c|MOD_CTRL) #endif #if defined __HAIKU__ #define SHORTCUT_PASTE (SDLK_v|MOD_ALT) #elif defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #define SHORTCUT_PASTE (SDLK_v|MOD_META) #else #define SHORTCUT_PASTE (SDLK_v|MOD_CTRL) #endif grafx2_2.4+git20180105/src/buttons.c0000664000000000000000000050413113223665306015375 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Yves Rizoud Copyright 2007-2017 Adrien Destugues (PulkoMandy) Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include #include #include #elif defined(__WIN32__) #include #include #else #include #endif // On Debian, this is already implied in dirent.h // I don't know which targets need it and what it does. - yr #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #include #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "graph.h" #include "engine.h" #include "readline.h" #include "filesel.h" #include "loadsave.h" #include "init.h" #include "buttons.h" #include "operatio.h" #include "pages.h" #include "palette.h" #include "errors.h" #include "readini.h" #include "saveini.h" #include "shade.h" #include "io.h" #include "help.h" #include "text.h" #include "sdlscreen.h" #include "windows.h" #include "brush.h" #include "input.h" #include "special.h" #include "tiles.h" #include "setup.h" #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include #include #elif defined(__MINT__) #include #include #elif defined(__WIN32__) #include #include #else #include #endif extern char Program_version[]; // generated in pversion.c extern short Old_MX; extern short Old_MY; //-- MODELE DE BOUTON DE MENU ------------------------------------------------ /* void Bouton_***(void) { short clicked_button; Open_window(310,190,"***"); Window_set_normal_button(103,137,80,14,"OK",0,1,SDLK_RETURN); // 1 Window_set_scroller_button(18,44,88,16,4,0); // 2 Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); } while (clicked_button!=1); Close_window(); Unselect_button(BOUTON_***); Display_cursor(); } */ void Message_out_of_memory(void) { short clicked_button; Open_window(216,76,"Not enough memory!"); Print_in_window(8,20,"Please consult the manual",MC_Black,MC_Light); Print_in_window(24,28,"to know how to obtain",MC_Black,MC_Light); Print_in_window(36,36,"more memory space.",MC_Black,MC_Light); Window_set_normal_button(60,53,40,14,"OK",1,1,SDLK_RETURN); // 1 Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do clicked_button=Window_clicked_button(); while ((clicked_button<=0) && (Key!=KEY_ESC) && (Key!=SDLK_o)); if(clicked_button<=0) Key=0; Close_window(); Display_cursor(); } void Button_Message_initial(void) { char str[30]; int x_pos,offs_y,x,y; int clicked_button=0; strcpy(str,"GrafX2 version "); strcat(str,Program_version); Open_window(260,172,str); Window_display_frame_in(10,20,239,62); Window_rectangle(11,21,237,60,MC_Black); for (y=23,offs_y=0; y<79; offs_y+=231,y++) for (x=14,x_pos=0; x_pos<231; x_pos++,x++) Pixel_in_window(x,y,Gfx->Logo_grafx2[offs_y+x_pos]); Print_in_window(130-4*26,88,"Copyright (c) 2007-2017 by",MC_Dark,MC_Light); Print_in_window(130-4*23,100,"the Grafx2 project team",MC_Black,MC_Light); Print_in_window(130-4*26,112,"Copyright (c) 1996-2001 by",MC_Dark,MC_Light); Print_in_window(130-4*13,122,"Sunset Design",MC_Black,MC_Light); //Print_in_window( 120-4*13,128,"(placeholder)",MC_Dark,MC_Light); Print_in_window(130-4*16,136,"http://grafx2.tk",MC_Dark,MC_Light); Window_set_normal_button(56, 151, 71, 14, "Anim", 0, (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION), KEY_NONE); Window_set_normal_button(133, 151, 71, 14, "Layers", 0, (Main_backups->Pages->Image_mode != IMAGE_MODE_LAYERED), KEY_NONE); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); while(!Mouse_K && !Key) Get_input(20); if (Mouse_K) { clicked_button = Window_get_clicked_button(); Wait_end_of_click(); } Close_window(); if (clicked_button > 0) { if (Main_backups->Pages->Image_mode == IMAGE_MODE_LAYERED) { Switch_layer_mode(IMAGE_MODE_ANIMATION); Config.Default_mode_layers = 0; } else { Switch_layer_mode(IMAGE_MODE_LAYERED); Config.Default_mode_layers = 1; } if (Check_menu_mode()) { Display_menu(); Display_all_screen(); } // Modify the mode for the spare too Spare_backups->Pages->Image_mode = Main_backups->Pages->Image_mode; Update_spare_buffers(Spare_image_width,Spare_image_height); Redraw_spare_image(); } Display_cursor(); } void Change_paintbrush_shape(byte shape) { Paintbrush_shape=shape; Display_paintbrush_in_menu(); switch (Current_operation) { case OPERATION_FILL : Paintbrush_shape_before_fill=shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; break; case OPERATION_COLORPICK : Paintbrush_shape_before_colorpicker=shape; Paintbrush_shape=PAINTBRUSH_SHAPE_NONE; break; // Note: Il existe un Paintbrush_shape_before_lasso, mais comme le lasso aura // t automatiquement dsactiv avant d'arriver ici, y'a pas de problme. } } //-------------------------------- UNDO/REDO --------------------------------- void Button_Undo(void) { Hide_cursor(); Undo(); Set_palette(Main_palette); Compute_optimal_menu_colors(Main_palette); Check_menu_mode(); Display_all_screen(); Unselect_button(BUTTON_UNDO); Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); Display_menu(); Display_cursor(); } void Button_Redo(void) { Hide_cursor(); Redo(); Set_palette(Main_palette); Compute_optimal_menu_colors(Main_palette); Check_menu_mode(); Display_all_screen(); Unselect_button(BUTTON_UNDO); Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); Display_menu(); Display_cursor(); } //---------------------------- SCROLL PALETTE LEFT --------------------------- void Button_Pal_left(void) { short cells; cells = (Config.Palette_vertical)?Palette_cells_X():Palette_cells_Y(); Hide_cursor(); if (First_color_in_palette) { if (First_color_in_palette>=cells) First_color_in_palette-=cells; else First_color_in_palette=0; Display_menu_palette(); } Unselect_button(BUTTON_PAL_LEFT); Display_cursor(); } void Button_Pal_left_fast(void) { short cells_x = Palette_cells_X(); short cells_y = Palette_cells_Y(); Hide_cursor(); if (First_color_in_palette) { if (First_color_in_palette>=cells_y*cells_x) First_color_in_palette-=cells_y*cells_x; else First_color_in_palette=0; Display_menu_palette(); } Unselect_button(BUTTON_PAL_LEFT); Display_cursor(); } //--------------------------- SCROLL PALETTE RIGHT --------------------------- void Button_Pal_right(void) { short cells; cells = (Config.Palette_vertical)?Palette_cells_X():Palette_cells_Y(); Hide_cursor(); if ((int)First_color_in_palette+Palette_cells_X()*Palette_cells_Y()<256) { First_color_in_palette+=cells; Display_menu_palette(); } Unselect_button(BUTTON_PAL_RIGHT); Display_cursor(); } void Button_Pal_right_fast(void) { short cells_x = Palette_cells_X(); short cells_y = Palette_cells_Y(); Hide_cursor(); if ((int)First_color_in_palette+cells_y*cells_x<256) { if ((int)First_color_in_palette+(cells_y)*cells_x*2<256) First_color_in_palette+=cells_x*cells_y; else { if (Config.Palette_vertical) First_color_in_palette=255/cells_x*cells_x-(cells_y-1)*cells_x; else First_color_in_palette=255/cells_y*cells_y-(cells_x-1)*cells_y; } Display_menu_palette(); } Unselect_button(BUTTON_PAL_RIGHT); Display_cursor(); } //-------------------- item de la forecolor dans le menu -------------------- void Button_Select_forecolor(void) { static long time_click = 0; long time_previous; int color; time_previous = time_click; time_click = SDL_GetTicks(); color=Pick_color_in_palette(); if (color == Fore_color) { // Check if it's a double-click if (time_click - time_previous < Config.Double_click_speed) { // Open palette window Button_Palette(); return; } } do { if (color != Fore_color && color!=-1) { Hide_cursor(); Set_fore_color(color); Display_cursor(); } // Wait loop after initial click while(Mouse_K) { Get_input(20); if (Button_under_mouse()==BUTTON_CHOOSE_COL) { color=Pick_color_in_palette(); if (color != Fore_color && color!=-1) { Hide_cursor(); Status_print_palette_color(color); Set_fore_color(color); Display_cursor(); } } } } while(Mouse_K); } //-------------------- item de la backcolor dans le menu -------------------- void Button_Select_backcolor(void) { int color; do { color=Pick_color_in_palette(); if (color!=-1 && color != Back_color) { Hide_cursor(); Status_print_palette_color(color); Set_back_color(color); Display_cursor(); } // Wait loop after initial click do { Get_input(20); if (Button_under_mouse()==BUTTON_CHOOSE_COL) break; // This will repeat this button's action } while(Mouse_K); } while(Mouse_K); } void Button_Hide_menu(void) { Hide_cursor(); if (Menu_is_visible) { Menu_is_visible=0; Menu_Y=Screen_height; if (Main_magnifier_mode) { Compute_magnifier_data(); } // On repositionne le dcalage de l'image pour qu'il n'y ait pas d'in- // -cohrences lorsqu'on sortira du mode Loupe. if (Main_offset_Y+Screen_height>Main_image_height) { if (Screen_height>Main_image_height) Main_offset_Y=0; else Main_offset_Y=Main_image_height-Screen_height; } // On fait pareil pour le brouillon if (Spare_offset_Y+Screen_height>Spare_image_height) { if (Screen_height>Spare_image_height) Spare_offset_Y=0; else Spare_offset_Y=Spare_image_height-Screen_height; } Compute_magnifier_data(); if (Main_magnifier_mode) Position_screen_according_to_zoom(); Compute_limits(); Compute_paintbrush_coordinates(); Display_all_screen(); } else { byte current_menu; Menu_is_visible=1; Menu_Y=Screen_height; for (current_menu = 0; current_menu < MENUBAR_COUNT; current_menu++) if (Menu_bars[current_menu].Visible) Menu_Y -= Menu_bars[current_menu].Height * Menu_factor_Y; Compute_magnifier_data(); if (Main_magnifier_mode) Position_screen_according_to_zoom(); Compute_limits(); Compute_paintbrush_coordinates(); Display_menu(); if (Main_magnifier_mode) Display_all_screen(); } Unselect_button(BUTTON_HIDE); Display_cursor(); } void Button_Toggle_toolbar(void) { T_Dropdown_button dropdown; T_Dropdown_choice *item; static char menu_name_tools[9] = " Tools"; static char menu_name_layers[9]= " Layers"; static char menu_name_anim[9] = " Anim"; menu_name_tools[0] = Menu_bars[MENUBAR_TOOLS ].Visible ? 22 : ' '; menu_name_layers[0] = Menu_bars[MENUBAR_LAYERS].Visible ? 22 : ' '; menu_name_anim[0] = Menu_bars[MENUBAR_ANIMATION].Visible ? 22 : ' '; Hide_cursor(); dropdown.Pos_X =Buttons_Pool[BUTTON_HIDE].X_offset; dropdown.Pos_Y =Buttons_Pool[BUTTON_HIDE].Y_offset; dropdown.Height =Buttons_Pool[BUTTON_HIDE].Height; dropdown.Dropdown_width=70; dropdown.First_item =NULL; dropdown.Bottom_up =1; Window_dropdown_add_item(&dropdown, 0, menu_name_tools); if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION || Main_backups->Pages->Nb_layers==1) Window_dropdown_add_item(&dropdown, 1, menu_name_layers); if (Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION || (Main_backups->Pages->Image_mode == IMAGE_MODE_LAYERED && Main_backups->Pages->Nb_layers==1)) Window_dropdown_add_item(&dropdown, 2, menu_name_anim); item=Dropdown_activate(&dropdown,0,Menu_Y+Menu_bars[MENUBAR_STATUS].Top*Menu_factor_Y); if (item) { switch (item->Number) { case 0: // tools Set_bar_visibility(MENUBAR_TOOLS, !Menu_bars[MENUBAR_TOOLS].Visible, 0); break; case 1: // layers if (Menu_bars[MENUBAR_ANIMATION].Visible) { Set_bar_visibility(MENUBAR_ANIMATION, 0, 0); Config.Default_mode_layers=1; } Set_bar_visibility(MENUBAR_LAYERS, !Menu_bars[MENUBAR_LAYERS].Visible, 0); if (Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION) Switch_layer_mode(IMAGE_MODE_LAYERED); break; case 2: // anim if (Menu_bars[MENUBAR_LAYERS].Visible) { Set_bar_visibility(MENUBAR_LAYERS, 0, 0); Config.Default_mode_layers=0; } Set_bar_visibility(MENUBAR_ANIMATION, !Menu_bars[MENUBAR_ANIMATION].Visible, 0); if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) Switch_layer_mode(IMAGE_MODE_ANIMATION); break; } // redraw image and menu Display_menu(); Display_all_screen(); } // Closing Window_dropdown_clear_items(&dropdown); Unselect_button(BUTTON_HIDE); Display_cursor(); } void Button_Toggle_all_toolbars(void) { // This is used to memorize the bars' visibility when temporarily hidden static word Last_visibility = 0xFFFF; int i; word current_visibility; Hide_cursor(); // Check which bars are visible current_visibility=0; for (i=MENUBAR_STATUS+1;iPages->Filename, Main_backups->Pages->File_directory); if ( (!File_exists(filename)) || Confirmation_box("Erase old file ?") ) { T_IO_Context save_context; Hide_cursor(); old_cursor_shape=Cursor_shape; Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Init_context_layered_image(&save_context, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); Save_image(&save_context); Destroy_context(&save_context); Hide_cursor(); Cursor_shape=old_cursor_shape; Display_cursor(); if (!File_error) // L'ayant sauve avec succs, return 1; // On peut quitter else // Il y a eu une erreur lors de la sauvegarde, return 0; // On ne peut donc pas quitter } else // L'utilisateur ne veut pas craser l'ancien fichier, return 0; // On doit donc rester case 3 : return 1; // Quitter } return 0; } void Button_Quit(void) { //short clicked_button; if (Button_Quit_local_function()) { if (Spare_image_is_modified) { Button_Page(); // On passe sur le brouillon // Si l'utilisateur prsente les derniers symptomes de l'abandon if (Button_Quit_local_function()) Quitting=1; } else Quitting=1; } if ( (Menu_is_visible) && (Mouse_Y+8>Menu_Y) ) Hide_cursor(); Unselect_button(BUTTON_QUIT); if ( (Menu_is_visible) && (Mouse_Y+8>Menu_Y) ) Display_cursor(); } //---------------------------- Effacer l'cran ------------------------------- void Button_Clear(void) { Hide_cursor(); Backup(); if (Stencil_mode && Config.Clear_with_stencil) Clear_current_image_with_stencil(Main_backups->Pages->Transparent_color,Stencil); else Clear_current_image(Main_backups->Pages->Transparent_color); Redraw_layered_image(); End_of_modification(); Display_all_screen(); Unselect_button(BUTTON_CLEAR); Display_cursor(); } void Button_Clear_with_backcolor(void) { Hide_cursor(); Backup(); if (Stencil_mode && Config.Clear_with_stencil) Clear_current_image_with_stencil(Back_color,Stencil); else Clear_current_image(Back_color); Redraw_layered_image(); End_of_modification(); Display_all_screen(); Unselect_button(BUTTON_CLEAR); Display_cursor(); } //------------------------------- Paramtres --------------------------------- #define SETTING_PER_PAGE 11 #define SETTING_PAGES 5 #define SETTING_HEIGHT 12 typedef struct { const char* Label; // Use NULL label to stop an array int Code; } T_Lookup; const T_Lookup Lookup_YesNo[] = { {"NO",0}, {"YES",1}, {NULL,-1}, }; const T_Lookup Lookup_FFF[] = { {"All",0}, {"Files",1}, {"Dirs.",2}, {NULL,-1}, }; const T_Lookup Lookup_AutoRes[] = { {"Internal",1}, {"Real",2}, {NULL,-1}, }; const T_Lookup Lookup_Coords[] = { {"Relative",1}, {"Absolute",2}, {NULL,-1}, }; const T_Lookup Lookup_MenuRatio[] = { {"None",0}, {"x2",254}, // -2 {"x3",253}, // -3 {"x4",252}, // -4 {"Moderate",2}, {"Maximum",1}, {NULL,-1}, }; const T_Lookup Lookup_MouseSpeed[] = { {"Normal",1}, {"/2",2}, {"/3",3}, {"/4",4}, {NULL,-1}, }; const T_Lookup Lookup_SwapButtons[] = { {"None",0}, {"Control",MOD_CTRL}, {"Alt",MOD_ALT}, {NULL,-1}, }; const T_Lookup Lookup_VirtualKeyboard[] = { {"Auto",0}, {"ON",1}, {"OFF",2}, {NULL,-1}, }; typedef struct { const char* Label; byte Type; // 0: label, 1+: setting (size in bytes) void * Value; int Min_value; int Max_value; int Digits; // Could be computed from Max_value...but don't bother. const T_Lookup * Lookup; } T_Setting; long int Get_setting_value(T_Setting *item) { switch(item->Type) { case 1: return *((byte *)(item->Value)); break; case 2: return *((word *)(item->Value)); break; case 4: default: return *((long int *)(item->Value)); break; } } void Set_setting_value(T_Setting *item, long int value) { switch(item->Type) { case 1: *((byte *)(item->Value)) = value; break; case 2: *((word *)(item->Value)) = value; break; case 4: default: *((long int *)(item->Value)) = value; break; } } // Fetch a label in a lookup table. Unknown values get label 0. const char *Lookup_code(int code, const T_Lookup *lookup) { int i; for(i=0; lookup[i].Label!=NULL; i++) { if (lookup[i].Code == code) return lookup[i].Label; } return lookup[0].Label; } /// Increase an enum to next-higher value (wrapping). int Lookup_next(int code, const T_Lookup *lookup) { int i; for(i=0; lookup[i].Label!=NULL; i++) { if (lookup[i].Code == code) { if (lookup[i+1].Label==NULL) return lookup[0].Code; return lookup[i+1].Code; } } return 0; } /// Decrease an enum to previous value (wrapping). int Lookup_previous(int code, const T_Lookup *lookup) { int count; int current=-1; for(count=0; lookup[count].Label!=NULL; count++) { if (lookup[count].Code == code) current=count; } return lookup[(current + count - 1) % count].Code; } void Settings_display_config(T_Setting *setting, T_Config * conf, T_Special_button *panel) { int i; // A single button Print_in_window(155,166,(conf->Auto_save)?"YES":" NO",MC_Black,MC_Light); // Clear all Window_rectangle(panel->Pos_X, panel->Pos_Y, panel->Width, panel->Height+1, MC_Light); for (i=0; iPos_X+3, panel->Pos_Y+i*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2, setting[i].Label, i==0?MC_White:MC_Dark, MC_Light); if(setting[i].Value) { int value = Get_setting_value(&setting[i]); if (setting[i].Lookup) { // Use a lookup table to print a label const char *str; str = Lookup_code(value,setting[i].Lookup); Print_in_window(panel->Pos_X+3+176, panel->Pos_Y+i*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2, str, MC_Black, MC_Light); } else { // Print a number char str[10]; Num2str(value,str,setting[i].Digits); Print_in_window(panel->Pos_X+3+176, panel->Pos_Y+i*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2, str, MC_Black, MC_Light); } } } Update_window_area(panel->Pos_X, panel->Pos_Y, panel->Width, panel->Height+1); } void Settings_save_config(T_Config * conf) { if (Save_CFG()) Error(0); else if (Save_INI(conf)) Error(0); } void Settings_load_config(T_Config * conf) { if (Load_CFG(0)) Error(0); else if (Load_INI(conf)) Error(0); } void Button_Settings(void) { short clicked_button; T_Config selected_config; byte config_is_reloaded=0; T_Special_button *panel; byte need_redraw=1; static byte current_page=0; // Definition of settings pages // Label,Type (0 = label, 1+ = setting size in bytes), // Value, min, max, digits, Lookup) T_Setting setting[SETTING_PER_PAGE*SETTING_PAGES] = { {" --- GUI ---",0,NULL,0,0,0,NULL}, {"Opening message:",1,&(selected_config.Opening_message),0,1,0,Lookup_YesNo}, {"Menu ratio adapt:",1,&(selected_config.Ratio),0,1,0,Lookup_MenuRatio}, {"Draw limits:",1,&(selected_config.Display_image_limits),0,1,0,Lookup_YesNo}, {"Coordinates:",1,&(selected_config.Coords_rel),0,1,0,Lookup_Coords}, {"Separate colors:",1,&(selected_config.Separate_colors),0,1,0,Lookup_YesNo}, {"Safety colors:",1,&(selected_config.Safety_colors),0,1,0,Lookup_YesNo}, {"Sync views:",1,&(selected_config.Sync_views),0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {" --- Input ---",0,NULL,0,0,0,NULL}, {"Scrollbar speed",0,NULL,0,0,0,NULL}, {" on left click:",1,&(selected_config.Delay_left_click_on_slider),1,255,4,NULL}, {" on right click:",1,&(selected_config.Delay_right_click_on_slider),1,255,4,NULL}, {"Merge movement:",1,&(selected_config.Mouse_merge_movement),0,100,4,NULL}, {"Double click speed:",2,&(selected_config.Double_click_speed),1,1999,4,NULL}, {"Double key speed:",2,&(selected_config.Double_key_speed),1,1999,4,NULL}, //{"Mouse speed (fullscreen)",0,NULL,0,0,0,NULL}, //{" horizontally:",1,&(selected_config.Mouse_sensitivity_index_x),1,4,0,Lookup_MouseSpeed}, //{" vertically:",1,&(selected_config.Mouse_sensitivity_index_y),1,4,0,Lookup_MouseSpeed}, {"Key to swap buttons:",2,&(selected_config.Swap_buttons),0,0,0,Lookup_SwapButtons}, {"Virtual keyboard",1,&(selected_config.Use_virtual_keyboard),0,2,0,Lookup_VirtualKeyboard}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {" --- Editing ---",0,NULL,0,0,0,NULL}, {"Adjust brush pick:",1,&(selected_config.Adjust_brush_pick),0,1,0,Lookup_YesNo}, {"Undo pages:",1,&(selected_config.Max_undo_pages),1,99,5,NULL}, {"Vertices per polygon:",4,&(selected_config.Nb_max_vertices_per_polygon),2,16384,5,NULL}, {"Fast zoom:",1,&(selected_config.Fast_zoom),0,1,0,Lookup_YesNo}, {"Clear with stencil:",1,&(selected_config.Clear_with_stencil),0,1,0,Lookup_YesNo}, {"Auto discontinuous:",1,&(selected_config.Auto_discontinuous),0,1,0,Lookup_YesNo}, {"Auto count colors:",1,&(selected_config.Auto_nb_used),0,1,0,Lookup_YesNo}, {"Right click colorpick:",1,&(selected_config.Right_click_colorpick),0,1,0,Lookup_YesNo}, {"Multi shortcuts:",1,&(selected_config.Allow_multi_shortcuts),0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, {" --- File selector ---",0,NULL,0,0,0,NULL}, {"Show in fileselector",0,NULL,0,0,0,NULL}, {" Hidden files:",4,&(selected_config.Show_hidden_files),0,1,0,Lookup_YesNo}, {" Hidden dirs:",4,&(selected_config.Show_hidden_directories),0,1,0,Lookup_YesNo}, {"Preview delay:",4,&(selected_config.Timer_delay), 1,256,3,NULL}, {"Maximize preview:",1,&(selected_config.Maximize_preview), 0,1,0,Lookup_YesNo}, {"Find file fast:",1,&(selected_config.Find_file_fast), 0,2,0,Lookup_FFF}, {"Auto set resolution:",1,&(selected_config.Auto_set_res), 0,1,0,Lookup_YesNo}, {" According to:",1,&(selected_config.Set_resolution_according_to), 1,2,0,Lookup_AutoRes}, {"Backup:",1,&(selected_config.Backup), 0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, {" --- Format options ---",0,NULL,0,0,0,NULL}, {"Screen size in GIF:",1,&(selected_config.Screen_size_in_GIF),0,1,0,Lookup_YesNo}, {"Clear palette:",1,&(selected_config.Clear_palette),0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, }; const char * help_section[SETTING_PAGES] = { "GUI", "INPUT", "EDITING", "FILE SELECTOR", "FILE FORMAT OPTIONS", }; selected_config=Config; Open_window(307,182,"Settings"); // Button Reload Window_set_normal_button( 6,163, 51,14,"Reload" ,0,1,SDLK_LAST); // 1 // Button Auto-save Window_set_normal_button( 73,163,107,14,"Auto-save: ",0,1,SDLK_LAST); // 2 // Button Save Window_set_normal_button(183,163, 51,14,"Save" ,0,1,SDLK_LAST); // 3 // Button Close Window_set_normal_button(250,163, 51,14,"Close" ,0,1,KEY_ESC); // 4 panel=Window_set_special_button(10, 21, 272,SETTING_PER_PAGE*SETTING_HEIGHT); // 5 Window_set_scroller_button(285,21,SETTING_PER_PAGE*SETTING_HEIGHT,SETTING_PAGES,1,current_page); // 6 Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { if (need_redraw) { Hide_cursor(); Settings_display_config(setting+current_page*SETTING_PER_PAGE, &selected_config, panel); if (need_redraw & 2) { // Including slider position Window_scroller_button_list->Position=current_page; Window_draw_slider(Window_scroller_button_list); } Display_cursor(); need_redraw=0; } clicked_button=Window_clicked_button(); switch(clicked_button) { case 1 : // Reload Settings_load_config(&selected_config); config_is_reloaded=1; need_redraw=1; break; case 2 : // Auto-save selected_config.Auto_save=!selected_config.Auto_save; need_redraw=1; break; case 3 : // Save Settings_save_config(&selected_config); break; // case 4: // Close case 5: // Panel area { T_Setting item; int num=(((short)Mouse_Y-Window_pos_Y)/Menu_factor_Y - panel->Pos_Y)/SETTING_HEIGHT; if (num >= 0 && num < SETTING_PER_PAGE) { item=setting[current_page*SETTING_PER_PAGE+num]; if (item.Type!=0) { // Remember which button is clicked byte old_mouse_k = Mouse_K; if (Window_normal_button_onclick(panel->Pos_X, panel->Pos_Y+num*SETTING_HEIGHT, panel->Width, SETTING_HEIGHT+1, 5)) { int value = Get_setting_value(&item); if (item.Lookup) { // Enum: toggle it if (old_mouse_k & LEFT_SIDE) value = Lookup_next(value, item.Lookup); else value = Lookup_previous(value, item.Lookup); Set_setting_value(&item, value); } else { // Numeric: edit it char str[10]; str[0]='\0'; if (! (old_mouse_k & RIGHT_SIDE)) Num2str(value,str,item.Digits+1); if (Readline(panel->Pos_X+3+176, panel->Pos_Y+num*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2,str,item.Digits+1,INPUT_TYPE_INTEGER)) { value=atoi(str); if (valueitem.Max_value) value = item.Max_value; Set_setting_value(&item, value); } Key=0; // Need to discard keys used during editing } } } } } need_redraw=1; break; case 6: // Scroller current_page = Window_attribute2; need_redraw=1; break; } if (Key == KEY_MOUSEWHEELDOWN) { if (current_page < (SETTING_PAGES-1)) { current_page++; need_redraw=2; } } else if (Key == KEY_MOUSEWHEELUP) { if (current_page > 0) { current_page--; need_redraw=2; } } else if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(NB_BUTTONS+0, help_section[current_page]); else if (Is_shortcut(Key,0x100+BUTTON_SETTINGS)) clicked_button=4; } while ( (clicked_button!=4) && (Key!=SDLK_RETURN) ); // Checks on change if (Config.Show_hidden_directories!=selected_config.Show_hidden_directories ||Config.Show_hidden_files!=selected_config.Show_hidden_files) { // Reset fileselector offsets // since different files are shown now Main_selector.Position=0; Main_selector.Offset=0; Spare_selector.Position=0; Spare_selector.Offset=0; Brush_selector.Position=0; Brush_selector.Offset=0; } if(Config.Allow_multi_shortcuts && !selected_config.Allow_multi_shortcuts) { // User just disabled multi shortcuts: make them unique now. Remove_duplicate_shortcuts(); } // Copy all Config=selected_config; if (config_is_reloaded) Compute_optimal_menu_colors(Main_palette); Close_window(); Unselect_button(BUTTON_SETTINGS); // Raffichage du menu pour que les inscriptions qui y figurent soient // retraces avec la nouvelle fonte Display_menu(); Display_cursor(); // On vrifie qu'on peut bien allouer le nombre de pages Undo. Set_number_of_backups(Config.Max_undo_pages); } // Data for skin selector T_Fileselector Skin_files_list; // Data for font selector T_Fileselector Font_files_list; // char * Format_font_filename(const char * fname) { static char result[12]; int c; int length; fname+=strlen(FONT_PREFIX); // Omit file prefix length=strlen(fname) - 4; // assume .png extension for (c=0;c<11 && c11) result[10] = ELLIPSIS_CHARACTER; return result; } // Add a skin to the list void Add_font_or_skin(const char *name) { const char * fname; int namelength; // Cut the long name to keep only filename (no directory) fname = Find_last_separator(name); if (fname) fname++; else fname = name; namelength = strlen(fname); if (namelength>=10 && fname[0]!='_' && !strncasecmp(fname, SKIN_PREFIX, strlen(SKIN_PREFIX)) && (!strcasecmp(fname + namelength - 4,".png") || !strcasecmp(fname + namelength - 4,".gif"))) { Add_element_to_list(&Skin_files_list, fname, Format_filename(fname, 19, 0), 0, ICON_NONE); if (fname[0]=='\0') return; } else if (namelength>=10 && !strncasecmp(fname, FONT_PREFIX, strlen(FONT_PREFIX)) && (!strcasecmp(fname + namelength - 4, ".png"))) { Add_element_to_list(&Font_files_list, fname, Format_font_filename(fname), 0, ICON_NONE); if (fname[0]=='\0') return; } } // Callback to display a skin name in the list void Draw_one_skin_name(word x, word y, word index, byte highlighted) { T_Fileselector_item * current_item; if (Skin_files_list.Nb_elements) { current_item = Get_item_by_index(&Skin_files_list, index); Print_in_window(x, y, current_item->Short_name, MC_Black, (highlighted)?MC_Dark:MC_Light); } } /// Skin selector window void Button_Skins(void) { short clicked_button; short temp; char skinsdir[MAX_PATH_CHARACTERS]; T_Dropdown_button * font_dropdown; T_Dropdown_button * cursor_dropdown; T_List_button * skin_list; T_Scroller_button * file_scroller; int selected_font = 0; int selected_cursor = Config.Cursor; byte separatecolors = Config.Separate_colors; byte showlimits = Config.Display_image_limits; byte need_load=1; int button; word x, y, x_pos, offs_y; char * cursors[] = { "Solid", "Transparent", "Thin" }; T_Gui_skin * gfx = NULL; byte * new_font; #define FILESEL_Y 34 // --- Read the contents of skins/ directory ------------------ // Here we use the same data container as the fileselectors. // Reinitialize the list Free_fileselector_list(&Skin_files_list); Free_fileselector_list(&Font_files_list); // Browse the "skins" directory strcpy(skinsdir, Data_directory); strcat(skinsdir, SKINS_SUBDIRECTORY); // Add each found file to the list For_each_file(skinsdir, Add_font_or_skin); // Sort it Sort_list_of_files(&Skin_files_list); Sort_list_of_files(&Font_files_list); selected_font = Find_file_in_fileselector(&Font_files_list, Config.Font_file); // -------------------------------------------------------------- Open_window(290, 140, "Skins"); // Frames Window_display_frame_in(6, FILESEL_Y - 2, 148, 84); // File selector // Texts Print_in_window( 172, 33,"Font:" ,MC_Black,MC_Light); Print_in_window( 172, 59,"Cursor:" ,MC_Black,MC_Light); // Ok button Window_set_normal_button(6, 120, 51, 14, "OK", 0, 1, SDLK_RETURN); // 1 // List of skins skin_list = Window_set_list_button( // Fileselector Window_set_special_button(8, FILESEL_Y + 1, 144, 80), // 2 // Scroller for the fileselector (file_scroller = Window_set_scroller_button(155, FILESEL_Y - 1, 82, Skin_files_list.Nb_elements, 10, 0)), // 3 Draw_one_skin_name, 2); // 4 skin_list->Cursor_position = Find_file_in_fileselector(&Skin_files_list, Config.Skin_file); // Buttons to choose a font font_dropdown = Window_set_dropdown_button(172, 43, 104, 11, 0, Get_item_by_index(&Font_files_list,selected_font)->Short_name,1,0,1,RIGHT_SIDE|LEFT_SIDE,0); // 5 for (temp=0; tempShort_name); // Cancel Window_set_normal_button(61, 120, 51,14,"Cancel",0,1,SDLK_ESCAPE); // 6 // Dropdown list to choose cursor type cursor_dropdown = Window_set_dropdown_button(172, 69, 104, 11, 0, cursors[selected_cursor], 1, 0, 1, RIGHT_SIDE|LEFT_SIDE,0); // 7 for (temp = 0; temp<3; temp++) Window_dropdown_add_item(cursor_dropdown, temp, cursors[temp]); Window_set_normal_button(172, 87, 14, 14, (Config.Display_image_limits)?"X":" ", -1, 1, SDLK_LAST); // 8 Print_in_window( 190, 85,"Draw picture", MC_Dark, MC_Light); Print_in_window( 190, 94,"limits", MC_Dark, MC_Light); Window_set_normal_button(172, 111, 14, 14, (Config.Separate_colors)?"X":" ", -1, 1, SDLK_LAST); // 9 Print_in_window( 190, 109,"Separate", MC_Dark, MC_Light); Print_in_window( 190, 118,"colors", MC_Dark, MC_Light); Window_redraw_list(skin_list); for (y = 14, offs_y = 0; offs_y < 16; offs_y++, y++) for (x = 6, x_pos = 0; x_pos<173; x_pos++, x++) Pixel_in_window(x, y, Gfx->Preview[offs_y][x_pos]); Update_window_area(0, 0, Window_width, Window_height); Display_cursor(); do { if (need_load) { need_load=0; Hide_cursor(); // (Re-)load GUI graphics from selected skins strcpy(skinsdir, Get_item_by_index(&Skin_files_list, skin_list->List_start + skin_list->Cursor_position)->Full_name); gfx = Load_graphics(skinsdir, NULL); if (gfx == NULL) // Error { Display_cursor(); Verbose_message("Error!", Gui_loading_error_message); Hide_cursor(); // Update preview Window_rectangle(6, 14, 173, 16, MC_Light); } else { // Update preview // Display the bitmap according to its own color indices for (y = 14, offs_y = 0; offs_y < 16; offs_y++, y++) for (x = 6, x_pos = 0; x_pos<173; x_pos++, x++) { if (gfx->Preview[offs_y][x_pos] == gfx->Color[0]) Pixel_in_window(x, y, MC_Black); else if (gfx->Preview[offs_y][x_pos] == gfx->Color[1]) Pixel_in_window(x, y, MC_Dark); else if (gfx->Preview[offs_y][x_pos] == gfx->Color[3]) Pixel_in_window(x, y, MC_White); else if (gfx->Preview[offs_y][x_pos] == gfx->Color[2]) Pixel_in_window(x, y, MC_Light); } // Actualize current screen according to preferred GUI colors // Note this only updates onscreen colors Set_color( MC_Black, gfx->Default_palette[gfx->Color[0]].R, gfx->Default_palette[gfx->Color[0]].G, gfx->Default_palette[gfx->Color[0]].B); Set_color( MC_Dark, gfx->Default_palette[gfx->Color[1]].R, gfx->Default_palette[gfx->Color[1]].G, gfx->Default_palette[gfx->Color[1]].B); Set_color( MC_Light, gfx->Default_palette[gfx->Color[2]].R, gfx->Default_palette[gfx->Color[2]].G, gfx->Default_palette[gfx->Color[2]].B); Set_color( MC_White, gfx->Default_palette[gfx->Color[3]].R, gfx->Default_palette[gfx->Color[3]].G, gfx->Default_palette[gfx->Color[3]].B); } Update_window_area(6, 14, 173, 16); Display_cursor(); } clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_SETTINGS, "SKINS"); switch(clicked_button) { case 1 : // OK break; case 2 : // double-click file: do nothing break; case 3 : // doesn't happen break; case 4 : // a file is selected need_load=1; break; case 5 : // Font dropdown { T_Fileselector_item* fontName; selected_font = Window_attribute2; // Get the index of the chosen font. fontName = Get_item_by_index(&Font_files_list,selected_font); new_font = Load_font(fontName->Full_name); if (new_font) { free(Menu_font); Menu_font = new_font; Print_in_window( 172, 33,"Font:" ,MC_Black,MC_Light); Print_in_window_limited(font_dropdown->Pos_X+2,font_dropdown->Pos_Y+(font_dropdown->Height-7)/2, fontName->Short_name,strlen(fontName->Short_name) ,MC_Black,MC_Light); Update_window_area(172, 33, 8 * 5, 8); } break; } // 6: Cancel case 7 : // Cursor selected_cursor = Window_attribute2; break; case 8: // Display limits showlimits = !showlimits; Hide_cursor(); Print_in_window(175, 90, (showlimits)?"X":" ", MC_Black, MC_Light); Display_cursor(); break; case 9: // Separate colors separatecolors = !separatecolors; Hide_cursor(); Print_in_window(175, 114, (separatecolors)?"X":" ", MC_Black, MC_Light); Display_cursor(); break; } } while ( (clicked_button!=1) && (clicked_button !=6) && (Key != SDLK_ESCAPE)); if(clicked_button == 1) { if (gfx != NULL) { Set_current_skin(skinsdir, gfx); } // (Re-)load the selected font new_font = Load_font(Get_item_by_index(&Font_files_list,selected_font)->Full_name); if (new_font) { const char * fname; free(Menu_font); Menu_font = new_font; fname = Get_item_by_index(&Font_files_list,selected_font)->Full_name; free(Config.Font_file); Config.Font_file = (char *)strdup(fname); } // Confirm the change of cursor shape Config.Cursor = selected_cursor; Config.Display_image_limits = showlimits; Config.Separate_colors = separatecolors; // Now find the best colors for the new skin in the current palette // and remap the skin Compute_optimal_menu_colors(Main_palette); } // We don't want to keep the skin's palette, as this would corrupt the current picture's one. Set_palette(Main_palette); Close_window(); Unselect_button(BUTTON_SETTINGS); // Raffichage du menu pour que les inscriptions qui y figurent soient retraces avec la nouvelle fonte Display_menu(); // Redraw all buttons, to ensure all specific sprites are in place. // This is necessary for multi-state buttons, for example Freehand. for (button=0; buttonPages->Nb_layers; i++) { if (i == Spare_current_layer) { // Copy the current layer memcpy(Spare_backups->Pages->Image[i].Pixels,Main_backups->Pages->Image[Main_current_layer].Pixels,Main_image_width*Main_image_height); } else { // Resize the original layer Copy_part_of_image_to_another( Spare_backups->Pages->Next->Image[i].Pixels,0,0,Min(old_width,Spare_image_width), Min(old_height,Spare_image_height),old_width, Spare_backups->Pages->Image[i].Pixels,0,0,Spare_image_width); } } // Copie des dimensions de l'image /* C'est inutile, le "Backuper et redimensionner brouillon" a dj modifi ces valeurs pour qu'elles soient correctes. */ /* Spare_image_width=Main_image_width; Spare_image_height=Main_image_height; */ Copy_view_to_spare(); // Update the visible buffer of the spare. // It's a bit complex because at the moment, to save memory, // the spare doesn't have a full visible_buffer + depth_buffer, // so I can't use exactly the same technique as for Main page. // (It's the same reason that the "Page" function gets complex, // it needs to rebuild a depth buffer only, trusting the // depth buffer that was already available in Spare_.) Update_spare_buffers(Spare_image_width,Spare_image_height); Redraw_spare_image(); } else Message_out_of_memory(); } void Copy_some_colors(void) { short index; byte confirmation=0; static byte mask_color_to_copy[256]; // static to use less stack memset(mask_color_to_copy,1,256); Menu_tag_colors("Tag colors to copy",mask_color_to_copy,&confirmation,0, NULL, 0xFFFF); if (confirmation) { // Make a backup with the same pixel data as previous history steps Backup_the_spare(LAYER_NONE); for (index=0; index<256; index++) { if (mask_color_to_copy[index]) memcpy(Spare_palette+index,Main_palette+index, sizeof(T_Components)); } } } void Button_Copy_page(void) { short clicked_button; Open_window(168,137,"Copy to spare page"); Window_set_normal_button(10, 20,148,14,"Pixels + palette" , 0,1,SDLK_RETURN); // 1 Window_set_normal_button(10, 37,148,14,"Pixels only" , 3,1,SDLK_x); // 2 Window_set_normal_button(10, 54,148,14,"Palette only" , 1,1,SDLK_p); // 3 Window_set_normal_button(10, 71,148,14,"Some colors only" , 6,1,SDLK_c); // 4 Window_set_normal_button(10, 88,148,14,"Palette and remap",13,1,SDLK_r); // 5 Window_set_normal_button(44,114, 80,14,"Cancel" , 0,1,KEY_ESC); // 6 Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_PAGE, NULL); else if (Is_shortcut(Key,0x200+BUTTON_PAGE)) clicked_button=6; } while (clicked_button<=0); Close_window(); Display_cursor(); switch (clicked_button) { case 1: // Pixels+palette // backup is done by the following function Copy_image_only(); // copie de la palette memcpy(Spare_palette,Main_palette,sizeof(T_Palette)); // Equivalent of 'end_of_modifications' for spare. Update_spare_buffers(Spare_image_width,Spare_image_height); Redraw_spare_image(); Spare_image_is_modified=1; if (Spare_tilemap_mode) Disable_spare_tilemap(); break; case 2: // Pixels only // backup is done by the following function Copy_image_only(); // Equivalent of 'end_of_modifications' for spare. Update_spare_buffers(Spare_image_width,Spare_image_height); Redraw_spare_image(); Spare_image_is_modified=1; if (Spare_tilemap_mode) Disable_spare_tilemap(); break; case 3: // Palette only Backup_the_spare(LAYER_NONE); // Copy palette memcpy(Spare_palette,Main_palette,sizeof(T_Palette)); // Equivalent of 'end_of_modifications' for spare. Update_spare_buffers(Spare_image_width,Spare_image_height); Redraw_spare_image(); Spare_image_is_modified=1; break; case 4: // Some colors // Will backup if needed Copy_some_colors(); break; case 5: // Palette and remap Backup_the_spare(LAYER_ALL); Remap_spare(); // Copy palette memcpy(Spare_palette,Main_palette,sizeof(T_Palette)); // Equivalent of 'end_of_modifications' for spare. Update_spare_buffers(Spare_image_width,Spare_image_height); Redraw_spare_image(); Spare_image_is_modified=1; break; } Hide_cursor(); Unselect_button(BUTTON_PAGE); Display_cursor(); } // -- Suppression d'une page ------------------------------------------------- void Button_Kill(void) { if ( (Main_backups->List_size==1) || (!Confirmation_box("Delete the current page?")) ) { if (Main_backups->List_size==1) Warning_message("You can't delete the last page."); Hide_cursor(); Unselect_button(BUTTON_KILL); Display_cursor(); } else { Hide_cursor(); Free_current_page(); Set_palette(Main_palette); Compute_optimal_menu_colors(Main_palette); Display_all_screen(); Unselect_button(BUTTON_KILL); Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); Display_menu(); Display_cursor(); } } //------------------------- Dimensions Image/Screen --------------------------- void Check_mode_button(short x_pos, short y_pos, byte state) { byte color; switch (state & 0x7F) { case 0 : color=MC_White; break; case 1 : color=MC_Light; break; case 2 : color=MC_Dark; break; default: color=MC_Black; } Window_rectangle(x_pos, y_pos, 9, 3, color); Update_window_area(x_pos, y_pos,9,3); } /// Number of video modes to display in the resolution menu #define MODELIST_LINES 10 void Display_modes_list(short list_start, short cursor_position) { short index,current_mode; short y_pos; byte text_color,background_color; char str[29]; char *ratio; for (current_mode=list_start,index=0; indexPosition!=list_start) { Window_scroller_button_list->Position=list_start; Window_draw_slider(Window_scroller_button_list); } Display_modes_list(list_start,cursor_position); Display_cursor(); } void Button_Resolution(void) { short clicked_button; int selected_mode; word chosen_width; word chosen_height; byte chosen_pixel; short list_start; short cursor_position; short temp; char str[5]; T_Special_button * input_width_button, * input_button_height; T_Dropdown_button * pixel_button; static const char *pixel_ratio_labels[PIXEL_MAX] ={ "Normal (1x1)", "Wide (2x1)", "Tall (1x2)", "Double (2x2)", "Triple (3x3)", "Wide2 (4x2)", "Tall2 (2x4)", "Tall3 (3x4)", "Quadruple (4x4)"}; Open_window(299,190,"Picture & screen sizes"); Print_in_window( 12, 21,"Picture size:" ,MC_Dark,MC_Light); Window_display_frame ( 8,17,195, 33); Window_set_normal_button(223, 18,67,14,"OK" ,0,1,SDLK_RETURN); // 1 Window_set_normal_button(223, 35,67,14,"Cancel" ,0,1,KEY_ESC); // 2 Print_in_window( 12, 37,"Width:" ,MC_Dark,MC_Light); input_width_button=Window_set_input_button( 60, 35,4); // 3 Print_in_window(108, 37,"Height:" ,MC_Dark,MC_Light); input_button_height=Window_set_input_button(164, 35,4); // 4 Window_display_frame ( 8,72,283,110); Window_display_frame_in (37,84,228,84); Window_rectangle (38,85,226,82,MC_Black); Print_in_window( 16, 76,"OK" ,MC_Dark,MC_Light); Print_in_window( 55, 76,"X Y" ,MC_Dark,MC_Light); Print_in_window(120, 76,"Win / Full" ,MC_Dark,MC_Light); Print_in_window(219, 76,"Ratio" ,MC_Dark,MC_Light); Print_in_window( 30,170,"\03" ,MC_Dark,MC_Light); Print_in_window( 62,170,"OK" ,MC_Dark,MC_Light); Print_in_window(102,170,"Imperfect" ,MC_Dark,MC_Light); Print_in_window(196,170,"Unsupported" ,MC_Dark,MC_Light); Window_set_special_button(38,86,225,80); // 5 selected_mode=Current_resolution; if (selected_mode>=MODELIST_LINES/2 && Nb_video_modes > MODELIST_LINES) { if (selected_mode>3; if (temp0) cursor_position--; else if (list_start>0) list_start--; Scroll_list_of_modes(list_start,cursor_position,&selected_mode); Key=0; break; case SDLK_DOWN : // Bas if (cursor_position<(MODELIST_LINES-1) && cursor_position<(Nb_video_modes-1)) cursor_position++; else if (list_start0) cursor_position=0; else { if (list_start>(MODELIST_LINES-1)) list_start-=(MODELIST_LINES-1); else list_start=0; } Scroll_list_of_modes(list_start,cursor_position,&selected_mode); Key=0; break; case SDLK_PAGEDOWN : // PageDown if (Nb_video_modesNumber; } else { Selected_freehand_mode++; if (Selected_freehand_mode>OPERATION_FILLED_CONTOUR) Selected_freehand_mode=OPERATION_CONTINUOUS_DRAW; } switch(Selected_freehand_mode) { default: case OPERATION_CONTINUOUS_DRAW: icon=-1; break; case OPERATION_DISCONTINUOUS_DRAW: icon=MENU_SPRITE_DISCONTINUOUS_DRAW; break; case OPERATION_POINT_DRAW: icon=MENU_SPRITE_POINT_DRAW; break; case OPERATION_FILLED_CONTOUR: icon=MENU_SPRITE_CONTOUR_DRAW; break; } Display_sprite_in_menu(BUTTON_DRAW,icon); Draw_menu_button(BUTTON_DRAW,BUTTON_PRESSED); Start_operation_stack(Selected_freehand_mode); Display_cursor(); Window_dropdown_clear_items(&dropdown); } // -- Gestion des boutons de rectangle vide et plein ------------------------ void Button_Empty_rectangle(void) { Hide_cursor(); Start_operation_stack(OPERATION_EMPTY_RECTANGLE); Display_cursor(); } void Button_Filled_rectangle(void) { Hide_cursor(); Start_operation_stack(OPERATION_FILLED_RECTANGLE); Display_cursor(); } // -- Gestion des boutons de cercle (ellipse) vide et plein(e) -------------- void Button_Empty_circle(void) { Hide_cursor(); Start_operation_stack(OPERATION_EMPTY_CIRCLE); Display_cursor(); } void Button_Empty_ellipse(void) { Hide_cursor(); Start_operation_stack(OPERATION_EMPTY_ELLIPSE); Display_cursor(); } void Button_Filled_circle(void) { Hide_cursor(); Start_operation_stack(OPERATION_FILLED_CIRCLE); Display_cursor(); } void Button_Filled_ellipse(void) { Hide_cursor(); Start_operation_stack(OPERATION_FILLED_ELLIPSE); Display_cursor(); } // -- Gestion du menu des dgrads ------------------------------------------ void Draw_button_gradient_style(short x_pos,short y_pos,int technique) { short line; // On commence par afficher les 2 cts qui constituent le dgrad de base: // Ct gauche (noir) Window_rectangle(x_pos+2, y_pos+2, 6, 10, MC_Black); // Ct droit (blanc) Window_rectangle(x_pos+8, y_pos+2, 5, 10, MC_White); switch(technique) { case 1 : // Dgrad de trames simples // Au centre, on place 10 lignes trames simplement for (line=2;line<2+10;line++) if (line&1) { // Lignes impaires Pixel_in_window(x_pos+ 5,y_pos+line,MC_White); Pixel_in_window(x_pos+ 7,y_pos+line,MC_White); Pixel_in_window(x_pos+ 8,y_pos+line,MC_Black); } else { // Lignes paires Pixel_in_window(x_pos+ 6,y_pos+line,MC_White); Pixel_in_window(x_pos+ 9,y_pos+line,MC_Black); } break; case 2 : // Dgrad de trames tendues // Au centre, on place 10 lignes trames de faon complique for (line=2;line<2+10;line++) if (line&1) { // Lignes impaires Pixel_in_window(x_pos+ 7,y_pos+line,MC_White); Pixel_in_window(x_pos+ 8,y_pos+line,MC_Black); Pixel_in_window(x_pos+10,y_pos+line,MC_Black); } else { // Lignes paires Pixel_in_window(x_pos+ 4,y_pos+line,MC_White); Pixel_in_window(x_pos+ 6,y_pos+line,MC_White); } } Update_window_area(x_pos+2,y_pos+2,10,10); } void Load_gradient_data(int index) { if (Main_backups->Pages->Gradients->Range[index].Start>Main_backups->Pages->Gradients->Range[index].End) Error(0); Gradient_lower_bound =Main_backups->Pages->Gradients->Range[index].Start; Gradient_upper_bound =Main_backups->Pages->Gradients->Range[index].End; Gradient_is_inverted =Main_backups->Pages->Gradients->Range[index].Inverse; Gradient_random_factor=Main_backups->Pages->Gradients->Range[index].Mix+1; Gradient_bounds_range=(Gradient_lower_boundPages->Gradients->Range[index].Technique) { case 0 : // Degrad de base Gradient_function=Gradient_basic; break; case 1 : // Dgrad de trames simples Gradient_function=Gradient_dithered; break; case 2 : // Dgrad de trames tendues Gradient_function=Gradient_extra_dithered; } } void Draw_gradient_preview(short start_x,short start_y,short width,short height,int index) { short x_pos; // Variables de balayage du block en bas de l'cran. short y_pos; short end_x; short end_y; Load_gradient_data(index); start_x=Window_pos_X+(start_x*Menu_factor_X); start_y=Window_pos_Y+(start_y*Menu_factor_Y); Gradient_total_range=width*Menu_factor_X; end_x=start_x+Gradient_total_range; end_y=start_y+(height*Menu_factor_Y); for (y_pos=start_y;y_posPages->Gradients,sizeof(T_Gradient_array)); Open_window(235,146,"Gradation menu"); Window_set_palette_button(48,19); // 1 // Slider for gradient selection gradient_scroller=Window_set_scroller_button(218,20,75,16,1,Current_gradient); // 2 // Slider for mix mix_scroller = Window_set_scroller_button(31,20,84,256,1, Main_backups->Pages->Gradients->Range[Current_gradient].Mix); // 3 // Direction Window_set_normal_button(8,20,15,14, (Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",0,1,SDLK_TAB); // 4 // Technique Window_set_normal_button(8,90,15,14,"",0,1,SDLK_TAB|MOD_SHIFT); // 5 Draw_button_gradient_style(8,90,Main_backups->Pages->Gradients->Range[Current_gradient].Technique); Window_set_normal_button(178,128,51,14,"OK",0,1,SDLK_RETURN); // 6 Window_set_normal_button(123,128,51,14,"Cancel",0,1,KEY_ESC); // 7 // Scrolling speed speed_scroller = Window_set_horizontal_scroller_button(99,111,130,106,1,Main_backups->Pages->Gradients->Range[Current_gradient].Speed); // 8 Num2str(Main_backups->Pages->Gradients->Range[Current_gradient].Speed,str,3); Print_in_window(73,113,str,MC_Black,MC_Light); Print_in_window(5,58,"MIX",MC_Dark,MC_Light); // Cycling mode on/off Window_set_normal_button(8,109,62,14,"",0,1,KEY_NONE); // 9 Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light); // On tagge les couleurs qui vont avec Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); Num2str(Current_gradient+1,str,2); Print_in_window(215,100,str,MC_Black,MC_Light); // On affiche le cadre autour de la prview Window_display_frame_in(7,127,110,16); // On affiche la preview Draw_gradient_preview(8,128,108,14,Current_gradient); first_color=last_color=(Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?Main_backups->Pages->Gradients->Range[Current_gradient].End:Main_backups->Pages->Gradients->Range[Current_gradient].Start; Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { old_mouse_x=Mouse_X; old_mouse_y=Mouse_Y; old_mouse_k=Mouse_K; if (changed_gradient_index) { // User has changed which gradient (0-15) he's watching changed_gradient_index=0; Hide_cursor(); // On affiche la valeur sous la jauge Num2str(Current_gradient+1,str,2); Print_in_window(215,100,str,MC_Black,MC_Light); // On tagge les couleurs qui vont avec Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // On affiche le sens qui va avec Print_in_window(12,23,(Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light); // On raffiche le mlange (jauge) qui va avec mix_scroller->Position=Main_backups->Pages->Gradients->Range[Current_gradient].Mix; Window_draw_slider(mix_scroller); // Update speed speed_scroller->Position=Main_backups->Pages->Gradients->Range[Current_gradient].Speed; Window_draw_slider(speed_scroller); Num2str(Main_backups->Pages->Gradients->Range[Current_gradient].Speed,str,3); Print_in_window(73,113,str,MC_Black,MC_Light); // Gradient # gradient_scroller->Position=Current_gradient; Window_draw_slider(gradient_scroller); // Technique (flat, dithered, very dithered) Draw_button_gradient_style(8,90,Main_backups->Pages->Gradients->Range[Current_gradient].Technique); // Rectangular gradient preview Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); } clicked_button=Window_clicked_button(); if (Input_sticky_control!=8 || !Mouse_K) { Allow_colorcycling=0; // Restore palette Set_palette(Main_palette); } switch(clicked_button) { case -1 : case 1 : // Palette if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) { Hide_cursor(); temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); if (!old_mouse_k) { // On vient de clicker // On met jour l'intervalle du dgrad first_color=last_color=Main_backups->Pages->Gradients->Range[Current_gradient].Start=Main_backups->Pages->Gradients->Range[Current_gradient].End=temp_color; // On tagge le bloc Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // Trac de la preview: Draw_gradient_preview(8,128,108,14,Current_gradient); } else { // On maintient le click, on va donc tester si le curseur bouge if (temp_color!=last_color) { // On commence par ordonner la 1re et dernire couleur du bloc if (first_colorPages->Gradients->Range[Current_gradient].Start=first_color; Main_backups->Pages->Gradients->Range[Current_gradient].End =temp_color; } else if (first_color>temp_color) { Main_backups->Pages->Gradients->Range[Current_gradient].Start=temp_color; Main_backups->Pages->Gradients->Range[Current_gradient].End =first_color; } else Main_backups->Pages->Gradients->Range[Current_gradient].Start=Main_backups->Pages->Gradients->Range[Current_gradient].End=first_color; // On tagge le bloc Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // Trac de la preview: Draw_gradient_preview(8,128,108,14,Current_gradient); last_color=temp_color; } } Display_cursor(); } break; case 2 : // Nouvel indice de dgrad // Nouvel indice dans Window_attribute2 Current_gradient=Window_attribute2; changed_gradient_index=1; break; case 3 : // Nouveau mlange de dgrad Hide_cursor(); // Nouvel mlange dans Window_attribute2 Main_backups->Pages->Gradients->Range[Current_gradient].Mix=Window_attribute2; // On affiche la nouvelle preview Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); break; case 4 : // Changement de sens Hide_cursor(); // On inverse le sens (par un XOR de 1) Main_backups->Pages->Gradients->Range[Current_gradient].Inverse^=1; Print_in_window(12,23,(Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light); // On affiche la nouvelle preview Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); break; case 5 : // Changement de technique Hide_cursor(); // On change la technique par (+1)%3 Main_backups->Pages->Gradients->Range[Current_gradient].Technique=(Main_backups->Pages->Gradients->Range[Current_gradient].Technique+1)%3; Draw_button_gradient_style(8,90,Main_backups->Pages->Gradients->Range[Current_gradient].Technique); // On affiche la nouvelle preview Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); case 8 : // Speed Main_backups->Pages->Gradients->Range[Current_gradient].Speed=Window_attribute2; Num2str(Main_backups->Pages->Gradients->Range[Current_gradient].Speed,str,3); Hide_cursor(); Print_in_window(73,113,str,MC_Black,MC_Light); Display_cursor(); Allow_colorcycling=1; break; case 9: // Cycling on/off cycling_mode = !cycling_mode; Hide_cursor(); Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light); Display_cursor(); break; } if (!Mouse_K) switch (Key) { case SDLK_BACKQUOTE : // Rcupration d'une couleur derrire le menu case SDLK_COMMA : Get_color_behind_window(&color,&click); if (click) { Hide_cursor(); temp_color=color; // On met jour l'intervalle du dgrad first_color=last_color=Main_backups->Pages->Gradients->Range[Current_gradient].Start=Main_backups->Pages->Gradients->Range[Current_gradient].End=temp_color; // On tagge le bloc Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // Trac de la preview: Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); Wait_end_of_click(); } Key=0; break; case KEY_MOUSEWHEELUP: if (Current_gradient>0) { Current_gradient--; changed_gradient_index=1; } break; case KEY_MOUSEWHEELDOWN: if (Current_gradient<15) { Current_gradient++; changed_gradient_index=1; } break; default: if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Window_help(BUTTON_GRADRECT, NULL); Key=0; break; } else if (Is_shortcut(Key,0x200+BUTTON_GRADRECT)) clicked_button=6; else if (Is_shortcut(Key,SPECIAL_CYCLE_MODE)) { // Cycling on/off cycling_mode = !cycling_mode; Hide_cursor(); Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light); Display_cursor(); } } } while (clicked_button!=6 && clicked_button!=7); Close_window(); // The Grad rect operation uses the same button as Grad menu. if (Current_operation != OPERATION_GRAD_RECTANGLE) Unselect_button(BUTTON_GRADRECT); Display_cursor(); Gradient_pixel=Display_pixel; Cycling_mode=cycling_mode; if (clicked_button==7) // Cancel { Current_gradient=old_current_gradient; memcpy(Main_backups->Pages->Gradients,&backup_gradients,sizeof(T_Gradient_array)); } } // -- Gestion des boutons de cercle / ellipse / rectangle dgrads -------------------- void Button_Grad_circle(void) { Hide_cursor(); Start_operation_stack(OPERATION_GRAD_CIRCLE); Display_cursor(); } void Button_Grad_ellipse(void) { Hide_cursor(); Start_operation_stack(OPERATION_GRAD_ELLIPSE); Display_cursor(); } void Button_Grad_rectangle(void) { Hide_cursor(); Start_operation_stack(OPERATION_GRAD_RECTANGLE); Display_cursor(); } // -- Gestion du bouton de remplissage --------------------------------------- void Button_Fill(void) { if (Current_operation!=OPERATION_FILL) { Hide_cursor(); if (Current_operation!=OPERATION_REPLACE) { Paintbrush_shape_before_fill=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; } else if ( (Mouse_Y=Main_X_zoom) ) ) Print_in_menu("X: Y: ",0); Start_operation_stack(OPERATION_FILL); Display_cursor(); } } void Button_Replace(void) { if (Current_operation!=OPERATION_REPLACE) { Hide_cursor(); if (Current_operation!=OPERATION_FILL) { Paintbrush_shape_before_fill=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; } if ( (Mouse_Y=Main_X_zoom) ) ) Print_in_menu("X: Y: ( )",0); Start_operation_stack(OPERATION_REPLACE); Display_cursor(); } } void Button_Unselect_fill(void) { Paintbrush_shape=Paintbrush_shape_before_fill; if (Current_operation==OPERATION_REPLACE) if ( (Mouse_Y=Main_X_zoom) ) ) Print_in_menu("X: Y: ",0); } //---------------------------- Menu des pinceaux ----------------------------- /// Checks if the current brush is identical to a preset one. byte Same_paintbrush(byte index) { if (Paintbrush_shape!=Paintbrush[index].Shape || Paintbrush_width!=Paintbrush[index].Width || Paintbrush_height!=Paintbrush[index].Height) return 0; if (Paintbrush_shape==PAINTBRUSH_SHAPE_MISC) { // Check all pixels int x,y; for(y=0;y=(NB_PAINTBRUSH_SPRITES+3)) { index = clicked_button-NB_PAINTBRUSH_SPRITES-3; if (Window_attribute2==1) // Set { // Store x_pos=13+((index+NB_PAINTBRUSH_SPRITES)%12)*24; y_pos=27+((index+NB_PAINTBRUSH_SPRITES)/12)*25; Store_brush(index); Hide_cursor(); Display_stored_brush_in_window(x_pos+2, y_pos+2, index); Display_cursor(); } else { // Restore and exit if (Restore_brush(index)) { Close_window(); break; } } } else if (clicked_button>=3) // Standard paintbrushes { if (Window_attribute2!=1) { // Select paintbrush Close_window(); Select_paintbrush(clicked_button-3); break; } else if (Window_attribute2==1) { // Store current index=clicked_button-3; if (!Store_paintbrush(index)) { // Redraw Hide_cursor(); x_pos=13+(index%12)*24; y_pos=27+(index/12)*25; Window_rectangle(x_pos,y_pos,20,20,MC_White); Display_paintbrush_in_window(x_pos+2,y_pos+2,index); Display_cursor(); } } } else if (clicked_button==1 || Is_shortcut(Key,0x100+BUTTON_PAINTBRUSHES)) { Close_window(); break; } else if (clicked_button==2) { int size; // Pick a standard shape Paintbrush_shape=Window_attribute2; // Assign a reasonable size size=Max(Paintbrush_width,Paintbrush_height); if (size==1) size=3; switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_HORIZONTAL_BAR: Set_paintbrush_size(size, 1); break; case PAINTBRUSH_SHAPE_VERTICAL_BAR: Set_paintbrush_size(1, size); break; case PAINTBRUSH_SHAPE_CROSS: case PAINTBRUSH_SHAPE_PLUS: case PAINTBRUSH_SHAPE_DIAMOND: Set_paintbrush_size(size|1,size|1); break; default: Set_paintbrush_size(size,size); break; } Close_window(); Change_paintbrush_shape(Paintbrush_shape); break; } } while (1); Unselect_button(BUTTON_PAINTBRUSHES); Display_cursor(); } void Button_Brush_monochrome(void) { Hide_cursor(); // On passe en brosse monochrome: Change_paintbrush_shape(PAINTBRUSH_SHAPE_MONO_BRUSH); Unselect_button(BUTTON_PAINTBRUSHES); Display_cursor(); } // -- Fonction renvoyant le mode vido le plus adapt l'image charge ----- #define TOLERANCE_X 8 #define TOLERANCE_Y 4 int Best_video_mode(void) { short best_width,best_height; int best_mode; short temp_x,temp_y; int mode; // Si mode fentre, on reste dans ce mode. if (Current_resolution == 0) return 0; // On commence par borner les dimensions, ou du moins les rendre cohrentes if ((Original_screen_X<=0) || (Config.Set_resolution_according_to==2)) Original_screen_X=Main_image_width; else if (Original_screen_X<320) Original_screen_X=320; if ((Original_screen_Y<=0) || (Config.Set_resolution_according_to==2)) Original_screen_Y=Main_image_height; else if (Original_screen_Y<200) Original_screen_Y=200; if ((Original_screen_X>1024) || (Original_screen_Y>768)) { Original_screen_X=1024; Original_screen_Y=768; } // Maintenant on peut chercher le mode qui correspond le mieux best_mode=Current_resolution; best_width=0; best_height=0; for (mode=1; mode On charge/sauve une image // Image=0 => On charge/sauve une brosse { byte confirm; byte old_cursor_shape; int new_mode; T_IO_Context context; static char filename [MAX_PATH_CHARACTERS]; static char directory[MAX_PATH_CHARACTERS]; if (image) { strcpy(filename, Main_backups->Pages->Filename); strcpy(directory, Main_backups->Pages->File_directory); Init_context_layered_image(&context, filename, directory); } else { strcpy(filename, Brush_filename); strcpy(directory, Brush_file_directory); Init_context_brush(&context, filename, directory); } confirm=Button_Load_or_Save(image?&Main_selector:&Brush_selector, 1, &context); if (confirm) { if (image) { if (Main_image_is_modified) confirm=Confirmation_box("Discard unsaved changes?"); } } // confirm is modified inside the first if, that's why we check it // again here if (confirm) { old_cursor_shape=Cursor_shape; Hide_cursor(); Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); if (image) { Original_screen_X=0; Original_screen_Y=0; } Load_image(&context); if (!image) { strcpy(Brush_filename, context.File_name); strcpy(Brush_file_directory, context.File_directory); Brush_fileformat = context.Format; Tiling_offset_X=0; Tiling_offset_Y=0; Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); Select_button(BUTTON_DRAW,LEFT_SIDE); if (Config.Auto_discontinuous) { // On se place en mode Dessin discontinu la main while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) Select_button(BUTTON_DRAW,RIGHT_SIDE); } Hide_cursor(); // On passe en brosse couleur: Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); } else { Hide_cursor(); Cursor_shape=old_cursor_shape; } if ( (File_error==1) || (Get_fileformat(Main_fileformat)->Palette_only) ) { if (File_error!=1) Compute_optimal_menu_colors(Main_palette); } else { if (image) { if (Main_magnifier_mode) { Pixel_preview=Pixel_preview_normal; Main_magnifier_mode=0; Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); } new_mode=Best_video_mode(); if ((Config.Auto_set_res) && (new_mode!=Current_resolution)) { Init_mode_video( Video_mode[new_mode].Width, Video_mode[new_mode].Height, Video_mode[new_mode].Fullscreen, Pixel_ratio); Display_menu(); } // In window mode, activate wide or tall pixels if the image says so. else if (!Video_mode[Current_resolution].Fullscreen && ((context.Ratio == PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) || (context.Ratio == PIXEL_TALL && Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2 && Pixel_ratio != PIXEL_TALL3))) { Init_mode_video( Video_mode[Current_resolution].Width, Video_mode[Current_resolution].Height, Video_mode[Current_resolution].Fullscreen, context.Ratio); Display_menu(); } else { Main_offset_X=0; Main_offset_Y=0; Compute_limits(); Compute_paintbrush_coordinates(); } Compute_optimal_menu_colors(Main_palette); Redraw_layered_image(); End_of_modification(); Check_menu_mode(); Display_all_screen(); Main_image_is_modified=0; } } Destroy_context(&context); Display_menu(); Display_cursor(); } Hide_cursor(); Print_filename(); Display_cursor(); Set_palette(Main_palette); } void Button_Load(void) { // On sauve l'tat actuel des paramtres de l'image pour pouvoir les // restituer en cas d'erreur n'affectant pas l'image Upload_infos_page_main(Main_backups->Pages); Load_picture(1); Tilemap_update(); } void Button_Reload(void) { byte old_cursor_shape; int new_mode; // On sauve l'tat actuel des paramtres de l'image pour pouvoir les // restituer en cas d'erreur n'affectant pas l'image Upload_infos_page_main(Main_backups->Pages); if ( (!Main_image_is_modified) || Confirmation_box("Discard unsaved changes ?") ) { T_IO_Context context; Hide_cursor(); old_cursor_shape=Cursor_shape; Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Original_screen_X=0; Original_screen_Y=0; Init_context_layered_image(&context, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); Load_image(&context); Hide_cursor(); Cursor_shape=old_cursor_shape; if (File_error!=1) { if (Main_magnifier_mode) { Pixel_preview=Pixel_preview_normal; Main_magnifier_mode=0; Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); } new_mode=Best_video_mode(); if ( ((Config.Auto_set_res) && (new_mode!=Current_resolution)) && (!Resolution_in_command_line) ) { Init_mode_video( Video_mode[new_mode].Width, Video_mode[new_mode].Height, Video_mode[new_mode].Fullscreen, Pixel_ratio); Display_menu(); } // In window mode, activate wide or tall pixels if the image says so. else if (!Video_mode[Current_resolution].Fullscreen && ((context.Ratio == PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) || (context.Ratio == PIXEL_TALL && Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2 && Pixel_ratio != PIXEL_TALL3))) { Init_mode_video( Video_mode[Current_resolution].Width, Video_mode[Current_resolution].Height, Video_mode[Current_resolution].Fullscreen, context.Ratio); Display_menu(); } else { Main_offset_X=0; Main_offset_Y=0; Compute_limits(); Compute_paintbrush_coordinates(); } Tilemap_update(); Redraw_layered_image(); End_of_modification(); Check_menu_mode(); Display_all_screen(); Main_image_is_modified=0; } Destroy_context(&context); } else Hide_cursor(); Compute_optimal_menu_colors(Main_palette); Display_menu(); if (Config.Display_image_limits) Display_image_limits(); Unselect_button(BUTTON_LOAD); Display_cursor(); } void Backup_filename(char * fname, char * backup_name) { short i; strcpy(backup_name,fname); for (i=strlen(fname)-strlen(Main_backups->Pages->Filename); backup_name[i]!='.'; i++); backup_name[i+1]='\0'; strcat(backup_name,"BAK"); } void Backup_existing_file(void) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier char new_filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier backup Get_full_filename(filename, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); // Calcul du nom complet du fichier backup Backup_filename(filename,new_filename); File_error=0; // On fait un backup si le nom du fichier n'est pas celui qu'on a choisi // pour nommer les backups (c'est vident!). if (strcmp(new_filename,filename)) { // S'il y avait dj un fichier Backup, on l'efface if ((File_exists(new_filename)) && (remove(new_filename)!=0)) File_error=1; if ((!File_error) && (rename(filename,new_filename)!=0)) File_error=1; } } void Save_picture(enum CONTEXT_TYPE type) { byte confirm; byte old_cursor_shape; T_IO_Context save_context; static char filename [MAX_PATH_CHARACTERS]; static char directory[MAX_PATH_CHARACTERS]; if (type == CONTEXT_MAIN_IMAGE) { strcpy(filename, Main_backups->Pages->Filename); strcpy(directory, Main_backups->Pages->File_directory); Init_context_layered_image(&save_context, filename, directory); save_context.Format = Main_fileformat; } else if (type == CONTEXT_BRUSH) { strcpy(filename, Brush_filename); strcpy(directory, Brush_file_directory); Init_context_brush(&save_context, filename, directory); save_context.Format = Brush_fileformat; } else if (type == CONTEXT_PALETTE) { char* dotpos; strcpy(filename, Main_backups->Pages->Filename); // Replace extension with PAL dotpos = strrchr(filename, '.'); if (dotpos == NULL) dotpos = filename + strlen(filename); strcpy(dotpos, ".pal"); strcpy(directory, Main_backups->Pages->File_directory); Init_context_layered_image(&save_context, filename, directory); save_context.Type = CONTEXT_PALETTE; // Set format to PAL save_context.Format = FORMAT_PAL; } else return; confirm=Button_Load_or_Save((type==CONTEXT_MAIN_IMAGE)?&Main_selector:&Brush_selector,0, &save_context); if (confirm && File_exists(save_context.File_name)) { confirm=Confirmation_box("Erase old file ?"); if (confirm && (Config.Backup)) { Backup_existing_file(); if (File_error) { confirm=0; Error(0); } } } if (confirm) { T_Format * format; old_cursor_shape=Cursor_shape; Hide_cursor(); Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Save_image(&save_context); format=Get_fileformat(save_context.Format); if (!File_error && type == CONTEXT_MAIN_IMAGE && !format->Palette_only && (Main_backups->Pages->Nb_layers==1 || format->Supports_layers)) { Main_image_is_modified=0; Main_fileformat=save_context.Format; strcpy(Main_backups->Pages->Filename, save_context.File_name); strcpy(Main_backups->Pages->File_directory, save_context.File_directory); } if (type == CONTEXT_BRUSH) { Brush_fileformat=save_context.Format; strcpy(Brush_filename, save_context.File_name); strcpy(Brush_file_directory, save_context.File_directory); } Hide_cursor(); Cursor_shape=old_cursor_shape; Display_cursor(); } Destroy_context(&save_context); Print_filename(); Set_palette(Main_palette); } void Button_Save(void) { Save_picture(CONTEXT_MAIN_IMAGE); } /// Save main image over existing file (no fileselector) void Button_Autosave(void) { byte old_cursor_shape; static char filename[MAX_PATH_CHARACTERS]; byte file_already_exists; Get_full_filename(filename, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); file_already_exists=File_exists(filename); if ( (!file_already_exists) || Confirmation_box("Erase old file ?") ) { if ((file_already_exists) && (Config.Backup)) Backup_existing_file(); else File_error=0; Hide_cursor(); if (!File_error) { T_IO_Context save_context; old_cursor_shape=Cursor_shape; Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Init_context_layered_image(&save_context, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); Save_image(&save_context); if (!File_error) { Main_image_is_modified=0; } Destroy_context(&save_context); Hide_cursor(); Cursor_shape=old_cursor_shape; } else Error(0); } else Hide_cursor(); Unselect_button(BUTTON_SAVE); Display_cursor(); } // -- Gestion des boutons de ligne ------------------------------------------ void Button_Lines(void) { Hide_cursor(); Start_operation_stack(Selected_line_mode); Display_cursor(); } void Button_Lines_switch_mode(void) { char icon; if (Selected_line_mode==OPERATION_LINE) Selected_line_mode=OPERATION_K_LINE; else { if (Selected_line_mode==OPERATION_K_LINE) Selected_line_mode=OPERATION_CENTERED_LINES; else Selected_line_mode=OPERATION_LINE; } switch(Selected_line_mode) { default: case OPERATION_LINE: icon=-1; break; case OPERATION_K_LINE: icon=MENU_SPRITE_K_LINE; break; case OPERATION_CENTERED_LINES: icon=MENU_SPRITE_CENTERED_LINES; break; } Hide_cursor(); Display_sprite_in_menu(BUTTON_LINES,icon); Draw_menu_button(BUTTON_LINES,BUTTON_PRESSED); Start_operation_stack(Selected_line_mode); Display_cursor(); } // -- Button de brosse ------------------------------------------------------ void Button_Brush(void) { Hide_cursor(); if (Current_operation!=OPERATION_GRAB_BRUSH) Start_operation_stack(OPERATION_GRAB_BRUSH); else Unselect_button(BUTTON_BRUSH); Display_cursor(); } void Button_Unselect_brush(void) { // On fait de notre mieux pour restaurer l'ancienne opration: Start_operation_stack(Operation_before_interrupt); } void Button_Restore_brush(void) { Hide_cursor(); // On passe en brosse couleur: Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); Unselect_button(BUTTON_BRUSH); Unselect_button(BUTTON_POLYBRUSH); Display_cursor(); } // -- Button de prise de brosse au lasso ------------------------------------ void Button_Lasso(void) { Hide_cursor(); if (Current_operation!=OPERATION_POLYBRUSH) { Paintbrush_shape_before_lasso=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Start_operation_stack(OPERATION_POLYBRUSH); } else Unselect_button(BUTTON_POLYBRUSH); Display_cursor(); } void Button_Unselect_lasso(void) { // On fait de notre mieux pour restaurer l'ancienne opration: Start_operation_stack(Operation_before_interrupt); Paintbrush_shape=Paintbrush_shape_before_lasso; } // -- Button de pipette ----------------------------------------------------- void Button_Colorpicker(void) { Hide_cursor(); if (Current_operation!=OPERATION_COLORPICK) { Colorpicker_color=-1; Start_operation_stack(OPERATION_COLORPICK); Paintbrush_shape_before_colorpicker=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_NONE; if (Operation_before_interrupt!=OPERATION_REPLACE) if ( (Mouse_Y=Main_X_zoom) ) ) Print_in_menu("X: Y: ( )",0); } else Unselect_button(BUTTON_COLORPICKER); Display_cursor(); } void Button_Unselect_colorpicker(void) { // Erase the color block which shows the picked color if (Operation_before_interrupt!=OPERATION_REPLACE) if ( (Mouse_Y=Main_X_zoom) ) ) Print_in_menu("X: Y: ",0); // On fait de notre mieux pour restaurer l'ancienne opration: if (Current_operation==OPERATION_COLORPICK) { Start_operation_stack(Operation_before_interrupt); Paintbrush_shape=Paintbrush_shape_before_colorpicker; } } // -- Inversion de la couleur Fore et de la couleur Back -- void Button_Invert_foreback(void) { byte temp_color; temp_color=Fore_color; Fore_color =Back_color; Back_color =temp_color; Hide_cursor(); Frame_menu_color(Back_color); Frame_menu_color(Fore_color); Reposition_palette(); Display_foreback(); Unselect_button(BUTTON_COLORPICKER); Display_cursor(); } // -- Gestion du bouton Loupe ----------------------------------------------- byte Coming_from_zoom_factor_menu=0; void Button_Magnify(void) { Hide_cursor(); if ( (Current_operation==OPERATION_MAGNIFY) || (Main_magnifier_mode) ) { Unselect_button(BUTTON_MAGNIFIER); } else { Compute_magnifier_data(); if ((!Config.Fast_zoom) || (Mouse_Y>=Menu_Y) || Coming_from_zoom_factor_menu) { Coming_from_zoom_factor_menu=0; Start_operation_stack(OPERATION_MAGNIFY); } else { /* Ceci est de la duplication de code de presque toute l'opration de */ /* la loupe... Il serait peut-tre plus propre de faire une procdure */ /* qui s'en charge... */ // On passe en mode loupe Main_magnifier_mode=1; // La fonction d'affichage dans la partie image est dsormais un affichage // spcial loupe. Pixel_preview=Pixel_preview_magnifier; // On calcule l'origine de la loupe Main_magnifier_offset_X=Mouse_X-(Main_magnifier_width>>1); Main_magnifier_offset_Y=Mouse_Y-(Main_magnifier_height>>1); // Calcul des coordonnes absolues de ce coin DANS L'IMAGE Main_magnifier_offset_X+=Main_offset_X; Main_magnifier_offset_Y+=Main_offset_Y; Clip_magnifier_offsets(&Main_magnifier_offset_X, &Main_magnifier_offset_Y); // On calcule les bornes visibles dans l'cran Position_screen_according_to_zoom(); Compute_limits(); Display_all_screen(); // Repositionner le curseur en fonction des coordonnes visibles Compute_paintbrush_coordinates(); } } Display_cursor(); Update_rect(0,0,0,0); } void Button_Magnify_menu(void) { T_Dropdown_button dropdown; T_Dropdown_choice *item; int i; const char text[NB_ZOOM_FACTORS][4] = {"x2", "x3", "x4", "x5", "x6", "x8", "x10", "x12", "x14", "x16", "x18", "x20", "x24", "x28", "x32"}; Hide_cursor(); dropdown.Pos_X =Buttons_Pool[BUTTON_MAGNIFIER].X_offset; dropdown.Pos_Y =Buttons_Pool[BUTTON_MAGNIFIER].Y_offset; dropdown.Height =Buttons_Pool[BUTTON_MAGNIFIER].Height; dropdown.Dropdown_width=28; dropdown.First_item =NULL; dropdown.Bottom_up =1; for(i = 0; i < NB_ZOOM_FACTORS; i++) { Window_dropdown_add_item(&dropdown, i, text[i]); } item=Dropdown_activate(&dropdown,0,Menu_Y); if (item) { Change_magnifier_factor(item->Number,0); } if ( (!item) && (!Main_magnifier_mode) && (Current_operation!=OPERATION_MAGNIFY) ) // Cancel Unselect_button(BUTTON_MAGNIFIER); Display_all_screen(); Display_cursor(); Update_rect(Main_separator_position,0,Screen_width-Main_separator_position,Menu_Y); if ( (item) && (!Main_magnifier_mode) && (Current_operation!=OPERATION_MAGNIFY) ) // Passage en mode zoom { Coming_from_zoom_factor_menu=1; Select_button(BUTTON_MAGNIFIER,LEFT_SIDE); } Window_dropdown_clear_items(&dropdown); } void Button_Unselect_magnifier(void) { if (Main_magnifier_mode) { // On sort du mode loupe Main_magnifier_mode=0; // --> Recalculer le dcalage de l'cran lorsqu'on sort de la loupe <-- // Centrage "brut" de lcran par rapport la loupe Main_offset_X=Main_magnifier_offset_X-((Screen_width-Main_magnifier_width)>>1); Main_offset_Y=Main_magnifier_offset_Y-((Menu_Y-Main_magnifier_height)>>1); // Correction en cas de dbordement de l'image if (Main_offset_X+Screen_width>Main_image_width) Main_offset_X=Main_image_width-Screen_width; if (Main_offset_X<0) Main_offset_X=0; if (Main_offset_Y+Menu_Y>Main_image_height) Main_offset_Y=Main_image_height-Menu_Y; if (Main_offset_Y<0) Main_offset_Y=0; // La fonction d'affichage dans l'image est dsormais un affichage normal. Pixel_preview=Pixel_preview_normal; // Calculer les bornes visibles dans l'cran Compute_limits(); Display_all_screen(); // <=> Display_screen(); // Repositionner le curseur en fonction des coordonnes visibles Compute_paintbrush_coordinates(); Old_MX = -1; Old_MY = -1; } else // On fait de notre mieux pour restaurer l'ancienne opration: Start_operation_stack(Operation_before_interrupt); } // ----------------------- Modifications de brosse --------------------------- void Button_Brush_FX(void) { short clicked_button; short index; Open_window(310,162,"Brush effects"); Window_display_frame( 6,19,298,61); Window_display_frame( 6,83,122,53); Window_display_frame(137,83,167,53); Window_set_normal_button(236,141, 67,14,"Cancel" ,0,1,KEY_ESC); // 1 Window_set_normal_button( 19, 46, 27,14,"X\035" ,0,1,Config_Key[SPECIAL_FLIP_X][0]); // 2 Window_set_normal_button( 19, 61, 27,14,"Y\022" ,0,1,Config_Key[SPECIAL_FLIP_Y][0]); // 3 Window_set_normal_button( 58, 46, 37,14,"90" ,0,1,Config_Key[SPECIAL_ROTATE_90][0]); // 4 Window_set_normal_button( 96, 46, 37,14,"180" ,0,1,Config_Key[SPECIAL_ROTATE_180][0]); // 5 Window_set_normal_button( 58, 61, 75,14,"any angle" ,0,1,Config_Key[SPECIAL_ROTATE_ANY_ANGLE][0]); // 6 Window_set_normal_button(145, 46, 67,14,"Stretch" ,0,1,Config_Key[SPECIAL_STRETCH][0]); // 7 Window_set_normal_button(145, 61, 67,14,"Distort" ,0,1,Config_Key[SPECIAL_DISTORT][0]); // 8 Window_set_normal_button(155, 99,131,14,"Recolorize" ,0,1,Config_Key[SPECIAL_RECOLORIZE_BRUSH][0]); // 9 Window_set_normal_button(155,117,131,14,"Get brush colors",0,1,Config_Key[SPECIAL_GET_BRUSH_COLORS][0]); // 10 // Boutons reprsentant les coins du brush handle: (HG,HD,C,BG,BD) Window_set_normal_button( 75, 90,11,11,"",0,1,Config_Key[SPECIAL_TOP_LEFT_ATTACHMENT][0]); // 11 Window_set_normal_button(103, 90,11,11,"",0,1,Config_Key[SPECIAL_TOP_RIGHT_ATTACHMENT][0]); // 12 Window_set_normal_button( 89,104,11,11,"",0,1,Config_Key[SPECIAL_CENTER_ATTACHMENT][0]); // 13 Window_set_normal_button( 75,118,11,11,"",0,1,Config_Key[SPECIAL_BOTTOM_LEFT_ATTACHMENT][0]); // 14 Window_set_normal_button(103,118,11,11,"",0,1,Config_Key[SPECIAL_BOTTOM_RIGHT_ATTACHMENT][0]); // 15 Window_set_normal_button(224,46,67,14,"Outline",0,1,Config_Key[SPECIAL_OUTLINE][0]); // 16 Window_set_normal_button(224,61,67,14,"Nibble" ,0,1,Config_Key[SPECIAL_NIBBLE][0]); // 17 Window_set_normal_button( 7,141, 60,14,"Load",0,1,Config_Key[SPECIAL_LOAD_BRUSH][0]); // 18 Window_set_normal_button( 70,141, 60,14,"Save",0,1,Config_Key[SPECIAL_SAVE_BRUSH][0]); // 19 Print_in_window( 80, 24,"Shape modifications",MC_Dark,MC_Light); Print_in_window( 10, 36,"Mirror",MC_Dark,MC_Light); Print_in_window( 72, 36,"Rotate",MC_Dark,MC_Light); Print_in_window(155, 36,"Deform",MC_Dark,MC_Light); Print_in_window(230, 36,"Borders",MC_Dark,MC_Light); Print_in_window(141, 88,"Colors modifications",MC_Dark,MC_Light); Print_in_window( 20,102,"Brush",MC_Dark,MC_Light); Print_in_window( 16,110,"handle",MC_Dark,MC_Light); // Dessin des pointills pour le "brush handle" for (index=0; index<13; index+=2) { Pixel_in_window( 88+index, 92,MC_Dark); Pixel_in_window( 88+index,126,MC_Dark); Pixel_in_window( 77,103+index,MC_Dark); Pixel_in_window(111,103+index,MC_Dark); } // Dessin des coins et du centre pour les boutons du "brush handle" // Coin HG Window_rectangle(77, 92, 7, 1, MC_Black); Window_rectangle(77, 92, 1, 7, MC_Black); // Coin HD Window_rectangle(105, 92, 7, 1, MC_Black); Window_rectangle(111, 92, 1, 7, MC_Black); // Centre Window_rectangle(91, 109, 7, 1, MC_Black); Window_rectangle(94, 106, 1, 7, MC_Black); // Coin BG Window_rectangle(77, 126, 7, 1, MC_Black); Window_rectangle(77, 120, 1, 7, MC_Black); // Coin BD Window_rectangle(105, 126, 7, 1, MC_Black); Window_rectangle(111, 120, 1, 7, MC_Black); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Key=0; Window_help(BUTTON_BRUSH_EFFECTS, NULL); } else if (Is_shortcut(Key,0x100+BUTTON_BRUSH_EFFECTS)) { clicked_button=1; } } while (clicked_button<=0); Close_window(); Unselect_button(BUTTON_BRUSH_EFFECTS); // Gestion du bouton click switch (clicked_button) { case 2 : // Flip X Flip_X_lowlevel(Brush_original_pixels, Brush_width, Brush_height); // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); break; case 3 : // Flip Y Flip_Y_lowlevel(Brush_original_pixels, Brush_width, Brush_height); // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); break; case 4 : // 90 Rotation Rotate_90_deg(); break; case 5 : // 180 Rotation Rotate_180_deg_lowlevel(Brush_original_pixels, Brush_width, Brush_height); Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); break; case 6 : // Any angle rotation Start_operation_stack(OPERATION_ROTATE_BRUSH); break; case 7 : // Stretch Start_operation_stack(OPERATION_STRETCH_BRUSH); break; case 8 : // Distort Start_operation_stack(OPERATION_DISTORT_BRUSH); break; case 9 : // Recolorize Remap_brush(); break; case 10 : // Get brush colors Display_cursor(); Get_colors_from_brush(); Hide_cursor(); break; case 11 : // Brush Attachment: Top-Left Brush_offset_X=0; Brush_offset_Y=0; break; case 12 : // Brush Attachment: Top-Right Brush_offset_X=(Brush_width-1); Brush_offset_Y=0; break; case 13 : // Brush Attachment: Center Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); break; case 14 : // Brush Attachment: Bottom-Left Brush_offset_X=0; Brush_offset_Y=(Brush_height-1); break; case 15 : // Brush Attachment: Bottom-Right Brush_offset_X=(Brush_width-1); Brush_offset_Y=(Brush_height-1); break; case 16 : // Outline Outline_brush(); break; case 17 : // Nibble Nibble_brush(); break; case 18 : // Load Display_cursor(); Load_picture(0); Hide_cursor(); break; case 19 : // Save Display_cursor(); Save_picture(CONTEXT_BRUSH); Hide_cursor(); break; } Display_cursor(); } //---------------------------- Courbes de Bzier ---------------------------- void Button_Curves(void) { Hide_cursor(); Start_operation_stack(Selected_curve_mode); Display_cursor(); } void Button_Curves_switch_mode(void) { if (Selected_curve_mode==OPERATION_4_POINTS_CURVE) Selected_curve_mode=OPERATION_3_POINTS_CURVE; else Selected_curve_mode=OPERATION_4_POINTS_CURVE; Hide_cursor(); Display_sprite_in_menu(BUTTON_CURVES,Selected_curve_mode==OPERATION_4_POINTS_CURVE?MENU_SPRITE_4_POINTS_CURVE:-1); Draw_menu_button(BUTTON_CURVES,BUTTON_PRESSED); Start_operation_stack(Selected_curve_mode); Display_cursor(); } //--------------------------------- Spray ----------------------------------- void Button_Airbrush(void) { Hide_cursor(); Start_operation_stack(OPERATION_AIRBRUSH); Display_cursor(); } void Refresh_airbrush_settings(byte selected_color, byte update_slider) { char str[3]; if (update_slider) { Window_scroller_button_list->Position=49-Airbrush_multi_flow[selected_color]; Window_draw_slider(Window_scroller_button_list); } Num2str(Airbrush_multi_flow[selected_color],str,2); Print_in_window(196,130,str,MC_Black,MC_Light); Update_window_area(Window_palette_button_list->Pos_X+4+(selected_color >> 4)*10, Window_palette_button_list->Pos_Y+3+(selected_color & 15)* 5, 2,5); } void Button_Airbrush_menu(void) { static byte spray_init=1; short clicked_button; char str[4]; word index; byte selected_color=Fore_color; byte old_airbrush_mode =Airbrush_mode; short old_airbrush_size =Airbrush_size; byte old_airbrush_delay =Airbrush_delay; byte old_airbrush_mono_flow=Airbrush_mono_flow; byte old_airbrush_multi_flow[256]; T_Special_button * input_size_button; T_Special_button * input_delay_button; T_Special_button * input_flow_button; T_Special_button * input_init_button; word old_mouse_x; word old_mouse_y; byte old_mouse_k; byte color; byte click; memcpy(old_airbrush_multi_flow,Airbrush_multi_flow,256); Open_window(226,170,"Spray"); Window_set_normal_button(110,148,51,14,"Cancel" ,0,1,KEY_ESC); // 1 Window_set_normal_button(166,148,51,14,"OK" ,0,1,SDLK_RETURN); // 2 Window_set_scroller_button(178,62,74,50,1,49-Airbrush_multi_flow[selected_color]); // 3 Window_set_palette_button(7,56); // 4 Window_set_normal_button( 8,148,83,14,"Mode: ",0,1,SDLK_TAB); // 5 if (Airbrush_mode) Print_in_window(50,151," Mono",MC_Black,MC_Light); else Print_in_window(50,151,"Multi",MC_Black,MC_Light); Window_set_normal_button(194, 62,19,14,"+1" ,0,1,SDLK_KP_PLUS); // 6 Window_set_normal_button(194, 79,19,14,"-1" ,0,1,SDLK_KP_MINUS); // 7 Window_set_normal_button(194, 96,19,14,"x2" ,0,1,SDLK_KP_MULTIPLY); // 8 Window_set_normal_button(194,113,19,14,"2" ,0,1,SDLK_KP_ENTER); // 9 Window_set_normal_button( 8, 37,43,14,"Clear" ,1,1,SDLK_c); // 10 Print_in_window(142,25,"Size:" ,MC_Dark,MC_Light); input_size_button = Window_set_input_button(186,23,3); // 11 Num2str(Airbrush_size,str,3); Window_input_content(input_size_button,str); Print_in_window(142,39,"Delay:" ,MC_Dark,MC_Light); input_delay_button = Window_set_input_button(194,37,2); // 12 Num2str(Airbrush_delay,str,2); Window_input_content(input_delay_button,str); Print_in_window( 27,24,"Mono-Flow:",MC_Dark,MC_Light); input_flow_button = Window_set_input_button(111,22,2); // 13 Num2str(Airbrush_mono_flow,str,2); Window_input_content(input_flow_button,str); Print_in_window( 67,40,"Init:",MC_Dark,MC_Light); input_init_button = Window_set_input_button(111,38,2); // 14 Num2str(spray_init,str,2); Window_input_content(input_init_button,str); Window_display_frame(173,56,45,86); Window_display_frame(137,19,81,33); // On tagge toutes les couleurs utilises for (index=0; index<256; index++) if (Airbrush_multi_flow[index]) Stencil_tag_color(index,MC_Black); // Et enfin, on tagge la couleur slectionne Stencil_tag_color(selected_color,MC_White); Refresh_airbrush_settings(selected_color,0); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); Stencil_update_color(selected_color); do { old_mouse_x=Mouse_X; old_mouse_y=Mouse_Y; old_mouse_k=Mouse_K; clicked_button=Window_clicked_button(); switch (clicked_button) { case 0 : case 2 : // OK break; case 1 : // Cancel Airbrush_mode =old_airbrush_mode; Airbrush_size =old_airbrush_size; Airbrush_delay =old_airbrush_delay; Airbrush_mono_flow=old_airbrush_mono_flow; memcpy(Airbrush_multi_flow,old_airbrush_multi_flow,256); break; case 3 : // Scroller Hide_cursor(); Airbrush_multi_flow[selected_color]=49-Window_attribute2; Refresh_airbrush_settings(selected_color,0); Display_cursor(); break; case -1 : case 4 : // Palette if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) { Hide_cursor(); Stencil_tag_color(selected_color,(Airbrush_multi_flow[selected_color])?MC_Black:MC_Light); Stencil_update_color(selected_color); // Mettre la couleur slectionne jour suivant le click selected_color=(clicked_button==4) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); if (Mouse_K==2) Airbrush_multi_flow[selected_color]=0; else if (Airbrush_multi_flow[selected_color]==0) Airbrush_multi_flow[selected_color]=spray_init; // Tagger la couleur slectionne en blanc Stencil_tag_color(selected_color,MC_White); Refresh_airbrush_settings(selected_color,1); Display_cursor(); Stencil_update_color(selected_color); } break; case 5 : // Toggle Mode Airbrush_mode=(Airbrush_mode+1)&1; Hide_cursor(); if (Airbrush_mode) Print_in_window(50,151," Mono",MC_Black,MC_Light); else Print_in_window(50,151,"Multi",MC_Black,MC_Light); Update_window_area(50,151,5*8,8); Display_cursor(); break; case 6 : // +1 for (index=0; index<256; index++) { if ( (Airbrush_multi_flow[index]) && (Airbrush_multi_flow[index]<49) ) Airbrush_multi_flow[index]++; } Hide_cursor(); Refresh_airbrush_settings(selected_color,1); Display_cursor(); break; case 7 : // -1 for (index=0; index<256; index++) { if (Airbrush_multi_flow[index]>1) Airbrush_multi_flow[index]--; } Hide_cursor(); Refresh_airbrush_settings(selected_color,1); Display_cursor(); break; case 8 : // x2 for (index=0; index<256; index++) { if (Airbrush_multi_flow[index]) { Airbrush_multi_flow[index]<<=1; if (Airbrush_multi_flow[index]>49) Airbrush_multi_flow[index]=49; } } Hide_cursor(); Refresh_airbrush_settings(selected_color,1); Display_cursor(); break; case 9 : // 2 for (index=0; index<256; index++) { if (Airbrush_multi_flow[index]>1) Airbrush_multi_flow[index]>>=1; } Hide_cursor(); Refresh_airbrush_settings(selected_color,1); Display_cursor(); break; case 10 : // Clear memset(Airbrush_multi_flow,0,256); // On raffiche les infos de la couleur slectionne Refresh_airbrush_settings(selected_color,1); // On efface les anciens TAGs Window_clear_tags(); // Tagger la couleur slectionne en blanc Stencil_tag_color(selected_color,MC_White); Stencil_update_color(selected_color); break; case 11 : // Size Num2str(Airbrush_size,str,3); Readline(188,25,str,3,INPUT_TYPE_INTEGER); Airbrush_size=atoi(str); // On corrige les dimensions if (Airbrush_size>256) { Airbrush_size=256; Num2str(Airbrush_size,str,3); Window_input_content(input_size_button,str); } else if (!Airbrush_size) { Airbrush_size=1; Num2str(Airbrush_size,str,3); Window_input_content(input_size_button,str); } Display_cursor(); break; case 12 : // Delay Num2str(Airbrush_delay,str,2); Readline(196,39,str,2,INPUT_TYPE_INTEGER); Airbrush_delay=atoi(str); // On corrige le delai if (Airbrush_delay>99) { Airbrush_delay=99; Num2str(Airbrush_delay,str,2); Window_input_content(input_delay_button,str); } Display_cursor(); break; case 13 : // Mono-Flow Num2str(Airbrush_mono_flow,str,2); Readline(113,24,str,2,INPUT_TYPE_INTEGER); Airbrush_mono_flow=atoi(str); // On corrige le flux if (!Airbrush_mono_flow) { Airbrush_mono_flow=1; Num2str(Airbrush_mono_flow,str,2); Window_input_content(input_flow_button,str); } Display_cursor(); break; case 14 : // Init Num2str(spray_init,str,2); Readline(113,40,str,2,INPUT_TYPE_INTEGER); spray_init=atoi(str); // On corrige la valeur if (spray_init>=50) { spray_init=49; Num2str(spray_init,str,2); Window_input_content(input_init_button,str); } else if (spray_init<1) { spray_init=1; Num2str(spray_init,str,2); Window_input_content(input_init_button,str); } Display_cursor(); break; } if (!Mouse_K) switch (Key) { case SDLK_BACKQUOTE : // Rcupration d'une couleur derrire le menu case SDLK_COMMA : Get_color_behind_window(&color,&click); if (click) { Hide_cursor(); Stencil_tag_color(selected_color,(Airbrush_multi_flow[selected_color])?MC_Black:MC_Light); Stencil_update_color(selected_color); // Mettre la couleur slectionne jour suivant le click selected_color=color; if (click==2) Airbrush_multi_flow[selected_color]=0; else if (Airbrush_multi_flow[selected_color]==0) Airbrush_multi_flow[selected_color]=spray_init; // Tagger la couleur slectionne en blanc Stencil_tag_color(selected_color,MC_White); Refresh_airbrush_settings(selected_color,1); Display_cursor(); Stencil_update_color(selected_color); Wait_end_of_click(); } Key=0; break; default: if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Window_help(BUTTON_AIRBRUSH, NULL); Key=0; break; } if (Is_shortcut(Key,0x200+BUTTON_AIRBRUSH)) { clicked_button=2; break; } } } while ( (clicked_button!=1) && (clicked_button!=2) ); Close_window(); /* // Tant que l'on aura pas rsolu le problme du dsenclenchement du mode // de dessin prcedent, il faudra laisser a en remarque et donc passer en // spray mme si on a click sur Cancel (idem pour OK (un peu plus bas)). if (clicked_button==1) // Cancel { if (Current_operation!=OPERATION_AIRBRUSH) Unselect_button(BUTTON_AIRBRUSH); } */ Display_cursor(); /* if (clicked_button==2) // OK */ if (Current_operation!=OPERATION_AIRBRUSH) Select_button(BUTTON_AIRBRUSH,LEFT_SIDE); } // -- Gestion des boutons de polygone vide et plein ------------------------- void Button_polygon(void) { Hide_cursor(); Start_operation_stack(OPERATION_POLYGON); Display_cursor(); } void Button_Polyform(void) { Hide_cursor(); Start_operation_stack(OPERATION_POLYFORM); Display_cursor(); } void Button_Polyfill(void) { Hide_cursor(); Start_operation_stack(OPERATION_POLYFILL); Display_cursor(); } void Button_Filled_polyform(void) { Hide_cursor(); Start_operation_stack(OPERATION_FILLED_POLYFORM); Display_cursor(); } // -- Boutons d'ajustement de l'image --------------------------------------- void Button_Adjust(void) { Hide_cursor(); Start_operation_stack(OPERATION_SCROLL); Display_cursor(); } // -- Menu des effets (Shade, Stencil, etc...) ------------------------------ void Display_effect_sprite(int sprite_number, short start_x, short start_y) { short x,y,x_pos,y_pos; for (y=0,y_pos=start_y;yEffect_sprite[sprite_number][y][x]); Update_rect(ToWinX(start_x),ToWinY(start_y),EFFECT_SPRITE_WIDTH*Menu_factor_X,EFFECT_SPRITE_HEIGHT*Menu_factor_Y); } void Display_effect_state(short x, short y, char * label, byte state) { Window_rectangle(x+22,y+5,12,8,MC_Light); Print_in_window(x+22,y+5,label,(state)?MC_White:MC_Black,MC_Light); if (state) Window_select_normal_button(x, y, 16, 16); else Window_unselect_normal_button(x, y, 16, 16); } #define C1 10 #define C2 99 #define C3 184 #define L1 19 #define L2 38 #define L3 57 #define L4 76 #define L5 95 void Display_effect_states(void) { Display_effect_state(C1, L2, "Shade" ,Shade_mode); Display_effect_state(C1, L3, "Q-shade",Quick_shade_mode); Display_effect_state(C1, L4, "Transp.",Colorize_mode); Display_effect_state(C1, L5, "Smooth" ,Smooth_mode); Display_effect_state(C2, L5, "Smear" ,Smear_mode); Display_effect_state(C2, L1, "Stencil",Stencil_mode); Display_effect_state(C2, L2, "Mask" ,Mask_mode); Display_effect_state(C2, L3, "Sieve" ,Sieve_mode); Display_effect_state(C3, L2, "Snap" ,Snap_mode); Display_effect_state(C3, L4, "Tiling" ,Tiling_mode); Display_effect_state(C2,L4, "8 bit" ,Main_backups->Pages->Image_mode > IMAGE_MODE_ANIMATION); Display_effect_state(C3,L3, "Tilemap",Main_tilemap_mode); } void Display_feedback_state(void) { Print_in_window(14,24,(Config.FX_Feedback)?"X":" ",MC_Black,MC_Light); } void Button_Effects(void) { short clicked_button; byte exit_by_close_button=0; Open_window(270,152,"Drawing modes (effects)"); Window_set_normal_button(C1, L2, 16,16,"",0,1,Config_Key[SPECIAL_SHADE_MODE][0]); // 1 Window_set_normal_button(C1, L3, 16,16,"",0,1,Config_Key[SPECIAL_QUICK_SHADE_MODE][0]); // 2 Window_set_normal_button(C1, L4, 16,16,"",0,1,Config_Key[SPECIAL_COLORIZE_MODE][0]); // 3 Window_set_normal_button(C1, L5, 16,16,"",0,1,Config_Key[SPECIAL_SMOOTH_MODE][0]); // 4 Window_set_normal_button(C2, L5, 16,16,"",0,1,Config_Key[SPECIAL_SMEAR_MODE][0]); // 5 Window_set_normal_button(C2, L1, 16,16,"",0,1,Config_Key[SPECIAL_STENCIL_MODE][0]); // 6 Window_set_normal_button(C2, L2, 16,16,"",0,1,Config_Key[SPECIAL_MASK_MODE][0]); // 7 Window_set_normal_button(C2, L3, 16,16,"",0,1,Config_Key[SPECIAL_SIEVE_MODE][0]); // 8 Window_set_normal_button(C3, L2, 16,16,"",0,1,Config_Key[SPECIAL_GRID_MODE][0]); // 9 Window_set_normal_button(C3, L4, 16,16,"",0,1,Config_Key[SPECIAL_TILING_MODE][0]); // 10 Window_set_normal_button(195,131, 68,14,"Close",0,1,SDLK_RETURN); // 11 Window_set_normal_button(118,131, 68,14,"All off",0,1,SDLK_DELETE); // 12 // "Feedback" frame Window_display_frame_mono(C1-5,L1+8,90,88,MC_Dark); Window_rectangle(C1-1, L1+2, 78, 14, MC_Light); Window_set_normal_button(C1+1,L1+2,14,14," ",0,1,SDLK_f); // 13 Print_in_window(28,24,"Feedback",MC_Dark,MC_Light); Window_set_normal_button(C2, L4, 16,16,"",0,1,Config_Key[SPECIAL_FORMAT_CHECKER_MENU][0]); // 14 Window_set_normal_button(C3, L3, 16,16,"",0,1,Config_Key[SPECIAL_TILEMAP_MODE][0]); // 15 // "Grid" frame Window_display_frame_mono(C3-5,L1+8,86,88,MC_Dark); Window_rectangle(C3-1, L1+2, 52, 14, MC_Light); Window_set_normal_button(C3+1,L1+2,14,14,Show_grid?"X":" ",0,1,Config_Key[SPECIAL_SHOW_GRID][0]); // 16 Print_in_window(C3+17,L1+5,"Grid",MC_Dark,MC_Light); Display_feedback_state(); Display_effect_sprite(EFFECTS_SPRITE_SHADE, C1+1,L2+1); Display_effect_sprite(EFFECTS_SPRITE_SHADE, C1+1,L3+1); Display_effect_sprite(EFFECTS_SPRITE_TRANSP, C1+1,L4+1); Display_effect_sprite(EFFECTS_SPRITE_SMOOTH, C1+1,L5+1); Display_effect_sprite(EFFECTS_SPRITE_SMEAR, C2+1,L5+1); Display_effect_sprite(EFFECTS_SPRITE_STENCIL,C2+1,L1+1); Display_effect_sprite(EFFECTS_SPRITE_MASK, C2+1,L2+1); Display_effect_sprite(EFFECTS_SPRITE_SIEVE, C2+1,L3+1); Display_effect_sprite(EFFECTS_SPRITE_GRID, C3+1,L2+1); Display_effect_sprite(EFFECTS_SPRITE_TILING, C3+1,L4+1); Display_effect_sprite(EFFECTS_SPRITE_8BIT, C2+1,L4+1); Display_effect_sprite(EFFECTS_SPRITE_TILING, C3+1,L3+1); // tilemap Display_effect_states(); Print_in_window(12,118,"click:",MC_Dark,MC_Light); Print_in_window(16,128,"Left:Switch",MC_Dark,MC_Light); Print_in_window(16,138,"Right:Edit",MC_Dark,MC_Light); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (Key==KEY_ESC || Is_shortcut(Key,0x100+BUTTON_EFFECTS)) { clicked_button=11; Key=0; } else if (Is_shortcut(Key,0x100+BUTTON_HELP)) { // Aide contextuelle switch(Window_get_clicked_button()) { case 1: Window_help(BUTTON_EFFECTS, "SHADE"); break; case 2: Window_help(BUTTON_EFFECTS, "QUICK SHADE"); break; case 3: Window_help(BUTTON_EFFECTS, "TRANSPARENCY"); break; case 4: Window_help(BUTTON_EFFECTS, "SMOOTH"); break; case 5: Window_help(BUTTON_EFFECTS, "SMEAR"); break; case 6: Window_help(BUTTON_EFFECTS, "STENCIL"); break; case 7: Window_help(BUTTON_EFFECTS, "MASK"); break; case 8: Window_help(BUTTON_EFFECTS, "SIEVE"); break; case 9: Window_help(BUTTON_EFFECTS, "GRID"); break; case 10: Window_help(BUTTON_EFFECTS, "TILING"); break; case 15: Window_help(BUTTON_EFFECTS, "TILEMAP"); break; default: Window_help(BUTTON_EFFECTS, NULL); } // Hack because we have used Window_get_clicked_button() Input_sticky_control=0; // } switch (clicked_button) { case 1 : // Shade if (Window_attribute1==LEFT_SIDE) { Button_Shade_mode(); Hide_cursor(); Display_effect_states(); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Shade_menu(); clicked_button=11; } break; case 2 : // Quick-shade if (Window_attribute1==LEFT_SIDE) { Button_Quick_shade_mode(); Hide_cursor(); Display_effect_states(); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Quick_shade_menu(); clicked_button=11; } break; case 3 : // Colorize / Transparency if (Window_attribute1==LEFT_SIDE) { Button_Colorize_mode(); Hide_cursor(); Display_effect_states(); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Colorize_menu(); clicked_button=11; } break; case 4 : // Smooth if (Window_attribute1==LEFT_SIDE) { Button_Smooth_mode(); Hide_cursor(); Display_effect_states(); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Smooth_menu(); clicked_button=11; } break; case 5 : // Smear Button_Smear_mode(); Hide_cursor(); Display_effect_states(); Display_cursor(); break; case 6 : // Stencil if (Window_attribute1==LEFT_SIDE) { Button_Stencil_mode(); Hide_cursor(); Display_effect_state(C2,L1,"Stencil",Stencil_mode); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Stencil_menu(); clicked_button=11; } break; case 7 : // Mask if (Window_attribute1==LEFT_SIDE) { Button_Mask_mode(); Hide_cursor(); Display_effect_state(C2,L2,"Mask",Mask_mode); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Mask_menu(); clicked_button=11; } break; case 8 : // Sieve if (Window_attribute1==LEFT_SIDE) { Button_Sieve_mode(); Hide_cursor(); Display_effect_state(C2,L3,"Sieve",Sieve_mode); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Sieve_menu(); clicked_button=11; } break; case 9 : // Grid if (Window_attribute1==LEFT_SIDE) { Button_Snap_mode(); Hide_cursor(); Display_effect_state(C3,L2,"Snap",Snap_mode); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Grid_menu(); clicked_button=11; } break; case 10 : // Tiling if (Window_attribute1==LEFT_SIDE) { Button_Tiling_mode(); Hide_cursor(); Display_effect_states(); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Tiling_menu(); clicked_button=11; } break; case 11 : // Close exit_by_close_button=1; break; case 12 : // All off Effects_off(); Hide_cursor(); Display_effect_states(); Display_cursor(); break; case 13 : // Feedback (pour Colorize et Shade) Config.FX_Feedback = !Config.FX_Feedback; Update_FX_feedback(Config.FX_Feedback); Hide_cursor(); Display_feedback_state(); Display_cursor(); break; case 14: // Constraint checker/enforcer if (Window_attribute1==LEFT_SIDE) { Button_Constraint_mode(); Hide_cursor(); Display_effect_state(C2,L4, "8 bit" ,Main_backups->Pages->Image_mode > IMAGE_MODE_ANIMATION); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Constraint_menu(); clicked_button = 11; } break; case 15: // Tilemap if (Window_attribute1==LEFT_SIDE) { Button_Tilemap_mode(); Hide_cursor(); Display_effect_state(C3,L3, "Tilemap" ,Main_tilemap_mode); Display_cursor(); } else { Close_window(); Display_cursor(); Button_Tilemap_menu(); clicked_button=11; } break; case 16: // Show grid Show_grid = !Show_grid; Hide_cursor(); Print_in_window(C3+4, L1+5, Show_grid?"X":" ", MC_Black, MC_Light); Display_cursor(); } } while (clicked_button!=11); if (exit_by_close_button) Close_window(); else Hide_cursor(); if (!Any_effect_active()) Unselect_button(BUTTON_EFFECTS); Display_cursor(); } #undef C2 // Callback to display a font name in the list void Draw_one_font_name(word x, word y, word index, byte highlighted) { Print_in_window(x,y,Font_label(index), MC_Black, (highlighted)?MC_Dark:MC_Light); } void Button_Text(void) { static char str[256]=""; static int font_size=32; static int antialias=1; static short list_start=0; // index de le premiere fonte dans le selector static short cursor_position=0; // index de la ligne active dans le selector static short selected_font_index=0; static short is_bold=0; static short is_italic=0; byte * new_brush=NULL; T_Palette text_palette; int new_width; int new_height; int clicked_button; const int NB_FONTS=8; char size_buffer[4]; T_Special_button * input_size_button; T_Special_button * input_text_button; T_Special_button * preview_button; T_Special_button * font_list_button; T_Scroller_button * font_scroller; T_List_button * font_list; byte redraw_is_needed=1; byte preview_is_needed=1; Open_window(288,180,"Text"); // Texte saisi Print_in_window(6,20,"Text:",MC_Dark,MC_Light); input_text_button = Window_set_input_button(48,18,29); // 1 // TrueType options Window_display_frame_in(182,34,100,68); Print_in_window(199,31,"TrueType", MC_Dark, MC_Light); // AA Window_set_normal_button(188,58,13,11,antialias?"X":" ",0,1,SDLK_a); // 2 Print_in_window(206,60,"AntiAlias", MC_Dark, MC_Light); // Bold Window_set_normal_button(188,72,13,11,is_bold?"X":" ",0,1,SDLK_b); // 3 Print_in_window(206,75,"Bold", MC_Dark, MC_Light); // Italic Window_set_normal_button(188,86,13,11,is_italic?"X":" ",0,1,SDLK_i); // 4 Print_in_window(206,89,"Italic", MC_Dark, MC_Light); // Scroller des fontes font_scroller = Window_set_scroller_button(165,35,NB_FONTS*8,Nb_fonts,NB_FONTS,list_start); // 5 // Liste des fontes disponibles font_list_button = Window_set_special_button(8,35,152,NB_FONTS*8); // 6 Window_display_frame_in(7, 33, 154, NB_FONTS*8+4); // Taille texte input_size_button = Window_set_input_button(220,43,3); // 7 Window_set_repeatable_button(202,43,13,11,"-",0,1,SDLK_LAST); // 8 Window_set_repeatable_button(251,43,13,11,"+",0,1,SDLK_LAST); // 9 // Preview preview_button = Window_set_special_button(8,106,273,50); // 10 Window_display_frame_in(7, 105, 275, 52); Window_set_normal_button(8,160,40,14,"OK",0,1,SDLK_RETURN); // 11 Window_set_normal_button(54,160,60,14,"Cancel",0,1,KEY_ESC); // 12 // List of fonts font_list = Window_set_list_button(font_list_button, font_scroller, Draw_one_font_name, 2); // 13 // Restore its settings from last passage in screen font_list->List_start = list_start; font_list->Cursor_position = cursor_position; Window_redraw_list(font_list); Update_window_area(0,0,Window_width, Window_height); // str texte Window_input_content(input_text_button,str); // Taille police redraw_is_needed=1; // -- while (1) { if (redraw_is_needed) { // Taille Num2str(font_size,size_buffer,3); Window_input_content(input_size_button,size_buffer); } if (preview_is_needed) { const char * preview_string = "AaBbCcDdEeFf012345"; byte is_truetype; if (str[0]) preview_string=str; is_truetype=TrueType_font(selected_font_index); free(new_brush); new_brush = Render_text(preview_string, selected_font_index, font_size, antialias, is_bold, is_italic, &new_width, &new_height, text_palette); // Background: if (antialias&&is_truetype) // Solid Window_rectangle(8, 106, 273, 50,MC_Black); else if (is_truetype) { long l = text_palette[Fore_color].R+text_palette[Fore_color].G+text_palette[Fore_color].B; Window_rectangle(8, 106, 273, 50,l>128*3? MC_Black:MC_Light); } else { long l = text_palette[Back_color].R+text_palette[Back_color].G+text_palette[Back_color].B; Window_rectangle(8, 106, 273, 50,l>128*3? MC_Light:MC_Black); } if (new_brush) { if (!is_truetype || (is_truetype&&antialias)) { // Display brush in remapped form. byte *remapped_brush; remapped_brush=(byte *)malloc(new_width*new_height); if (remapped_brush) { // This code is mostly copied from Remap_brush() short x_pos; short y_pos; int color; byte colmap[256]; for (color=0;color<=255;color++) colmap[color]=0; for (y_pos=0;y_posPos_X*Menu_factor_X, Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y, 0, 0, Min(preview_button->Width*Menu_factor_X, new_width), Min(preview_button->Height*Menu_factor_Y, new_height), Back_color, new_width); free(remapped_brush); } } else { // Solid Display_brush( new_brush, Window_pos_X+preview_button->Pos_X*Menu_factor_X, Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y, 0, 0, Min(preview_button->Width*Menu_factor_X, new_width), Min(preview_button->Height*Menu_factor_Y, new_height), Back_color, new_width); } } Update_window_area( preview_button->Pos_X, preview_button->Pos_Y, preview_button->Width, preview_button->Height); } if (redraw_is_needed || preview_is_needed) { redraw_is_needed=0; preview_is_needed=0; Display_cursor(); } clicked_button=Window_clicked_button(); if (clicked_button==0) { if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_TEXT, NULL); else if (Is_shortcut(Key,0x100+BUTTON_TEXT)) clicked_button=12; } switch(clicked_button) { case 1: // Texte saisi Readline_ex(50,20,str,29,250,INPUT_TYPE_STRING,0); preview_is_needed=1; break; case 2: // AA antialias = (antialias==0); Hide_cursor(); Print_in_window(191,60,antialias?"X":" ", MC_Black, MC_Light); preview_is_needed=1; break; case 3: // Bold is_bold = (is_bold==0); Hide_cursor(); Print_in_window(191,74,is_bold?"X":" ", MC_Black, MC_Light); preview_is_needed=1; break; case 4: // Italic is_italic = (is_italic==0); Hide_cursor(); Print_in_window(191,88,is_italic?"X":" ", MC_Black, MC_Light); preview_is_needed=1; break; case 5: // Scroller des fontes /* Cannot happen, event is catched by the list control */ break; case 13: // Font selection selected_font_index = Window_attribute2; Hide_cursor(); preview_is_needed=1; break; case 7: // Taille du texte (nombre) Readline(222,45,size_buffer,3,INPUT_TYPE_INTEGER); font_size=atoi(size_buffer); // On corrige les dimensions if (font_size < 1) { font_size = 1; } else if (font_size>500) { font_size = 500; } redraw_is_needed=1; preview_is_needed=1; break; case 8: // Taille - if (font_size > 1) { font_size--; Hide_cursor(); redraw_is_needed=1; preview_is_needed=1; } break; case 9: // Taille + if (font_size < 255) { font_size++; Hide_cursor(); redraw_is_needed=1; preview_is_needed=1; } break; case 6: // Double-click font selector case 11: // OK // Save the selector settings list_start = font_list->List_start; cursor_position = font_list->Cursor_position; if (!new_brush) { // Si echec de rendu Close_window(); Unselect_button(BUTTON_TEXT); Display_cursor(); Error(0); return; } if (Realloc_brush(new_width, new_height, new_brush, NULL)) { free(new_brush); Close_window(); Unselect_button(BUTTON_TEXT); Display_cursor(); Error(0); } // Grab palette memcpy(Brush_original_palette, text_palette,sizeof(T_Palette)); // Remap to image's palette Remap_brush(); Brush_offset_X=Brush_width>>1; Brush_offset_Y=Brush_height>>1; // Fermeture Close_window(); Unselect_button(BUTTON_TEXT); // On passe en brosse: Display_cursor(); if (antialias || !TrueType_font(selected_font_index)) Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); else Change_paintbrush_shape(PAINTBRUSH_SHAPE_MONO_BRUSH); // Activate alpha mode if (antialias && TrueType_font(selected_font_index)) { Shade_mode=0; Quick_shade_mode=0; Smooth_mode=0; Tiling_mode=0; Smear_mode=0; Colorize_mode=1; Colorize_current_mode=3; Effect_function=Effect_alpha_colorize; Draw_menu_button(BUTTON_EFFECTS,BUTTON_PRESSED); } Select_button(BUTTON_DRAW,LEFT_SIDE); if (Config.Auto_discontinuous) { // On se place en mode Dessin discontinu la main while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) Select_button(BUTTON_DRAW,RIGHT_SIDE); } //Display_cursor(); return; case 12: // Cancel // Save the selector settings list_start = font_list->List_start; cursor_position = font_list->Cursor_position; free(new_brush); new_brush = NULL; Close_window(); Unselect_button(BUTTON_TEXT); Display_cursor(); return; } } } void Display_stored_brush_in_window(word x_pos,word y_pos,int index) { if (Brush_container[index].Paintbrush_shape < PAINTBRUSH_SHAPE_MAX) { int x,y; int offset_x=0, offset_y=0; //int brush_offset_x=0, brush_offset_y=0; // Determine draw offset (small brushes are stacked on corner of their preview) if (Brush_container[index].WidthBRUSH_CONTAINER_PREVIEW_WIDTH) brush_offset_x = (Paintbrush_width-BRUSH_CONTAINER_PREVIEW_WIDTH)/2; if (Paintbrush_height>BRUSH_CONTAINER_PREVIEW_HEIGHT) brush_offset_y = (Paintbrush_height-BRUSH_CONTAINER_PREVIEW_HEIGHT)/2; for (y=0; yBRUSH_CONTAINER_PREVIEW_WIDTH || Brush_height>BRUSH_CONTAINER_PREVIEW_HEIGHT) { // Scale Rescale(Brush_original_pixels, Brush_width, Brush_height, (byte *)(Brush_container[index].Thumbnail), BRUSH_CONTAINER_PREVIEW_WIDTH, BRUSH_CONTAINER_PREVIEW_HEIGHT, 0, 0); } else { // Direct copy Copy_part_of_image_to_another(Brush_original_pixels, 0,0,Brush_width, Brush_height,Brush_width,(byte *)(Brush_container[index].Thumbnail),0,0,BRUSH_CONTAINER_PREVIEW_WIDTH); } } else { Error(0); } } } /// Retrieve a normal paintbrush void Select_paintbrush(int index) { int x_pos,y_pos; Paintbrush_shape=Paintbrush[index].Shape; if (Paintbrush[index].Width<=PAINTBRUSH_WIDTH && Paintbrush[index].Height<=PAINTBRUSH_HEIGHT) { Paintbrush_width=Paintbrush[index].Width; Paintbrush_height=Paintbrush[index].Height; Paintbrush_offset_X=Paintbrush[index].Offset_X; Paintbrush_offset_Y=Paintbrush[index].Offset_Y; for (y_pos=0; y_posPAINTBRUSH_WIDTH) x_off=(Paintbrush_width-PAINTBRUSH_WIDTH)/2; if (Paintbrush_height>PAINTBRUSH_HEIGHT) y_off=(Paintbrush_height-PAINTBRUSH_HEIGHT)/2; for (y_pos=0; y_pos>1; Paintbrush_offset_Y=Paintbrush_height>>1; } else { // Recreate the brush pixels from its shape and dimensions Set_paintbrush_size(Paintbrush_width,Paintbrush_height); } } // Color brushes if (shape == PAINTBRUSH_SHAPE_COLOR_BRUSH || shape == PAINTBRUSH_SHAPE_MONO_BRUSH) { Paintbrush_shape=shape; if (!Realloc_brush(Brush_container[index].Width,Brush_container[index].Height,NULL,NULL)) { // Recover pixels memcpy(Brush_original_pixels, Brush_container[index].Brush, (long)Brush_height*Brush_width); // Grab palette memcpy(Brush_original_palette, Brush_container[index].Palette, sizeof(T_Palette)); // Recover colormap memcpy(Brush_colormap, Brush_container[index].Colormap, 256); // Remap using current colormap Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Brush_offset_X=Brush_width>>1; Brush_offset_Y=Brush_height>>1; } } Change_paintbrush_shape(shape); return 1; } void Button_Brush_container(void) { short clicked_button; short x_pos,y_pos; byte index; Open_window(BRUSH_CONTAINER_COLUMNS*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+8, BRUSH_CONTAINER_ROWS*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+40, "Brushes"); Window_set_normal_button( (BRUSH_CONTAINER_COLUMNS*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)-59)/2, (BRUSH_CONTAINER_ROWS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18, 67,14,"Cancel",0,1,KEY_ESC); // 1 index=0; for (index=0; index < BRUSH_CONTAINER_ROWS*BRUSH_CONTAINER_COLUMNS; index++) { x_pos = (index % BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+7; y_pos = (index / BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18; Window_set_normal_button( x_pos, y_pos, BRUSH_CONTAINER_PREVIEW_WIDTH+2, BRUSH_CONTAINER_PREVIEW_HEIGHT+2, "",0,1,SDLK_LAST); Display_stored_brush_in_window(x_pos+1, y_pos+1, index); } Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); //if (Is_shortcut(Key,0x100+BUTTON_HELP)) // Window_help(BUTTON_PAINTBRUSHES, NULL); if (clicked_button == 1) break; if (clicked_button>1) { index = clicked_button-2; if (Window_attribute1==RIGHT_SIDE) { // Store x_pos = (index % BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+7; y_pos = (index / BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18; Store_brush(index); Hide_cursor(); Display_stored_brush_in_window(x_pos+1, y_pos+1, index); Display_cursor(); } else { // Restore and exit if (Restore_brush(index)) break; } } } while (1); Close_window(); //Unselect_button(BUTTON_PAINTBRUSHES); Display_cursor(); } byte Any_effect_active(void) { return Shade_mode||Quick_shade_mode||Colorize_mode||Smooth_mode||Tiling_mode||Smear_mode ||Stencil_mode||Mask_mode||Sieve_mode||Snap_mode||Main_tilemap_mode || (Main_backups->Pages->Image_mode > IMAGE_MODE_ANIMATION); } grafx2_2.4+git20180105/src/graph.h0000664000000000000000000001452613223665306015011 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007-2008 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file graph.h /// Graphic functions that target the screen and/or image. ////////////////////////////////////////////////////////////////////////////// void Shade_list_to_lookup_tables(word * list, short step, byte mode, byte * table_inc, byte * table_dec ); void Transform_point(short x, short y, float cos_a, float sin_a, short * rx, short * ry); int Init_mode_video(int width, int height, int fullscreen,int pixel_ratio); byte No_effect(word x,word y,byte color); byte Effect_shade(word x,word y,byte color); byte Effect_quick_shade(word x,word y,byte color); byte Effect_tiling(word x,word y,byte color); byte Effect_smooth(word x,word y,byte color); byte Effect_layer_copy(word x,word y,byte color); void Display_foreback(void); void Display_pixel(word x,word y,byte color); void Display_paintbrush(short x,short y,byte color); void Draw_paintbrush(short x,short y,byte color); void Hide_paintbrush(short x,short y); void Resize_image(word chosen_width,word chosen_height); void Fill_general(byte fill_color); void Replace(byte New_color); void Pixel_figure_preview (word x_pos,word y_pos,byte color); void Pixel_figure_preview_auto(word x_pos,word y_pos); void Pixel_figure_preview_xor(short x_pos,short y_pos,byte color); void Pixel_figure_preview_xorback(word x_pos,word y_pos,byte color); void Pixel_figure_in_brush(word x_pos,word y_pos,byte color); void Draw_empty_circle_general(short center_x,short center_y,short radius,byte color); void Draw_empty_circle_permanent(short center_x,short center_y,short radius,byte color); void Draw_empty_circle_preview (short center_x,short center_y,short radius,byte color); void Hide_empty_circle_preview (short center_x,short center_y,short radius); void Draw_empty_circle_general(short center_x,short center_y,short radius,byte color); void Draw_filled_circle (short center_x,short center_y,short radius,byte color); int Circle_squared_diameter(int diameter); void Draw_empty_ellipse_permanent(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color); void Draw_empty_ellipse_preview (short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color); void Hide_empty_ellipse_preview (short center_x,short center_y,short horizontal_radius,short vertical_radius); void Draw_filled_ellipse (short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color); void Clamp_coordinates_regular_angle(short ax, short ay, short* bx, short* by); void Draw_line_general(short start_x,short start_y,short end_x,short end_y, byte color); void Draw_line_permanent (short start_x,short start_y,short end_x,short end_y,byte color); void Draw_line_preview (short start_x,short start_y,short end_x,short end_y,byte color); void Draw_line_preview_xor(short start_x,short start_y,short end_x,short end_y,byte color); void Draw_line_preview_xorback(short start_x,short start_y,short end_x,short end_y,byte color); void Hide_line_preview (short start_x,short start_y,short end_x,short end_y); void Draw_empty_rectangle(short start_x,short start_y,short end_x,short end_y,byte color); void Draw_filled_rectangle(short start_x,short start_y,short end_x,short end_y,byte color); void Draw_curve_permanent(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color); void Draw_curve_preview (short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color); void Hide_curve_preview (short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color); void Airbrush(short clicked_button); void Gradient_basic (long index,short x_pos,short y_pos); void Gradient_dithered (long index,short x_pos,short y_pos); void Gradient_extra_dithered(long index,short x_pos,short y_pos); void Degrade_aleatoire (long index,short x_pos,short y_pos); void Draw_grad_circle (short center_x,short center_y,short radius,short spot_x,short spot_y); void Draw_grad_ellipse(short center_x,short center_y,short horizontal_radius,short vertical_radius,short spot_x,short spot_y); void Draw_grad_rectangle(short rax,short ray,short rbx,short rby,short vax,short vay, short vbx, short vby); void Polyfill_general(int vertices, short * points, int color); void Polyfill(int vertices, short * points, int color); /// Remap the spare page according to the main page's palette void Remap_spare(void); /// /// All the figure-drawing functions work by calling this function for each /// pixel to draw. Before calling these functions, you should assign /// ::Pixel_figure depending on what you where you want to draw: /// - ::Pixel_figure_preview : On screen. /// - ::Pixel_figure_preview_xor : On screen, XORing the color. /// - ::Pixel_figure_permanent : On screen and in the image. /// - ::Pixel_figure_clear_preview : On screen, reverting to the image's pixels. extern Func_pixel Pixel_figure; void Update_part_of_screen(short x, short y, short width, short height); void Redraw_grid(short x, short y, unsigned short w, unsigned short h); void Pixel_in_spare(word x,word y, byte color); void Pixel_in_current_layer(word x,word y, byte color); byte Read_pixel_from_current_screen (word x,word y); byte Read_pixel_from_current_layer(word x,word y); /// Paint a single pixel in image only. extern Func_pixel Pixel_in_current_screen; /// Paint a single pixel in image AND on screen. extern Func_pixel Pixel_in_current_screen_with_preview; /// Sets ::Pixel_in_current_screen and ::Pixel_in_current_screen_with_preview void Update_pixel_renderer(void); grafx2_2.4+git20180105/src/grafx2.rdef0000664000000000000000000000410413223665306015561 0ustar rootroot resource vector_icon array { $"6E6369660705000300FFFF036E0070020006023EEB4C3EBC16BEBC163EEB4C4B" $"486546B13B0005AAFFFF0422B8020102023F30000000000000003F0000488000" $"48C000FF04FCFFFF0080FFEB0005FF02010202BECF30AFF9E52FA1B2BE90DF4B" $"0DC74AD26C004D037C00FF73096FFF0C0A1020203420402C4C20602060345440" $"604C60604C60405434602060204C2C4020340A06B3BEB3D33522382626262638" $"22350A065E224C22402E43314E265A260A06B3CB5EB3CB4C2E403143264E265A" $"0A04B5532A2A2A2A2EB5532E0A042A2E2E2E2E322A320A042A362E362E3A2A3A" $"0A0432B54636B546362A322A0A04322E362E36323232060FFFAFAA3FC2A9C2C4" $"C38CC1E5C1C6C3A4C2A9C5EDC1C6C50EC2A9C5EDC332C567C332C567C29BC4D2" $"C332C34BC29BC3E0C3CAC2B6C557C34BC4C0C2B6C597C38AC5C5C428C5BBC3D8" $"C5C5C428C5C5C8FBC66AC99D51C982C77CC890C9A1C674C918C5ED51C87451C8" $"74C682C6FF51C413C687C589C676C399C5E0C2C4C640C322C4FDC1E50637FFAA" $"FEFFAAAAAAAAA86A86FAAB3FB771C442B771C442B663C551B771C816B663C707" $"B880C924BB45C816BA36C924BBE5C776BC09C5CABC26C69BBC09C5CABCCCC68E" $"BD2EC62CBB45C442BA1FC568BA81C5CABB38C513BB38C513BBB6C5E7BAE3C7B4" $"BB99C6FDBA0AC88CB7D3C7B4B8ACC88CB6FBC6DCB7D3C4A4B6FBC57DB7D3C4A4" $"BB45C133BB45C133BBB1C0C7BCCCC133BC60C0C7BD39C19FBCCCC2BBBD39C24F" $"BCCCC2BBBC09C37FBDF2C568BE54C506BD07C3B9BF63C3F7C102C259BF7AC0D1" $"C102BF4947C0D1C411BF49473BC3AFBC9CC34DBC3AC228BD60C0A0BBD8C214BA" $"64C523C523BE37C5ADBDAEC5ADBA64C8F7BA64C980B9DAC5ADB9DAB607C523B6" $"91B9DAC1DABFDCBBD8C34DBF4947C00DC03E3BC03E3BBF9CBD1FBDF23BBE94BD" $"1FBD50BE64BDF2C00DBD50BF6BBDF2C00DC03EC259BF2FC368BD1CC32FBD2EC3" $"1DBD2EC31DBDD1C27ABD2EC0D1BDD1C173BC8CC02FBAE3C0D1BB85C02FBAE3C0" $"D10A042AB5532EB5532E2A2A2A080A030100000A02010102BFFFFC3098AAB098" $"AABFFFFC4BFEDD4BFEF20A01070401050607080B000A0501091001158200040A" $"05010A1001178110040A04020203000A000100100217830004157F00040A0602" $"030202C0000018ED4E98ED4EC000004C00004BFFFF" }; resource app_signature "application/x-vnd.GrafX2"; resource app_version { major = 2, middle = 5, minor = 2126, variety = B_APPV_BETA, internal = 0, short_info = "GrafX2", long_info = "The ultimate 256-color painting program" }; grafx2_2.4+git20180105/src/special.h0000664000000000000000000000355413223665307015330 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include "struct.h" ////////////////////////////////////////////////////////////////////////////// ///@file special.h /// Editor functions that can be hooked to a keyboard shortcut, but don't have /// a menu button associated to them. ////////////////////////////////////////////////////////////////////////////// void Set_paintbrush_size(int width, int height); void Smaller_paintbrush(void); void Bigger_paintbrush(void); void Special_next_forecolor(void); void Special_previous_forecolor(void); void Special_next_backcolor(void); void Special_previous_backcolor(void); void Special_next_user_forecolor(void); void Special_previous_user_forecolor(void); void Special_next_user_backcolor(void); void Special_previous_user_backcolor(void); void Scroll_screen(short delta_x,short delta_y); void Scroll_magnifier(short delta_x,short delta_y); void Zoom(short delta); void Zoom_set(int index); void Display_stored_brush_in_window(word x,word y,int number); void Store_brush(int index); byte Restore_brush(int index); /*! Command that sets the transparency level. */ void Transparency_set(byte amount); grafx2_2.4+git20180105/src/SDLMain.m0000664000000000000000000002664713223665306015153 0ustar rootroot/* SDLMain.m - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn Feel free to customize this file to suit your needs */ #import "SDL.h" #import "SDLMain.h" #import /* for MAXPATHLEN */ #import /* For some reaon, Apple removed setAppleMenu from the headers in 10.4, but the method still is there and works. To avoid warnings, we declare it ourselves here. */ @interface NSApplication(SDL_Missing_Methods) - (void)setAppleMenu:(NSMenu *)menu; @end /* Use this flag to determine whether we use SDLMain.nib or not */ #define SDL_USE_NIB_FILE 0 /* Use this flag to determine whether we use CPS (docking) or not */ #define SDL_USE_CPS 1 #ifdef SDL_USE_CPS /* Portions of CPS.h */ typedef struct CPSProcessSerNum { UInt32 lo; UInt32 hi; } CPSProcessSerNum; extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); #endif /* SDL_USE_CPS */ static int gArgc; static char **gArgv; static BOOL gFinderLaunch; static BOOL gCalledAppMainline = FALSE; static NSString *getApplicationName(void) { NSDictionary *dict; NSString *appName = 0; /* Determine the application name */ dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); if (dict) appName = [dict objectForKey: @"CFBundleName"]; if (![appName length]) appName = [[NSProcessInfo processInfo] processName]; return appName; } #if SDL_USE_NIB_FILE /* A helper category for NSString */ @interface NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; @end #endif @interface SDLApplication : NSApplication @end @implementation SDLApplication /* Invoked from the Quit menu item */ - (void)terminate:(id)sender { /* Post a SDL_QUIT event */ SDL_Event event; event.type = SDL_QUIT; SDL_PushEvent(&event); } /* override NSApplication:sendEvent, to keep Cocoa from beeping on non-command keystrokes */ - (void)sendEvent:(NSEvent *)anEvent { if (NSKeyDown == [anEvent type] || NSKeyUp == [anEvent type]) { if ([anEvent modifierFlags] & NSCommandKeyMask) { // SDL_SetModState(SDL_GetModState() /*| KMOD_META*/); [super sendEvent: anEvent]; } } else { [super sendEvent: anEvent]; } } @end /* The main class of the application, the application's delegate */ @implementation SDLMain /* Set the working directory to the .app's parent directory */ - (void) setupWorkingDirectory:(BOOL)shouldChdir { if (shouldChdir) { char parentdir[MAXPATHLEN]; CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) { assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ } CFRelease(url); CFRelease(url2); } } #if SDL_USE_NIB_FILE /* Fix menu to contain the real app name instead of "SDL App" */ - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName { NSRange aRange; NSEnumerator *enumerator; NSMenuItem *menuItem; aRange = [[aMenu title] rangeOfString:@"SDL App"]; if (aRange.length != 0) [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; enumerator = [[aMenu itemArray] objectEnumerator]; while ((menuItem = [enumerator nextObject])) { aRange = [[menuItem title] rangeOfString:@"SDL App"]; if (aRange.length != 0) [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; if ([menuItem hasSubmenu]) [self fixMenu:[menuItem submenu] withAppName:appName]; } [ aMenu sizeToFit ]; } #else static void setApplicationMenu(void) { /* warning: this code is very odd */ NSMenu *appleMenu; NSMenuItem *menuItem; NSString *title; NSString *appName; appName = getApplicationName(); appleMenu = [[NSMenu alloc] initWithTitle:@""]; /* Add menu items */ title = [@"About " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Hide " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Quit " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; /* Put menu into the menubar */ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; [menuItem setSubmenu:appleMenu]; [[NSApp mainMenu] addItem:menuItem]; /* Tell the application object that this is now the application menu */ [NSApp setAppleMenu:appleMenu]; /* Finally give up our references to the objects */ [appleMenu release]; [menuItem release]; } /* Create a window menu */ static void setupWindowMenu(void) { NSMenu *windowMenu; NSMenuItem *windowMenuItem; NSMenuItem *menuItem; windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; /* "Minimize" item */ menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; [windowMenu addItem:menuItem]; [menuItem release]; /* Put menu into the menubar */ windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; [windowMenuItem setSubmenu:windowMenu]; [[NSApp mainMenu] addItem:windowMenuItem]; /* Tell the application object that this is now the window menu */ [NSApp setWindowsMenu:windowMenu]; /* Finally give up our references to the objects */ [windowMenu release]; [windowMenuItem release]; } /* Replacement for NSApplicationMain */ static void CustomApplicationMain (int argc, char **argv) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDLMain *sdlMain; /* Ensure the application object is initialised */ [SDLApplication sharedApplication]; #ifdef SDL_USE_CPS { CPSProcessSerNum PSN; /* Tell the dock about us */ if (!CPSGetCurrentProcess(&PSN)) if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) if (!CPSSetFrontProcess(&PSN)) [SDLApplication sharedApplication]; } #endif /* SDL_USE_CPS */ /* Set up the menubar */ [NSApp setMainMenu:[[NSMenu alloc] init]]; setApplicationMenu(); setupWindowMenu(); /* Create SDLMain and make it the app delegate */ sdlMain = [[SDLMain alloc] init]; [NSApp setDelegate:sdlMain]; /* Start the main event loop */ [NSApp run]; [sdlMain release]; [pool release]; } #endif /* * Catch document open requests...this lets us notice files when the app * was launched by double-clicking a document, or when a document was * dragged/dropped on the app's icon. You need to have a * CFBundleDocumentsType section in your Info.plist to get this message, * apparently. * * Files are added to gArgv, so to the app, they'll look like command line * arguments. Previously, apps launched from the finder had nothing but * an argv[0]. * * This message may be received multiple times to open several docs on launch. * * This message is ignored once the app's mainline has been called. */ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { const char *temparg; size_t arglen; char *arg; char **newargv; if (!gFinderLaunch) /* MacOS is passing command line args. */ return FALSE; if (gCalledAppMainline) /* app has started, ignore this document. */ return FALSE; temparg = [filename UTF8String]; arglen = SDL_strlen(temparg) + 1; arg = (char *) SDL_malloc(arglen); if (arg == NULL) return FALSE; newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); if (newargv == NULL) { SDL_free(arg); return FALSE; } gArgv = newargv; SDL_strlcpy(arg, temparg, arglen); gArgv[gArgc++] = arg; gArgv[gArgc] = NULL; return TRUE; } /* Called when the internal event loop has just started running */ - (void) applicationDidFinishLaunching: (NSNotification *) note { int status; /* Set the working directory to the .app's parent directory */ [self setupWorkingDirectory:gFinderLaunch]; #if SDL_USE_NIB_FILE /* Set the main menu to contain the real app name instead of "SDL App" */ [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; #endif setenv("SDL_ENABLEAPPEVENTS", "1", 1); /* Hand off to main application code */ gCalledAppMainline = TRUE; status = SDL_main (gArgc, gArgv); /* We're done, thank you for playing */ exit(status); } @end @implementation NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString { unsigned int bufferSize; unsigned int selfLen = [self length]; unsigned int aStringLen = [aString length]; unichar *buffer; NSRange localRange; NSString *result; bufferSize = selfLen + aStringLen - aRange.length; buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); /* Get first part into buffer */ localRange.location = 0; localRange.length = aRange.location; [self getCharacters:buffer range:localRange]; /* Get middle part into buffer */ localRange.location = 0; localRange.length = aStringLen; [aString getCharacters:(buffer+aRange.location) range:localRange]; /* Get last part into buffer */ localRange.location = aRange.location + aRange.length; localRange.length = selfLen - localRange.location; [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; /* Build output string */ result = [NSString stringWithCharacters:buffer length:bufferSize]; NSDeallocateMemoryPages(buffer, bufferSize); return result; } @end #ifdef main # undef main #endif /* Main entry point to executable - should *not* be SDL_main! */ int main (int argc, char **argv) { /* Copy the arguments into a global variable */ /* This is passed if we are launched by double-clicking */ if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { gArgv = (char **) SDL_malloc(sizeof (char *) * 2); gArgv[0] = argv[0]; gArgv[1] = NULL; gArgc = 1; gFinderLaunch = YES; } else { int i; gArgc = argc; gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); for (i = 0; i <= argc; i++) gArgv[i] = argv[i]; gFinderLaunch = NO; } #if SDL_USE_NIB_FILE [SDLApplication poseAsClass:[NSApplication class]]; NSApplicationMain (argc, argv); #else CustomApplicationMain (argc, argv); #endif return 0; } grafx2_2.4+git20180105/src/pxsimple.c0000664000000000000000000003132013223665306015533 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxsimple.h" void Pixel_simple (word x,word y,byte color) /* Affiche un pixel de la color aux coords x;y l'cran */ { *(Screen_pixels + x + y * VIDEO_LINE_WIDTH)=color; } byte Read_pixel_simple (word x,word y) /* On retourne la couleur du pixel aux coords donnes */ { return *( Screen_pixels + y * VIDEO_LINE_WIDTH + x ); } void Block_simple (word start_x,word start_y,word width,word height,byte color) /* On affiche un rectangle de la couleur donne */ { SDL_Rect rectangle; rectangle.x=start_x; rectangle.y=start_y; rectangle.w=width; rectangle.h=height; SDL_FillRect(Screen_SDL,&rectangle,color); } void Display_part_of_screen_simple (word width,word height,word image_width) /* Afficher une partie de l'image telle quelle sur l'cran */ { byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'cran (dest) byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de dpart ds la source (src) int y; for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne memcpy(dest,src,width); // On passe la ligne suivante src+=image_width; dest+=VIDEO_LINE_WIDTH; } //Update_rect(0,0,width,height); } void Pixel_preview_normal_simple (word x,word y,byte color) /* Affichage d'un pixel dans l'cran, par rapport au dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure Pixel_Preview_Loupe_SDL. */ { // if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) Pixel_simple(x-Main_offset_X,y-Main_offset_Y,color); } void Pixel_preview_magnifier_simple (word x,word y,byte color) { // Affiche le pixel dans la partie non zoome Pixel_simple(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) { // On est dedans int height; int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_simple( Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, y_zoom, Main_magnifier_factor, height, color ); } } void Horizontal_XOR_line_simple(word x_pos,word y_pos,word width) { //On calcule la valeur initiale de dest: byte* dest=y_pos*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; int x; for (x=0;x 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *dest = *src; } // Pixel suivant src++; dest++; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH - width; src = src + brush_width - width; } Update_rect(x_pos,y_pos,width,height); } void Display_brush_mono_simple(word x_pos, word y_pos, word x_offset, word y_offset, word width, word height, byte transp_color, byte color, word brush_width) /* On affiche la brosse en monochrome */ { byte* dest=y_pos*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; // dest = adr Destination // l'cran byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds // la brosse int x,y; for(y=height;y!=0;y--) //Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { if (*src!=transp_color) *dest=color; // On passe au pixel suivant src++; dest++; } // On passe la ligne suivante src+=brush_width-width; dest+=VIDEO_LINE_WIDTH-width; } Update_rect(x_pos,y_pos,width,height); } void Clear_brush_simple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width) { byte* dest=Screen_pixels+x_pos+y_pos*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'cran (dest) byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de dpart ds la source (src) int y; (void)x_offset; // unused (void)y_offset; // unused (void)transp_color; // unused for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne memcpy(dest,src,width); // On passe la ligne suivante src+=image_width; dest+=VIDEO_LINE_WIDTH; } Update_rect(x_pos,y_pos,width,height); } // Affiche une brosse (arbitraire) l'cran void Display_brush_simple(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; // src = Position dans la brosse byte* src = brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *dest = *src; } // Pixel suivant src++; dest++; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH - width; src = src + brush_width - width; } } void Remap_screen_simple(word x_pos,word y_pos,word width,word height,byte * conversion_table) { // dest = coords a l'cran byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; int x,y; // Pour chaque ligne for(y=height;y>0;y--) { // Pour chaque pixel for(x=width;x>0;x--) { *dest = conversion_table[*dest]; dest ++; } dest = dest + VIDEO_LINE_WIDTH - width; } Update_rect(x_pos,y_pos,width,height); } void Display_line_on_screen_simple(word x_pos,word y_pos,word width,byte * line) /* On affiche toute une ligne de pixels. Utilis pour les textes. */ { memcpy(Screen_pixels+x_pos+y_pos*VIDEO_LINE_WIDTH,line,width); } void Display_transparent_mono_line_on_screen_simple( word x_pos, word y_pos, word width, byte* line, byte transp_color, byte color) // Affiche une ligne l'cran avec une couleur + transparence. // Utilis par les brosses en mode zoom { byte* dest = Screen_pixels+ y_pos * VIDEO_LINE_WIDTH + x_pos; int x; // Pour chaque pixel for(x=0;x 0); src += image_width; } // ATTENTION on n'arrive jamais ici ! } void Display_transparent_line_on_screen_simple(word x_pos,word y_pos,word width,byte* line,byte transp_color) { byte* src = line; byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; word x; // Pour chaque pixel de la ligne for(x = width;x > 0;x--) { if(*src!=transp_color) *dest = *src; src++; dest++; } } // Affiche une partie de la brosse couleur zoome void Display_brush_color_zoom_simple(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle de la brosse byte * buffer) { byte* src = Brush+y_offset*brush_width + x_offset; word y = y_pos; byte bx; // Pour chaque ligne while(1) { Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche facteur fois la ligne zoome for(bx=Main_magnifier_factor;bx>0;bx--) { Display_transparent_line_on_screen_simple(x_pos,y,width*Main_magnifier_factor,buffer,transp_color); y++; if(y==end_y_pos) { return; } } src += brush_width; } // ATTENTION zone jamais atteinte } void Display_brush_mono_zoom_simple(word x_pos, word y_pos, word x_offset, word y_offset, word width, // width non zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle de la brosse byte * buffer ) { byte* src = Brush + y_offset * brush_width + x_offset; int y=y_pos; //Pour chaque ligne zoomer : while(1) { int bx; // src = Ligne originale // On clate la ligne Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche la ligne Facteur fois l'cran (sur des // lignes conscutives) bx = Main_magnifier_factor; // Pour chaque ligne cran do { // On affiche la ligne zoome Display_transparent_mono_line_on_screen_simple( x_pos, y, width * Main_magnifier_factor, buffer, transp_color, color ); // On passe la ligne suivante y++; // On vrifie qu'on est pas la ligne finale if(y == end_y_pos) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); Update_rect( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); return; } bx --; } while (bx > 0); // Passage la ligne suivante dans la brosse aussi src+=brush_width; } } void Clear_brush_scaled_simple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer) { // En fait on va recopier l'image non zoome dans la partie zoome ! byte* src = Main_screen + y_offset * image_width + x_offset; int y = y_pos; int bx; (void)transp_color; // unused // Pour chaque ligne zoomer while(1){ Zoom_a_line(src,buffer,Main_magnifier_factor,width); bx=Main_magnifier_factor; // Pour chaque ligne do{ Display_line_on_screen_simple(x_pos,y, width * Main_magnifier_factor,buffer); // Ligne suivante y++; if(y==end_y_pos) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); Update_rect(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); return; } bx--; }while(bx!=0); src+= image_width; } } grafx2_2.4+git20180105/src/op_c.c0000664000000000000000000011263113223665306014617 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2017 Thomas Bernard Copyright 2010 Alexander Filyanov Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include #include #include #include #include #include "op_c.h" #include "errors.h" #include "colorred.h" // If GRAFX2_QUANTIZE_CLUSTER_POPULATION_SPLIT is defined, // the clusters are splitted in two half of equal (pixel) population. // Otherwise, they are splitted in two half of equal volume. #define GRAFX2_QUANTIZE_CLUSTER_POPULATION_SPLIT // If GRAFX2_QUANTIZE_CLUSTER_SORT_BY_VOLUME is defined // the clusters are sorted by volume. Otherwise, they // are sorted by length of the diagonal //#define GRAFX2_QUANTIZE_CLUSTER_SORT_BY_VOLUME int Convert_24b_bitmap_to_256_fast(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette); /// Convert RGB to HSL. /// Both input and output are in the 0..255 range to use in the palette screen void RGB_to_HSL(int r,int g,int b,byte * hr,byte * sr,byte* lr) { double rd,gd,bd,h,s,l,max,min; // convert RGB to HSV rd = r / 255.0; // rd,gd,bd range 0-1 instead of 0-255 gd = g / 255.0; bd = b / 255.0; // compute maximum of rd,gd,bd if (rd>=gd) { if (rd>=bd) max = rd; else max = bd; } else { if (gd>=bd) max = gd; else max = bd; } // compute minimum of rd,gd,bd if (rd<=gd) { if (rd<=bd) min = rd; else min = bd; } else { if (gd<=bd) min = gd; else min = bd; } l = (max + min) / 2.0; if(max==min) s = h = 0; else { if (l<=0.5) s = (max - min) / (max + min); else s = (max - min) / (2 - (max + min)); if (max == rd) h = 42.5 * (gd-bd)/(max-min); else if (max == gd) h = 42.5 * (bd-rd)/(max-min)+85; else h = 42.5 * (rd-gd)/(max-min)+170; if (h<0) h+=255; } *hr = h; *lr = (l*255.0); *sr = (s*255.0); } /// Convert HSL back to RGB /// Input and output are all in range 0..255 void HSL_to_RGB(byte h,byte s,byte l, byte* r, byte* g, byte* b) { float rf =0 ,gf = 0,bf = 0; float hf,lf,sf; float p,q; if(s==0) { *r=*g=*b=l; return; } hf = h / 255.0; lf = l / 255.0; sf = s / 255.0; if (lf<=0.5) q = lf*(1+sf); else q = lf+sf-lf*sf; p = 2*lf-q; rf = hf + (1 / 3.0); gf = hf; bf = hf - (1 / 3.0); if (rf < 0) rf+=1; if (rf > 1) rf-=1; if (gf < 0) gf+=1; if (gf > 1) gf-=1; if (bf < 0) bf+=1; if (bf > 1) bf-=1; if (rf < 1/6.0) rf = p + ((q-p)*6*rf); else if(rf < 0.5) rf = q; else if(rf < 2/3.0) rf = p + ((q-p)*6*(2/3.0-rf)); else rf = p; if (gf < 1/6.0) gf = p + ((q-p)*6*gf); else if(gf < 0.5) gf = q; else if(gf < 2/3.0) gf = p + ((q-p)*6*(2/3.0-gf)); else gf = p; if (bf < 1/6.0) bf = p + ((q-p)*6*bf); else if(bf < 0.5) bf = q; else if(bf < 2/3.0) bf = p + ((q-p)*6*(2/3.0-bf)); else bf = p; *r = rf * (255); *g = gf * (255); *b = bf * (255); } /// /// Returns a value that is high when color is near white, /// and low when it's darker. Used for sorting. long Perceptual_lightness(T_Components *color) { return 26*color->R*26*color->R + 55*color->G*55*color->G + 19*color->B*19*color->B; } // Handlers for the occurences tables // This table is used to count the occurence of an (RGB) pixel value in the // source 24bit image. These count are then used by the median cut algorithm to // decide which cluster to split. /// Initialize an occurence table void OT_init(T_Occurrence_table * t) { int size; size=(t->rng_r)*(t->rng_g)*(t->rng_b)*sizeof(int); memset(t->table,0,size); // Set it to 0 } /// Allocate an occurence table for given number of bits T_Occurrence_table * OT_new(int nbb_r,int nbb_g,int nbb_b) { T_Occurrence_table * n; int size; n=(T_Occurrence_table *)malloc(sizeof(T_Occurrence_table)); if (n!=0) { // Copy passed parameters n->nbb_r=nbb_r; n->nbb_g=nbb_g; n->nbb_b=nbb_b; // Compute others n->rng_r=(1<rng_g=(1<rng_b=(1<dec_r=nbb_g+nbb_b; n->dec_g=nbb_b; n->dec_b=0; n->red_r=8-nbb_r; n->red_g=8-nbb_g; n->red_b=8-nbb_b; // Allocate the table size=(n->rng_r)*(n->rng_g)*(n->rng_b); n->table=(int *)calloc(size, sizeof(int)); if (n->table == NULL) { // Not enough memory ! free(n); n=NULL; } } return n; } /// Delete a table and free the memory void OT_delete(T_Occurrence_table * t) { free(t->table); free(t); t = NULL; } /// Get number of occurences for a given color int OT_get(T_Occurrence_table * t, byte r, byte g, byte b) { int index; // Drop bits as needed index=(r<dec_r) | (g<dec_g) | (b<dec_b); return t->table[index]; } /// Add 1 to the count for a color void OT_inc(T_Occurrence_table * t,byte r,byte g,byte b) { int index; // Drop bits as needed r=(r>>t->red_r); g=(g>>t->red_g); b=(b>>t->red_b); // Compute the address index=(r<dec_r) | (g<dec_g) | (b<dec_b); t->table[index]++; } /// Count the use of each color in a 24bit picture and fill in the table void OT_count_occurrences(T_Occurrence_table* t, T_Bitmap24B image, int size) { T_Bitmap24B ptr; int index; for (index = size, ptr = image; index > 0; index--, ptr++) OT_inc(t, ptr->R, ptr->G, ptr->B); } /// Count the total number of pixels in an occurence table int OT_count_colors(T_Occurrence_table * t) { int val; // Computed return value int nb; // Number of colors to test int i; // Loop index val = 0; nb=(t->rng_r)*(t->rng_g)*(t->rng_b); for (i = 0; i < nb; i++) if (t->table[i]>0) val++; return val; } // Cluster management // Clusters are boxes in the RGB spaces, defined by 6 corner coordinates : // Rmax, Rmin, Vmax (or Gmax), Vmin, Rmax, Rmin // The median cut algorithm start with a single cluster covering the whole // colorspace then split it in two smaller clusters on the longest axis until // there are 256 non-empty clusters (with some tricks if the original image // actually has less than 256 colors) // Each cluster also store the number of pixels that are inside and the // rmin, rmax, vmin, vmax, bmin, bmax values are the first/last values that // actually are used by a pixel in the cluster // When you split a big cluster there may be some space between the splitting // plane and the first pixel actually in a cluster /// Pack a cluster, ie compute its {r,v,b}{min,max} values void Cluster_pack(T_Cluster * c,const T_Occurrence_table * const to) { int rmin,rmax,vmin,vmax,bmin,bmax; int r,g,b; // Find min. and max. values actually used for each component in this cluster // Pre-shift everything to avoid using OT_Get and be faster. // GIMP use only 6 bits for G and B components in this table. rmin=c->rmax << to->dec_r; rmax=c->rmin << to->dec_r; vmin=c->vmax << to->dec_g; vmax=c->vmin << to->dec_g; bmin=c->bmax << to->dec_b; bmax=c->bmin << to->dec_b; c->occurences=0; // Unoptimized code kept here for documentation purpose because the optimized // one is unreadable : run over the whole cluster and find the min and max, // and count the occurences at the same time. /* for (r=c->rmin<dec_r;r<=c->rmax<dec_r;r+=1<dec_r) for (g=c->vmin<dec_g;g<=c->vmax<dec_g;g+=1<dec_g) for (b=c->bmin;b<=c->bmax;b++) { nbocc=to->table[r + g + b]; // OT_get if (nbocc) { if (rrmax) rmax=r; if (gvmax) vmax=g; if (bbmax) bmax=b; c->occurences+=nbocc; } } */ // Optimized version : find the extremums one at a time, so we can reduce the // area to seek for the next one. Start at the edges of the cluster and go to // the center until we find a pixel. for(r=c->rmin<dec_r;r<=c->rmax<dec_r;r+=1<dec_r) for(g=c->vmin<dec_g;g<=c->vmax<dec_g;g+=1<dec_g) for(b=c->bmin;b<=c->bmax;b++) { if(to->table[r + g + b]) // OT_get { rmin=r; goto RMAX; } } RMAX: for(r=c->rmax<dec_r;r>=rmin;r-=1<dec_r) for(g=c->vmin<dec_g;g<=c->vmax<dec_g;g+=1<dec_g) for(b=c->bmin;b<=c->bmax;b++) { if(to->table[r + g + b]) // OT_get { rmax=r; goto VMIN; } } VMIN: for(g=c->vmin<dec_g;g<=c->vmax<dec_g;g+=1<dec_g) for(r=rmin;r<=rmax;r+=1<dec_r) for(b=c->bmin;b<=c->bmax;b++) { if(to->table[r + g + b]) // OT_get { vmin=g; goto VMAX; } } VMAX: for(g=c->vmax<dec_g;g>=vmin;g-=1<dec_g) for(r=rmin;r<=rmax;r+=1<dec_r) for(b=c->bmin;b<=c->bmax;b++) { if(to->table[r + g + b]) // OT_get { vmax=g; goto BMIN; } } BMIN: for(b=c->bmin;b<=c->bmax;b++) for(r=rmin;r<=rmax;r+=1<dec_r) for(g=vmin;g<=vmax;g+=1<dec_g) { if(to->table[r + g + b]) // OT_get { bmin=b; goto BMAX; } } BMAX: for(b=c->bmax;b>=bmin;b--) for(r=rmin;r<=rmax;r+=1<dec_r) for(g=vmin;g<=vmax;g+=1<dec_g) { if(to->table[r + g + b]) // OT_get { bmax=b; goto ENDCRUSH; } } ENDCRUSH: // We still need to seek the internal part of the cluster to count pixels // inside it for(r=rmin;r<=rmax;r+=1<dec_r) for(g=vmin;g<=vmax;g+=1<dec_g) for(b=bmin;b<=bmax;b++) { c->occurences+=to->table[r + g + b]; // OT_get } // Unshift the values and put them in the cluster info c->rmin=rmin>>to->dec_r; c->rmax=rmax>>to->dec_r; c->vmin=vmin>>to->dec_g; c->vmax=vmax>>to->dec_g; c->bmin=bmin; c->bmax=bmax; // Find the longest axis to know which way to split the cluster r = c->rmax-c->rmin; g = c->vmax-c->vmin; b = c->bmax-c->bmin; c->data.cut.sqdiag = r*r+g*g+b*b; c->data.cut.volume = (r+1)*(g+1)*(b+1); if (g>=r) { // G>=R if (g>=b) { // G>=R et G>=B c->data.cut.plus_large=1; } else { // G>=R et Gdata.cut.plus_large=2; } } else { // R>G if (r>=b) { // R>G et R>=B c->data.cut.plus_large=0; } else { // R>G et Rdata.cut.plus_large=2; } } } #ifndef GRAFX2_QUANTIZE_CLUSTER_POPULATION_SPLIT /// Split a cluster on its longest axis. /// c = source cluster, c1, c2 = output after split /// the two output cluster have half volume (and not half population) void Cluster_split_volume(T_Cluster * c, T_Cluster * c1, T_Cluster * c2, int hue) { int r,g,b; if (hue == 0) // split on red { r = (c->rmin + c->rmax) / 2; c1->Rmin=c->Rmin; c1->Rmax=r; c1->rmin=c->rmin; c1->rmax=r; c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; c1->vmin=c->vmin; c1->vmax=c->vmax; c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; c1->bmin=c->bmin; c1->bmax=c->bmax; c2->Rmin=r+1; c2->Rmax=c->Rmax; c2->rmin=r+1; c2->rmax=c->rmax; c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; c2->vmin=c->vmin; c2->vmax=c->vmax; c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; c2->bmin=c->bmin; c2->bmax=c->bmax; } else if (hue==1) // split on green { g = (c->vmin + c->vmax) / 2; c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; c1->rmin=c->rmin; c1->rmax=c->rmax; c1->Gmin=c->Gmin; c1->Vmax=g; c1->vmin=c->vmin; c1->vmax=g; c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; c1->bmin=c->bmin; c1->bmax=c->bmax; c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; c2->rmin=c->rmin; c2->rmax=c->rmax; c2->Gmin=g+1; c2->Vmax=c->Vmax; c2->vmin=g+1; c2->vmax=c->vmax; c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; c2->bmin=c->bmin; c2->bmax=c->bmax; } else { b = (c->bmin + c->bmax) / 2; c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; c1->rmin=c->rmin; c1->rmax=c->rmax; c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; c1->vmin=c->vmin; c1->vmax=c->vmax; c1->Bmin=c->Bmin; c1->Bmax=b; c1->bmin=c->bmin; c1->bmax=b; c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; c2->rmin=c->rmin; c2->rmax=c->rmax; c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; c2->vmin=c->vmin; c2->vmax=c->vmax; c2->Bmin=b+1; c2->Bmax=c->Bmax; c2->bmin=b+1; c2->bmax=c->bmax; } } #else // GRAFX2_QUANTIZE_CLUSTER_POPULATION_SPLIT /// Split a cluster on its longest axis. /// c = source cluster, c1, c2 = output after split /// the two output clusters have half population (and not half volume) void Cluster_split(T_Cluster * c, T_Cluster * c1, T_Cluster * c2, int hue, const T_Occurrence_table * const to) { int limit; int cumul; int r, g, b; // Split criterion: each of the cluster will have the same number of pixels limit = c->occurences / 2; cumul = 0; if (hue == 0) // split on red { // Run over the cluster until we reach the requested number of pixels for (r = c->rmin<dec_r; r<=c->rmax<dec_r; r+=1<dec_r) { for (g = c->vmin<dec_g; g<=c->vmax<dec_g; g+=1<dec_g) { for (b = c->bmin; b<=c->bmax; b++) { cumul+=to->table[r + g + b]; if (cumul>=limit) break; } if (cumul>=limit) break; } if (cumul>=limit) break; } r>>=to->dec_r; g>>=to->dec_g; // More than half of the cluster pixel have r = rmin. Ensure we split somewhere anyway. if (r == c->rmin) r++; c1->Rmin=c->Rmin; c1->Rmax=r-1; c1->rmin=c->rmin; c1->rmax=r-1; c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; c1->vmin=c->vmin; c1->vmax=c->vmax; c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; c1->bmin=c->bmin; c1->bmax=c->bmax; c2->Rmin=r; c2->Rmax=c->Rmax; c2->rmin=r; c2->rmax=c->rmax; c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; c2->vmin=c->vmin; c2->vmax=c->vmax; c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; c2->bmin=c->bmin; c2->bmax=c->bmax; } else if (hue==1) // split on green { for (g=c->vmin<dec_g;g<=c->vmax<dec_g;g+=1<dec_g) { for (r=c->rmin<dec_r;r<=c->rmax<dec_r;r+=1<dec_r) { for (b=c->bmin;b<=c->bmax;b++) { cumul+=to->table[r + g + b]; if (cumul>=limit) break; } if (cumul>=limit) break; } if (cumul>=limit) break; } r>>=to->dec_r; g>>=to->dec_g; if (g == c->vmin) g++; c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; c1->rmin=c->rmin; c1->rmax=c->rmax; c1->Gmin=c->Gmin; c1->Vmax=g-1; c1->vmin=c->vmin; c1->vmax=g-1; c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; c1->bmin=c->bmin; c1->bmax=c->bmax; c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; c2->rmin=c->rmin; c2->rmax=c->rmax; c2->Gmin=g; c2->Vmax=c->Vmax; c2->vmin=g; c2->vmax=c->vmax; c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; c2->bmin=c->bmin; c2->bmax=c->bmax; } else // split on blue { for (b=c->bmin;b<=c->bmax;b++) { for (g=c->vmin<dec_g;g<=c->vmax<dec_g;g+=1<dec_g) { for (r=c->rmin<dec_r;r<=c->rmax<dec_r;r+=1<dec_r) { cumul+=to->table[r + g + b]; if (cumul>=limit) break; } if (cumul>=limit) break; } if (cumul>=limit) break; } r>>=to->dec_r; g>>=to->dec_g; if (b == c->bmin) b++; c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; c1->rmin=c->rmin; c1->rmax=c->rmax; c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; c1->vmin=c->vmin; c1->vmax=c->vmax; c1->Bmin=c->Bmin; c1->Bmax=b-1; c1->bmin=c->bmin; c1->bmax=b-1; c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; c2->rmin=c->rmin; c2->rmax=c->rmax; c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; c2->vmin=c->vmin; c2->vmax=c->vmax; c2->Bmin=b; c2->Bmax=c->Bmax; c2->bmin=b; c2->bmax=c->bmax; } } #endif // GRAFX2_QUANTIZE_CLUSTER_POPULATION_SPLIT /// Compute the mean R, G, B (for palette generation) and H, L (for palette sorting) void Cluster_compute_hue(T_Cluster * c,T_Occurrence_table * to) { int cumul_r,cumul_g,cumul_b; int r,g,b; int nbocc; byte s=0; cumul_r=cumul_g=cumul_b=0; for (r=c->rmin;r<=c->rmax;r++) for (g=c->vmin;g<=c->vmax;g++) for (b=c->bmin;b<=c->bmax;b++) { nbocc=OT_get(to,r,g,b); if (nbocc) { cumul_r+=r*nbocc; cumul_g+=g*nbocc; cumul_b+=b*nbocc; } } c->data.pal.r=(cumul_r<red_r)/c->occurences; c->data.pal.g=(cumul_g<red_g)/c->occurences; c->data.pal.b=(cumul_b<red_b)/c->occurences; RGB_to_HSL(c->data.pal.r, c->data.pal.g, c->data.pal.b, &c->data.pal.h, &s, &c->data.pal.l); } // Cluster set management // A set of clusters in handled as a list, the median cut algorithm pops a // cluster from the list, split it, and pushes back the two splitted clusters // until the lit grows to 256 items // Debug helper : check if a cluster set has the right count value /* void CS_Check(T_Cluster_set* cs) { int i; T_Cluster* c = cs->clusters; for (i = cs->nb; i > 0; i--) { assert( c != NULL); c = c->next; } assert(c == NULL); } */ /* void Cluster_Print(T_Cluster* node) { printf("R %d %d\tG %d %d\tB %d %d\n", node->Rmin, node->Rmax, node->Gmin, node->Vmax, node->Bmin, node->Bmax); } */ // translate R G B values to 8 8 8 void CT_set_trad(CT_Tree* colorTree, byte Rmin, byte Gmin, byte Bmin, byte Rmax, byte Gmax, byte Bmax, byte index, const T_Occurrence_table * to) { Rmin <<= to->red_r; Rmax <<= to->red_r; Rmax += ((1 << to->red_r) - 1); Gmin <<= to->red_g; Gmax <<= to->red_g; Gmax += ((1 << to->red_g) - 1); Bmin <<= to->red_b; Bmax <<= to->red_b; Bmax += ((1 << to->red_b) - 1); CT_set(colorTree, Rmin, Gmin, Bmin, Rmax, Gmax, Bmax, index); } /// Setup the first cluster before we start the operations /// This one covers the full palette range void CS_Init(T_Cluster_set * cs, T_Occurrence_table * to) { cs->clusters->Rmin = cs->clusters->rmin = 0; cs->clusters->Gmin = cs->clusters->vmin = 0; cs->clusters->Bmin = cs->clusters->bmin = 0; cs->clusters->Rmax = cs->clusters->rmax = to->rng_r - 1; cs->clusters->Vmax = cs->clusters->vmax = to->rng_g - 1; cs->clusters->Bmax = cs->clusters->bmax = to->rng_b - 1; cs->clusters->next = NULL; Cluster_pack(cs->clusters, to); cs->nb = 1; } /// Allocate a new cluster set T_Cluster_set * CS_New(int nbmax, T_Occurrence_table * to) { T_Cluster_set * n; n=(T_Cluster_set *)malloc(sizeof(T_Cluster_set)); if (n != NULL) { // Copy requested params n->nb_max = OT_count_colors(to); // If the number of colors asked is > 256, we ceil it because we know we // don't want more if (n->nb_max > nbmax) { n->nb_max = nbmax; } // Allocate the first cluster n->clusters=(T_Cluster *)malloc(sizeof(T_Cluster)); if (n->clusters != NULL) CS_Init(n, to); else { // No memory free ! Sorry ! free(n); n = NULL; } } return n; } /// Free a cluster set void CS_Delete(T_Cluster_set * cs) { T_Cluster* nxt; while (cs->clusters != NULL) { nxt = cs->clusters->next; free(cs->clusters); cs->clusters = nxt; } free(cs); cs = NULL; } /// Pop a cluster from the cluster list void CS_Get(T_Cluster_set * cs, T_Cluster ** c) { // Just remove and return the first cluster, which has the biggest volume. // or the longest diagonal *c = cs->clusters; cs->clusters = (*c)->next; --cs->nb; } /// Push a copy of a cluster in the list /// return -1 in case of error int CS_Set(T_Cluster_set * cs,T_Cluster * c) { T_Cluster* current = cs->clusters; T_Cluster* prev = NULL; // Search the first cluster that is smaller than ours #ifdef GRAFX2_QUANTIZE_CLUSTER_SORT_BY_VOLUME while (current && current->data.cut.volume > c->data.cut.volume) #else while (current && current->data.cut.sqdiag > c->data.cut.sqdiag) #endif { prev = current; current = current->next; } // Now insert our cluster just before the one we found c -> next = current; current = malloc(sizeof(T_Cluster)); if(current == NULL) return -1; *current = *c ; if (prev) prev->next = current; else cs->clusters = current; cs->nb++; return 0; } /// This is the main median cut algorithm and the function actually called to /// reduce the palette. We get the number of pixels for each collor in the /// occurence table and generate the cluster set from it. // 1) RGB space is a big box // 2) We seek the pixels with extreme values // 3) We split the box in 2 parts on its longest axis // 4) We pack the 2 resulting boxes again to leave no empty space between the box border and the first pixel // 5) We take the box with the biggest number of pixels inside and we split it again // 6) Iterate until there are 256 boxes. Associate each of them to its middle color // At the same time, put the split clusters in the color tree for later palette lookup int CS_Generate(T_Cluster_set * cs, const T_Occurrence_table * const to, CT_Tree* colorTree) { T_Cluster* current; T_Cluster Nouveau1; T_Cluster Nouveau2; // There are less than 256 boxes while (cs->nbnb_max) { // Get the biggest one CS_Get(cs,¤t); //Cluster_Print(current); // We are going to split this cluster, so add it to the color tree. It is a split cluster, // not a final one. We KNOW its two child will get added later (either because they are split, // or because they are part of the final cluster set). So, we add thiscluster with a NULL index. CT_set_trad(colorTree,current->Rmin, current->Gmin, current->Bmin, current->Rmax, current->Vmax, current->Bmax, 0, to); // Split it if (current->data.cut.volume <= 1) { // Sorry, but there's nothing more to split ! // The biggest cluster only has one color... free(current); break; } #ifndef GRAFX2_QUANTIZE_CLUSTER_POPULATION_SPLIT Cluster_split_volume(current, &Nouveau1, &Nouveau2, current->data.cut.plus_large); #else Cluster_split(current, &Nouveau1, &Nouveau2, current->data.cut.plus_large, to); #endif free(current); // Pack the 2 new clusters (the split may leave some empty space between the // box border and the first actual pixel) Cluster_pack(&Nouveau1, to); Cluster_pack(&Nouveau2, to); // Put them back in the list if (Nouveau1.occurences != 0) { if(CS_Set(cs,&Nouveau1) < 0) return -1; } if (Nouveau2.occurences != 0) { if(CS_Set(cs,&Nouveau2) < 0) return -1; } } return 0; } /// Compute the color associated to each box in the list void CS_Compute_colors(T_Cluster_set * cs, T_Occurrence_table * to) { T_Cluster * c; for (c=cs->clusters;c!=NULL;c=c->next) { Cluster_compute_hue(c,to); } } // We sort the clusters on two criterions to get a somewhat coherent palette. // TODO : It would be better to do this in one single pass. /// Sort the clusters by chrominance value void CS_Sort_by_chrominance(T_Cluster_set * cs) { T_Cluster* nc; T_Cluster* prev = NULL; T_Cluster* place; T_Cluster* newlist = NULL; while (cs->clusters) { // Remove the first cluster from the original list nc = cs->clusters; cs->clusters = cs->clusters->next; // Find his position in the new list for (place = newlist; place != NULL; place = place->next) { if (place->data.pal.h > nc->data.pal.h) break; prev = place; } // Chain it there nc->next = place; if (prev) prev->next = nc; else newlist = nc; prev = NULL; } // Put the new list back in place cs->clusters = newlist; } /// Sort the clusters by luminance value void CS_Sort_by_luminance(T_Cluster_set * cs) { T_Cluster* nc; T_Cluster* prev = NULL; T_Cluster* place; T_Cluster* newlist = NULL; while (cs->clusters) { // Remove the first cluster from the original list nc = cs->clusters; cs->clusters = cs->clusters->next; // Find its position in the new list for (place = newlist; place != NULL; place = place->next) { if (place->data.pal.l > nc->data.pal.l) break; prev = place; } // Chain it there nc->next = place; if (prev) prev->next = nc; else newlist = nc; // reset prev pointer prev = NULL; } // Put the new list back in place cs->clusters = newlist; } /// Generates the palette from the clusters, then the conversion table to map (RGB) to a palette index void CS_Generate_color_table_and_palette(T_Cluster_set * cs,CT_Tree* tc,T_Components * palette, T_Occurrence_table * to) { int index; T_Cluster* current = cs->clusters; for (index=0;indexnb;index++) { palette[index].R=current->data.pal.r; palette[index].G=current->data.pal.g; palette[index].B=current->data.pal.b; CT_set_trad(tc,current->Rmin, current->Gmin, current->Bmin, current->Rmax, current->Vmax, current->Bmax, index, to); current = current->next; } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////// Mthodes de gestion des dgrads // ///////////////////////////////////////////////////////////////////////////// void GS_Init(T_Gradient_set * ds,T_Cluster_set * cs) { ds->gradients[0].nb_colors=1; ds->gradients[0].min=cs->clusters->data.pal.h; ds->gradients[0].max=cs->clusters->data.pal.h; ds->gradients[0].hue=cs->clusters->data.pal.h; // Et hop : le 1er ensemble de dgrads est initialis ds->nb=1; } T_Gradient_set * GS_New(T_Cluster_set * cs) { T_Gradient_set * n; n=(T_Gradient_set *)malloc(sizeof(T_Gradient_set)); if (n!=NULL) { // On recopie les paramtres demands n->nb_max=cs->nb_max; // On tente d'allouer la table n->gradients=(T_Gradient *)malloc((n->nb_max)*sizeof(T_Gradient)); if (n->gradients!=0) // C'est bon! On initialise GS_Init(n,cs); else { // Table impossible allouer free(n); n=NULL; } } return n; } void GS_Delete(T_Gradient_set * ds) { free(ds->gradients); free(ds); } void GS_Generate(T_Gradient_set * ds,T_Cluster_set * cs) { int id; // Les indexs de parcours des ensembles int best_gradient; // Meilleur dgrad int best_diff; // Meilleure diffrence de chrominance int diff; // difference de chrominance courante T_Cluster * current = cs->clusters; // Pour chacun des clusters traiter do { // On recherche le dgrad le plus proche de la chrominance du cluster best_gradient=-1; best_diff=99999999; for (id=0;idnb;id++) { diff=abs(current->data.pal.h - ds->gradients[id].hue); if ((best_diff>diff) && (diff<16)) { best_gradient=id; best_diff=diff; } } // Si on a trouv un dgrad dans lequel inclure le cluster if (best_gradient!=-1) { // On met jour le dgrad if (current->data.pal.h < ds->gradients[best_gradient].min) ds->gradients[best_gradient].min=current->data.pal.h; if (current->data.pal.h > ds->gradients[best_gradient].max) ds->gradients[best_gradient].max=current->data.pal.h; ds->gradients[best_gradient].hue=((ds->gradients[best_gradient].hue* ds->gradients[best_gradient].nb_colors) +current->data.pal.h) /(ds->gradients[best_gradient].nb_colors+1); ds->gradients[best_gradient].nb_colors++; } else { // On cre un nouveau dgrad best_gradient=ds->nb; ds->gradients[best_gradient].nb_colors=1; ds->gradients[best_gradient].min=current->data.pal.h; ds->gradients[best_gradient].max=current->data.pal.h; ds->gradients[best_gradient].hue=current->data.pal.h; ds->nb++; } current->data.pal.h=best_gradient; } while((current = current->next)); // On redistribue les valeurs dans les clusters current = cs -> clusters; do current->data.pal.h=ds->gradients[current->data.pal.h].hue; while((current = current ->next)); } /// Compute best palette for given picture. /// /// The picture is first depth-reduced to the given /// r,g,b resolution, then the median cut algorithm is used to find 256 colors which are suitable /// for the given picture. /// /// @returns a conversion tree to be used for converting the picture to indexed with the generated palette (with or without dithering). /// /// @param image The true-color image for which the palette needs to be optimized /// @param size in pixels (number of pixels, the height/width doesn't matter) /// @param palette pointer to the space where the palette will be stored (256 entries at most) /// @param r Resolution for red /// @param g Resolution for green /// @param b Resolution for blue CT_Tree* Optimize_palette(T_Bitmap24B image, int size, T_Components * palette, int r, int g, int b) { T_Occurrence_table * to; CT_Tree* tc; T_Cluster_set * cs; T_Gradient_set * ds; // Allocate all the elements to = 0; tc = 0; cs = 0; ds = 0; to = OT_new(r, g, b); if (to == NULL) return 0; tc = CT_new(); if (tc == NULL) { OT_delete(to); return NULL; } // Count pixels for each color OT_count_occurrences(to, image, size); cs = CS_New(256, to); if (cs == NULL) { CT_delete(tc); OT_delete(to); return NULL; } //CS_Check(cs); // Ok, everything was allocated // Generate the cluster set with median cut algorithm if(CS_Generate(cs, to, tc) < 0) { CS_Delete(cs); CT_delete(tc); OT_delete(to); return NULL; } //CS_Check(cs); // Compute the color data for each cluster (palette entry + HL) CS_Compute_colors(cs, to); //CS_Check(cs); ds = GS_New(cs); if (ds!= NULL) { GS_Generate(ds, cs); GS_Delete(ds); } // Sort the clusters on L and H to get a nice palette CS_Sort_by_luminance(cs); //CS_Check(cs); CS_Sort_by_chrominance(cs); //CS_Check(cs); // And finally generate the conversion table to map RGB > pal. index CS_Generate_color_table_and_palette(cs, tc, palette, to); //CS_Check(cs); CS_Delete(cs); OT_delete(to); return tc; } /// Change a value with proper ceiling and flooring int Modified_value(int value,int modif) { value+=modif; if (value<0) { value=0; } else if (value>255) { value=255; } return value; } /// Convert a 24b image to 256 colors (with a given palette and conversion table) /// This destroys the 24b picture ! /// Uses floyd steinberg dithering. void Convert_24b_bitmap_to_256_Floyd_Steinberg(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette,CT_Tree* tc) { T_Bitmap24B current; T_Bitmap24B c_plus1; T_Bitmap24B u_minus1; T_Bitmap24B next; T_Bitmap24B u_plus1; T_Bitmap256 d; int x_pos,y_pos; int red,green,blue; float e_red,e_green,e_blue; // On initialise les variables de parcours: current =source; // Le pixel dont on s'occupe next =current+width; // Le pixel en dessous c_plus1 =current+1; // Le pixel droite u_minus1=next-1; // Le pixel en bas gauche u_plus1 =next+1; // Le pixel en bas droite d =dest; // On parcours chaque pixel: for (y_pos=0;y_posR; green =current->G; blue =current->B; // Cherche la couleur correspondant dans la palette et la range dans l'image de destination *d=CT_get(tc,red,green,blue); // Puis on calcule pour chaque composante l'erreur de l'approximation red-=palette[*d].R; green -=palette[*d].G; blue -=palette[*d].B; // Et dans chaque pixel voisin on propage l'erreur // A droite: e_red=(red*7)/16.0; e_green =(green *7)/16.0; e_blue =(blue *7)/16.0; if (x_pos+1R=Modified_value(c_plus1->R,e_red); c_plus1->G=Modified_value(c_plus1->G,e_green ); c_plus1->B=Modified_value(c_plus1->B,e_blue ); } // En bas gauche: if (y_pos+10) { u_minus1->R=Modified_value(u_minus1->R,e_red); u_minus1->G=Modified_value(u_minus1->G,e_green ); u_minus1->B=Modified_value(u_minus1->B,e_blue ); } // En bas: e_red=(red*5/16.0); e_green =(green*5 /16.0); e_blue =(blue*5 /16.0); next->R=Modified_value(next->R,e_red); next->G=Modified_value(next->G,e_green ); next->B=Modified_value(next->B,e_blue ); // En bas droite: if (x_pos+1R=Modified_value(u_plus1->R,e_red); u_plus1->G=Modified_value(u_plus1->G,e_green ); u_plus1->B=Modified_value(u_plus1->B,e_blue ); } } // On passe au pixel suivant : current++; c_plus1++; u_minus1++; next++; u_plus1++; d++; } } } /// Converts from 24b to 256c without dithering, using given conversion table void Convert_24b_bitmap_to_256_nearest_neighbor(T_Bitmap256 dest, T_Bitmap24B source, int width, int height, T_Components * palette, CT_Tree* tc) { T_Bitmap24B current; T_Bitmap256 d; int x_pos, y_pos; int red, green, blue; (void)palette; // unused // On initialise les variables de parcours: current =source; // Le pixel dont on s'occupe d =dest; // On parcours chaque pixel: for (y_pos = 0; y_pos < height; y_pos++) { for (x_pos = 0 ;x_pos < width; x_pos++) { // On prends la meilleure couleur de la palette qui traduit la couleur // 24 bits de la source: red = current->R; green = current->G; blue = current->B; // Cherche la couleur correspondant dans la palette et la range dans // l'image de destination *d = CT_get(tc, red, green, blue); // On passe au pixel suivant : current++; d++; } } } // These are the allowed precisions for all the tables. // For some of them only the first one may work because of ugly optimizations static const byte precision_24b[]= { 8,8,8, 6,6,6, 6,6,5, 5,6,5, 5,5,5, 5,5,4, 4,5,4, 4,4,4, 4,4,3, 3,4,3, 3,3,3, 3,3,2}; // Give this one a 24b source, get back the 256c bitmap and its palette int Convert_24b_bitmap_to_256(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette) { #if defined(__GP2X__) || defined(__gp2x__) || defined(__WIZ__) || defined(__CAANOO__) return Convert_24b_bitmap_to_256_fast(dest, source, width, height, palette); #else CT_Tree* table; // table de conversion int ip; // index de prcision pour la conversion // On essaye d'obtenir une table de conversion qui loge en mmoire, avec la // meilleure prcision possible for (ip=0;ip<(10*3);ip+=3) { table = Optimize_palette(source,width*height,palette, precision_24b[ip], precision_24b[ip+1], precision_24b[ip+2]); if (table != NULL) { break; } } if (table!=NULL) { //Convert_24b_bitmap_to_256_Floyd_Steinberg(dest,source,width,height,palette,table); Convert_24b_bitmap_to_256_nearest_neighbor(dest,source,width,height,palette,table); CT_delete(table); return 0; } else return 1; #endif } //Really small, fast and ugly converter(just for handhelds) #include "global.h" #include #include "engine.h" #include "windows.h" extern void Set_palette_fake_24b(T_Palette palette); /// Really small, fast and dirty convertor(just for handhelds) int Convert_24b_bitmap_to_256_fast(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette) { int size; Set_palette_fake_24b(palette); size = width*height; while(size--) { //Set palette color index to destination bitmap *dest = ((source->R >> 5) << 5) | ((source->G >> 5) << 2) | ((source->B >> 6)); source++; dest++; } return 0; } grafx2_2.4+git20180105/src/pxwide.h0000664000000000000000000000643713223665306015212 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file pxwide.h /// Renderer for wide pixels (2x1). ////////////////////////////////////////////////////////////////////////////// #include "struct.h" void Pixel_wide (word x,word y,byte color); byte Read_pixel_wide (word x,word y); void Block_wide (word start_x,word start_y,word width,word height,byte color); void Pixel_preview_normal_wide (word x,word y,byte color); void Pixel_preview_magnifier_wide (word x,word y,byte color); void Horizontal_XOR_line_wide (word x_pos,word y_pos,word width); void Vertical_XOR_line_wide (word x_pos,word y_pos,word height); void Display_brush_color_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_brush_mono_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); void Clear_brush_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); void Remap_screen_wide (word x_pos,word y_pos,word width,word height,byte * conversion_table); void Display_part_of_screen_wide (word width,word height,word image_width); void Display_line_on_screen_wide (word x_pos,word y_pos,word width,byte * line); void Read_line_screen_wide (word x_pos,word y_pos,word width,byte * line); void Display_part_of_screen_scaled_wide(word width,word height,word image_width,byte * buffer); void Display_brush_color_zoom_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); void Display_brush_mono_zoom_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); void Clear_brush_scaled_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); void Display_brush_wide (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_line_on_screen_fast_wide (word x_pos,word y_pos,word width,byte * line); void Display_transparent_line_on_screen_wide(word x_pos,word y_pos,word width,byte* line,byte transp_color); grafx2_2.4+git20180105/src/errors.h0000664000000000000000000000440313223665306015215 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Adrien Destugues Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file errors.h /// Functions and macros for tracing and error reporting. ////////////////////////////////////////////////////////////////////////////// #ifdef __VBCC__ #define __func__ "stupid compiler !" #endif /// Prints the source filename, line number, function name, a string and an integer. #define DEBUG(y,z) printf("%s %d %s | %s : %d###\n",__FILE__,__LINE__,__func__,y,(unsigned int)z) /// Same as ::DEBUG but in hexadecimal #define DEBUGX(y,z) printf("%s %d %s | %s : %X###\n",__FILE__,__LINE__,__func__,y,(unsigned int)z) /// Helper function used by the macro ::Error void Error_function(int error_code, const char *filename, int line_number, const char *function_name); /// /// Report a run-time error: It will print to standard output some information /// about the calling function, and then: /// - If the error code is 0, just do a red screen flash and resume. /// - If the error code is non-zero, abort the program. #define Error(n) Error_function(n, __FILE__,__LINE__,__func__) /// Helper function used by the macro ::Warning void Warning_function(const char *message, const char *filename, int line_number, const char *function_name); /// /// Report a run-time abnormal condition : It will print to standard output /// some information about the calling function, and then resume silently. /// This is most useful in debugger so you can put a breakpoint on /// ::Warning_function and examine the stack trace. #define Warning(msg) Warning_function(msg, __FILE__,__LINE__,__func__) grafx2_2.4+git20180105/src/text.h0000664000000000000000000000523113223665307014666 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file text.h /// Functions related to rendering text as a brush, using TrueType or SFont. ////////////////////////////////////////////////////////////////////////////// /// Initialization of text settings, needs to be called once on program startup. void Init_text(void); /// Returns true if text.c was compiled with TrueType support. int TrueType_is_supported(void); /// Add a new font to the list to propose to the user. void Add_font(const char *name); /// /// Creates a brush, from the parameters given: /// @param str The text to render /// @param font_number The index of the font to use. Pass 0 for the first font you declared with ::Add_font(), 1 for the second etc. /// @param size The size in points (unused for bitmap fonts) /// @param antialias Boolean, true to use antialiasing in TrueType /// @param bold Boolean, true to use bold rendering in TrueType /// @param italic Boolean, true to use italic rendering in TrueType /// @param width Returns the width of the created brush, in pixels. /// @param height Returns the height of the created brush, in pixels. /// @param palette Returns the custom palette for the brush. /// Returns true on success. byte *Render_text(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height, T_Palette palette); /// Finds a label to display for a font declared with ::Add_font(). char * Font_label(int index); /// Finds the filename of a font declared with ::Add_font(). char * Font_name(int index); /// Returns true if the font of this number is TrueType, false if it's a SFont bitmap. int TrueType_font(int index); /// /// Number of fonts declared with a series of ::Add_font(). This is public for /// convenience, but functionaly it is read-only. extern int Nb_fonts; grafx2_2.4+git20180105/src/realpath.c0000664000000000000000000001040613223665306015474 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 500 #endif #include #include #include #include #include #if defined(__AROS__) || defined(__linux__) || defined(__GLIBC__)|| defined(__MINT__) || defined(__FreeBSD__) #include #endif #if defined(__AROS__) || defined(__BEOS__) || defined(__MORPHOS__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(__amigaos__) // These platforms don't have realpath(). // We use the following implementation, found in: // http://amiga.sourceforge.net/amigadevhelp/FUNCTIONS/GeekGadgets/realpath/ex02_realpath.c // // When tested on Debian, this piece of code doesn't resolve // symbolic link in the filename itself, only on the directories in // the path. So this implementation is limited, it's really better to // use realpath() if your platform has it. #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(__amigaos__) // This is a random default value ... #define PATH_MAX 32768 #endif static char *sep(char *path) { char *tmp, c; tmp = strrchr(path, '/'); if(tmp) { c = tmp[1]; tmp[1] = 0; if (chdir(path)) { return NULL; } tmp[1] = c; return tmp + 1; } return path; } // Find the real path of _path by chdir to it and then getcwd. // If resolved_path is null, it is allocated. char *Realpath(const char *_path, char *resolved_path) { #if defined(__AROS__) int fd = open("", O_RDONLY); // GrafX2 is compiled without Unix support #else int fd = open(".", O_RDONLY); #endif int l; char current_dir_path[PATH_MAX]; char path[PATH_MAX], lnk[PATH_MAX], *tmp = (char *)""; if (fd < 0) { return NULL; } getcwd(current_dir_path,PATH_MAX); strncpy(path, _path, PATH_MAX); if (chdir(path)) { if (errno == ENOTDIR) { #if defined(__WIN32__) || defined(__MORPHOS__) || defined(__amigaos__) // No symbolic links and no readlink() l = -1; #else l = readlink(path, lnk, PATH_MAX); #endif if (!(tmp = sep(path))) { resolved_path = NULL; goto abort; } if (l < 0) { if (errno != EINVAL) { resolved_path = NULL; goto abort; } } else { lnk[l] = 0; if (!(tmp = sep(lnk))) { resolved_path = NULL; goto abort; } } } else { resolved_path = NULL; goto abort; } } if(resolved_path==NULL) // if we called realpath with null as a 2nd arg resolved_path = (char*) malloc( PATH_MAX ); if (!getcwd(resolved_path, PATH_MAX)) { resolved_path = NULL; goto abort; } if(strcmp(resolved_path, "/") && *tmp) { strcat(resolved_path, "/"); } strcat(resolved_path, tmp); abort: chdir(current_dir_path); close(fd); return resolved_path; } #elif defined (__WIN32__) // Mingw has a working equivalent. It only has reversed arguments. char *Realpath(const char *_path, char *resolved_path) { return _fullpath(resolved_path,_path,260); } #else #include // Use the stdlib function. char *Realpath(const char *_path, char *resolved_path) { // While linux version of realpath handles the resolved_path being a // null pointer, this is not the case for other platforms (Haiku), nor // specified by the open group in POSIX. So, be safe and allocate // ourselves. if(resolved_path==NULL) // if we called realpath with null as a 2nd arg resolved_path = (char*) malloc( PATH_MAX ); return realpath(_path, resolved_path); } #endif grafx2_2.4+git20180105/src/init.h0000664000000000000000000000351313223665306014645 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file init.h /// Initialization (and some de-initialization) functions. ////////////////////////////////////////////////////////////////////////////// T_Gui_skin *Load_graphics(const char * skin_file, T_Gradient_array *gradients); void Set_current_skin(const char *skinfile, T_Gui_skin *gfx); void Init_buttons(void); void Init_operations(void); void Init_brush_container(void); int Load_CFG(int reload_all); int Save_CFG(void); void Set_all_video_modes(void); void Set_config_defaults(void); void Init_sighandler(void); void Init_paintbrushes(void); /// Set application icon(s) void Define_icon(void); extern char Gui_loading_error_message[512]; /// /// Loads a 8x8 monochrome font, the kind used in all menus and screens. /// This function allocates the memory, and returns a pointer to it when /// successful. /// If an error is encountered, it frees what needs it, prints an error message /// in ::Gui_loading_error_message, and returns NULL. byte * Load_font(const char * font_name); grafx2_2.4+git20180105/src/gfx2.ico0000664000000000000000000006117613223665306015104 0ustar rootroot 00h ( 00 h^"00 %'  nM h^(0`fUUUUUUUPf̏UUUUUUPl̏PUUUU\UUPlU\UU\UPPU\UP̏ \\PPUŏ\P̌ \U_UUUPUUPlX\PlUPlXUP\P̈\Pl\UP̏UUl̏\PlU\Pl̏̏̏P̏lP̏̏lPfPlflfPfflllflf̌PfffflόPflffl̏fl̏̌lfflffffoffffl̆ȏolflfl|lllflf|ffffff`ffflfff|`fflff`̏`ffoolffff????( @UUUUUUUUP\\PPxu\\\\P\PP|\\|\PP P|||P̌Pl||l|wx|`xl|`x||`L||lǏ@F||f@Flll|w f@lllwww|@fƆ@fllll`lwww|@hff@ffll`l@nhff@f`f@????(  UUP|\UP\\PUP PlPflfffflo(0`   8++5888rRTTT3n9K'S+\4a2g8m9v=z?\|@wNʄRn|**   * $**$ * $******$ * $*****$ ***$** ***$**$** *******$** $*********$**$**$************$*** $*$*$**$*$*$$*** ****$$*$$*$$*** $*$**$****$*** **$********* **$***$$**$****** **$*************** ** **$$*$$*******$* **$*$**$$*********$****$$***$***$*$*********$**** *$**$$**$**$* ***$**$*** $****$**$** **$***$** ********$ $*******$  ******$**$  $**$**$   ****$* &   **$$*** &   **$$**$&    $*$*$*   **$$***   **$$*$**     **$**$****   **$********$* **    %**$$$****$$* **      '!***********     )!**$*****     )!$*$***    )!*$* **  )"$** ***  ("$** ****** ** * &** ****** ***** **&*** *  ***************&**************????( @ +999eeIrRb3n9\|@                      ????( \|@(0` %  |@`2|@8rR\\\\\\\\\\\\\\|@|@||8rR\\\\\\\\\\\\\\|@||\8rR\\\\\\\\\\\\\|@||\8rR\\\\\\\\\\\\\|\8rR\\\\\\\||\88\\\\|\858\\\\|\\\\||\\\\\|\\\\\\\\|\\\\\\|@||||||\|\\\|@|||||\\|\\|@|||\|\\\\|@|\\\\|@||||\\\ |@|\\\\rR+|@|||||\\\rRz?|@||||\\rRw>||||\\\rRn;||\rRg8|rR8g8|||||\8S+||\85|@|||\5+n9||\8+n9|\8+n9||\8888n9|@||\8888n9|@|||\8888n9|@|@|@|@|\8888|@|@|@|@|@|@|@||\8888|@|@|@|@|@|@|@|@|@|||\TTT|@|@|@|@|@|@|@|@|@|||\888|@|@|@|@|@|@|@|@|@|||@|@|@|@|@|@||||@|@|@|@|@|@|@|@|@|||@|@|@|@|@|@|@|@|@|@|@|||@|@|@|@|@|@|@|@|@|@|@|@|@\4||||||@|@|@|@|@|@|@|@|@5wN|@|@|@|@|@|@+5wN||@|@|@|@|@|@|@|@n9+wN|||@|@|@|@|@|@|@|@|@|@|@|@n9+wN||@|@|@|@|@|@|@|@|@|@|@|@|@n9888ʄR3|v=|@|@|@|@|@|@|@|@|@|@|@n9888ʄRK'|3|@|@|@|@|@|@|@|@888c3|@l8|@|@|@|@|@888`2|@|@|@|@|@|@888 888 ????( @ 5\\\\\\\rR55eI\\\\\\\\\\eI55eI\\\\\\eI55eI\\\\\eI55eI\\eI5eI\\\eI\\\\|@5|@b35|@b355|@b355|@b355b355n955+55ee55e|@e55e|@e55e|@|@e55e|@|@|@|@e5|@|@|@e|@|@|@|@|@|@|@|@|@|@|@|@|@|@|@|@b3|@|@|@|@|@|@|@|@b355|@|@|@|@|@|@|@|@b355|@|@|@|@|@|@|@b355|@|@|@|@|@b355|@|@555(  @\\\\\\\\\\\\\\\\\\\|@\|@\|@|@|@|@|@|@|@|@|@|@|@|@|@|@|@grafx2_2.4+git20180105/src/brush_ops.c0000664000000000000000000007720413223665306015711 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 2009 Franck Charlet Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file brush_ops.c /// Code for operations about the brush (grabbing, rotating, ...) and magnifier ////////////////////////////////////////////////////////////////////////////// #include #include #include "brush.h" #include "buttons.h" #include "engine.h" #include "global.h" #include "graph.h" #include "misc.h" #include "operatio.h" #include "pages.h" #include "sdlscreen.h" #include "windows.h" #if defined(__VBCC__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) #define M_PI 3.141592653589793238462643 #endif /// Simulates clicking the "Draw" button. void Return_to_draw_mode(void) { // Comme l'enclenchement du bouton efface le curseur, il faut l'afficher au // pralable: Display_cursor(); if (Mouse_K) Wait_end_of_click(); // !!! Efface la croix puis affiche le viseur !!! Select_button(BUTTON_DRAW,LEFT_SIDE); // Dsenclenche au passage le bouton brosse if (Config.Auto_discontinuous) { // On se place en mode Dessin discontinu la main while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) Select_button(BUTTON_DRAW,RIGHT_SIDE); } // Maintenant, il faut reffacer le curseur parce qu'il sera raffich en fin // d'appel cette action: Hide_cursor(); // On passe en brosse couleur: Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: Y:",0); Print_coordinates(); } // ---------------------------------------------------------- OPERATION_MAGNIFY void Magnifier_12_0(void) // Opration : 4 (item d'une Loupe) // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { // On passe en mode loupe Main_magnifier_mode=1; // La fonction d'affichage dans la partie image est dsormais un affichage // spcial loupe. Pixel_preview=Pixel_preview_magnifier; // On calcule l'origine de la loupe Main_magnifier_offset_X=Mouse_X-(Main_magnifier_width>>1); Main_magnifier_offset_Y=Mouse_Y-(Main_magnifier_height>>1); // Calcul des coordonnes absolues de ce coin DANS L'IMAGE Main_magnifier_offset_X+=Main_offset_X; Main_magnifier_offset_Y+=Main_offset_Y; Clip_magnifier_offsets(&Main_magnifier_offset_X, &Main_magnifier_offset_Y); // On calcule les bornes visibles dans l'cran Position_screen_according_to_zoom(); Compute_limits(); Display_all_screen(); // Repositionner le curseur en fonction des coordonnes visibles Compute_paintbrush_coordinates(); // On fait de notre mieux pour restaurer l'ancienne opration: Start_operation_stack(Operation_before_interrupt); Display_cursor(); Wait_end_of_click(); } /////////////////////////////////////////////////////////// OPERATION_COLORPICK void Colorpicker_12_0(void) // // Opration : OPERATION_COLORPICK // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui // { Init_start_operation(); if (Mouse_K==LEFT_SIDE) { Set_fore_color(Colorpicker_color); } else { Set_back_color(Colorpicker_color); } Operation_push(Mouse_K); } void Colorpicker_1_1(void) // // Opration : OPERATION_COLORPICK // Click Souris: 1 // Taille_Pile : 1 // // Souris efface: Non // { char str[4]; if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0) && (Paintbrush_X=0) && (Paintbrush_Y>=0) && (Paintbrush_X=0) && (Paintbrush_Y>=0) && (Paintbrush_X=Main_X_zoom) ) ) Print_in_menu("X: Y: ",0); Print_coordinates(); Display_cursor(); } ////////////////////////////////////////////////////// OPERATION_GRAB_BRUSH void Brush_12_0(void) // // Opration : OPERATION_GRAB_BRUSH // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui // { Init_start_operation(); if (Mouse_K==RIGHT_SIDE) // Besoin d'effacer la brosse aprs ? { Operation_push(1); // Puisque la zone o on prend la brosse sera efface, on fait un backup Backup(); } else Operation_push(0); // On laisse une trace du curseur pour que l'utilisateur puisse visualiser // o demarre sa brosse: Display_cursor(); Operation_push(Paintbrush_X); // Dbut X Operation_push(Paintbrush_Y); // Dbut Y Operation_push(Paintbrush_X); // Dernire position X Operation_push(Paintbrush_Y); // Dernire position Y if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("\035: 1 \022: 1",0); } void Brush_12_5(void) // // Opration : OPERATION_GRAB_BRUSH // Click Souris: 1 ou 2 // Taille_Pile : 5 // // Souris efface: Non // { char str[5]; short start_x; short start_y; short old_x; short old_y; short width; short height; Operation_pop(&old_y); Operation_pop(&old_x); if ( (Menu_is_visible) && ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) ) { if (Config.Coords_rel) { Operation_pop(&start_y); Operation_pop(&start_x); Operation_push(start_x); Operation_push(start_y); width=((start_x1) width--; if (height>1) height--; } Num2str(width,str,4); Print_in_menu(str,2); Num2str(height,str,4); Print_in_menu(str,11); } else Print_coordinates(); } Display_all_screen(); x=Paintbrush_X; y=Paintbrush_Y; if (Snap_mode && Config.Adjust_brush_pick) { dx=Paintbrush_X-start_x; dy=Paintbrush_Y-start_y; if (dx<0) x++; else {if (dx>0) x--;} if (dy<0) y++; else {if (dy>0) y--;} Stretch_brush_preview(start_x,start_y,x,y); } else Stretch_brush_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y); old_x=Paintbrush_X; old_y=Paintbrush_Y; Paintbrush_X=start_x; Paintbrush_Y=start_y; Display_cursor(); Paintbrush_X=old_x; Paintbrush_Y=old_y; Display_cursor(); Operation_stack_size-=2; Operation_push(x); Operation_push(y); Operation_push(start_x); Operation_push(start_y); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(2); } void Stretch_brush_0_7(void) // // Opration : OPERATION_STRETCH_BRUSH // Click Souris: 0 // Taille_Pile : 7 // // Souris efface: Non // { char str[5]; short start_x; short start_y; short old_x; short old_y; short width=0; short height=0; byte size_change; short prev_state; Operation_pop(&prev_state); Operation_pop(&old_y); Operation_pop(&old_x); Operation_pop(&start_y); Operation_pop(&start_x); if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=3)) { if (Menu_is_visible) { if (Config.Coords_rel) { width=((start_x1)?start_x+(Brush_width>>1)-1:1; height=(Brush_height>1)?start_y+(Brush_height>>1)-1:1; break; case 'X': // Moiti X width=(Brush_width>1)?start_x+(Brush_width>>1)-1:1; height=start_y+Brush_height-1; break; case 'Y': // Moiti Y width=start_x+Brush_width-1; height=(Brush_height>1)?start_y+(Brush_height>>1)-1:1; break; case 'n': // Normal width=start_x+Brush_width-1; height=start_y+Brush_height-1; break; default : size_change=0; } Key_ANSI=0; } else size_change=0; if (size_change) { // On efface la preview de la brosse (et la croix) Display_all_screen(); old_x=Paintbrush_X; old_y=Paintbrush_Y; Paintbrush_X=start_x; Paintbrush_Y=start_y; Display_cursor(); Paintbrush_X=old_x; Paintbrush_Y=old_y; Stretch_brush_preview(start_x,start_y,width,height); Display_cursor(); Operation_stack_size-=2; Operation_push(width); Operation_push(height); } Operation_push(start_x); Operation_push(start_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(3); } void Stretch_brush_2_7(void) // // Opration : OPERATION_STRETCH_BRUSH // Click Souris: 2 // Taille_Pile : 7 // // Souris efface: Oui // { short computed_x; short computed_y; short start_x; short start_y; Operation_stack_size-=3; Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&computed_y); Operation_pop(&computed_x); // On efface la preview de la brosse (et la croix) Display_all_screen(); // Et enfin on stocke pour de bon la nouvelle brosse tire Stretch_brush(start_x,start_y,computed_x,computed_y); Return_to_draw_mode(); } //////////////////////////////////////////////////// OPERATION_ROTATE_BRUSH void Rotate_brush_12_0(void) // // Opration : OPERATION_ROTATE_BRUSH // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui // { Init_start_operation(); if (Mouse_K==LEFT_SIDE) { Brush_rotation_center_X=Paintbrush_X+(Brush_width>>1)-Brush_width; Brush_rotation_center_Y=Paintbrush_Y; Brush_rotation_center_is_defined=1; Operation_push(Paintbrush_X); // Dernire position calcule X Operation_push(Paintbrush_Y); // Dernire position calcule Y Operation_push(Paintbrush_X); // Dernire position X Operation_push(Paintbrush_Y); // Dernire position Y Operation_push(1); // State prcdent if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("Angle: 0 ",0); } else { Start_operation_stack(Operation_before_interrupt); Wait_end_of_click(); // FIXME: celui-la il donne un rsultat pas trs chouette en visuel } } void Rotate_brush_1_5(void) // // Opration : OPERATION_ROTATE_BRUSH // Click Souris: 1 // Taille_Pile : 5 // // Souris efface: Non // { char str[4]; short old_x; short old_y; short prev_state; float angle; int dx,dy; short cursor_x,cursor_y; Operation_pop(&prev_state); Operation_pop(&old_y); Operation_pop(&old_x); // On corrige les coordonnes de la ligne si la touche shift est appuye... cursor_x = Paintbrush_X; cursor_y = Paintbrush_Y; if(SDL_GetModState() & KMOD_SHIFT) Clamp_coordinates_regular_angle(Brush_rotation_center_X,Brush_rotation_center_Y,&cursor_x,&cursor_y); if ( (cursor_x!=old_x) || (cursor_y!=old_y) || (prev_state!=2) ) { if ( (Brush_rotation_center_X==cursor_x) && (Brush_rotation_center_Y==cursor_y) ) angle=0.0; else { dx=cursor_x-Brush_rotation_center_X; dy=cursor_y-Brush_rotation_center_Y; angle=M_2PI-atan2(dy,dx); } if (Menu_is_visible) { if (Config.Coords_rel) { Num2str((int)(angle*180.0/M_PI),str,3); Print_in_menu(str,7); } else Print_coordinates(); } Display_all_screen(); Rotate_brush_preview(angle); Display_cursor(); Operation_stack_size-=2; Operation_push(cursor_x); Operation_push(cursor_y); } Operation_push(cursor_x); Operation_push(cursor_y); Operation_push(2); } void Rotate_brush_0_5(void) // // Opration : OPERATION_ROTATE_BRUSH // Click Souris: 0 // Taille_Pile : 5 // // Souris efface: Non // { char str[4]; short old_x; short old_y; short computed_x=0; short computed_y=0; byte angle_change; short prev_state; float angle=0.0; int dx,dy; short cursor_x, cursor_y; Operation_pop(&prev_state); Operation_pop(&old_y); Operation_pop(&old_x); // On corrige les coordonnes de la ligne si la touche shift est appuye... cursor_x = Paintbrush_X; cursor_y = Paintbrush_Y; if(SDL_GetModState() & KMOD_SHIFT) Clamp_coordinates_regular_angle(Brush_rotation_center_X,Brush_rotation_center_Y,&cursor_x,&cursor_y); if ((cursor_x!=old_x) || (cursor_y!=old_y) || (prev_state!=3)) { Hide_cursor(); if ( (Brush_rotation_center_X==cursor_x) && (Brush_rotation_center_Y==cursor_y) ) angle=0.0; else { dx=cursor_x-Brush_rotation_center_X; dy=cursor_y-Brush_rotation_center_Y; angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); if (dy>0) angle=M_2PI-angle; } if (Menu_is_visible) { if (Config.Coords_rel) { Num2str(Round(angle*180.0/M_PI),str,3); Print_in_menu(str,7); } else Print_coordinates(); } Display_cursor(); } // Utilise Key_ANSI au lieu de Key, car Get_input() met ce dernier // zero si une operation est en cours (Operation_stack_size!=0) if (Key_ANSI) { angle_change=1; computed_x=Brush_rotation_center_X; computed_y=Brush_rotation_center_Y; switch (Key_ANSI) { case '6': angle= 0.0 ; computed_x++; break; case '9': angle=M_PI*0.25; computed_x++; computed_y--; break; case '8': angle=M_PI*0.5 ; computed_y--; break; case '7': angle=M_PI*0.75; computed_x--; computed_y--; break; case '4': angle=M_PI ; computed_x--; break; case '1': angle=M_PI*1.25; computed_x--; computed_y++; break; case '2': angle=M_PI*1.5 ; computed_y++; break; case '3': angle=M_PI*1.75; computed_x++; computed_y++; break; default : angle_change=0; } Key_ANSI=0; } else angle_change=0; if (angle_change) { // On efface la preview de la brosse Display_all_screen(); Rotate_brush_preview(angle); Display_cursor(); Operation_stack_size-=2; Operation_push(computed_x); Operation_push(computed_y); } Operation_push(cursor_x); Operation_push(cursor_y); Operation_push(3); } void Rotate_brush_2_5(void) // // Opration : OPERATION_ROTATE_BRUSH // Click Souris: 2 // Taille_Pile : 5 // // Souris efface: Oui // { short computed_x; short computed_y; int dx,dy; float angle; // On efface la preview de la brosse Display_all_screen(); Operation_stack_size-=3; Operation_pop(&computed_y); Operation_pop(&computed_x); // Calcul de l'angle par rapport la dernire position calcule if ( (Brush_rotation_center_X==computed_x) && (Brush_rotation_center_Y==computed_y) ) angle=0.0; else { dx=computed_x-Brush_rotation_center_X; dy=computed_y-Brush_rotation_center_Y; angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); if (dy>0) angle=M_2PI-angle; } // Et enfin on stocke pour de bon la nouvelle brosse tire Rotate_brush(angle); Return_to_draw_mode(); } ///////////////////////////////////////////////////// OPERATION_DISTORT_BRUSH /// Draws a 2x2 XOR square at the specified picture coordinates, on the screen. void Draw_stretch_spot(short x_pos, short y_pos) { short x,y; for (y=y_pos-1;y=Limit_top && y<=Limit_visible_bottom) for (x=x_pos-1;x=Limit_left && x<=Limit_visible_right) Pixel_preview(x,y,xor_lut[Read_pixel(x-Main_offset_X,y-Main_offset_Y)]); Update_part_of_screen(x_pos-1, y_pos-1, 2, 2); } void Distort_brush_0_0(void) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 0 // Taille_Pile : 0 // // Souris efface: Non // { if ( Menu_is_visible ) { Print_in_menu("POSITION BRUSH TO START ",0); } } void Distort_brush_1_0(void) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 1 // Taille_Pile : 0 // // Souris efface: Non // { short x_pos, y_pos; Init_start_operation(); Paintbrush_hidden=1; Hide_cursor(); // Top left angle x_pos=Paintbrush_X-Brush_offset_X; y_pos=Paintbrush_Y-Brush_offset_Y; Draw_stretch_spot(x_pos,y_pos); Operation_push(x_pos); Operation_push(y_pos); // Top right angle x_pos+=Brush_width; Draw_stretch_spot(x_pos,y_pos); Operation_push(x_pos); Operation_push(y_pos); // Bottom right angle y_pos+=Brush_height; Draw_stretch_spot(x_pos,y_pos); Operation_push(x_pos); Operation_push(y_pos); // Bottom left angle x_pos-=Brush_width; Draw_stretch_spot(x_pos,y_pos); Operation_push(x_pos); Operation_push(y_pos); Distort_brush_preview( Operation_stack[1], Operation_stack[2], Operation_stack[3], Operation_stack[4], Operation_stack[5], Operation_stack[6], Operation_stack[7], Operation_stack[8]); Display_cursor(); Update_part_of_screen(Paintbrush_X-Brush_offset_X, Paintbrush_Y-Brush_offset_Y, Brush_width, Brush_height); Wait_end_of_click(); // Erase the message in status bar if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); } } void Distort_brush_1_8(void) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 1 // Taille_Pile : 8 // // Souris efface: No // { // How far (in pixels) you can catch a handle #define REACH_DISTANCE 100 short i; short x[4]; short y[4]; long best_distance=REACH_DISTANCE; short best_spot=-1; for (i=3;i>=0;i--) { long distance; Operation_pop(&y[i]); Operation_pop(&x[i]); distance=Distance(Paintbrush_X,Paintbrush_Y,x[i],y[i]); if (distance-1) { Operation_push(best_spot); } if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } void Distort_brush_1_9(void) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 1 // Taille_Pile : 9 // // Souris efface: No // { short i; short x[4]; short y[4]; short selected_corner; // Pop all arguments Operation_pop(&selected_corner); for (i=3;i>=0;i--) { Operation_pop(&y[i]); Operation_pop(&x[i]); } if (Paintbrush_X!=x[selected_corner] || Paintbrush_Y!=y[selected_corner]) { Hide_cursor(); // Easiest refresh mode: make no assumptions on how the brush was // displayed before. Display_all_screen(); x[selected_corner]=Paintbrush_X; y[selected_corner]=Paintbrush_Y; for (i=0;i<4;i++) Draw_stretch_spot(x[i],y[i]); Distort_brush_preview(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]); Display_cursor(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } Update_rect(0,0,Screen_width,Menu_Y); } // Push back all arguments for (i=0;i<4;i++) { Operation_push(x[i]); Operation_push(y[i]); } Operation_push(selected_corner); } void Distort_brush_0_9(void) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 0 // Taille_Pile : 9 // // Souris efface: No // { short selected_corner; Operation_pop(&selected_corner); } void Distort_brush_2_0(void) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: Oui // { Paintbrush_hidden=0; Display_all_screen(); // Erase the message in status bar if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); } Return_to_draw_mode(); } void Distort_brush_2_8(void) // // Opration : OPERATION_DISTORT_BRUSH // Click Souris: 2 // Taille_Pile : 8 // // Souris efface: Oui // { short i; short x[4]; short y[4]; // Pop all arguments for (i=3;i>=0;i--) { Operation_pop(&y[i]); Operation_pop(&x[i]); } Distort_brush(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]); Paintbrush_hidden=0; Display_all_screen(); Return_to_draw_mode(); } grafx2_2.4+git20180105/src/operatio.c0000664000000000000000000027774513223665306015543 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 2009 Franck Charlet Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "engine.h" #include "graph.h" #include "operatio.h" #include "buttons.h" #include "pages.h" #include "errors.h" #include "sdlscreen.h" #include "brush.h" #include "windows.h" #include "input.h" #include "special.h" #include "tiles.h" // PI is NOT part of math.h according to C standards... #if defined(__GP2X__) || defined(__VBCC__) #define M_PI 3.14159265358979323846 #endif /// Time (in SDL ticks) when the next airbrush drawing should be done. Also used /// for discontinuous freehand drawing. Uint32 Airbrush_next_time; void Start_operation_stack(word new_operation) { // This part handles things that must be done when exiting an operation. Brush_rotation_center_is_defined=0; switch(Current_operation) { case OPERATION_ROTATE_BRUSH: End_brush_rotation(); break; default: break; } // On mmorise l'opration prcdente si on dmarre une interruption switch(new_operation) { case OPERATION_MAGNIFY: case OPERATION_COLORPICK: case OPERATION_RMB_COLORPICK: case OPERATION_GRAB_BRUSH: case OPERATION_POLYBRUSH: case OPERATION_STRETCH_BRUSH: case OPERATION_PAN_VIEW: Operation_before_interrupt=Current_operation; // On passe l'operation demande Current_operation=new_operation; break; case OPERATION_ROTATE_BRUSH: Begin_brush_rotation(); Operation_before_interrupt=Current_operation; // On passe l'operation demande Current_operation=new_operation; break; default : // On passe l'operation demande Current_operation=new_operation; Operation_before_interrupt=Current_operation; } // On spcifie si l'opration autorise le changement de couleur au clavier switch(new_operation) { case OPERATION_CONTINUOUS_DRAW: case OPERATION_DISCONTINUOUS_DRAW: case OPERATION_AIRBRUSH: case OPERATION_CENTERED_LINES: Allow_color_change_during_operation=1; break; default : Allow_color_change_during_operation=0; } // Et on passe au curseur qui va avec Cursor_shape=CURSOR_FOR_OPERATION[new_operation]; Operation_stack_size=0; } void Init_start_operation(void) { Operation_in_magnifier=(Mouse_X>=Main_X_zoom); Smear_start=1; } void Operation_push(short value) { Operation_stack[++Operation_stack_size]=value; } void Operation_pop(short * value) { *value=Operation_stack[Operation_stack_size--]; } byte Paintbrush_shape_before_operation; byte Paintbrush_hidden_before_scroll; short Distance(short x1, short y1, short x2, short y2) { short x2_moins_x1=x2-x1; short y2_minus_y1=y2-y1; return Round( sqrt( (x2_moins_x1*x2_moins_x1) + (y2_minus_y1*y2_minus_y1) ) ); } void Display_coords_rel_or_abs(short start_x, short start_y) { char str[6]; if (Config.Coords_rel) { if (Menu_is_visible) { if (Paintbrush_X>start_x) { Num2str(Paintbrush_X-start_x,str,5); str[0]='+'; } else if (Paintbrush_Xstart_y) { Num2str(Paintbrush_Y-start_y,str,5); str[0]='+'; } else if (Paintbrush_YAirbrush_next_time) { Airbrush_next_time+=Airbrush_delay*10; Hide_cursor(); // On affiche dfinitivement le pinceau Draw_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color); Display_cursor(); } } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } // ---------- void Freehand_mode2_2_0(void) // Opration : OPERATION_DISCONTINUOUS_DRAW // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: Oui { if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=Shade_table_right; Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Print_coordinates(); Airbrush_next_time = SDL_GetTicks() + Airbrush_delay*10; // On affiche dfinitivement le pinceau Draw_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color); } void Freehand_mode2_2_2(void) // Opration : OPERATION_DISCONTINUOUS_DRAW // Click Souris: 2 // Taille_Pile : 2 // // Souris efface: Non { short start_x; short start_y; Operation_pop(&start_y); Operation_pop(&start_x); if ( (start_x!=Paintbrush_X) || (start_y!=Paintbrush_Y) ) { Print_coordinates(); if (SDL_GetTicks()>Airbrush_next_time) { Airbrush_next_time+=Airbrush_delay*10; Hide_cursor(); // On affiche dfinitivement le pinceau Draw_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color); Display_cursor(); } } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } ////////////////////////////////////////////////////// OPERATION_POINT_DRAW void Freehand_mode3_1_0(void) // Opration : OPERATION_POINT_DRAW // Click Souris: 1 // Taille_Pile : 0 // // Souris efface: Oui { Init_start_operation(); Backup(); Shade_table=Shade_table_left; // On affiche dfinitivement le pinceau Draw_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color); Operation_push(0); // On change simplement l'tat de la pile... } void Freehand_Mode3_2_0(void) // Opration : OPERATION_POINT_DRAW // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: Oui { if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=Shade_table_right; // On affiche dfinitivement le pinceau Draw_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color); Operation_push(0); // On change simplement l'tat de la pile... } void Freehand_mode3_0_1(void) // Opration : OPERATION_POINT_DRAW // Click Souris: 0 // Taille_Pile : 1 // // Souris efface: Non { End_of_modification(); Operation_stack_size--; } ///////////////////////////////////////////////////////////// OPERATION_LINE void Line_12_0(void) // Opration : OPERATION_LINE // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui // Dbut du trac d'une ligne (premier clic) { if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Paintbrush_shape_before_operation=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; if (Mouse_K==LEFT_SIDE) { Shade_table=Shade_table_left; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Fore_color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); Operation_push(Fore_color); } else { Shade_table=Shade_table_right; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Back_color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); Operation_push(Back_color); } if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Line_12_5(void) // Opration : OPERATION_LINE // Click Souris: 1 // Taille_Pile : 5 // // Souris efface: Non // Poursuite du trac d'une ligne (dplacement de la souris en gardant le // curseur appuy) { short start_x; short start_y; short end_x; short end_y; short cursor_x; short cursor_y; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); cursor_x = Paintbrush_X; cursor_y = Paintbrush_Y; // On corrige les coordonnes de la ligne si la touche shift est appuye... if(SDL_GetModState() & KMOD_SHIFT) Clamp_coordinates_regular_angle(start_x,start_y,&cursor_x,&cursor_y); // On vient de bouger if ((cursor_x!=end_x) || (cursor_y!=end_y)) { Hide_cursor(); Display_coords_rel_or_abs(start_x,start_y); Hide_line_preview(start_x,start_y,end_x,end_y); if (Mouse_K==LEFT_SIDE) { Pixel_figure_preview (start_x,start_y,Fore_color); Draw_line_preview (start_x,start_y,cursor_x,cursor_y,Fore_color); } else { Pixel_figure_preview (start_x,start_y,Back_color); Draw_line_preview (start_x,start_y,cursor_x,cursor_y,Back_color); } Operation_push(start_x); Operation_push(start_y); Operation_push(cursor_x); Operation_push(cursor_y); Display_cursor(); } else { Operation_push(start_x); Operation_push(start_y); Operation_push(end_x); Operation_push(end_y); } } void Line_0_5(void) // Opration : OPERATION_LINE // Click Souris: 0 // Taille_Pile : 5 // // Souris efface: Oui // End du trac d'une ligne (relachage du bouton) { short start_x; short start_y; short end_x; short end_y; short color; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&color); Paintbrush_shape=Paintbrush_shape_before_operation; Pixel_figure_preview_auto (start_x,start_y); Hide_line_preview (start_x,start_y,end_x,end_y); Draw_paintbrush (start_x,start_y,color); Draw_line_permanent(start_x,start_y,end_x,end_y,color); End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } /////////////////////////////////////////////////////////// OPERATION_K_LINE void K_line_12_0(void) // Opration : OPERATION_K_LINE // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { byte color; if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; Paintbrush_shape_before_operation=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; // On place temporairement le dbut de la ligne qui ne s'afficherait pas sinon Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Mouse_K | 0x80); Operation_push(color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); // Taille de pile 6 : phase d'appui, non interruptible } void K_line_12_6(void) // Opration : OPERATION_K_LINE // Click Souris: 1 ou 2 | 0 // Taille_Pile : 6 | 7 // // Souris efface: Non { short start_x; short start_y; short end_x; short end_y; short color; Operation_pop(&end_y); Operation_pop(&end_x); if ((Paintbrush_X!=end_x) || (Paintbrush_Y!=end_y)) { Hide_cursor(); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&color); Display_coords_rel_or_abs(start_x,start_y); Hide_line_preview(start_x,start_y,end_x,end_y); Pixel_figure_preview (start_x,start_y,color); Draw_line_preview (start_x,start_y,Paintbrush_X,Paintbrush_Y,color); Operation_push(color); Operation_push(start_x); Operation_push(start_y); Display_cursor(); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void K_line_0_6(void) // Opration : OPERATION_K_LINE // Click Souris: 0 // Taille_Pile : 6 // // Souris efface: Oui { short start_x; short start_y; short end_x; short end_y; short color; short direction; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&color); Operation_pop(&direction); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Pixel_figure_preview_auto (start_x,start_y); Hide_line_preview (start_x,start_y,end_x,end_y); /* Doesn't work if fast moving Pixel_figure_preview_xor (start_x,start_y, 0); Draw_line_preview_xor (start_x,start_y,end_x,end_y,0); */ Paintbrush_shape=Paintbrush_shape_before_operation; if (direction & 0x80) { Draw_paintbrush(start_x,start_y,color); direction=(direction & 0x7F); } Draw_line_permanent(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Operation_push(direction); Operation_push(direction); // Valeur bidon servant de nouvel tat de pile Operation_push(color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); // Taille de pile 7 : phase de "repos", interruptible (comme Elliot Ness :)) } void K_line_12_7(void) // Opration : OPERATION_K_LINE // Click Souris: 1 ou 2 // Taille_Pile : 7 // // Souris efface: Oui { short start_x; short start_y; short end_x; short end_y; short color; short direction; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&color); Operation_pop(&direction); Operation_pop(&direction); if (direction==Mouse_K) { Operation_push(direction); Operation_push(color); Operation_push(start_x); Operation_push(start_y); Operation_push(end_x); Operation_push(end_y); // Taille de pile 6 : phase d'appui, non interruptible } else { // La srie de ligne est termine, il faut donc effacer la dernire // preview de ligne Pixel_figure_preview_auto (start_x,start_y); Hide_line_preview (start_x,start_y,end_x,end_y); Display_cursor(); Wait_end_of_click(); Hide_cursor(); Paintbrush_shape=Paintbrush_shape_before_operation; End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } } /////////////////////////////////////////////////// OPERATION_RECTANGLE_????? void Rectangle_12_0(void) // Opration : OPERATION_EMPTY_RECTANGLE / OPERATION_FILLED_RECTANGLE // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { if (Rightclick_colorpick(0)) return; Init_start_operation(); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("\035: 1 \022: 1",0); // On laisse une trace du curseur l'cran Display_cursor(); if (Mouse_K==LEFT_SIDE) { Shade_table=Shade_table_left; Operation_push(Fore_color); } else { Shade_table=Shade_table_right; Operation_push(Back_color); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Rectangle_12_5(void) // Opration : OPERATION_EMPTY_RECTANGLE / OPERATION_FILLED_RECTANGLE // Click Souris: 1 ou 2 // Taille_Pile : 5 // // Souris efface: Non { short start_x; short start_y; short old_x; short old_y; char str[5]; Operation_pop(&old_y); Operation_pop(&old_x); if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) { Operation_pop(&start_y); Operation_pop(&start_x); if ((Config.Coords_rel) && (Menu_is_visible)) { Num2str(((start_xcenter_x)?tangent_x-center_x :center_x-tangent_x; vertical_radius =(tangent_y>center_y)?tangent_y-center_y :center_y-tangent_y; Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); horizontal_radius=(Paintbrush_X>center_x)?Paintbrush_X-center_x :center_x-Paintbrush_X; vertical_radius =(Paintbrush_Y>center_y)?Paintbrush_Y-center_y :center_y-Paintbrush_Y; Draw_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius,color); Display_cursor(); } Operation_push(color); Operation_push(center_x); Operation_push(center_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Empty_ellipse_0_5(void) // // Opration : OPERATION_EMPTY_ELLIPSE // Click Souris: 0 // Taille_Pile : 5 (color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) // // Souris efface: Oui // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short horizontal_radius; short vertical_radius; Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); horizontal_radius=(tangent_x>center_x)?tangent_x-center_x :center_x-tangent_x; vertical_radius =(tangent_y>center_y)?tangent_y-center_y :center_y-tangent_y; Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); Paintbrush_shape=Paintbrush_shape_before_operation; Draw_empty_ellipse_permanent(center_x,center_y,horizontal_radius,vertical_radius,color); End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } Cursor_shape=CURSOR_SHAPE_XOR_TARGET; } void Filled_ellipse_0_5(void) // // Opration : OPERATION_FILLED_ELLIPSE // Click Souris: 0 // Taille_Pile : 5 (color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) // // Souris efface: Oui // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short horizontal_radius; short vertical_radius; Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); horizontal_radius=(tangent_x>center_x)?tangent_x-center_x :center_x-tangent_x; vertical_radius =(tangent_y>center_y)?tangent_y-center_y :center_y-tangent_y; Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); Paintbrush_shape=Paintbrush_shape_before_operation; Draw_filled_ellipse(center_x,center_y,horizontal_radius,vertical_radius,color); End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } Cursor_shape=CURSOR_SHAPE_XOR_TARGET; } ////////////////////////////////////////////////////////////// OPERATION_FILL void Fill_1_0(void) // // Opration : OPERATION_FILL // Click Souris: 1 // Taille_Pile : 0 // // Souris efface: Oui // { Hide_cursor(); // Pas besoin d'initialiser le dbut d'opration car le Smear n'affecte pas // le Fill, et on se fout de savoir si on est dans la partie gauche ou // droite de la loupe. // On ne s'occupe pas de faire un Backup: c'est "Fill_general" qui s'en charge. Shade_table=Shade_table_left; Fill_general(Fore_color); Display_cursor(); End_of_modification(); Wait_end_of_click(); } void Fill_2_0(void) // // Opration : OPERATION_FILL // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: Non // { if (Rightclick_colorpick(1)) return; Hide_cursor(); // Pas besoin d'initialiser le dbut d'opration car le Smear n'affecte pas // le Fill, et on se fout de savoir si on est dans la partie gauche ou // droite de la loupe. // On ne s'occupe pas de faire un Backup: c'est "Fill_general" qui s'en charge. Shade_table=Shade_table_right; Fill_general(Back_color); Display_cursor(); End_of_modification(); Wait_end_of_click(); } ///////////////////////////////////////////////////////// OPERATION_REPLACE void Replace_1_0(void) // // Opration : OPERATION_REPLACE // Click Souris: 1 // Taille_Pile : 0 // // Souris efface: Non // { Hide_cursor(); Init_start_operation(); Backup(); // Shade_table=Shade_table_left; Replace(Fore_color); End_of_modification(); Display_all_screen(); Display_cursor(); Wait_end_of_click(); } void Replace_2_0(void) // // Opration : OPERATION_REPLACE // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: Non // { if (Rightclick_colorpick(1)) return; Hide_cursor(); Init_start_operation(); Backup(); // Shade_table=Shade_table_right; Replace(Back_color); End_of_modification(); Display_all_screen(); Display_cursor(); Wait_end_of_click(); } /////////////////////////////////////////////////// OPERATION_4_POINTS_CURVE void Draw_curve_cross(short x_pos, short y_pos) { short start_x,end_x; short start_y,end_y; short i,temp; //byte temp2; if (x_pos>=Limit_left+3) start_x=0; else start_x=3-(x_pos-Limit_left); if (y_pos>=Limit_top+3) start_y=0; else start_y=3-(y_pos-Limit_top); if (x_pos<=Limit_visible_right-3) end_x=6; else end_x=3+(Limit_visible_right-x_pos); if (y_pos<=Limit_visible_bottom-3) end_y=6; else end_y=3+(Limit_visible_bottom-y_pos); if (start_x<=end_x && start_y<=end_y) { for (i=start_x; i<=end_x; i++) { temp=x_pos+i-3; Pixel_preview(temp,y_pos,xor_lut[Read_pixel(temp -Main_offset_X, y_pos-Main_offset_Y)]); } for (i=start_y; i<=end_y; i++) { temp=y_pos+i-3; Pixel_preview(x_pos,temp,xor_lut[Read_pixel(x_pos-Main_offset_X, temp -Main_offset_Y)]); } Update_part_of_screen(x_pos+start_x-3,y_pos+start_y-3,end_x-start_x+1,end_y-start_y+1); } } void Curve_34_points_1_0(void) // // Opration : OPERATION_COURBE_?_POINTS // Click Souris: 1 // Taille_Pile : 0 // // Souris efface: Oui // { Init_start_operation(); Backup(); Shade_table=Shade_table_left; Paintbrush_hidden=1; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Fore_color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Fore_color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Curve_34_points_2_0(void) // // Opration : OPERATION_COURBE_?_POINTS // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: Oui // { if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=Shade_table_right; Paintbrush_hidden=1; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Back_color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Back_color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Curve_34_points_1_5(void) // // Opration : OPERATION_COURBE_?_POINTS // Click Souris: 1 // Taille_Pile : 5 // // Souris efface: Non // { short x1,x2,y1,y2; Operation_pop(&y2); Operation_pop(&x2); Operation_pop(&y1); Operation_pop(&x1); if ( (y2!=Paintbrush_Y) || (x2!=Paintbrush_X) ) { Hide_cursor(); Display_coords_rel_or_abs(x1,y1); Hide_line_preview(x1,y1,x2,y2); Pixel_figure_preview (x1,y1,Fore_color); Draw_line_preview (x1,y1,Paintbrush_X,Paintbrush_Y,Fore_color); Display_cursor(); } Operation_push(x1); Operation_push(y1); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Curve_34_points_2_5(void) // // Opration : OPERATION_COURBE_?_POINTS // Click Souris: 2 // Taille_Pile : 5 // // Souris efface: Non // { short x1,x2,y1,y2; Operation_pop(&y2); Operation_pop(&x2); Operation_pop(&y1); Operation_pop(&x1); if ( (y2!=Paintbrush_Y) || (x2!=Paintbrush_X) ) { Hide_cursor(); Display_coords_rel_or_abs(x1,y1); Hide_line_preview(x1,y1,x2,y2); Pixel_figure_preview (x1,y1,Back_color); Draw_line_preview (x1,y1,Paintbrush_X,Paintbrush_Y,Back_color); Display_cursor(); } Operation_push(x1); Operation_push(y1); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } byte Cursor_hidden_before_curve; void Curve_4_points_0_5(void) // // Opration : OPERATION_4_POINTS_CURVE // Click Souris: 0 // Taille_Pile : 5 // // Souris efface: Oui // { short x1,y1,x2,y2,x3,y3,x4,y4; short third_x,third_y; short color; Operation_pop(&y4); Operation_pop(&x4); Operation_pop(&y1); Operation_pop(&x1); Operation_pop(&color); third_x=Round_div(abs(x4-x1),3); third_y=Round_div(abs(y4-y1),3); if (x1B=(8/3) * C->P *x3=Round((bx+x4)/2.0); // _/ P3 P2=middle of [P1,B] *y3=Round((by+y4)/2.0); // P4*-- P3=middle of [P4,B] } void Curve_3_points_0_5(void) // // Opration : OPERATION_3_POINTS_CURVE // Click Souris: 0 // Taille_Pile : 5 // // Souris efface: Oui // { short x1,y1,x2,y2,x3,y3,x4,y4; short color; Operation_pop(&y4); Operation_pop(&x4); Operation_pop(&y1); Operation_pop(&x1); Operation_pop(&color); Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); if (!Config.Stylus_mode) { Hide_line_preview(x1,y1,x4,y4); Draw_curve_preview(x1,y1,x2,y2,x3,y3,x4,y4,color); } if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } Operation_push(color); Operation_push(x1); Operation_push(y1); Operation_push(x2); Operation_push(y2); Operation_push(x3); Operation_push(y3); Operation_push(x4); Operation_push(y4); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); if (Config.Stylus_mode) { Display_cursor(); while(!Mouse_K) Get_input(20); Hide_cursor(); Hide_line_preview(x1,y1,x4,y4); } } void Curve_drag(void) { short x1,y1,x2,y2,x3,y3,x4,y4; short old_x,old_y; short color; Operation_pop(&old_y); Operation_pop(&old_x); if ( (Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) ) { Operation_pop(&y4); Operation_pop(&x4); Operation_pop(&y3); Operation_pop(&x3); Operation_pop(&y2); Operation_pop(&x2); Operation_pop(&y1); Operation_pop(&x1); Operation_pop(&color); Hide_cursor(); Print_coordinates(); Hide_curve_preview(x1,y1,x2,y2,x3,y3,x4,y4,color); Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); Draw_curve_preview (x1,y1,x2,y2,x3,y3,x4,y4,color); Display_cursor(); Operation_push(color); Operation_push(x1); Operation_push(y1); Operation_push(x2); Operation_push(y2); Operation_push(x3); Operation_push(y3); Operation_push(x4); Operation_push(y4); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Curve_finalize(void) { short x1,y1,x2,y2,x3,y3,x4,y4; short old_x,old_y; short color; Operation_pop(&old_y); Operation_pop(&old_x); Operation_pop(&y4); Operation_pop(&x4); Operation_pop(&y3); Operation_pop(&x3); Operation_pop(&y2); Operation_pop(&x2); Operation_pop(&y1); Operation_pop(&x1); Operation_pop(&color); Paintbrush_hidden=0; Hide_cursor(); Hide_curve_preview (x1,y1,x2,y2,x3,y3,x4,y4,color); Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); Draw_curve_permanent(x1,y1,x2,y2,x3,y3,x4,y4,color); End_of_modification(); Display_cursor(); Wait_end_of_click(); } void Curve_3_points_0_11(void) // // Opration : OPERATION_3_POINTS_CURVE // Click Souris: 0 // Taille_Pile : 11 // // Souris efface: Non // { if (!Config.Stylus_mode) Curve_drag(); else Curve_finalize(); } void Curve_3_points_12_11(void) // // Opration : OPERATION_3_POINTS_CURVE // Click Souris: 1 ou 2 // Taille_Pile : 11 // // Souris efface: Oui // { if (!Config.Stylus_mode) Curve_finalize(); else Curve_drag(); } ///////////////////////////////////////////////////////////// OPERATION_AIRBRUSH void Airbrush_1_0(void) // // Opration : OPERATION_AIRBRUSH // Click Souris: 1 // Taille_Pile : 0 // // Souris efface: Non // { Init_start_operation(); Backup(); Shade_table=Shade_table_left; if (SDL_GetTicks()>Airbrush_next_time) { Airbrush(LEFT_SIDE); Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Airbrush_2_0(void) // // Opration : OPERATION_AIRBRUSH // Click Souris: 2 // Taille_Pile : 0 // // Souris efface: Non // { if (Rightclick_colorpick(1)) return; Init_start_operation(); Backup(); Shade_table=Shade_table_right; if (SDL_GetTicks()>Airbrush_next_time) { Airbrush(RIGHT_SIDE); Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Airbrush_12_2(void) // // Opration : OPERATION_AIRBRUSH // Click Souris: 1 ou 2 // Taille_Pile : 2 // // Souris efface: Non // { short old_x,old_y; Uint32 now; Operation_pop(&old_y); Operation_pop(&old_x); if ( (Menu_is_visible) && ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) ) { Hide_cursor(); Print_coordinates(); Display_cursor(); } now=SDL_GetTicks(); if (now>Airbrush_next_time) { //Airbrush_next_time+=Airbrush_delay*10; // Time is now reset, because the += was death spiral // if drawing took more time than the frequency. Airbrush_next_time=now+Airbrush_delay*10; Airbrush(Mouse_K_unique); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Airbrush_0_2(void) // // Opration : OPERATION_AIRBRUSH // Click Souris: 0 // Taille_Pile : 2 // // Souris efface: Non // { Operation_stack_size-=2; End_of_modification(); } ////////////////////////////////////////////////////////// OPERATION_POLYGON void Polygon_12_0(void) // Opration : OPERATION_POLYGON // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { byte color; if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; Paintbrush_shape_before_operation=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; // On place temporairement le dbut de la ligne qui ne s'afficherait pas sinon Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Mouse_K | 0x80); Operation_push(color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); // Taille de pile 8 : phase d'appui, non interruptible } void Polygon_12_9(void) // Opration : OPERATION_POLYGON // Click Souris: 1 ou 2 // Taille_Pile : 9 // // Souris efface: Oui { short start_x; short start_y; short end_x; short end_y; short color; short direction; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&color); Operation_pop(&direction); Operation_pop(&direction); if (direction==Mouse_K) { Operation_push(direction); Operation_push(color); Operation_push(start_x); Operation_push(start_y); Operation_push(end_x); Operation_push(end_y); // Taille de pile 8 : phase d'appui, non interruptible } else { // La srie de ligne est termine, il faut donc effacer la dernire // preview de ligne et relier le dernier point avec le premier Pixel_figure_preview_auto (start_x,start_y); Hide_line_preview (start_x,start_y,end_x,end_y); Operation_pop(&end_y); Operation_pop(&end_x); Paintbrush_shape=Paintbrush_shape_before_operation; // Le pied aurait t de ne pas repasser sur le 1er point de la 1re ligne // mais c'est pas possible :( Draw_line_permanent(start_x,start_y,end_x,end_y,color); Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Display_cursor(); End_of_modification(); Wait_end_of_click(); Hide_cursor(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } Paintbrush_shape=Paintbrush_shape_before_operation; } } ////////////////////////////////////////////////////////// OPERATION_POLYFILL void Polyfill_12_0(void) // Opration : OPERATION_POLYFILL // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { byte color; if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; Paintbrush_hidden=1; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; Polyfill_table_of_points=(short *) malloc((Config.Nb_max_vertices_per_polygon<<1)*sizeof(short)); Polyfill_table_of_points[0]=Paintbrush_X; Polyfill_table_of_points[1]=Paintbrush_Y; Polyfill_number_of_points=1; // On place temporairement le dbut de la ligne qui ne s'afficherait pas sinon Pixel_figure_preview_xor(Paintbrush_X,Paintbrush_Y,0); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Mouse_K | 0x80); Operation_push(color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); // Taille de pile 8 : phase d'appui, non interruptible } void Polyfill_0_8(void) // Opration : OPERATION_POLYFILL // Click Souris: 0 // Taille_Pile : 8 // // Souris efface: Oui { short start_x; short start_y; short end_x; short end_y; short color; short direction; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&color); Operation_pop(&direction); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Draw_line_preview_xor(start_x,start_y,end_x,end_y,0); if (direction & 0x80) direction=(direction & 0x7F); Operation_push(direction); // Valeur bidon servant de nouvel tat de pile Operation_push(direction); Operation_push(color); Draw_line_preview_xor(start_x,start_y,Paintbrush_X,Paintbrush_Y,0); if (Polyfill_number_of_pointsPages->Image_mode != IMAGE_MODE_ANIMATION) { // Ensure the backup visible image is up-to-date // (after swapping some layers on/off, it gets outdated) memcpy(Main_visible_image_backup.Image, Main_visible_image.Image, Main_image_width*Main_image_height); } } Update_screen_targets(); Cursor_hidden_before_scroll=Cursor_hidden; Cursor_hidden=1; if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); } void Scroll_12_5(void) // // Opration : OPERATION_SCROLL // Click Souris: 1 ou 2 // Taille_Pile : 5 // // Souris efface: Non // { short center_x; short center_y; short x_pos; short y_pos; short x_offset; short y_offset; short side; //char str[5]; Operation_pop(&side); Operation_pop(&y_pos); Operation_pop(&x_pos); Operation_pop(¢er_y); Operation_pop(¢er_x); if ( (Paintbrush_X!=x_pos) || (Paintbrush_Y!=y_pos) ) { // L'utilisateur a boug, il faut scroller l'image if (Paintbrush_X>=center_x) x_offset=(Paintbrush_X-center_x)%Main_image_width; else x_offset=Main_image_width-((center_x-Paintbrush_X)%Main_image_width); if (Paintbrush_Y>=center_y) y_offset=(Paintbrush_Y-center_y)%Main_image_height; else y_offset=Main_image_height-((center_y-Paintbrush_Y)%Main_image_height); Display_coords_rel_or_abs(center_x,center_y); if (side == RIGHT_SIDE) { // All layers at once Scroll_picture(Screen_backup, Main_screen, x_offset,y_offset); } else { // One layer at once Scroll_picture(Main_backups->Pages->Next->Image[Main_current_layer].Pixels, Main_backups->Pages->Image[Main_current_layer].Pixels, x_offset, y_offset); Redraw_current_layer(); } Display_all_screen(); } Operation_push(center_x); Operation_push(center_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(side); } void Scroll_0_5(void) // // Opration : OPERATION_SCROLL // Click Souris: 0 // Taille_Pile : 5 // // Souris efface: Oui // { // All layers at once short center_x; short center_y; short x_pos; short y_pos; short x_offset; short y_offset; short side; int i; Operation_pop(&side); Operation_pop(&y_pos); Operation_pop(&x_pos); Operation_pop(¢er_y); Operation_pop(¢er_x); if (side == RIGHT_SIDE) { // All layers at once if (x_pos>=center_x) x_offset=(x_pos-center_x)%Main_image_width; else x_offset=Main_image_width-((center_x-x_pos)%Main_image_width); if (y_pos>=center_y) y_offset=(y_pos-center_y)%Main_image_height; else y_offset=Main_image_height-((center_y-y_pos)%Main_image_height); // Do the actual scroll operation on all layers. for (i=0; iPages->Nb_layers; i++) //if ((1<Pages->Next->Image[i].Pixels, Main_backups->Pages->Image[i].Pixels, x_offset, y_offset); // Update the depth buffer too ... // It would be faster to scroll it, but we don't have method // for in-place scrolling. Update_depth_buffer(); } else { // One layer : everything was done while dragging the mouse } if (Main_tilemap_mode) Tilemap_update(); Cursor_hidden=Cursor_hidden_before_scroll; End_of_modification(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } //////////////////////////////////////////////////// OPERATION_GRAD_CIRCLE void Grad_circle_12_0(void) // // Opration : OPERATION_GRAD_CIRCLE // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { byte color; Init_start_operation(); Backup(); Load_gradient_data(Current_gradient); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; Paintbrush_hidden_before_scroll=Paintbrush_hidden; Paintbrush_hidden=1; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("Radius: 0 ",0); Operation_push(Mouse_K); Operation_push(color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Grad_circle_12_6(void) // // Opration : OPERATION_GRAD_CIRCLE // Click Souris: 1 ou 2 // Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) // // Souris efface: Non // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short radius; char str[5]; Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); if ( (tangent_x!=Paintbrush_X) || (tangent_y!=Paintbrush_Y) ) { Hide_cursor(); Cursor_shape=CURSOR_SHAPE_TARGET; if ((Config.Coords_rel) && (Menu_is_visible)) { Num2str(Distance(center_x,center_y,Paintbrush_X,Paintbrush_Y),str,4); Print_in_menu(str,7); } else Print_coordinates(); Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ ((tangent_y-center_y)*(tangent_y-center_y)); radius=sqrt(Circle_limit); Hide_empty_circle_preview(center_x,center_y,radius); Circle_limit=((Paintbrush_X-center_x)*(Paintbrush_X-center_x))+ ((Paintbrush_Y-center_y)*(Paintbrush_Y-center_y)); radius=sqrt(Circle_limit); Draw_empty_circle_preview(center_x,center_y,radius,color); Display_cursor(); } Operation_push(color); Operation_push(center_x); Operation_push(center_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Grad_circle_0_6(void) // // Opration : OPERATION_GRAD_CIRCLE // Click Souris: 0 // Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) // // Souris efface: Oui // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short click; short radius; Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); Operation_pop(&click); if (click==LEFT_SIDE) { Operation_push(click); Operation_push(color); Operation_push(center_x); Operation_push(center_y); Operation_push(tangent_x); Operation_push(tangent_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); // On change la forme du curseur Cursor_shape=CURSOR_SHAPE_XOR_TARGET; // On affiche une croix XOR au centre du cercle Draw_curve_cross(center_x,center_y); if (Menu_is_visible) { if (Config.Coords_rel) Print_in_menu("X: Y:",0); else Print_in_menu("X: Y: ",0); Display_coords_rel_or_abs(center_x,center_y); } } else { Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ ((tangent_y-center_y)*(tangent_y-center_y)); radius=sqrt(Circle_limit); Hide_empty_circle_preview(center_x,center_y,radius); Paintbrush_hidden=Paintbrush_hidden_before_scroll; Cursor_shape=CURSOR_SHAPE_TARGET; Draw_filled_circle(center_x,center_y,radius,Back_color); End_of_modification(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } } void Grad_circle_12_8(void) // // Opration : OPERATION_GRAD_CIRCLE // Click Souris: 0 // Taille_Pile : 8 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente, old_x, old_y) // // Souris efface: Oui // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short old_mouse_k; short radius; Operation_stack_size-=2; // On fait sauter les 2 derniers lts de la pile Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); Operation_pop(&old_mouse_k); Hide_cursor(); // On efface la croix XOR au centre du cercle Draw_curve_cross(center_x,center_y); Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ ((tangent_y-center_y)*(tangent_y-center_y)); radius=sqrt(Circle_limit); Hide_empty_circle_preview(center_x,center_y,radius); Paintbrush_hidden=Paintbrush_hidden_before_scroll; Cursor_shape=CURSOR_SHAPE_TARGET; if (Mouse_K==old_mouse_k) Draw_grad_circle(center_x,center_y,radius,Paintbrush_X,Paintbrush_Y); Cursor_shape=CURSOR_SHAPE_XOR_TARGET; Display_cursor(); End_of_modification(); Wait_end_of_click(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } void Grad_circle_or_ellipse_0_8(void) // // Opration : OPERATION_{CERCLE|ELLIPSE}_DEGRADE // Click Souris: 0 // Taille_Pile : 8 // // Souris efface: Non // { short start_x; short start_y; short tangent_x; short tangent_y; short old_x; short old_y; Operation_pop(&old_y); Operation_pop(&old_x); if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) { Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(&start_y); Operation_pop(&start_x); Display_coords_rel_or_abs(start_x,start_y); Operation_push(start_x); Operation_push(start_y); Operation_push(tangent_x); Operation_push(tangent_y); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } ////////////////////////////////////////////////// OPERATION_GRAD_ELLIPSE void Grad_ellipse_12_0(void) // // Opration : OPERATION_GRAD_ELLIPSE // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { byte color; Init_start_operation(); Backup(); Load_gradient_data(Current_gradient); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; Paintbrush_hidden_before_scroll=Paintbrush_hidden; Paintbrush_hidden=1; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Mouse_K); Operation_push(color); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Grad_ellipse_12_6(void) // // Opration : OPERATION_GRAD_ELLIPSE // Click Souris: 1 ou 2 // Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) // // Souris efface: Non // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short horizontal_radius; short vertical_radius; Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); if ( (tangent_x!=Paintbrush_X) || (tangent_y!=Paintbrush_Y) ) { Hide_cursor(); Cursor_shape=CURSOR_SHAPE_TARGET; Display_coords_rel_or_abs(center_x,center_y); horizontal_radius=(tangent_x>center_x)?tangent_x-center_x :center_x-tangent_x; vertical_radius =(tangent_y>center_y)?tangent_y-center_y :center_y-tangent_y; Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); horizontal_radius=(Paintbrush_X>center_x)?Paintbrush_X-center_x :center_x-Paintbrush_X; vertical_radius =(Paintbrush_Y>center_y)?Paintbrush_Y-center_y :center_y-Paintbrush_Y; Draw_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius,color); Display_cursor(); } Operation_push(color); Operation_push(center_x); Operation_push(center_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Grad_ellipse_0_6(void) // // Opration : OPERATION_GRAD_ELLIPSE // Click Souris: 0 // Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) // // Souris efface: Oui // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short click; //short radius; short horizontal_radius; short vertical_radius; Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); Operation_pop(&click); if (click==LEFT_SIDE) { Operation_push(click); Operation_push(color); Operation_push(center_x); Operation_push(center_y); Operation_push(tangent_x); Operation_push(tangent_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); // On change la forme du curseur Cursor_shape=CURSOR_SHAPE_XOR_TARGET; // On affiche une croix XOR au centre du cercle Draw_curve_cross(center_x,center_y); if (Menu_is_visible) { if (Config.Coords_rel) Print_in_menu("X: Y:",0); else Print_in_menu("X: Y: ",0); Display_coords_rel_or_abs(center_x,center_y); } } else { horizontal_radius=(tangent_x>center_x)?tangent_x-center_x :center_x-tangent_x; vertical_radius =(tangent_y>center_y)?tangent_y-center_y :center_y-tangent_y; Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); Paintbrush_hidden=Paintbrush_hidden_before_scroll; Cursor_shape=CURSOR_SHAPE_TARGET; Draw_filled_ellipse(center_x,center_y,horizontal_radius,vertical_radius,Back_color); End_of_modification(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } } void Grad_ellipse_12_8(void) // // Opration : OPERATION_GRAD_ELLIPSE // Click Souris: 0 // Taille_Pile : 8 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente, old_x, old_y) // // Souris efface: Oui // { short tangent_x; short tangent_y; short center_x; short center_y; short color; short horizontal_radius; short vertical_radius; short old_mouse_k; Operation_stack_size-=2; // On fait sauter les 2 derniers lts de la pile Operation_pop(&tangent_y); Operation_pop(&tangent_x); Operation_pop(¢er_y); Operation_pop(¢er_x); Operation_pop(&color); Operation_pop(&old_mouse_k); Hide_cursor(); // On efface la croix XOR au centre de l'ellipse Draw_curve_cross(center_x,center_y); horizontal_radius=(tangent_x>center_x)?tangent_x-center_x :center_x-tangent_x; vertical_radius =(tangent_y>center_y)?tangent_y-center_y :center_y-tangent_y; Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); Paintbrush_hidden=Paintbrush_hidden_before_scroll; Cursor_shape=CURSOR_SHAPE_XOR_TARGET; if (Mouse_K==old_mouse_k) Draw_grad_ellipse(center_x,center_y,horizontal_radius,vertical_radius,Paintbrush_X,Paintbrush_Y); Display_cursor(); End_of_modification(); Wait_end_of_click(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } /****************************** * Operation_Rectangle_Degrade * ******************************/ // 1) trac d'un rectangle classique avec les lignes XOR // 2) trac d'une ligne vecteur de dgrad, comme une ligne normale // 3) dessin du dgrad void Grad_rectangle_12_0(void) // Opration : OPERATION_GRAD_RECTANGLE // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui // Initialisation de l'tape 1, on commence dessiner le rectangle { Init_start_operation(); Backup(); Load_gradient_data(Current_gradient); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("\035: 1 \022: 1",0); // On laisse une trace du curseur l'cran Display_cursor(); if (Mouse_K==LEFT_SIDE) { Shade_table=Shade_table_left; Operation_push(Mouse_K); } else { Shade_table=Shade_table_right; Operation_push(Mouse_K); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Grad_rectangle_12_5(void) // Opration : OPERATION_GRAD_RECTANGLE // Click Souris: 1 ou 2 // Taille_Pile : 5 // // Souris efface: Non // Modification de la taille du rectangle { short start_x; short start_y; short old_x; short old_y; char str[5]; Operation_pop(&old_y); Operation_pop(&old_x); if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) { Operation_pop(&start_y); Operation_pop(&start_x); if ((Config.Coords_rel) && (Menu_is_visible)) { Num2str(((start_x Min(Main_image_width, Main_magnifier_mode?Main_separator_position:Screen_width)) { offset_width = end_x - Min(Main_image_width, Main_magnifier_mode?Main_separator_position:Screen_width); } if (end_y-Main_offset_Y > Min(Main_image_height, Menu_Y)) offset_height = end_y - Min(Main_image_height, Menu_Y); if (width == 0) { // Single line Vertical_XOR_line(start_x-Main_offset_X, start_y - Main_offset_Y, height - offset_height + 1); } else if (height == 0) { // Single line Horizontal_XOR_line(start_x-Main_offset_X, start_y - Main_offset_Y, width - offset_width + 1); } else { // Dessin dans la zone de dessin normale Horizontal_XOR_line(start_x-Main_offset_X, start_y - Main_offset_Y, width - offset_width + 1); // If not, this line is out of the picture so there is no need to draw it if (offset_height == 0 || end_y - 1 > Menu_Y + Main_offset_Y) { Horizontal_XOR_line(start_x - Main_offset_X, end_y - Main_offset_Y, width - offset_width + 1); } if (height > offset_height + 2) { Vertical_XOR_line(start_x-Main_offset_X, start_y - Main_offset_Y + 1, height - offset_height - 1); if (offset_width == 0) { Vertical_XOR_line(end_x - Main_offset_X, start_y - Main_offset_Y + 1, height - offset_height - 1); } } } Update_rect(start_x - Main_offset_X, start_y - Main_offset_Y, width + 1 - offset_width, height + 1 - offset_height); // Dessin dans la zone zoome if (Main_magnifier_mode && start_x <= Limit_right_zoom && end_x > Limit_left_zoom && start_y <= Limit_bottom_zoom && end_y > Limit_top_zoom ) { offset_width = 0; offset_height = 0; if (start_xLimit_right_zoom) // On dpasse du zoom droite offset_width += end_x - Limit_right_zoom; if(start_yLimit_bottom_zoom) // On dpasse du zoom en bas offset_height += end_y - Limit_bottom_zoom; if(width > offset_width) { if(offset_top==0) // La ligne du haut est visible Horizontal_XOR_line_zoom(offset_left>0?offset_left:start_x,start_y,width-offset_width+1); if(height!=0 && end_y<=Limit_bottom_zoom) // La ligne du bas est visible Horizontal_XOR_line_zoom(offset_left>0?offset_left:start_x,end_y,width-offset_width+1); } if (width==0 && height!=0 && height > offset_height && offset_left==0) { // Single vertical line Vertical_XOR_line_zoom(start_x,offset_top!=0?offset_top:start_y,height-offset_height); } else { if(height > offset_height + 2) { if(offset_left==0) // La ligne de gauche est visible Vertical_XOR_line_zoom(start_x,offset_top!=0?offset_top:(start_y+1),height-offset_height-(offset_top==0)+(end_y>Limit_bottom_zoom)); if(end_x<=Limit_right_zoom) // La ligne de droite est visible Vertical_XOR_line_zoom(end_x,offset_top!=0?offset_top:(start_y+1),height-offset_height-(offset_top==0)+(end_y>Limit_bottom_zoom)); } } } } void Grad_rectangle_0_5(void) // OPERATION_GRAD_RECTANGLE // click souris 0 // Taile pile : 5 // // Souris efface : non // Le rectangle est en place, maintenant il faut tracer le vecteur de dgrad, // on doit donc attendre que l'utilisateur clique quelque part // On stocke tout de suite les coordonnes du pinceau comme a on change d'tat et on passe la suite { // !!! Cette fonction remet start_x start_y end_x end_y dans la pile la fin donc il ne faut pas les modifier ! (sauf ventuellement un tri) short start_x; short start_y; short end_x; short end_y; // Trac propre du rectangle Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); // This trick will erase the large crosshair at original position, // in normal and zoomed views. Paintbrush_X = start_x; Paintbrush_Y = start_y; if (start_x>end_x) SWAP_SHORTS(start_x, end_x) if (start_y>end_y) SWAP_SHORTS(start_y, end_y) Hide_cursor(); // Check if the rectangle is not fully outside the picture if (start_x > Main_image_width // Rectangle at right of picture || start_y > Main_image_height // Rectangle below picture || start_y - 1 - Main_offset_Y > Menu_Y ) // Rectangle below viewport { Operation_pop(&end_y); // reset the stack return; // cancel the operation } Draw_xor_rect(start_x, start_y, end_x, end_y); Operation_push(start_x); Operation_push(start_y); Operation_push(end_x); Operation_push(end_y); // On ajoute des trucs dans la pile pour forcer le passage l'tape suivante Operation_push(end_x); Operation_push(end_y); } void Grad_rectangle_0_7(void) // OPERATION_GRAD_RECTANGLE // click souris 0 // Taile pile : 5 // // Souris efface : non // On continue attendre que l'utilisateur clique en gardant les coords jour { Operation_stack_size -= 2; Print_coordinates(); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Grad_rectangle_12_7(void) // Opration : OPERATION_GRAD_RECTANGLE // Click Souris: 1 ou 2 // Taille_Pile : 7 // // Souris efface: Oui // Dbut du trac du vecteur (premier clic) // On garde les anciennes coordonnes dans la pile, et on ajoute les nouvelles par dessus // Si l'utilisateur utilise le mauvais bouton, on annule le trac. Mais a nous oblige vider toute la pile pour vrifier :( { short start_x,end_x,start_y,end_y,vax,vay,click; Operation_pop(&vay); Operation_pop(&vax); Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&click); if(click==Mouse_K) { Operation_push(click); Operation_push(start_x); Operation_push(start_y); Operation_push(end_x); Operation_push(end_y); Operation_push(vax); Operation_push(vay); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } else { // Mauvais bouton > anulation de l'opration. // On a dj vid la pile, il reste effacer le rectangle XOR Draw_xor_rect(start_x, start_y, end_x, end_y); } } void Grad_rectangle_12_9(void) // Opration : OPERATION_GRAD_RECTANGLE // Click Souris: 1 // Taille_Pile : 9 // // Souris efface: Oui // Poursuite du trac du vecteur (dplacement de la souris en gardant le curseur appuy) { short start_x; short start_y; short end_x; short end_y; short cursor_x; short cursor_y; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); cursor_x = Paintbrush_X; cursor_y = Paintbrush_Y; // On corrige les coordonnes de la ligne si la touche shift est appuye... if(SDL_GetModState() & KMOD_SHIFT) Clamp_coordinates_regular_angle(start_x,start_y,&cursor_x,&cursor_y); if ((cursor_x!=end_x) || (cursor_y!=end_y)) { Display_coords_rel_or_abs(start_x,start_y); Draw_line_preview_xor(start_x,start_y,end_x,end_y,0); Draw_line_preview_xor(start_x,start_y,cursor_x,cursor_y,0); } Operation_push(start_x); Operation_push(start_y); Operation_push(cursor_x); Operation_push(cursor_y); } void Grad_rectangle_0_9(void) // Opration : OPERATION_GRAD_RECTANGLE // Click Souris: 0 // Taille_Pile : 9 // // Souris efface: Oui // Ouf, fini ! on dessine enfin le rectangle avec son dgrad { short rect_start_x; short rect_start_y; short rect_end_x; short rect_end_y; short vector_start_x; short vector_start_y; short vector_end_x; short vector_end_y; Operation_pop(&vector_end_y); Operation_pop(&vector_end_x); Operation_pop(&vector_start_y); Operation_pop(&vector_start_x); Operation_pop(&rect_end_y); Operation_pop(&rect_end_x); Operation_pop(&rect_start_y); Operation_pop(&rect_start_x); Operation_stack_size--; Hide_cursor(); // Maintenant on efface tout le bazar temporaire : rectangle et ligne XOR Draw_xor_rect(rect_start_x, rect_start_y, rect_end_x, rect_end_y); Hide_line_preview(vector_start_x,vector_start_y,vector_end_x,vector_end_y); // Et enfin on trace le rectangle avec le dgrad dedans ! if (vector_end_x==vector_start_x && vector_end_y==vector_start_y) { // Vecteur nul > pas de rectangle trac } else { Draw_grad_rectangle(rect_start_x,rect_start_y,rect_end_x,rect_end_y,vector_start_x,vector_start_y,vector_end_x,vector_end_y); } Display_cursor(); End_of_modification(); Wait_end_of_click(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); Print_coordinates(); } } /////////////////////////////////////////////////// OPERATION_CENTERED_LINES void Centered_lines_12_0(void) // Opration : OPERATION_CENTERED_LINES // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Oui { if (Rightclick_colorpick(0)) return; Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: 0 Y: 0",0); Operation_push(Mouse_K); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Centered_lines_12_3(void) // Opration : OPERATION_CENTERED_LINES // Click Souris: 1 ou 2 // Taille_Pile : 3 // // Souris efface: Non { short start_x; short start_y; Operation_pop(&start_y); Operation_pop(&start_x); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Centered_lines_0_3(void) // Opration : OPERATION_CENTERED_LINES // Click Souris: 0 // Taille_Pile : 3 // // Souris efface: Oui { short start_x; short start_y; short Button; short color; Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&Button); color=(Button==LEFT_SIDE)?Fore_color:Back_color; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); Paintbrush_shape_before_operation=Paintbrush_shape; Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Operation_push(Button); Operation_push(Paintbrush_X); // Nouveau dbut X Operation_push(Paintbrush_Y); // Nouveau dbut Y Operation_push(Paintbrush_X); // Nouvelle dernire fin X Operation_push(Paintbrush_Y); // Nouvelle dernire fin Y Operation_push(Paintbrush_X); // Nouvelle dernire position X Operation_push(Paintbrush_Y); // Nouvelle dernire position Y } void Centered_lines_12_7(void) // Opration : OPERATION_CENTERED_LINES // Click Souris: 1 ou 2 // Taille_Pile : 7 // // Souris efface: Non { short Button; short start_x; short start_y; short end_x; short end_y; short last_x; short last_y; short color; Operation_pop(&last_y); Operation_pop(&last_x); Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&Button); if (Mouse_K==Button) { if ( (end_x!=Paintbrush_X) || (end_y!=Paintbrush_Y) || (last_x!=Paintbrush_X) || (last_y!=Paintbrush_Y) ) { Hide_cursor(); color=(Button==LEFT_SIDE)?Fore_color:Back_color; Paintbrush_shape=Paintbrush_shape_before_operation; Pixel_figure_preview_auto (start_x,start_y); Hide_line_preview (start_x,start_y,last_x,last_y); Smear_start=1; Draw_paintbrush (start_x,start_y,color); Draw_line_permanent(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); Draw_line_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); Display_cursor(); } Operation_push(Button); Operation_push(start_x); Operation_push(start_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } else { Hide_cursor(); Paintbrush_shape=Paintbrush_shape_before_operation; Pixel_figure_preview_auto (start_x,start_y); Hide_line_preview (start_x,start_y,last_x,last_y); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); Print_coordinates(); } Display_cursor(); End_of_modification(); Wait_end_of_click(); } } void Centered_lines_0_7(void) // Opration : OPERATION_CENTERED_LINES // Click Souris: 0 // Taille_Pile : 7 // // Souris efface: Non { short Button; short start_x; short start_y; short end_x; short end_y; short last_x; short last_y; short color; Operation_pop(&last_y); Operation_pop(&last_x); Operation_pop(&end_y); Operation_pop(&end_x); if ((Paintbrush_X!=last_x) || (Paintbrush_Y!=last_y)) { Hide_cursor(); Operation_pop(&start_y); Operation_pop(&start_x); Operation_pop(&Button); color=(Button==LEFT_SIDE)?Fore_color:Back_color; Display_coords_rel_or_abs(start_x,start_y); Hide_line_preview(start_x,start_y,last_x,last_y); Pixel_figure_preview(start_x,start_y,color); Draw_line_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); Operation_push(Button); Operation_push(start_x); Operation_push(start_y); Display_cursor(); } Operation_push(end_x); Operation_push(end_y); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } ///////////////////////////////////////////////////////////// OPERATION_PAN_VIEW void Pan_view_0_0(void) // Opration : OPERATION_PAN_VIEW // Click Souris: 0 // Taille_Pile : 0 // // Souris efface: Non { if (Pan_shortcut_pressed) { Print_coordinates(); } else { // End of operation, return to previous Hide_cursor(); Start_operation_stack(Operation_before_interrupt); Display_cursor(); } } void Pan_view_12_0(void) // Opration : OPERATION_PAN_VIEW // Click Souris: 1 ou 2 // Taille_Pile : 0 // // Souris efface: Non // First time the user clicks { Init_start_operation(); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Pan_view_12_2(void) // Opration : OPERATION_PAN_VIEW // Click Souris: 1 ou 2 // Taille_Pile : 2 // // Souris efface: Non // While dragging view { short start_x; short start_y; Operation_pop(&start_y); Operation_pop(&start_x); if (Paintbrush_X!=start_x || Paintbrush_Y!=start_y) { // User moved if (Main_magnifier_mode) Scroll_magnifier(start_x-Paintbrush_X,start_y-Paintbrush_Y); else Scroll_screen(start_x-Paintbrush_X,start_y-Paintbrush_Y); } // The "scroll" functions have actualized the Paintbrush_X and Y if (Paintbrush_X!=start_x || Paintbrush_Y!=start_y) { Print_coordinates(); } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } void Pan_view_0_2(void) // Opration : OPERATION_PAN_VIEW // Click Souris: 0 // Taille_Pile : 2 // // Souris efface: Non // When releasing after dragging { short start_x; short start_y; Operation_pop(&start_y); Operation_pop(&start_x); if (!Pan_shortcut_pressed) { // End of operation, return to previous Hide_cursor(); Start_operation_stack(Operation_before_interrupt); Display_cursor(); } } grafx2_2.4+git20180105/src/transform.c0000664000000000000000000003542513223665307015720 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2009 Yves Rizoud Copyright 2009 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include "global.h" #include "struct.h" #include "transform.h" #include "engine.h" #include "sdlscreen.h" #include "windows.h" #include "input.h" #include "help.h" #include "misc.h" // Num2str #include "readline.h" #include "buttons.h" // Message_out_of_memory() #include "pages.h" // Backup_with_new_dimensions() #include "tiles.h" /// Reduces a fraction A/B to its smallest representation. ie (40,60) becomes (2/3) void Factorize(short *a, short *b) { // Method: brute-force. short factor; factor=2; while (factor<=*a && factor<=*b) { if (((*a % factor) == 0) && ((*b % factor) == 0)) { // common factor is found *a/=factor; *b/=factor; // restart factor=2; } else factor++; } } /// Multiplies original_size by new_ratio/old_ratio, but keeps result in 1-9999 range. short Compute_dimension(short original_size, short new_ratio, short old_ratio) { long amount; amount = (long)original_size*new_ratio/old_ratio; if (amount>9999) return 9999; else if (amount<1) return 1; else return amount; } void Button_Transform_menu(void) { enum RESIZE_UNIT { UNIT_PIXELS = 1, UNIT_PERCENT = 2, UNIT_RATIO = 3 }; char buffer[5]; short clicked_button; const char * unit_label[] = { "", "Pixels ", "Percent", "Ratio "}; short last_unit_index = -1; short old_ratio_width; short old_ratio_height; short new_ratio_width; short new_ratio_height; short new_width=Main_image_width; short new_height=Main_image_height; byte need_display_size = 0; // Persistent data static short unit_index = 1; // 1= Pixels, 2= Percent, 3=Ratio static short ratio_is_locked = 1; // True if X and Y resize should go together T_Dropdown_button * unit_button; T_Special_button * input_button[4]; short *input_value[4]; // Set initial ratio if (unit_index == UNIT_PERCENT) new_ratio_width=old_ratio_width=new_ratio_height=old_ratio_height=100; else new_ratio_width=old_ratio_width=new_ratio_height=old_ratio_height=1; Open_window(215,165,"Picture transform"); Window_display_frame( 5, 15,205,91); Window_display_frame( 5,110, 55,49); Window_display_frame(64,110, 85,49); Window_set_normal_button(154,140, 54,14,"Cancel",0,1,KEY_ESC); // 1 Print_in_window( 9,114,"Mirror",MC_Dark,MC_Light); Window_set_normal_button( 17,125, 27,14,"X\035" ,1,1,SDLK_x); // 2 Window_set_normal_button( 17,140, 27,14,"Y\022" ,1,1,SDLK_y); // 3 Print_in_window( 84,114,"Rotate",MC_Dark,MC_Light); Window_set_normal_button( 69,125, 37,14,"-90" ,0,1,SDLK_LAST); // 4 Window_set_normal_button(107,125, 37,14,"+90" ,0,1,SDLK_LAST); // 5 Window_set_normal_button( 69,140, 75,14,"180" ,0,1,SDLK_LAST); // 6 Print_in_window( 87, 19,"Resize",MC_Dark,MC_Light); Window_set_normal_button( 80, 86, 60,14,"RESIZE",1,1,SDLK_r); // 7 Print_in_window( 51, 34,"New",MC_Dark,MC_Light); Print_in_window( 96, 34,"Old",MC_Dark,MC_Light); Print_in_window( 30, 44,"X:",MC_Dark,MC_Light); Print_in_window( 30, 59,"Y:",MC_Dark,MC_Light); Print_in_window( 80, 44,":",MC_Dark,MC_Light); Print_in_window( 80, 59,":",MC_Dark,MC_Light); Print_in_window( 44, 75,"Lock proportions",MC_Dark,MC_Light); Window_set_normal_button( 28, 72, 13,13,ratio_is_locked?"X":" ",0,1,SDLK_l);// 8 unit_button = Window_set_dropdown_button(128,50,69,11,69,unit_label[unit_index],1,0,1,LEFT_SIDE|RIGHT_SIDE,0);// 9 Window_dropdown_add_item(unit_button,UNIT_PIXELS,unit_label[UNIT_PIXELS]); Window_dropdown_add_item(unit_button,UNIT_PERCENT,unit_label[UNIT_PERCENT]); Window_dropdown_add_item(unit_button,UNIT_RATIO,unit_label[UNIT_RATIO]); input_button[0] = Window_set_input_button(45,43,4); // 10 input_button[1] = Window_set_input_button(89,43,4); // 11 input_button[2] = Window_set_input_button(45,58,4); // 12 input_button[3] = Window_set_input_button(89,58,4); // 13 Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { // Display the coordinates with the right unit if (last_unit_index != unit_index) { switch(unit_index) { case UNIT_PIXELS: default: input_value[0]=&new_width; input_value[1]=&Main_image_width; // Don't worry, it's read-only input_value[2]=&new_height; input_value[3]=&Main_image_height; // Don't worry, it's read-only break; case UNIT_PERCENT: case UNIT_RATIO: input_value[0]=&new_ratio_width; input_value[1]=&old_ratio_width; input_value[2]=&new_ratio_height; input_value[3]=&old_ratio_height; break; } need_display_size=1; last_unit_index=unit_index; } if (need_display_size) { short i; Hide_cursor(); for (i=0;i<4;i++) { // "Old" values are not editable, unless the unit is "ratio" byte color = ((unit_index!=UNIT_RATIO) && (i==1 || i==3)) ? MC_Dark : MC_Black; Num2str(*(input_value[i]),buffer,4); Print_in_window_limited(input_button[i]->Pos_X+2,input_button[i]->Pos_Y+2,buffer,input_button[i]->Width/8,color,MC_Light); } Display_cursor(); need_display_size=0; } clicked_button=Window_clicked_button(); // Contextual help if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Key=0; Window_help(BUTTON_ADJUST, "PICTURE TRANSFORM"); } else if (Is_shortcut(Key,0x200+BUTTON_ADJUST)) clicked_button=1; else switch(clicked_button) { case 9: // Unit switch(Window_attribute2) { case UNIT_PIXELS: // Do nothing, pixel size was already computed. break; case UNIT_PERCENT: if (unit_index == UNIT_RATIO) { // Approximate from current ratio new_ratio_width = Compute_dimension(new_ratio_width,100,old_ratio_width); new_ratio_height = Compute_dimension(new_ratio_height,100,old_ratio_height); old_ratio_width = 100; old_ratio_height = 100; // Update pixel dimensions, to match percentage exactly new_width=Compute_dimension(Main_image_width, new_ratio_width, old_ratio_width); new_height=Compute_dimension(Main_image_height, new_ratio_height, old_ratio_height); } else // unit_index == UNIT_PIXELS { // Approximate from current pixel size new_ratio_width = new_width*100/Main_image_width; new_ratio_height = new_height*100/Main_image_height; old_ratio_width = 100; old_ratio_height = 100; } break; case UNIT_RATIO: if (unit_index == UNIT_PERCENT) { // Compute simplest ratio from current % Factorize(&new_ratio_width, &old_ratio_width); Factorize(&new_ratio_height, &old_ratio_height); } else // unit_index == UNIT_PIXELS { // Compute simplest ratio from current pixel size new_ratio_width = new_width; new_ratio_height = new_height; old_ratio_width = Main_image_width; old_ratio_height = Main_image_height; Factorize(&new_ratio_width, &old_ratio_width); Factorize(&new_ratio_height, &old_ratio_height); } break; } unit_index = Window_attribute2; break; case 8: // Lock proportions ratio_is_locked = ! ratio_is_locked; Hide_cursor(); Print_in_window(31,75,(ratio_is_locked)?"X":" ",MC_Black,MC_Light); Display_cursor(); break; case 11: // input old width case 13: // input old height // "Old" values are not editable, unless the unit is "ratio" if (unit_index!=UNIT_RATIO) break; case 10: // input new width case 12: // input new height Num2str(*( input_value[clicked_button-10]),buffer,4); Hide_cursor(); if (Readline(input_button[clicked_button-10]->Pos_X+2, input_button[clicked_button-10]->Pos_Y+2, buffer, 4, INPUT_TYPE_INTEGER)) { // Accept entered value *(input_value[clicked_button-10])=atoi(buffer); // 0 is not acceptable size if (*(input_value[clicked_button-10])==0) { *(input_value[clicked_button-10])=1; } // Adapt the other coordinate if X and Y are locked if (ratio_is_locked) { if (clicked_button == 10 || clicked_button == 11 ) { // Get Y value because X changed if (unit_index == UNIT_PIXELS) { new_height=Compute_dimension(Main_image_height, new_width, Main_image_width); } else { // Copy the whole ratio new_ratio_height=new_ratio_width; old_ratio_height=old_ratio_width; } } else // (clicked_button == 12 || clicked_button == 13) { // Get X value because Y changed if (unit_index == UNIT_PIXELS) { new_width=Compute_dimension(Main_image_width, new_height, Main_image_height); } else { // Copy the whole ratio new_ratio_width=new_ratio_height; old_ratio_width=old_ratio_height; } } } // Re-compute ratio from size in pixels if (unit_index == UNIT_PIXELS) { //new_width=(long)Main_image_width*new_ratio_width/old_ratio_width; //new_height=(long)Main_image_height*new_ratio_height/old_ratio_height; } else // Re-compute size in pixels from ratio { new_width=Compute_dimension(Main_image_width,new_ratio_width,old_ratio_width); new_height=Compute_dimension(Main_image_height,new_ratio_height,old_ratio_height); } need_display_size=1; } Display_cursor(); break; } } while (clicked_button<=0 || clicked_button>=8); Close_window(); // The Scroll operation uses the same button as transformation menu. if (Current_operation != OPERATION_SCROLL) Unselect_button(BUTTON_ADJUST); if (clicked_button != 1) // 1 is Cancel { short old_width; short old_height; // Determine new image dimensions switch (clicked_button) { case 7 : // Resize // Keep new_width and new_height as entered. break; case 2 : // Flip X case 3 : // Flip Y case 6 : // 180 Rotation new_width=Main_image_width; new_height=Main_image_height; break; case 4 : // -90 Rotation case 5 : // +90 Rotation new_width=Main_image_height; new_height=Main_image_width; break; } // Memorize the current dimensions old_width=Main_image_width; old_height=Main_image_height; Upload_infos_page_main(Main_backups->Pages); // Allocate a new page if (Backup_with_new_dimensions(new_width,new_height)) { // The new image is allocated, the new dimensions are already updated. Main_image_is_modified=1; // Process the transformation: switch(clicked_button) { int i; case 2 : // Flip X for (i=0; iPages->Nb_layers; i++) { memcpy(Main_backups->Pages->Image[i].Pixels,Main_backups->Pages->Next->Image[i].Pixels,Main_image_width*Main_image_height); Flip_X_lowlevel(Main_backups->Pages->Image[i].Pixels, Main_image_width, Main_image_height); } break; case 3 : // Flip Y for (i=0; iPages->Nb_layers; i++) { memcpy(Main_backups->Pages->Image[i].Pixels,Main_backups->Pages->Next->Image[i].Pixels,Main_image_width*Main_image_height); Flip_Y_lowlevel(Main_backups->Pages->Image[i].Pixels, Main_image_width, Main_image_height); } break; case 4 : // -90 Rotation for (i=0; iPages->Nb_layers; i++) { Rotate_270_deg_lowlevel(Main_backups->Pages->Next->Image[i].Pixels, Main_backups->Pages->Image[i].Pixels, old_width, old_height); } break; case 5 : // +90 Rotation for (i=0; iPages->Nb_layers; i++) { Rotate_90_deg_lowlevel(Main_backups->Pages->Next->Image[i].Pixels, Main_backups->Pages->Image[i].Pixels, old_width, old_height); } break; case 6 : // 180 Rotation for (i=0; iPages->Nb_layers; i++) { memcpy(Main_backups->Pages->Image[i].Pixels,Main_backups->Pages->Next->Image[i].Pixels,Main_image_width*Main_image_height); Rotate_180_deg_lowlevel(Main_backups->Pages->Image[i].Pixels, Main_image_width, Main_image_height); } break; case 7 : // Resize for (i=0; iPages->Nb_layers; i++) { Rescale(Main_backups->Pages->Next->Image[i].Pixels, old_width, old_height, Main_backups->Pages->Image[i].Pixels, Main_image_width, Main_image_height, 0, 0); } break; } /* for (i=0; iPages->Next->Image[i].Pixels,0,0,Min(old_width,Main_image_width), Min(old_height,Main_image_height),old_width, Main_backups->Pages->Image[i].Pixels,0,0,Main_image_width); } */ Redraw_layered_image(); Display_all_screen(); End_of_modification(); Tilemap_update(); } else { Display_cursor(); Message_out_of_memory(); Hide_cursor(); } } Display_cursor(); } grafx2_2.4+git20180105/src/shade.c0000664000000000000000000010205213223665307014760 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include "global.h" #include "graph.h" #include "engine.h" #include "errors.h" #include "misc.h" #include "readline.h" #include "help.h" #include "sdlscreen.h" #include "windows.h" #include "input.h" #include "shade.h" void Button_Shade_mode(void) { if (Shade_mode) Effect_function=No_effect; else { Effect_function=Effect_shade; Quick_shade_mode=0; Colorize_mode=0; Smooth_mode=0; Tiling_mode=0; Smear_mode=0; } Shade_mode=!Shade_mode; } void Button_Quick_shade_mode(void) { if (Quick_shade_mode) Effect_function=No_effect; else { Effect_function=Effect_quick_shade; Shade_mode=0; Colorize_mode=0; Smooth_mode=0; Tiling_mode=0; Smear_mode=0; } Quick_shade_mode=!Quick_shade_mode; } void Shade_draw_grad_ranges(void) { word cursor=0; word nb_shades=0; short shade_processed,shade_processed_old; word shade_size=0; word start_shade=0; short x_pos,y_pos; short x_size,y_size; short start_x,start_y,end_x,end_y; // On commence par compter le nombre de shades while (cursor<512) { while ((cursor<512) && (Shade_list[Shade_current].List[cursor]&0xFF00)) cursor++; if (cursor<512) { nb_shades++; while ( (cursor<512) && (!(Shade_list[Shade_current].List[cursor]&0xFF00)) ) cursor++; } } // Maintenant qu'on sait combien il y en a, on les affiche: if (nb_shades) { x_size=Menu_factor_X<<6; y_size=Menu_factor_Y*48; start_x=Window_pos_X+(Menu_factor_X*224); start_y=Window_pos_Y+(Menu_factor_Y*35); end_x=start_x+x_size; end_y=start_y+y_size; cursor=0; shade_processed_old=-1; for (y_pos=start_y;y_posshade_processed_old) { // On commence par sauter tous les vides jusqu'au prochain shade while ((cursor<512) && (Shade_list[Shade_current].List[cursor]&0xFF00)) cursor++; start_shade=cursor; // puis regarde sa taille while ((cursor<512) && (!(Shade_list[Shade_current].List[cursor]&0xFF00))) cursor++; shade_size=cursor-start_shade; shade_processed_old=shade_processed; } for (x_pos=start_x;x_pos=selection_start) && (position<=selection_end)) { Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y,MC_White); Block(x_pos,y_pos+Menu_factor_Y,Menu_factor_X<<2,Menu_factor_Y,MC_Black); } else Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y<<1,MC_White); } else // "enable" { if ((position>=selection_start) && (position<=selection_end)) Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y<<1,MC_Black); else Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y<<1,MC_Light); } } Update_window_area(8,131,64<<2,8<<3); } void Display_selected_cell_color(word selection_start,word selection_end) { char str[4]; if ((selection_start!=selection_end) || (Shade_list[Shade_current].List[selection_start]&0x0100)) strcpy(str," "); else Num2str(Shade_list[Shade_current].List[selection_start]&0xFF,str,3); Print_in_window(213,115,str,MC_Black,MC_Light); } void Display_selected_color(word selection_start,word selection_end) { char str[4]; if (selection_start!=selection_end) strcpy(str," "); else Num2str(selection_start,str,3); Print_in_window(213,106,str,MC_Black,MC_Light); } void Display_shade_mode(short x,short y,byte mode) { char str[7]; switch (mode) { case SHADE_MODE_NORMAL : strcpy(str,"Normal"); break; case SHADE_MODE_LOOP : strcpy(str," Loop "); break; default : // SHADE_MODE_NOSAT strcpy(str,"No sat"); } Print_in_window(x,y,str,MC_Black,MC_Light); } void Display_all_shade(word selection_start1,word selection_end1, word selection_start2,word selection_end2) { word line, column; word position; for (line=0; line<8; line++) for (column=0; column<64; column++) { position=(line<<6)+column; // On regarde si c'est une couleur ou un bloc vide if (Shade_list[Shade_current].List[position]&0x0100) // Vide { Window_display_frame_out((column<<2)+8,(line*7)+127,4,4); Window_rectangle((column<<2)+9, (line*7)+128, 2,2,MC_Light); } else // color Window_rectangle((column<<2)+8, (line*7)+127, 4,4, Shade_list[Shade_current].List[position]&0xFF); } Update_window_area(7,126,(64<<2)+2,(8<<2)+2); Tag_shades(selection_start2,selection_end2); Shade_draw_grad_ranges(); Display_selected_cell_color(selection_start2,selection_end2); Display_selected_color(selection_start1,selection_end1); Display_shade_mode(250,110,Shade_list[Shade_current].Mode); } void Remove_shade(word selection_start,word selection_end) { word temp; if (selection_end=512) temp=512-selection_start; for (cursor=511;cursor>=limit;cursor--) Shade_list[Shade_current].List[cursor]=Shade_list[Shade_current].List[cursor-temp]; for (cursor=selection_start+temp;selection_start=512) return; for (cursor=511;cursor>position;cursor--) Shade_list[Shade_current].List[cursor]=Shade_list[Shade_current].List[cursor-1]; Shade_list[Shade_current].List[position]=0x0100; } short Wait_click_in_shade_table() { short selected_cell=-1; byte old_hide_cursor; Hide_cursor(); old_hide_cursor=Cursor_hidden; Cursor_hidden=0; Cursor_shape=CURSOR_SHAPE_TARGET; Display_cursor(); while (selected_cell<0) { Get_input(20); if ( (Mouse_K==LEFT_SIDE) && ( ( (Window_click_in_rectangle(8,127,263,179)) && (((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)%7)<4) ) || ( (Mouse_X=Window_pos_X+(Window_width*Menu_factor_X)) || (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y)) ) ) ) selected_cell=(((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)/7)<<6)+ ((((Mouse_X-Window_pos_X)/Menu_factor_X)-8 )>>2); if ((Mouse_K==RIGHT_SIDE) || (Key==KEY_ESC)) selected_cell=512; // valeur indiquant que l'on n'a rien choisi } Hide_cursor(); Cursor_shape=CURSOR_SHAPE_ARROW; Cursor_hidden=old_hide_cursor; Display_cursor(); return selected_cell; } void Swap_shade(short block_1_start,short block_2_start,short block_size) { short pos_1; short pos_2; short end_1; short end_2; word temp; word * temp_shade; // On fait une copie de la liste temp_shade=(word *)malloc(512*sizeof(word)); memcpy(temp_shade,Shade_list[Shade_current].List,512*sizeof(word)); // On calcul les dernires couleurs de chaque bloc. end_1=block_1_start+block_size-1; end_2=block_2_start+block_size-1; if ((block_2_start>=block_1_start) && (block_2_start<=end_1)) { // Le bloc destination commence dans le bloc source. for (pos_1=block_1_start,pos_2=end_1+1;pos_1<=end_2;pos_1++) { // Il faut transformer la case pos_1 en pos_2: Shade_list[Shade_current].List[pos_1]=temp_shade[pos_2]; // On gre la mise jour de pos_2 if (pos_2==end_2) pos_2=block_1_start; else pos_2++; } } else if ((block_2_start=block_1_start)) { // Le bloc destination dborde dans le bloc source. for (pos_1=block_2_start,pos_2=block_1_start;pos_1<=end_1;pos_1++) { // Il faut transformer la couleur pos_1 en pos_2: Shade_list[Shade_current].List[pos_1]=temp_shade[pos_2]; // On gre la mise jour de pos_2 if (pos_2==end_1) pos_2=block_2_start; else pos_2++; } } else { // Le bloc source et le bloc destination sont distincts. for (pos_1=block_1_start,pos_2=block_2_start;pos_1<=end_1;pos_1++,pos_2++) { // On change les cases temp =Shade_list[Shade_current].List[pos_1]; Shade_list[Shade_current].List[pos_1]=Shade_list[Shade_current].List[pos_2]; Shade_list[Shade_current].List[pos_2]=temp; } } free(temp_shade); } int Menu_shade(void) { short clicked_button; // Numro du bouton sur lequel l'utilisateur a click char str[4]; // str d'affichage du n de shade actif et du Pas word old_mouse_x, old_mouse_x2; // Mmo. de l'ancienne pos. du curseur word old_mouse_y, old_mouse_y2; byte old_mouse_k, old_mouse_k2; byte temp_color; // Variables de gestion des clicks dans la palette byte first_color = Fore_color; byte last_color = Fore_color; word selection_start = 0; word selection_end = 0; T_Special_button * input_button; short temp, temp2; word temp_cell; word * buffer; // buffer du Copy/Paste word * undo_buffer; // buffer du Undo word * temp_ptr; byte color; byte click; buffer =(word *)malloc(512*sizeof(word)); undo_buffer =(word *)malloc(512*sizeof(word)); temp_ptr=(word *)malloc(512*sizeof(word)); // Ouverture de la fentre du menu Open_window(310,190,"Shade"); // Dclaration & trac du bouton de palette Window_set_palette_button(5,16); // 1 // Dclaration & trac du scroller de slection du n de dgrad Window_set_scroller_button(192,17,84,8,1,Shade_current); // 2 // Dclaration & trac de la zone de dfinition des dgrads Window_set_special_button(8,127,256,53); // 3 // Dclaration & trac des boutons de sortie Window_set_normal_button(207,17,51,14,"Cancel",0,1,KEY_ESC); // 4 Window_set_normal_button(261,17,43,14,"OK" ,0,1,SDLK_RETURN); // 5 // Dclaration & trac des boutons de copie de shade Window_set_normal_button(206,87,27,14,"Cpy" ,1,1,SDLK_c); // 6 Window_set_normal_button(234,87,43,14,"Paste" ,1,1,SDLK_p); // 7 // On tagge le bloc Tag_color_range(Fore_color,Fore_color); // Trac d'un cadre creux autour du bloc dgrad Window_display_frame_in(171,26,18,66); Window_rectangle(172,27,16,64,MC_Black); // Trac d'un cadre creux autour de tous les dgrads Window_display_frame_in(223,34,66,50); Shade_draw_grad_ranges(); // Trac d'un cadre autour de la zone de dfinition de dgrads Window_display_frame(5,124,262,61); Display_all_shade(first_color,last_color,selection_start,selection_end); // Dclaration & trac des boutons d'dition de shade Window_set_normal_button( 6,107,27,14,"Ins" ,0,1,SDLK_INSERT); // 8 Window_set_normal_button( 38,107,27,14,"Del" ,0,1,SDLK_DELETE); // 9 Window_set_normal_button( 66,107,43,14,"Blank",1,1,SDLK_b); // 10 Window_set_normal_button(110,107,27,14,"Inv" ,1,1,SDLK_i); // 11 Window_set_normal_button(138,107,27,14,"Swp" ,1,1,SDLK_s); // 12 // Dclaration & trac des boutons de taggage Print_in_window(268,123,"Disbl"/*"Dsabl"*/,MC_Dark,MC_Light); Window_set_normal_button(274,133,27,14,"Set" ,0,1,SDLK_F1); // 13 Window_set_normal_button(274,148,27,14,"Clr" ,0,1,SDLK_F2); // 14 // Dclaration & trac de la zone de saisie du pas Print_in_window(272,165,"Step",MC_Dark,MC_Light); input_button = Window_set_input_button(274,174,3); // 15 Num2str(Shade_list[Shade_current].Step,str,3); Window_input_content(input_button,str); // Button Undo Window_set_normal_button(170,107,35,14,"Undo",1,1,SDLK_u); // 16 // Button Clear Window_set_normal_button(278,87,27,14,"Clr",0,1,SDLK_BACKSPACE); // 17 // Button Mode Window_set_normal_button(244,107,60,14,"",0,1,SDLK_TAB); // 18 // Affichage du n de shade actif Num2str(Shade_current+1,str,1); Print_in_window(210,55,str,MC_Black,MC_Light); memcpy(buffer ,Shade_list[Shade_current].List,512*sizeof(word)); memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); Update_window_area(0,0,310,190); Display_cursor(); do { old_mouse_x=old_mouse_x2=Mouse_X; old_mouse_y=old_mouse_y2=Mouse_Y; old_mouse_k=old_mouse_k2=Mouse_K; clicked_button=Window_clicked_button(); switch (clicked_button) { case 0 : break; case -1 : case 1 : // Gestion de la palette if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) { Hide_cursor(); temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); if (!old_mouse_k) { // On vient de clicker // On met jour l'intervalle du Shade first_color=last_color=temp_color; // On tagge le bloc Tag_color_range(first_color,last_color); // Trac du bloc dgrad: Display_grad_block_in_window(172,27,16,64,first_color,last_color); } else { // On maintient le click, on va donc tester si le curseur bouge if (temp_color!=last_color) { last_color=temp_color; // On tagge le bloc if (first_color<=temp_color) { Tag_color_range(first_color,last_color); Display_grad_block_in_window(172,27,16,64,first_color,last_color); } else { Tag_color_range(last_color,first_color); Display_grad_block_in_window(172,27,16,64,last_color,first_color); } } } // On affiche le numro de la couleur slectionne Display_selected_color(first_color,last_color); Display_cursor(); } break; case 2 : // Gestion du changement de Shade (scroller) Hide_cursor(); Shade_current=Window_attribute2; // Affichade du n de shade actif Num2str(Shade_current+1,str,1); Print_in_window(210,55,str,MC_Black,MC_Light); // Affichade du Pas Num2str(Shade_list[Shade_current].Step,str,3); Print_in_window(276,176,str,MC_Black,MC_Light); // Trac du bloc dgrad: Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); // On place le nouveau shade dans le buffer du Undo memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); break; case 3 : // Gestion de la zone de dfinition de shades if (((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)%7)<4) if ( (Mouse_X!=old_mouse_x2) || (Mouse_Y!=old_mouse_y2) || (Mouse_K!=old_mouse_k2) ) { Hide_cursor(); selection_end=(((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)/7)<<6)+ ((((Mouse_X-Window_pos_X)/Menu_factor_X)-8 )>>2); if (!old_mouse_k2) // On vient de clicker selection_start=selection_end; Tag_shades(selection_start,selection_end); Display_selected_cell_color(selection_start,selection_end); Display_cursor(); } break; case 5: // Ok if (selection_start == selection_end && Shade_list[Shade_current].List[selection_start] > 0) Set_fore_color(Shade_list[Shade_current].List[selection_start]); else if (first_color == last_color) Set_fore_color(first_color); break; case 6 : // Copy memcpy(buffer,Shade_list[Shade_current].List,512*sizeof(word)); break; case 7 : // Paste // On place le shade dans le buffer du Undo memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); // Et on le modifie memcpy(Shade_list[Shade_current].List,buffer,512*sizeof(word)); Hide_cursor(); Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); break; case 8 : // Insert // On place le shade dans le buffer du Undo memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); // Et on le modifie if (first_color<=last_color) temp=last_color-first_color; else temp=first_color-last_color; if (selection_start==selection_end) // Une couleur slectionne { if (Window_attribute1==2) Remove_shade(selection_start,selection_start+temp); } else // Un bloc slectionn { Remove_shade(selection_start,selection_end); if (first_color<=last_color) temp=last_color-first_color; else temp=first_color-last_color; if (selection_start=512) selection_start=511; selection_end=selection_start; Hide_cursor(); Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); break; case 9 : // Delete // On place le shade dans le buffer du Undo memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); // Et on le modifie Remove_shade(selection_start,selection_end); if (selection_start<=selection_end) selection_end=selection_start; else selection_start=selection_end; Hide_cursor(); Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); break; case 10 : // Blank // On place le shade dans le buffer du Undo memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); // Et on le modifie if (Window_attribute1==RIGHT_SIDE) // Click droit { if (selection_start!=selection_end) { if (selection_start<=selection_end) { Insert_empty_cell_in_shade(selection_start); Insert_empty_cell_in_shade(selection_end+2); } else { Insert_empty_cell_in_shade(selection_end); Insert_empty_cell_in_shade(selection_start+2); } } else Insert_empty_cell_in_shade(selection_start); if (selection_start<511) selection_start++; if (selection_end<511) selection_end++; } else // Click gauche { if (selection_start<=selection_end) { temp=selection_start; temp2=selection_end; } else { temp=selection_end; temp2=selection_start; } while (temp<=temp2) Shade_list[Shade_current].List[temp++]=0x0100; } Hide_cursor(); Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); break; case 11 : // Invert // On place le shade dans le buffer du Undo memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); // Et on le modifie if (selection_start<=selection_end) { temp=selection_start; temp2=selection_end; } else { temp=selection_end; temp2=selection_start; } for (;temp255) { temp=255; Num2str(temp,str,3); Window_input_content(input_button,str); } Shade_list[Shade_current].Step=temp; Display_cursor(); break; case 16 : // Undo memcpy(temp_ptr,undo_buffer,512*sizeof(word)); memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); memcpy(Shade_list[Shade_current].List,temp_ptr,512*sizeof(word)); Hide_cursor(); Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); break; case 17 : // Clear memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); for (temp=0;temp<512;temp++) Shade_list[Shade_current].List[temp]=0x0100; Hide_cursor(); Display_all_shade(first_color,last_color,selection_start,selection_end); Display_cursor(); break; case 18 : // Mode Shade_list[Shade_current].Mode=(Shade_list[Shade_current].Mode+1)%3; Hide_cursor(); Display_shade_mode(250,110,Shade_list[Shade_current].Mode); Display_cursor(); } if (!Mouse_K) switch (Key) { case SDLK_LEFTBRACKET : // Dcaler couleur dans palette vers la gauche case SDLK_RIGHTBRACKET : // Dcaler couleur dans palette vers la droite if (first_color==last_color) { if (Key==SDLK_LEFTBRACKET) { first_color--; last_color--; } else { first_color++; last_color++; } Hide_cursor(); Tag_color_range(first_color,first_color); Block(Window_pos_X+(Menu_factor_X*172), Window_pos_Y+(Menu_factor_Y*27), Menu_factor_X<<4,Menu_factor_Y*64,first_color); // On affiche le numro de la couleur slectionne Display_selected_color(first_color,last_color); Display_cursor(); } Key=0; break; case SDLK_UP : // Select Haut case SDLK_DOWN : // Select Bas case SDLK_LEFT : // Select Gauche case SDLK_RIGHT : // Select Droite if (selection_start==selection_end) { switch (Key) { case SDLK_UP : // Select Haut if (selection_start>=64) { selection_start-=64; selection_end-=64; } else selection_start=selection_end=0; break; case SDLK_DOWN : // Select Bas if (selection_start<448) { selection_start+=64; selection_end+=64; } else selection_start=selection_end=511; break; case SDLK_LEFT : // Select Gauche if (selection_start>0) { selection_start--; selection_end--; } break; default : // Select Droite if (selection_start<511) { selection_start++; selection_end++; } } Hide_cursor(); Tag_shades(selection_start,selection_start); Display_selected_cell_color(selection_start,selection_start); Display_cursor(); } Key=0; break; case SDLK_BACKQUOTE : // Rcupration d'une couleur derrire le menu case SDLK_COMMA : Get_color_behind_window(&color,&click); if (click) { Hide_cursor(); temp_color=color; // On met jour l'intervalle du Shade first_color=last_color=temp_color; // On tagge le bloc Tag_color_range(first_color,last_color); // Trac du bloc dgrad: Display_grad_block_in_window(172,27,16,64,first_color,last_color); // On affiche le numro de la couleur slectionne Display_selected_color(first_color,last_color); Display_cursor(); Wait_end_of_click(); } Key=0; break; default: if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Key=0; Window_help(BUTTON_EFFECTS, "SHADE"); } else if (Is_shortcut(Key,SPECIAL_SHADE_MENU)) clicked_button=5; } } while ((clicked_button!=4) && (clicked_button!=5)); Close_window(); free(undo_buffer); free(buffer); free(temp_ptr); return (clicked_button==5); } /// Handles the screen with Shade settings. /// @return true if user clicked ok, false if he cancelled int Shade_settings_menu(void) { T_Shade * initial_shade_list; // Anciennes donnes des shades byte old_shade; // old n de shade actif int return_code; // Backup des anciennes donnes initial_shade_list=(T_Shade *)malloc(sizeof(Shade_list)); memcpy(initial_shade_list,Shade_list,sizeof(Shade_list)); old_shade=Shade_current; return_code = Menu_shade(); if (!return_code) // Cancel { memcpy(Shade_list,initial_shade_list,sizeof(Shade_list)); Shade_current=old_shade; } else // OK { Shade_list_to_lookup_tables(Shade_list[Shade_current].List, Shade_list[Shade_current].Step, Shade_list[Shade_current].Mode, Shade_table_left,Shade_table_right); } free(initial_shade_list); Display_cursor(); return return_code; } void Button_Shade_menu(void) { if (Shade_settings_menu()) { // If user clicked OK while in the menu, activate Shade mode. if (!Shade_mode) Button_Shade_mode(); } } void Button_Quick_shade_menu(void) { short clicked_button; int temp; char str[4]; byte step_backup=Quick_shade_step; // Backup des byte loop_backup=Quick_shade_loop; // anciennes donnes T_Special_button * step_button; Open_window(142,56,"Quick-shade"); Window_set_normal_button(76,36,60,14,"OK",0,1,SDLK_RETURN); // 1 Window_set_normal_button( 6,36,60,14,"Cancel",0,1,KEY_ESC); // 2 Window_set_normal_button(76,18,60,14,"",0,1,SDLK_TAB); // 3 Display_shade_mode(83,21,Quick_shade_loop); // Dclaration & trac de la zone de saisie du pas Print_in_window(5,21,"Step",MC_Dark,MC_Light); step_button = Window_set_input_button(40,19,3); // 4 Num2str(Quick_shade_step,str,3); Window_input_content(step_button,str); Update_window_area(0,0,142,56); Display_cursor(); do { clicked_button=Window_clicked_button(); switch (clicked_button) { case 3 : // Mode Quick_shade_loop=(Quick_shade_loop+1)%3; Hide_cursor(); Display_shade_mode(83,21,Quick_shade_loop); Display_cursor(); break; case 4 : // Saisie du pas Num2str(Quick_shade_step,str,3); Readline(42,21,str,3,INPUT_TYPE_INTEGER); temp=atoi(str); // On corrige le pas if (!temp) { temp=1; Num2str(temp,str,3); Window_input_content(step_button,str); } else if (temp>255) { temp=255; Num2str(temp,str,3); Window_input_content(step_button,str); } Quick_shade_step=temp; Display_cursor(); } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "QUICK SHADE"); else if (Is_shortcut(Key,SPECIAL_QUICK_SHADE_MENU)) clicked_button=1; } while ((clicked_button!=1) && (clicked_button!=2)); Close_window(); if (clicked_button==2) // Cancel { Quick_shade_step=step_backup; Quick_shade_loop=loop_backup; } else // OK { // Si avant de rentrer dans le menu on n'tait pas en mode Quick-Shade if (!Quick_shade_mode) Button_Quick_shade_mode(); // => On y passe (cool!) } Display_cursor(); } grafx2_2.4+git20180105/src/pxwide.c0000664000000000000000000003337713223665306015210 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxwide.h" #define ZOOMX 2 #define ZOOMY 1 void Pixel_wide (word x,word y,byte color) /* Affiche un pixel de la color aux coords x;y l'cran */ { *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; } byte Read_pixel_wide (word x,word y) /* On retourne la couleur du pixel aux coords donnes */ { return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); } void Block_wide (word start_x,word start_y,word width,word height,byte color) /* On affiche un rectangle de la couleur donne */ { SDL_Rect rectangle; rectangle.x=start_x*ZOOMX; rectangle.y=start_y*ZOOMY; rectangle.w=width*ZOOMX; rectangle.h=height*ZOOMY; SDL_FillRect(Screen_SDL,&rectangle,color); } void Display_part_of_screen_wide (word width,word height,word image_width) /* Afficher une partie de l'image telle quelle sur l'cran */ { byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'cran (dest) byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de dpart ds la source (src) int y; int dy; for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne for (dy=width;dy>0;dy--) { *(dest+1)=*dest=*src; src++; dest+=ZOOMX; } // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } //Update_rect(0,0,width,height); } void Pixel_preview_normal_wide (word x,word y,byte color) /* Affichage d'un pixel dans l'cran, par rapport au dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure Pixel_Preview_Loupe_SDL. */ { // if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) Pixel_wide(x-Main_offset_X,y-Main_offset_Y,color); } void Pixel_preview_magnifier_wide (word x,word y,byte color) { // Affiche le pixel dans la partie non zoome Pixel_wide(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) { // On est dedans int height; int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_wide( Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, y_zoom, Main_magnifier_factor, height, color ); } } void Horizontal_XOR_line_wide(word x_pos,word y_pos,word width) { //On calcule la valeur initiale de dest: byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; int x; for (x=0;x0;i--) { *dest=*(dest+1)=xor_lut[*dest]; dest+=VIDEO_LINE_WIDTH*ZOOMY; } } void Display_brush_color_wide(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = Brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+1) = *dest = *src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } Update_rect(x_pos,y_pos,width,height); } void Display_brush_mono_wide(word x_pos, word y_pos, word x_offset, word y_offset, word width, word height, byte transp_color, byte color, word brush_width) /* On affiche la brosse en monochrome */ { byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination // l'cran byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds // la brosse int x,y; for(y=height;y!=0;y--) //Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { if (*src!=transp_color) *(dest+1)=*dest=color; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=brush_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Clear_brush_wide(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width) { byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'cran (dest) byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de dpart ds la source (src) int y; int x; (void)x_offset; // unused (void)y_offset; // unused (void)transp_color; // unused for(y=height;y!=0;y--) // Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { *(dest+1)=*dest=*src; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } // Affiche une brosse (arbitraire) l'cran void Display_brush_wide(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+1) = *dest = *src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } } void Remap_screen_wide(word x_pos,word y_pos,word width,word height,byte * conversion_table) { // dest = coords a l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; int x,y; // Pour chaque ligne for(y=height;y>0;y--) { // Pour chaque pixel for(x=width;x>0;x--) { *(dest+1) = *dest = conversion_table[*dest]; dest +=ZOOMX; } dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Display_line_on_screen_fast_wide(word x_pos,word y_pos,word width,byte * line) /* On affiche toute une ligne de pixels telle quelle. */ /* Utilise si le buffer contient dja des pixel doubls. */ { memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); } void Display_line_on_screen_wide(word x_pos,word y_pos,word width,byte * line) /* On affiche une ligne de pixels en les doublant. */ { int x; byte *dest; dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; for(x=width;x>0;x--) { *(dest+1)=*dest=*line; dest+=ZOOMX; line++; } } void Display_transparent_mono_line_on_screen_wide( word x_pos, word y_pos, word width, byte* line, byte transp_color, byte color) // Affiche une ligne l'cran avec une couleur + transparence. // Utilis par les brosses en mode zoom { byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; int x; // Pour chaque pixel for(x=0;x 0); src += image_width; } // ATTENTION on n'arrive jamais ici ! } void Display_transparent_line_on_screen_wide(word x_pos,word y_pos,word width,byte* line,byte transp_color) { byte* src = line; byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; word x; // Pour chaque pixel de la ligne for(x = width;x > 0;x--) { if(*src!=transp_color) { *(dest+1) = *dest = *src; } src++; dest+=ZOOMX; } } // Affiche une partie de la brosse couleur zoome void Display_brush_color_zoom_wide(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle de la brosse byte * buffer) { byte* src = Brush+y_offset*brush_width + x_offset; word y = y_pos; byte bx; // Pour chaque ligne while(1) { Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche facteur fois la ligne zoome for(bx=Main_magnifier_factor;bx>0;bx--) { Display_transparent_line_on_screen_wide(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); y++; if(y==end_y_pos) { return; } } src += brush_width; } // ATTENTION zone jamais atteinte } void Display_brush_mono_zoom_wide(word x_pos, word y_pos, word x_offset, word y_offset, word width, // width non zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle de la brosse byte * buffer ) { byte* src = Brush + y_offset * brush_width + x_offset; int y=y_pos*ZOOMY; //Pour chaque ligne zoomer : while(1) { int bx; // src = Ligne originale // On clate la ligne Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche la ligne Facteur fois l'cran (sur des // lignes conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome Display_transparent_mono_line_on_screen_wide( x_pos, y, width * Main_magnifier_factor, buffer, transp_color, color ); // On passe la ligne suivante y++; // On vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); Update_rect( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); return; } bx --; } while (bx > 0); // Passage la ligne suivante dans la brosse aussi src+=brush_width; } } void Clear_brush_scaled_wide(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer) { // En fait on va recopier l'image non zoome dans la partie zoome ! byte* src = Main_screen + y_offset * image_width + x_offset; int y = y_pos; int bx; (void)transp_color; // unused // Pour chaque ligne zoomer while(1){ Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); bx=Main_magnifier_factor; // Pour chaque ligne do{ Display_line_on_screen_fast_wide(x_pos,y, width * Main_magnifier_factor,buffer); // Ligne suivante y++; if(y==end_y_pos) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); Update_rect(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); return; } bx--; }while(bx!=0); src+= image_width; } } grafx2_2.4+git20180105/src/engine.h0000664000000000000000000001317513223665306015154 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file engine.h /// Utility functions for the menu and all windows. ////////////////////////////////////////////////////////////////////////////// #ifndef __ENGINE_H__ #define __ENGINE_H__ #include "struct.h" void Main_handler (void); void Draw_menu_button (byte btn_number,byte pressed); void Unselect_button (int btn_number); void Select_button (int btn_number,byte click); void Open_window (word width,word height, const char * title); void Close_window (void); void Open_popup (word x_pos, word y_pos, word width, word height); void Close_popup (void); void Window_draw_normal_bouton(word x_pos,word y_pos,word width,word height, const char * title,byte undersc_letter,byte clickable); void Window_select_normal_button(word x_pos,word y_pos,word width,word height); void Window_unselect_normal_button(word x_pos,word y_pos,word width,word height); void Window_draw_palette_bouton(word x_pos,word y_pos); void Compute_slider_cursor_length(T_Scroller_button * button); void Window_draw_slider(T_Scroller_button * button); void Window_draw_scroller_button(T_Scroller_button * button); void Window_input_content(T_Special_button * button, const char * content); void Window_clear_input_button(T_Special_button * button); void Window_draw_input_bouton(word x_pos, word y_pos, word width_in_characters); T_Normal_button * Window_set_normal_button(word x_pos, word y_pos, word width, word height, const char * title, byte undersc_letter, byte clickable, word shortcut); T_Normal_button * Window_set_repeatable_button(word x_pos, word y_pos, word width, word height, const char * title, byte undersc_letter, byte clickable, word shortcut); T_Palette_button * Window_set_palette_button(word x_pos, word y_pos); void Window_clear_tags(void); void Tag_color_range(byte start, byte end); T_Scroller_button * Window_set_scroller_button(word x_pos, word y_pos, word height, word nb_elements, word nb_elements_visible, word initial_position); T_Scroller_button * Window_set_horizontal_scroller_button(word x_pos, word y_pos, word height, word nb_elements, word nb_elements_visible, word initial_position); T_Special_button * Window_set_special_button(word x_pos, word y_pos, word width, word height); T_Special_button * Window_set_input_button(word x_pos, word y_pos, word width_in_characters); T_Dropdown_button * Window_set_dropdown_button(word x_pos, word y_pos, word width, word height, word dropdown_width, const char *label, byte display_choice, byte display_centered, byte display_arrow, byte active_button,byte bottom_up); /// Adds an item to a dropdown menu void Window_dropdown_add_item(T_Dropdown_button * dropdown, word btn_number, const char *label); void Window_dropdown_clear_items(T_Dropdown_button * dropdown); /// /// Displays a dropped-down menu and handles the UI logic until the user /// releases a mouse button. /// This function then clears the dropdown and returns the selected item, /// or NULL if the user wasn't highlighting an item when he closed. T_Dropdown_choice * Dropdown_activate(T_Dropdown_button *button, short off_x, short off_y); T_List_button * Window_set_list_button(T_Special_button * entry_button, T_Scroller_button * scroller, Func_draw_list_item draw_list_item, byte color_index); void Window_redraw_list(T_List_button * list); byte Window_click_in_rectangle(short start_x, short start_y, short end_x, short end_y); short Wait_click_in_palette(T_Palette_button * button); short Window_normal_button_onclick(word x_pos, word y_pos, word width, word height, short btn_number); void Get_color_behind_window(byte * color, byte * click); short Window_clicked_button(void); int Button_under_mouse(void); short Window_get_clicked_button(void); void Remap_window_backgrounds(byte * conversion_table, int Min_Y, int Max_Y); void Pixel_background(int x_pos, int y_pos, byte color); /// /// Updates the status bar line with a color number. /// Used when hovering the menu palette. void Status_print_palette_color(byte color); /// Puts the user in wait mode for the specified time ( in 1/100s), /// though the mouse still works. void Delay_with_active_mouse(int delay); /// /// Based on which toolbars are visible, updates their offsets and /// computes ::Menu_height and ::Menu_Y void Compute_menu_offsets(void); /// /// Shows or hides a tolbar from the menu. /// If with_redraw is set to zero, the caller should /// redraw itself using Display_menu() and Display_all_screen(). void Set_bar_visibility(word bar, int visible, int with_redraw); /// /// Checks if the current menu toolbars suit the current image type : /// layered vs anim. If they don't fit, swap the toolbars and return 1: /// The caller is then responsible for refreshing the screen by calling /// Display_menu() and Display_all_screen() int Check_menu_mode(void); #endif grafx2_2.4+git20180105/src/readini.h0000664000000000000000000000217313223665306015316 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file readini.h /// Reading settings in gfx2.ini ////////////////////////////////////////////////////////////////////////////// int Load_INI(T_Config * conf); int Load_INI_seek_pattern(char * buffer,char * pattern); void Load_INI_clear_string(char * str, byte keep_comments); grafx2_2.4+git20180105/src/SDLMain.h0000664000000000000000000000046313223665306015132 0ustar rootroot/* SDLMain.m - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn Feel free to customize this file to suit your needs */ #import @interface SDLMain : NSObject @end grafx2_2.4+git20180105/src/buttons_effects.c0000664000000000000000000011604313223665306017075 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2007-2017 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ //////////////////////////////////////////////////////////////////////////// ///@file buttons_effects.c /// Handles all the effects buttons and setup windows in the effects menu. //////////////////////////////////////////////////////////////////////////// #include #include #include #include "brush.h" #include "buttons.h" #include "engine.h" #include "global.h" #include "graph.h" #include "help.h" #include "input.h" #include "misc.h" #include "pages.h" #include "readline.h" #include "sdlscreen.h" #include "struct.h" #include "windows.h" #include "tiles.h" //---------- Menu dans lequel on tagge des couleurs (genre Stencil) ---------- void Menu_tag_colors(char * window_title, byte * table, byte * mode, byte can_cancel, const char *help_section, word close_shortcut) { short clicked_button; byte backup_table[256]; word index; word old_mouse_x; word old_mouse_y; byte old_mouse_k; byte tagged_color; byte color; byte click; Open_window(176,150,window_title); Window_set_palette_button(6,38); // 1 Window_set_normal_button( 7, 19,78,14,"Clear" ,1,1,SDLK_c); // 2 Window_set_normal_button(91, 19,78,14,"Invert",1,1,SDLK_i); // 3 if (can_cancel) { Window_set_normal_button(91,129,78,14,"OK" ,0,1,SDLK_RETURN); // 4 Window_set_normal_button( 7,129,78,14,"Cancel",0,1,KEY_ESC); // 5 // On enregistre la table dans un backup au cas o on ferait Cancel memcpy(backup_table,table,256); } else Window_set_normal_button(49,129,78,14,"OK" ,0,1,SDLK_RETURN); // 4 // On affiche l'tat actuel de la table for (index=0; index<=255; index++) Stencil_tag_color(index, (table[index])?MC_Black:MC_Light); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { old_mouse_x=Mouse_X; old_mouse_y=Mouse_Y; old_mouse_k=Mouse_K; clicked_button=Window_clicked_button(); switch (clicked_button) { case 0 : break; case -1 : case 1 : // Palette if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) { Hide_cursor(); tagged_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); table[tagged_color]=(Mouse_K==LEFT_SIDE); Stencil_tag_color(tagged_color,(Mouse_K==LEFT_SIDE)?MC_Black:MC_Light); Display_cursor(); Stencil_update_color(tagged_color); } break; case 2 : // Clear memset(table,0,256); Hide_cursor(); for (index=0; index<=255; index++) Stencil_tag_color(index,MC_Light); Display_cursor(); Update_window_area(0,0,Window_width, Window_height); break; case 3 : // Invert Hide_cursor(); for (index=0; index<=255; index++) Stencil_tag_color(index,(table[index]^=1)?MC_Black:MC_Light); Display_cursor(); Update_window_area(0,0,Window_width, Window_height); } if (!Mouse_K) switch (Key) { case SDLK_BACKQUOTE : // Rcupration d'une couleur derrire le menu case SDLK_COMMA : Get_color_behind_window(&color,&click); if (click) { Hide_cursor(); tagged_color=color; table[tagged_color]=(click==LEFT_SIDE); Stencil_tag_color(tagged_color,(click==LEFT_SIDE)?MC_Black:MC_Light); Stencil_update_color(tagged_color); Display_cursor(); Wait_end_of_click(); } Key=0; break; default: if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Window_help(BUTTON_EFFECTS, help_section); Key=0; break; } else if (Is_shortcut(Key,close_shortcut)) { clicked_button=4; } } } while (clicked_button<4); Close_window(); if (clicked_button==5) // Cancel memcpy(table,backup_table,256); else // OK *mode=1; Display_cursor(); } byte Selected_Constraint_Mode = 0; // Constaint enforcer/checker ------------------------------------------------ void Button_Constraint_mode() { int pixel; if (Main_backups->Pages->Image_mode > IMAGE_MODE_ANIMATION) { // Disable Switch_layer_mode(IMAGE_MODE_LAYERED); return; } if (Selected_Constraint_Mode <= IMAGE_MODE_ANIMATION) Selected_Constraint_Mode = IMAGE_MODE_EGX; if (Selected_Constraint_Mode == IMAGE_MODE_MODE5) { if (Main_backups->Pages->Image_mode != IMAGE_MODE_LAYERED || Main_backups->Pages->Nb_layers!=5 || (Main_image_width%48)) { Verbose_message("Error!", "This emulation of Amstrad CPC's Mode5 can only be used on a 5-layer image whose width is a multiple of 48."); return; } for (pixel=0; pixel < Main_image_width*Main_image_height; pixel++) { if (Main_backups->Pages->Image[4].Pixels[pixel]>3) { Verbose_message("Error!", "This emulation of Amstrad CPC's Mode5 needs all pixels of layer 5 to use colors 0-3."); return; } } // TODO set the palette to a CPC one ? } // TODO backup Switch_layer_mode(Selected_Constraint_Mode); } void Button_Constraint_menu(void) { short clicked_button; T_Dropdown_button* dropdown; Open_window(154,79,"8-bit constraints"); Window_set_normal_button(21,55,51,14,"Cancel",0,1,KEY_ESC); // 1 Window_set_normal_button(82,55,51,14,"OK" ,0,1,SDLK_RETURN); // 2 dropdown = Window_set_dropdown_button(17, 21, 120, 14, 120, "Constraints", 1, 0, 1, RIGHT_SIDE|LEFT_SIDE, 0); // 3 Window_dropdown_add_item(dropdown, IMAGE_MODE_ZX, "ZX Spectrum"); //Window_dropdown_add_item(dropdown, IMAGE_MODE_GBC, "Game Boy Color"); Window_dropdown_add_item(dropdown, IMAGE_MODE_THOMSON, "40col (MO/TO)"); Window_dropdown_add_item(dropdown, IMAGE_MODE_EGX, "EGX (CPC)"); Window_dropdown_add_item(dropdown, IMAGE_MODE_EGX2, "EGX2 (CPC)"); Window_dropdown_add_item(dropdown, IMAGE_MODE_MODE5, "Mode 5 (CPC)"); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (clicked_button == 3) Selected_Constraint_Mode = Window_attribute2; } while ( (clicked_button!=1) && (clicked_button!=2) ); Close_window(); if (clicked_button==2) // OK { if ((Selected_Constraint_Mode > IMAGE_MODE_ANIMATION) && (Main_backups->Pages->Image_mode <= IMAGE_MODE_ANIMATION)) Button_Constraint_mode(); } Display_cursor(); } // Tilemap mode void Button_Tilemap_mode(void) { Main_tilemap_mode=!Main_tilemap_mode; Tilemap_update(); } void Button_Tilemap_menu(void) { short clicked_button; byte flip_x=Config.Tilemap_allow_flipped_x; byte flip_y=Config.Tilemap_allow_flipped_y; byte count=Config.Tilemap_show_count; Open_window(166,120,"Tilemap options"); Window_set_normal_button(6,102,51,14,"Cancel",0,1,KEY_ESC); // 1 Window_set_normal_button(110,102,51,14,"OK" ,0,1,SDLK_RETURN); // 2 Print_in_window(24,21, "Detect mirrored",MC_Dark,MC_Light); Window_display_frame(5,17,155,56); Print_in_window(37,37, "Horizontally",MC_Black,MC_Light); Window_set_normal_button(18,34,13,13,flip_x?"X":"",0,1,0); // 3 Print_in_window(37,55, "Vertically",MC_Black,MC_Light); Window_set_normal_button(18,52,13,13,flip_y?"X":"",0,1,0); // 4 Print_in_window(27,81, "Show count",MC_Black,MC_Light); Window_set_normal_button(7,78,13,13,count?"X":"",0,1,0); // 5 Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); switch (clicked_button) { case 3 : // Horizontal flip flip_x=!flip_x; Hide_cursor(); Print_in_window(21,37,flip_x?"X":" ", MC_Black, MC_Light); Display_cursor(); break; case 4 : // Vertical flip flip_y=!flip_y; Hide_cursor(); Print_in_window(21,55,flip_y?"X":" ", MC_Black, MC_Light); Display_cursor(); break; case 5 : // Count count=!count; Hide_cursor(); Print_in_window(10,81,count?"X":" ", MC_Black, MC_Light); Display_cursor(); break; } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "TILEMAP"); } while ( (clicked_button!=1) && (clicked_button!=2) ); if (clicked_button==2) // OK { byte changed = Config.Tilemap_allow_flipped_x!=flip_x || Config.Tilemap_allow_flipped_y!=flip_y || !Main_tilemap_mode; Config.Tilemap_allow_flipped_x=flip_x; Config.Tilemap_allow_flipped_y=flip_y; Config.Tilemap_show_count=count; if (changed) { Main_tilemap_mode=1; Tilemap_update(); } } Close_window(); Display_cursor(); } //--------------------------------- Stencil ---------------------------------- void Button_Stencil_mode(void) { Stencil_mode=!Stencil_mode; } void Stencil_tag_color(byte color, byte tag_color) { Window_rectangle(Window_palette_button_list->Pos_X+4+(color >> 4)*10, Window_palette_button_list->Pos_Y+3+(color & 15)* 5, 2,5,tag_color); } void Stencil_update_color(byte color) { Update_window_area(Window_palette_button_list->Pos_X+4+(color >> 4)*10, Window_palette_button_list->Pos_Y+3+(color & 15)* 5, 2,5); } void Button_Stencil_menu(void) { Menu_tag_colors("Stencil",Stencil,&Stencil_mode,1, "STENCIL", SPECIAL_STENCIL_MENU); } //--------------------------------- Masque ----------------------------------- void Button_Mask_mode(void) { Mask_mode=!Mask_mode; } void Button_Mask_menu(void) { Menu_tag_colors("Mask",Mask_table,&Mask_mode,1, "MASK", SPECIAL_MASK_MENU); } // -------------------------------- Grille ----------------------------------- void Button_Snap_mode(void) { Hide_cursor(); Snap_mode=!Snap_mode; Compute_paintbrush_coordinates(); Display_cursor(); } void Button_Grid_menu(void) { short clicked_button; word chosen_X =Snap_width; word chosen_Y =Snap_height; short dx_selected=Snap_offset_X; short dy_selected=Snap_offset_Y; // Entering this window automatically enables "snap" char snapgrid = 1; T_Special_button * input_x_button; T_Special_button * input_y_button; T_Special_button * input_dx_button; T_Special_button * input_dy_button; char str[4]; Open_window(149,118,"Grid"); Window_set_normal_button(12,92,51,14,"Cancel",0,1,KEY_ESC); // 1 Window_set_normal_button(86,92,51,14,"OK" ,0,1,SDLK_RETURN); // 2 Print_in_window(11,26, "X:",MC_Dark,MC_Light); input_x_button = Window_set_input_button(29,24,3); // 3 Num2str(chosen_X,str,3); Window_input_content(input_x_button,str); Print_in_window(11,47, "Y:",MC_Dark,MC_Light); input_y_button = Window_set_input_button(29,45,3); // 4 Num2str(chosen_Y,str,3); Window_input_content(input_y_button,str); Print_in_window(77,26,"dX:",MC_Dark,MC_Light); input_dx_button = Window_set_input_button(103,24,3); // 5 Num2str(dx_selected,str,3); Window_input_content(input_dx_button,str); Print_in_window(77,47,"dY:",MC_Dark,MC_Light); input_dy_button = Window_set_input_button(103,45,3); // 6 Num2str(dy_selected,str,3); Window_set_normal_button(12, 62, 14, 14, " ", 0, 1, 0); // 7 if (snapgrid) Print_in_window(16, 65, "X", MC_Black, MC_Light); Print_in_window(32, 65,"Snap",MC_Dark,MC_Light); Window_input_content(input_dy_button,str); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); switch (clicked_button) { case 3 : Num2str(chosen_X,str,3); Readline(31,26,str,3,INPUT_TYPE_INTEGER); chosen_X=atoi(str); // On corrige les dimensions if ((!chosen_X) || (chosen_X>999)) { if (!chosen_X) chosen_X=1; else chosen_X=999; Num2str(chosen_X,str,3); Window_input_content(input_x_button,str); } if (dx_selected>=chosen_X) { dx_selected=chosen_X-1; Num2str(dx_selected,str,3); Window_input_content(input_dx_button,str); } Display_cursor(); break; case 4 : Num2str(chosen_Y,str,3); Readline(31,47,str,3,INPUT_TYPE_INTEGER); chosen_Y=atoi(str); // On corrige les dimensions if ((!chosen_Y) || (chosen_Y>999)) { if (!chosen_Y) chosen_Y=1; else chosen_Y=999; Num2str(chosen_Y,str,3); Window_input_content(input_y_button,str); } if (dy_selected>=chosen_Y) { dy_selected=chosen_Y-1; Num2str(dy_selected,str,3); Window_input_content(input_dy_button,str); } Display_cursor(); break; case 5 : Num2str(dx_selected,str,3); Readline(105,26,str,3,INPUT_TYPE_INTEGER); dx_selected=atoi(str); // On corrige les dimensions if (dx_selected>=chosen_X) dx_selected=chosen_X-1; Num2str(dx_selected,str,3); Window_input_content(input_dx_button,str); Display_cursor(); break; case 6 : Num2str(dy_selected,str,3); Readline(105,47,str,3,INPUT_TYPE_INTEGER); dy_selected=atoi(str); // On corrige les dimensions if (dy_selected>=chosen_Y) dy_selected=chosen_Y-1; Num2str(dy_selected,str,3); Window_input_content(input_dy_button,str); Display_cursor(); case 7: snapgrid = !snapgrid; Hide_cursor(); Print_in_window(16, 65, snapgrid?"X":" ", MC_Black, MC_Light); Display_cursor(); break; } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "GRID"); } while ( (clicked_button!=1) && (clicked_button!=2) ); if (clicked_button==2) // OK { byte modified; modified = Snap_width!=chosen_X || Snap_height!=chosen_Y || Snap_offset_X!=dx_selected || Snap_offset_Y!=dy_selected; Snap_width=chosen_X; Snap_height=chosen_Y; Snap_offset_X=dx_selected; Snap_offset_Y=dy_selected; Snap_mode=snapgrid; if (modified) { Tilemap_update(); Disable_spare_tilemap(); } } Close_window(); Display_cursor(); } void Button_Show_grid(void) { Show_grid = !Show_grid; Hide_cursor(); Display_all_screen(); Display_cursor(); } // -- Mode Smooth ----------------------------------------------------------- void Button_Smooth_mode(void) { if (Smooth_mode) Effect_function=No_effect; else { Effect_function=Effect_smooth; Shade_mode=0; Quick_shade_mode=0; Colorize_mode=0; Tiling_mode=0; Smear_mode=0; } Smooth_mode=!Smooth_mode; } byte Smooth_default_matrices[4][3][3]= { { {1,2,1}, {2,4,2}, {1,2,1} }, { {1,3,1}, {3,9,3}, {1,3,1} }, { {0,1,0}, {1,2,1}, {0,1,0} }, { {2,3,2}, {3,1,3}, {2,3,2} } }; void Button_Smooth_menu(void) { short clicked_button; word x,y,i,j; byte chosen_matrix[3][3]; T_Special_button * matrix_input[3][3]; char str[3]; Open_window(142,109,"Smooth"); Window_set_normal_button(82,59,53,14,"Cancel",0,1,KEY_ESC); // 1 Window_set_normal_button(82,88,53,14,"OK" ,0,1,SDLK_RETURN); // 2 Window_display_frame(6,17,130,37); for (x=11,y=0; y<4; x+=31,y++) { Window_set_normal_button(x,22,27,27,"",0,1,SDLK_LAST); // 3,4,5,6 for (j=0; j<3; j++) for (i=0; i<3; i++) Print_char_in_window(x+2+(i<<3),24+(j<<3),'0'+Smooth_default_matrices[y][i][j],MC_Black,MC_Light); } Window_display_frame(6,58, 69,45); for (j=0; j<3; j++) for (i=0; i<3; i++) { matrix_input[i][j]=Window_set_input_button(10+(i*21),62+(j*13),2); // 7..15 chosen_matrix[i][j] = Smooth_matrix[i][j] ; Num2str(chosen_matrix[i][j], str, 2); Window_input_content(matrix_input[i][j],str); } Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (clicked_button>2) { if (clicked_button<=6) { memcpy(chosen_matrix,Smooth_default_matrices[clicked_button-3],sizeof(chosen_matrix)); Hide_cursor(); for (j=0; j<3; j++) for (i=0; i<3; i++) { Num2str(chosen_matrix[i][j],str,2); Window_input_content(matrix_input[i][j],str); } Display_cursor(); } else { i=clicked_button-7; x=i%3; y=i/3; Num2str(chosen_matrix[x][y],str,2); Readline(matrix_input[x][y]->Pos_X+2, matrix_input[x][y]->Pos_Y+2, str,2,INPUT_TYPE_INTEGER); chosen_matrix[x][y]=atoi(str); Display_cursor(); } } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "SMOOTH"); else if (Is_shortcut(Key,SPECIAL_SMOOTH_MENU)) clicked_button=2; } while ((clicked_button!=1) && (clicked_button!=2)); Close_window(); if (clicked_button==2) // OK { memcpy(Smooth_matrix,chosen_matrix,sizeof(Smooth_matrix)); Smooth_mode=0; // On le met 0 car la fonct suivante va le passer 1 Button_Smooth_mode(); } Display_cursor(); } // -- Mode Smear ------------------------------------------------------------ void Button_Smear_mode(void) { if (!Smear_mode) { if (!Colorize_mode) Effect_function=No_effect; Shade_mode=0; Quick_shade_mode=0; Smooth_mode=0; Tiling_mode=0; } Smear_mode=!Smear_mode; } // -- Mode Colorize --------------------------------------------------------- void Compute_colorize_table(void) { word index; word factor_a; word factor_b; factor_a=256*(100-Colorize_opacity)/100; factor_b=256*( Colorize_opacity)/100; for (index=0;index<256;index++) { Factors_table[index]=index*factor_a; Factors_inv_table[index]=index*factor_b; } } void Button_Colorize_mode(void) { if (Colorize_mode) Effect_function=No_effect; else { switch(Colorize_current_mode) { case 0 : Effect_function=Effect_interpolated_colorize; break; case 1 : Effect_function=Effect_additive_colorize; break; case 2 : Effect_function=Effect_substractive_colorize; break; case 3 : Effect_function=Effect_alpha_colorize; } Shade_mode=0; Quick_shade_mode=0; Smooth_mode=0; Tiling_mode=0; } Colorize_mode=!Colorize_mode; } void Button_Colorize_display_selection(int mode) { short y_pos=0; // Ligne o afficher les flches de slection // On commence par effacer les anciennes slections: // Partie gauche Print_in_window(4,37," ",MC_Black,MC_Light); Print_in_window(4,57," ",MC_Black,MC_Light); Print_in_window(4,74," ",MC_Black,MC_Light); Print_in_window(4,91," ",MC_Black,MC_Light); // Partie droite Print_in_window(129,37," ",MC_Black,MC_Light); Print_in_window(129,57," ",MC_Black,MC_Light); Print_in_window(129,74," ",MC_Black,MC_Light); Print_in_window(129,91," ",MC_Black,MC_Light); // Ensuite, on affiche la flche l o il le faut: switch(mode) { case 0 : // Mthode interpole y_pos=37; break; case 1 : // Mthode additive y_pos=57; break; case 2 : // Mthode soustractive y_pos=74; break; case 3 : // Mthode alpha y_pos=91; } Print_in_window(4,y_pos,"\020",MC_Black,MC_Light); Print_in_window(129,y_pos,"\021",MC_Black,MC_Light); } void Button_Colorize_menu(void) { short chosen_opacity; short selected_mode; short clicked_button; char str[4]; Open_window(140,135,"Transparency"); Print_in_window(16,23,"Opacity:",MC_Dark,MC_Light); Window_set_input_button(87,21,3); // 1 Print_in_window(117,23,"%",MC_Dark,MC_Light); Window_set_normal_button(16,34,108,14,"Interpolate",1,1,SDLK_i); // 2 Window_display_frame(12,18,116,34); Window_set_normal_button(16,54,108,14,"Additive" ,2,1,SDLK_d); // 3 Window_set_normal_button(16,71,108,14,"Subtractive",1,1,SDLK_s); // 4 Window_set_normal_button(16,88,108,14,"Alpha",1,1,SDLK_a); // 4 Window_set_normal_button(16,111, 51,14,"Cancel" ,0,1,KEY_ESC); // 5 Window_set_normal_button(73,111, 51,14,"OK" ,0,1,SDLK_RETURN); // 6 Num2str(Colorize_opacity,str,3); Window_input_content(Window_special_button_list,str); Button_Colorize_display_selection(Colorize_current_mode); chosen_opacity=Colorize_opacity; selected_mode =Colorize_current_mode; Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); switch(clicked_button) { case 1: // Zone de saisie de l'opacit Num2str(chosen_opacity,str,3); Readline(89,23,str,3,INPUT_TYPE_INTEGER); chosen_opacity=atoi(str); // On corrige le pourcentage if (chosen_opacity>100) { chosen_opacity=100; Num2str(chosen_opacity,str,3); Window_input_content(Window_special_button_list,str); } Display_cursor(); break; case 2: // Interpolated method case 3: // Additive method case 4: // Substractive method case 5: // Alpha method selected_mode=clicked_button-2; Hide_cursor(); Button_Colorize_display_selection(selected_mode); Display_cursor(); } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "TRANSPARENCY"); else if (Is_shortcut(Key,SPECIAL_COLORIZE_MENU)) clicked_button=7; } while (clicked_button<6); Close_window(); if (clicked_button==7) // OK { Colorize_opacity =chosen_opacity; Colorize_current_mode=selected_mode; Compute_colorize_table(); Colorize_mode=0; // On le met 0 car la fonct suivante va le passer 1 Button_Colorize_mode(); } Display_cursor(); } // -- Mode Tiling ----------------------------------------------------------- void Button_Tiling_mode(void) { if (Tiling_mode) Effect_function=No_effect; else { Effect_function=Effect_tiling; Shade_mode=0; Quick_shade_mode=0; Colorize_mode=0; Smooth_mode=0; Smear_mode=0; } Tiling_mode=!Tiling_mode; } void Button_Tiling_menu(void) { short clicked_button; short chosen_offset_x=Tiling_offset_X; short chosen_offset_y=Tiling_offset_Y; char str[5]; T_Special_button * input_offset_x_button; T_Special_button * input_offset_y_button; Open_window(138,79,"Tiling"); Window_set_normal_button(13,55,51,14,"Cancel",0,1,KEY_ESC); // 1 Window_set_normal_button(74,55,51,14,"OK" ,0,1,SDLK_RETURN); // 2 input_offset_x_button = Window_set_input_button(91,21,4); // 3 input_offset_y_button = Window_set_input_button(91,35,4); // 4 Print_in_window(12,23,"Offset X:",MC_Dark,MC_Light); Print_in_window(12,37,"Offset Y:",MC_Dark,MC_Light); Num2str(Tiling_offset_X,str,4); Window_input_content(input_offset_x_button,str); Num2str(Tiling_offset_Y,str,4); Window_input_content(input_offset_y_button,str); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (clicked_button==3) // Zone de saisie du dcalage X { Num2str(chosen_offset_x,str,4); Readline(93,23,str,4,INPUT_TYPE_INTEGER); chosen_offset_x=atoi(str); // On corrige le dcalage en X if (chosen_offset_x>=Brush_width) { chosen_offset_x=Brush_width-1; Num2str(chosen_offset_x,str,4); Window_input_content(input_offset_x_button,str); } Display_cursor(); } else if (clicked_button==4) // Zone de saisie du dcalage Y { Num2str(chosen_offset_y,str,4); Readline(93,37,str,4,INPUT_TYPE_INTEGER); chosen_offset_y=atoi(str); // On corrige le dcalage en Y if (chosen_offset_y>=Brush_height) { chosen_offset_y=Brush_height-1; Num2str(chosen_offset_y,str,4); Window_input_content(input_offset_y_button,str); } Display_cursor(); } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "TILING"); } while ( (clicked_button!=1) && (clicked_button!=2) ); Close_window(); if (clicked_button==2) // OK { Tiling_offset_X=chosen_offset_x; Tiling_offset_Y=chosen_offset_y; if (!Tiling_mode) Button_Tiling_mode(); } Display_cursor(); } // -- All modes off --------------------------------------------------------- void Effects_off(void) { Effect_function=No_effect; Shade_mode=0; Quick_shade_mode=0; Colorize_mode=0; Smooth_mode=0; Tiling_mode=0; Smear_mode=0; Stencil_mode=0; Mask_mode=0; Sieve_mode=0; Snap_mode=0; Main_tilemap_mode=0; } // -- Mode Sieve (Sieve) ---------------------------------------------------- void Button_Sieve_mode(void) { Sieve_mode=!Sieve_mode; } void Draw_sieve_scaled(short origin_x, short origin_y) { short x_pos; short y_pos; short x_size; short y_size; short start_x=Window_pos_X+(Menu_factor_X*230); short start_y=Window_pos_Y+(Menu_factor_Y*78); x_size=Menu_factor_X*5; // |_ Taille d'une case y_size=Menu_factor_Y*5; // | de la trame zoome // On efface de contenu prcdent Block(origin_x,origin_y, Menu_factor_X*Window_special_button_list->Width, Menu_factor_Y*Window_special_button_list->Height,MC_Light); for (y_pos=0; y_posSieve_pattern[index][j&0xF]>>(15-(i&0xF)))&1)?MC_White:MC_Black); Update_rect(ToWinX(10),ToWinY(22),ToWinL(12*23+16),ToWinH(16)); } void Copy_preset_sieve(byte index) { short i,j; for (j=0; j<16; j++) for (i=0; i<16; i++) Sieve[i][j]=(Gfx->Sieve_pattern[index][j]>>(15-i))&1; Sieve_width=16; Sieve_height=16; } void Invert_trame(void) { byte x_pos,y_pos; for (y_pos=0; y_posPos_X+2, button_bg_color->Pos_Y+2, 7, 7, (default_bg_color)?MC_White:MC_Black); Window_set_repeatable_button(109, 69,11,11,"\030",0,1,SDLK_UP); // 13 Window_set_repeatable_button(109, 93,11,11,"\031",0,1,SDLK_DOWN); // 14 Window_set_repeatable_button( 97, 81,11,11,"\033",0,1,SDLK_LEFT); // 15 Window_set_repeatable_button(121, 81,11,11,"\032",0,1,SDLK_RIGHT); // 16 for (index=0; index<12; index++) Window_set_normal_button((index*23)+8,20,20,20,"",0,1,SDLK_F1+index); // 17 -> 28 Draw_preset_sieve_patterns(); origin_x=Window_pos_X+(Menu_factor_X*Window_special_button_list->Pos_X); origin_y=Window_pos_Y+(Menu_factor_Y*Window_special_button_list->Pos_Y); Num2str(Sieve_width,str,2); Print_in_window(71,120,str,MC_Black,MC_Light); Num2str(Sieve_height,str,2); Print_in_window(71,136,str,MC_Black,MC_Light); Draw_sieve_scaled(origin_x,origin_y); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); origin_x=Window_pos_X+(Menu_factor_X*Window_special_button_list->Pos_X); origin_y=Window_pos_Y+(Menu_factor_Y*Window_special_button_list->Pos_Y); switch (clicked_button) { case -1 : case 0 : break; case 1 : // Zone de dessin de la trame /* // Version qui n'accepte pas les clicks sur la grille x_pos=(Mouse_X-origin_x)/Menu_factor_X; y_pos=(Mouse_Y-origin_y)/Menu_factor_Y; if ( (x_pos%5<4) && (y_pos%5<4) ) { x_pos/=5; y_pos/=5; if ( (x_pos16)?16:Brush_width; Sieve_height=(Brush_height>16)?16:Brush_height; for (y_pos=0; y_pos>1); Brush_offset_Y=(Brush_height>>1); Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); break; case 8 : // Rduire hauteur if (Sieve_height>1) { Hide_cursor(); Sieve_height--; Num2str(Sieve_height,str,2); Print_in_window(71,136,str,MC_Black,MC_Light); Draw_sieve_scaled(origin_x,origin_y); Display_cursor(); Update_sieve_area(origin_x, origin_y); } break; case 9 : // Agrandir hauteur if (Sieve_height<16) { Hide_cursor(); for (index=0; index1) { Hide_cursor(); Sieve_width--; Num2str(Sieve_width,str,2); Print_in_window(71,120,str,MC_Black,MC_Light); Draw_sieve_scaled(origin_x,origin_y); Display_cursor(); Update_sieve_area(origin_x, origin_y); } break; case 11 : // Agrandir largeur if (Sieve_width<16) { Hide_cursor(); for (index=0; indexPos_X+2, button_bg_color->Pos_Y+2, 7, 7, (default_bg_color)?MC_White:MC_Black); Display_cursor(); Update_window_area( button_bg_color->Pos_X+2, button_bg_color->Pos_Y+2, 7, 7); break; case 13 : // Scroll vers le haut Hide_cursor(); for (x_pos=0; x_pos0; y_pos--) Sieve[x_pos][y_pos]=Sieve[x_pos][y_pos-1]; Sieve[x_pos][0]=temp; } Draw_sieve_scaled(origin_x,origin_y); Display_cursor(); Update_sieve_area(origin_x, origin_y); break; case 15 : // Scroll vers la gauche Hide_cursor(); for (y_pos=0; y_pos0; x_pos--) Sieve[x_pos][y_pos]=Sieve[x_pos-1][y_pos]; Sieve[0][y_pos]=temp; } Draw_sieve_scaled(origin_x,origin_y); Display_cursor(); Update_sieve_area(origin_x, origin_y); break; default : // Boutons de trames prdfinies Hide_cursor(); Copy_preset_sieve(clicked_button-17); Draw_sieve_scaled(origin_x,origin_y); Num2str(Sieve_width,str,2); Print_in_window(71,120,str,MC_Black,MC_Light); Num2str(Sieve_height,str,2); Print_in_window(71,136,str,MC_Black,MC_Light); Draw_sieve_scaled(origin_x,origin_y); Display_cursor(); Update_sieve_area(origin_x, origin_y); } if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Key=0; Window_help(BUTTON_EFFECTS, "SIEVE"); } } while ( (clicked_button!=2) && (clicked_button!=3) ); Close_window(); if (clicked_button==2) // Cancel { Sieve_width=old_sieve_width; Sieve_height=old_sieve_height; memcpy(Sieve,old_sieve,256); } if ( (clicked_button==3) && (!Sieve_mode) ) // OK Button_Sieve_mode(); Display_cursor(); } grafx2_2.4+git20180105/src/pxtriple.c0000664000000000000000000004064213223665306015550 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxtriple.h" #define ZOOMX 3 #define ZOOMY 3 void Pixel_triple (word x,word y,byte color) /* Affiche un pixel de la color aux coords x;y l'cran */ { *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 2)=color; } byte Read_pixel_triple (word x,word y) /* On retourne la couleur du pixel aux coords donnes */ { return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); } void Block_triple (word start_x,word start_y,word width,word height,byte color) /* On affiche un rectangle de la couleur donne */ { SDL_Rect rectangle; rectangle.x=start_x*ZOOMX; rectangle.y=start_y*ZOOMY; rectangle.w=width*ZOOMX; rectangle.h=height*ZOOMY; SDL_FillRect(Screen_SDL,&rectangle,color); } void Display_part_of_screen_triple (word width,word height,word image_width) /* Afficher une partie de l'image telle quelle sur l'cran */ { byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'cran (dest) byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de dpart ds la source (src) int y; int dy; for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne for (dy=width;dy>0;dy--) { *(dest+2)=*(dest+1)=*dest=*src; src++; dest+=ZOOMX; } // On double la ligne qu'on vient de copier memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On la triple memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } //Update_rect(0,0,width,height); } void Pixel_preview_normal_triple (word x,word y,byte color) /* Affichage d'un pixel dans l'cran, par rapport au dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure Pixel_Preview_Loupe_SDL. */ { // if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) Pixel_triple(x-Main_offset_X,y-Main_offset_Y,color); } void Pixel_preview_magnifier_triple (word x,word y,byte color) { // Affiche le pixel dans la partie non zoome Pixel_triple(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) { // On est dedans int height; int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_triple( Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, y_zoom, Main_magnifier_factor, height, color ); } } void Horizontal_XOR_line_triple(word x_pos,word y_pos,word width) { //On calcule la valeur initiale de dest: byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; int x; for (x=0;x0;i--) { *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=xor_lut[*dest]; dest+=VIDEO_LINE_WIDTH*ZOOMY; } } void Display_brush_color_triple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = Brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+2*VIDEO_LINE_WIDTH+2) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+2) = *(dest+1) = *dest = *src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } Update_rect(x_pos,y_pos,width,height); } void Display_brush_mono_triple(word x_pos, word y_pos, word x_offset, word y_offset, word width, word height, byte transp_color, byte color, word brush_width) /* On affiche la brosse en monochrome */ { byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination // l'cran byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds // la brosse int x,y; for(y=height;y!=0;y--) //Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { if (*src!=transp_color) *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=color; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=brush_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Clear_brush_triple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width) { byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'cran (dest) byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de dpart ds la source (src) int y; int x; (void)x_offset; // unused (void)y_offset; // unused (void)transp_color; // unused for(y=height;y!=0;y--) // Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*src; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } // Affiche une brosse (arbitraire) l'cran void Display_brush_triple(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } } void Remap_screen_triple(word x_pos,word y_pos,word width,word height,byte * conversion_table) { // dest = coords a l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; int x,y; // Pour chaque ligne for(y=height;y>0;y--) { // Pour chaque pixel for(x=width;x>0;x--) { *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest= conversion_table[*dest]; dest +=ZOOMX; } dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Display_line_on_screen_fast_triple(word x_pos,word y_pos,word width,byte * line) /* On affiche toute une ligne de pixels telle quelle. */ /* Utilise si le buffer contient dja des pixel doubls. */ { memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); } void Display_line_on_screen_triple(word x_pos,word y_pos,word width,byte * line) /* On affiche une ligne de pixels en les doublant. */ { int x; byte *dest; dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; for(x=width;x>0;x--) { *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*line; dest+=ZOOMX; line++; } } void Display_transparent_mono_line_on_screen_triple( word x_pos, word y_pos, word width, byte* line, byte transp_color, byte color) // Affiche une ligne l'cran avec une couleur + transparence. // Utilis par les brosses en mode zoom { byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; int x; // Pour chaque pixel for(x=0;x 0); src += image_width; } // ATTENTION on n'arrive jamais ici ! } // Affiche une partie de la brosse couleur zoome void Display_brush_color_zoom_triple(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle de la brosse byte * buffer) { byte* src = Brush+y_offset*brush_width + x_offset; word y = y_pos; byte bx; // Pour chaque ligne while(1) { Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche facteur fois la ligne zoome for(bx=Main_magnifier_factor;bx>0;bx--) { byte* line_src = buffer; byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; word x; // Pour chaque pixel de la ligne for(x = width*Main_magnifier_factor;x > 0;x--) { if(*line_src!=transp_color) { *(dest+2)=*(dest+1)=*dest = *line_src; } line_src++; dest+=ZOOMX; } // Double the line memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); // Triple the line memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); y++; if(y==end_y_pos) { return; } } src += brush_width; } // ATTENTION zone jamais atteinte } void Display_brush_mono_zoom_triple(word x_pos, word y_pos, word x_offset, word y_offset, word width, // width non zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle de la brosse byte * buffer ) { byte* src = Brush + y_offset * brush_width + x_offset; int y=y_pos*ZOOMY; //Pour chaque ligne zoomer : while(1) { int bx; // src = Ligne originale // On clate la ligne Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche la ligne Facteur fois l'cran (sur des // lignes conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome Display_transparent_mono_line_on_screen_triple( x_pos, y, width * Main_magnifier_factor, buffer, transp_color, color ); // On passe la ligne suivante y++; // On vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); Update_rect( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); return; } bx --; } while (bx > 0); // Passage la ligne suivante dans la brosse aussi src+=brush_width; } } void Clear_brush_scaled_triple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer) { // En fait on va recopier l'image non zoome dans la partie zoome ! byte* src = Main_screen + y_offset * image_width + x_offset; int y = y_pos; int bx; (void)transp_color; // unused // Pour chaque ligne zoomer while(1){ Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); bx=Main_magnifier_factor; // Pour chaque ligne do{ // TODO a verifier Display_line_on_screen_fast_triple(x_pos,y, width * Main_magnifier_factor,buffer); // Ligne suivante y++; if(y==end_y_pos) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); Update_rect(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); return; } bx--; }while(bx!=0); src+= image_width; } } grafx2_2.4+git20180105/src/haiku.h0000664000000000000000000000046213223665306015003 0ustar rootroot#include "struct.h" /* * Haiku specific code was moved here, because the API is C++. * It can't be compiled in the usual C files. * So we provide a C wrapper to the functons we need. */ #ifndef __HAIKU_H #define __HAIKU_H qword haiku_get_free_space(char* path); char* haiku_get_clipboard(); #endif grafx2_2.4+git20180105/src/misc.h0000664000000000000000000001627013223665306014641 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file misc.h /// Miscellanous unsorted functions. ////////////////////////////////////////////////////////////////////////////// #include "struct.h" #define SWAP_BYTES(a,b) { byte c=a; a=b; b=c;} #define SWAP_WORDS(a,b) { word c=a; a=b; b=c;} #define SWAP_DWORDS(a,b) { dword c=a; a=b; b=c;} #define SWAP_SHORTS(a,b) { short c=a; a=b; b=c;} #define SWAP_FLOATS(a,b) { float c=a; a=b; b=c;} #define SWAP_PBYTES(a,b) { byte * c=a; a=b; b=c;} void Copy_image_to_brush(short start_x,short start_y,short Brush_width,short Brush_height,word image_width); void Remap_general_lowlevel(byte * conversion_table,byte * in_buffer, byte *out_buffer,short width,short height,short buffer_width); void Scroll_picture(byte * main_src, byte * main_dest, short x_offset,short y_offset); void Wait_end_of_click(void); void Set_color(byte color, byte red, byte green, byte blue); void Set_palette(T_Palette palette); void Palette_256_to_64(T_Palette palette); void Palette_64_to_256(T_Palette palette); void Clear_current_image(byte color); void Clear_current_image_with_stencil(byte color, byte * stencil); dword Round_div(dword numerator,dword divisor); word Count_used_colors(dword * usage); word Count_used_colors_area(dword* usage, word start_x, word start_y, word width, word height); word Count_used_colors_screen_area(dword* usage, word start_x, word start_y, word width, word height); void Pixel_in_brush (word x,word y,byte color); byte Read_pixel_from_spare_screen(word x,word y); byte Read_pixel_from_backup_screen (word x,word y); byte Read_pixel_from_feedback_screen (word x,word y); byte Read_pixel_from_brush (word x,word y); void Ellipse_compute_limites(short horizontal_radius,short vertical_radius); // Calcule les valeurs suivantes en fonction des deux paramtres: // // Ellipse_vertical_radius_squared // Ellipse_horizontal_radius_squared // Ellipse_Limit_High // Ellipse_Limit_Low byte Pixel_in_ellipse(void); // Indique si le pixel se trouvant Ellipse_cursor_X pixels // (Ellipse_cursor_X>0 = droite, Ellipse_cursor_X<0 = gauche) et // Ellipse_cursor_Y pixels (Ellipse_cursor_Y>0 = en bas, // Ellipse_cursor_Y<0 = en haut) du centre se trouve dans l'ellipse en // cours. byte Pixel_in_circle(void); // Indique si le pixel se trouvant Circle_cursor_X pixels // (Circle_cursor_X>0 = droite, Circle_cursor_X<0 = gauche) et // Circle_cursor_Y pixels (Circle_cursor_Y>0 = en bas, // Circle_cursor_Y<0 = en haut) du centre se trouve dans le cercle en // cours. // Gestion du chrono dans les fileselects void Init_chrono(dword delay); void Check_timer(void); void Replace_colors_within_limits(byte * replace_table); byte Effect_interpolated_colorize (word x,word y,byte color); byte Effect_additive_colorize (word x,word y,byte color); byte Effect_substractive_colorize(word x,word y,byte color); byte Effect_alpha_colorize(word x,word y,byte color); byte Effect_sieve(word x,word y); /// /// Inverts a pixel buffer, according to a horizontal axis. /// @param src Pointer to the pixel buffer to process. /// @param width Width of the buffer. /// @param height Height of the buffer. void Flip_Y_lowlevel(byte *src, short width, short height); /// /// Inverts a pixel buffer, according to a vertical axis. /// @param src Pointer to the pixel buffer to process. /// @param width Width of the buffer. /// @param height Height of the buffer. void Flip_X_lowlevel(byte *src, short width, short height); /// /// Rotate a pixel buffer by 90 degrees, clockwise. /// @param source Source pixel buffer. /// @param dest Destination pixel buffer. /// @param width Width of the original buffer (height of the destination one). /// @param height Height of the original buffer (width of the destination one). void Rotate_90_deg_lowlevel(byte * source, byte * dest, short width, short height); /// /// Rotate a pixel buffer by 90 degrees, counter-clockwise. /// @param source Source pixel buffer. /// @param dest Destination pixel buffer. /// @param width Width of the original buffer (height of the destination one). /// @param height Height of the original buffer (width of the destination one). void Rotate_270_deg_lowlevel(byte * source, byte * dest, short width, short height); /// /// Rotate a pixel buffer by 180 degrees. /// @param src The pixel buffer (source and destination). /// @param width Width of the buffer. /// @param height Height of the buffer. void Rotate_180_deg_lowlevel(byte *src, short width, short height); /// /// Copies an image to another, rescaling it and optionally flipping it. /// @param src_buffer Original image (address of first byte) /// @param src_width Original image's width in pixels /// @param src_height Original image's height in pixels /// @param dst_buffer Destination image (address of first byte) /// @param dst_width Destination image's width in pixels /// @param dst_height Destination image's height in pixels /// @param x_flipped Boolean, true to flip the image horizontally /// @param y_flipped Boolean, true to flip the image vertically void Rescale(byte *src_buffer, short src_width, short src_height, byte *dst_buffer, short dst_width, short dst_height, short x_flipped, short y_flipped); void Zoom_a_line(byte * original_line,byte * zoomed_line,word factor,word width); void Copy_part_of_image_to_another(byte * source,word source_x,word source_y,word width,word height,word source_width,byte * dest,word dest_x,word dest_y,word destination_width); // -- Gestion du chrono -- byte Timer_state; // State du chrono: 0=Attente d'un Xme de seconde // 1=Il faut afficher la preview // 2=Plus de chrono gerer pour l'instant dword Timer_delay; // Nombre de 18.2me de secondes demands dword Timer_start; // Heure de dpart du chrono byte New_preview_is_needed; // Boolen "Il faut relancer le chrono de preview" #if defined (__MINT__) void Atari_Memory_free(unsigned long *stRam,unsigned long *ttRam); #else unsigned long Memory_free(void); #endif #define Num2str(a,b,c) sprintf(b,"%*lu",c,(long)(a)) #define Dec2str(a,b,c) sprintf(b,"%.*f",c,(double)(a)) short Round(float value); short Round_div_max(short numerator,short divisor); /* round number n to d decimal points */ double Fround(double n, unsigned d); int Min(int a,int b); int Max(int a,int b); char* Mode_label(int mode); int Convert_videomode_arg(const char *argument); int Popcount_word(word x); int Popcount_dword(dword x); grafx2_2.4+git20180105/src/readini.c0000664000000000000000000006762313223665306015324 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 500 #endif #include #include #include #include #include "const.h" #include "errors.h" #include "global.h" #include "misc.h" #include "readini.h" #include "setup.h" #include "realpath.h" #include "io.h" #include "windows.h" void Load_INI_clear_string(char * str, byte keep_comments) { int index; int equal_found=0; for (index=0;str[index]!='\0';) { if ((str[index]=='=')) { equal_found=1; index++; // On enleve les espaces aprs le '=' while (str[index]==' ' || str[index]=='\t') memmove(str+index,str+index+1,strlen(str+index)); } else if ((str[index]==' ' && !equal_found) || (str[index]=='\t')) { // Suppression d'un espace ou d'un tab: memmove(str+index,str+index+1,strlen(str+index)); } else if (!keep_comments && ((str[index]==';') || (str[index]=='#'))) { // Comment str[index]='\0'; } else if ((str[index]=='\r') || (str[index]=='\n')) { // Line break str[index]='\0'; } else { if (!equal_found) { // Passage en majuscule d'un caractre: #ifndef GCWZERO //this causes gcw to crash str[index]=toupper((int)str[index]); #endif } index++; } } // On enlve les espaces avant la fin de chaine while (index>0 && (str[index-1]==' ' || str[index-1]=='\t')) { index--; str[index]='\0'; } } int Load_INI_seek_pattern(char * buffer,char * pattern) { int buffer_index; int pattern_index; // A partir de chaque lettre de la chane buffer for (buffer_index=0;buffer[buffer_index]!='\0';buffer_index++) { // On regarde si la chane pattern est quivalente la position courante // de la chane buffer: for (pattern_index=0;(pattern[pattern_index]!='\0') && (buffer[buffer_index+pattern_index]==pattern[pattern_index]);pattern_index++); // Si on a trouv la chane pattern dans la chane buffer, on renvoie la // position laquelle on l'a trouve (+1 pour que si on la trouve au // dbut a ne renvoie pas la mme chose que si on ne l'avait pas // trouve): if (pattern[pattern_index]=='\0') return (buffer_index+1); } // Si on ne l'a pas trouve, on renvoie 0: return 0; } int Load_INI_reach_group(FILE * file,char * buffer,char * group) { int stop_seek; char * group_upper; char * upper_buffer; // On alloue les zones de mmoire: group_upper=(char *)malloc(1024); upper_buffer=(char *)malloc(1024); // On commence par se faire une version majuscule du groupe rechercher: strcpy(group_upper,group); Load_INI_clear_string(group_upper, 0); stop_seek=0; do { // On lit une ligne dans le fichier: if (fgets(buffer,1024,file)==0) { free(upper_buffer); free(group_upper); return ERROR_INI_CORRUPTED; } Line_number_in_INI_file++; // On s'en fait une version en majuscule: strcpy(upper_buffer,buffer); Load_INI_clear_string(upper_buffer, 0); // On compare la chane avec le groupe recherch: stop_seek=Load_INI_seek_pattern(upper_buffer,group_upper); } while (!stop_seek); free(upper_buffer); free(group_upper); return 0; } /// /// Find the next string in the .INI file. /// @param file INI file currently opened /// @param buffer Current text buffer, preserved from one call to the next /// @param option_name string to search /// @param return_code the found value will be copied there. (must be allocaed) /// @param raw_text Boolean: true to return the raw value (up to end-of-line), false to strip comments. int Load_INI_get_string(FILE * file,char * buffer,char * option_name,char * return_code, byte raw_text) { int stop_seek; char * option_upper; char * upper_buffer; int buffer_index; // On alloue les zones de mmoire: option_upper=(char *)malloc(1024); upper_buffer=(char *)malloc(1024); // On commence par se faire une version majuscule de l'option rechercher: strcpy(option_upper,option_name); Load_INI_clear_string(option_upper, 0); stop_seek=0; do { // On lit une ligne dans le fichier: if (fgets(buffer,1024,file)==NULL) { free(upper_buffer); free(option_upper); return ERROR_INI_CORRUPTED; } Line_number_in_INI_file++; // On s'en fait une version en majuscule: strcpy(upper_buffer,buffer); Load_INI_clear_string(upper_buffer, raw_text); // On compare la chane avec l'option recherche: stop_seek=Load_INI_seek_pattern(upper_buffer,option_upper); // Si on l'a trouve: if (stop_seek) { // On se positionne juste aprs la chane "=" buffer_index=Load_INI_seek_pattern(upper_buffer,"="); strcpy(return_code, upper_buffer + buffer_index); } } while (!stop_seek); free(upper_buffer); free(option_upper); return 0; } int Load_INI_get_value(char * str,int * index,int * value) { int negative = 0; // On teste si la valeur actuelle est YES (ou Y): if (Load_INI_seek_pattern(str+(*index),"yes,")==1) { (*value)=1; (*index)+=4; return 0; } if (strcmp(str+(*index),"yes")==0) { (*value)=1; (*index)+=3; return 0; } if (Load_INI_seek_pattern(str+(*index),"y,")==1) { (*value)=1; (*index)+=2; return 0; } if (strcmp(str+(*index),"y")==0) { (*value)=1; (*index)+=1; return 0; } // On teste si la valeur actuelle est NO (ou N): if (Load_INI_seek_pattern(str+(*index),"no,")==1) { (*value)=0; (*index)+=3; return 0; } if (strcmp(str+(*index),"no")==0) { (*value)=0; (*index)+=2; return 0; } if (Load_INI_seek_pattern(str+(*index),"n,")==1) { (*value)=0; (*index)+=2; return 0; } if (strcmp(str+(*index),"n")==0) { (*value)=0; (*index)+=1; return 0; } if (str[*index]=='$') { (*value)=0; for (;;) { (*index)++; if ((str[*index]>='0') && (str[*index]<='9')) (*value)=((*value)*16)+str[*index]-'0'; else if ((str[*index]>='A') && (str[*index]<='F')) (*value)=((*value)*16)+str[*index]-'A'+10; else if (str[*index]==',') { (*index)++; return 0; } else if (str[*index]=='\0') return 0; else return ERROR_INI_CORRUPTED; } } if (str[*index]=='-') { negative = 1; // next character (*index)++; // Fall thru } if ((str[*index]>='0') && (str[*index]<='9')) { (*value)=0; for (;;) { if ((str[*index]>='0') && (str[*index]<='9')) { (*value)=((*value)*10)+str[*index]-'0'; if (negative) { (*value)*= -1; // This is to do it once per number. negative = 0; } } else if (str[*index]==',') { (*index)++; return 0; } else if (str[*index]=='\0') return 0; else return ERROR_INI_CORRUPTED; (*index)++; } } else return ERROR_INI_CORRUPTED; } int Load_INI_get_values(FILE * file,char * buffer,char * option_name,int nb_expected_values,int * values) { int stop_seek; char * option_upper; char * upper_buffer; int buffer_index; int nb_values; // On alloue les zones de mmoire: option_upper=(char *)malloc(1024); upper_buffer=(char *)malloc(1024); // On commence par se faire une version majuscule de l'option rechercher: strcpy(option_upper,option_name); Load_INI_clear_string(option_upper, 0); stop_seek=0; do { // On lit une ligne dans le fichier: if (fgets(buffer,1024,file)==0) { free(upper_buffer); free(option_upper); return ERROR_INI_CORRUPTED; } Line_number_in_INI_file++; // On s'en fait une version en majuscule: strcpy(upper_buffer,buffer); Load_INI_clear_string(upper_buffer, 0); // On compare la chane avec l'option recherche: stop_seek=Load_INI_seek_pattern(upper_buffer,option_upper); // Si on l'a trouve: if (stop_seek) { nb_values=0; // On se positionne juste aprs la chane "=" buffer_index=Load_INI_seek_pattern(upper_buffer,"="); // Tant qu'on a pas atteint la fin de la ligne while (upper_buffer[buffer_index]!='\0') { if (Load_INI_get_value(upper_buffer,&buffer_index,values+nb_values)) { free(upper_buffer); free(option_upper); return ERROR_INI_CORRUPTED; } if ( ((++nb_values) == nb_expected_values) && (upper_buffer[buffer_index]!='\0') ) { // Too many values ! free(upper_buffer); free(option_upper); return ERROR_INI_CORRUPTED; } } if (nb_valuesStylus_mode = 1; #else conf->Stylus_mode = 0; #endif // On alloue les zones de mmoire: buffer=(char *)malloc(1024); filename=(char *)malloc(256); // On calcule le nom du fichier qu'on manipule: strcpy(filename,Config_directory); strcat(filename,INI_FILENAME); file=fopen(filename,"r"); if (file==0) { // Si le fichier ini est absent on le relit depuis gfx2def.ini strcpy(filename,Data_directory); strcat(filename,INIDEF_FILENAME); file=fopen(filename,"r"); if (file == 0) { free(filename); free(buffer); return ERROR_INI_MISSING; } } if ((return_code=Load_INI_reach_group(file,buffer,"[MOUSE]"))) goto Erreur_Retour; if ((return_code=Load_INI_get_values (file,buffer,"X_sensitivity",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>4)) conf->Mouse_sensitivity_index_x=1; else conf->Mouse_sensitivity_index_x=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Y_sensitivity",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>4)) conf->Mouse_sensitivity_index_y=1; else conf->Mouse_sensitivity_index_y=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"X_correction_factor",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>4)) goto Erreur_ERREUR_INI_CORROMPU; // Deprecated setting, unused if ((return_code=Load_INI_get_values (file,buffer,"Y_correction_factor",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>4)) goto Erreur_ERREUR_INI_CORROMPU; // Deprecated setting, unused if ((return_code=Load_INI_get_values (file,buffer,"Cursor_aspect",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>3)) goto Erreur_ERREUR_INI_CORROMPU; conf->Cursor=values[0]-1; if ((return_code=Load_INI_reach_group(file,buffer,"[MENU]"))) goto Erreur_Retour; conf->Fav_menu_colors[0].R=0; conf->Fav_menu_colors[0].G=0; conf->Fav_menu_colors[0].B=0; conf->Fav_menu_colors[3].R=255; conf->Fav_menu_colors[3].G=255; conf->Fav_menu_colors[3].B=255; if ((return_code=Load_INI_get_values (file,buffer,"Light_color",3,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>63)) goto Erreur_ERREUR_INI_CORROMPU; if ((values[1]<0) || (values[1]>63)) goto Erreur_ERREUR_INI_CORROMPU; if ((values[2]<0) || (values[2]>63)) goto Erreur_ERREUR_INI_CORROMPU; conf->Fav_menu_colors[2].R=(values[0]<<2)|(values[0]>>4); conf->Fav_menu_colors[2].G=(values[1]<<2)|(values[1]>>4); conf->Fav_menu_colors[2].B=(values[2]<<2)|(values[2]>>4); if ((return_code=Load_INI_get_values (file,buffer,"Dark_color",3,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>63)) goto Erreur_ERREUR_INI_CORROMPU; if ((values[1]<0) || (values[1]>63)) goto Erreur_ERREUR_INI_CORROMPU; if ((values[2]<0) || (values[2]>63)) goto Erreur_ERREUR_INI_CORROMPU; conf->Fav_menu_colors[1].R=(values[0]<<2)|(values[0]>>4); conf->Fav_menu_colors[1].G=(values[1]<<2)|(values[1]>>4); conf->Fav_menu_colors[1].B=(values[2]<<2)|(values[2]>>4); if ((return_code=Load_INI_get_values (file,buffer,"Menu_ratio",1,values))) goto Erreur_Retour; if ((values[0]<-4) || (values[0]>2)) goto Erreur_ERREUR_INI_CORROMPU; conf->Ratio=values[0]; if ((return_code=Load_INI_reach_group(file,buffer,"[FILE_SELECTOR]"))) goto Erreur_Retour; if ((return_code=Load_INI_get_values (file,buffer,"Show_hidden_files",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Show_hidden_files=values[0]?1:0; if ((return_code=Load_INI_get_values (file,buffer,"Show_hidden_directories",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Show_hidden_directories=values[0]?1:0; /* if ((return_code=Load_INI_get_values (file,buffer,"Show_system_directories",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Show_system_directories=values[0]?1:0; */ if ((return_code=Load_INI_get_values (file,buffer,"Preview_delay",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>256)) goto Erreur_ERREUR_INI_CORROMPU; conf->Timer_delay=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Maximize_preview",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Maximize_preview=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Find_file_fast",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>2)) goto Erreur_ERREUR_INI_CORROMPU; conf->Find_file_fast=values[0]; if ((return_code=Load_INI_reach_group(file,buffer,"[LOADING]"))) goto Erreur_Retour; if ((return_code=Load_INI_get_values (file,buffer,"Auto_set_resolution",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Auto_set_res=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Set_resolution_according_to",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>2)) goto Erreur_ERREUR_INI_CORROMPU; conf->Set_resolution_according_to=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Clear_palette",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Clear_palette=values[0]; if ((return_code=Load_INI_reach_group(file,buffer,"[MISCELLANEOUS]"))) goto Erreur_Retour; if ((return_code=Load_INI_get_values (file,buffer,"Draw_limits",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Display_image_limits=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Adjust_brush_pick",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Adjust_brush_pick=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Coordinates",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>2)) goto Erreur_ERREUR_INI_CORROMPU; conf->Coords_rel=2-values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Backup",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Backup=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Undo_pages",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>99)) goto Erreur_ERREUR_INI_CORROMPU; conf->Max_undo_pages=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Gauges_scrolling_speed_Left",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>255)) goto Erreur_ERREUR_INI_CORROMPU; conf->Delay_left_click_on_slider=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Gauges_scrolling_speed_Right",1,values))) goto Erreur_Retour; if ((values[0]<1) || (values[0]>255)) goto Erreur_ERREUR_INI_CORROMPU; conf->Delay_right_click_on_slider=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Auto_save",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Auto_save=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Vertices_per_polygon",1,values))) goto Erreur_Retour; if ((values[0]<2) || (values[0]>16384)) goto Erreur_ERREUR_INI_CORROMPU; conf->Nb_max_vertices_per_polygon=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Fast_zoom",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Fast_zoom=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Separate_colors",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Separate_colors=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"FX_feedback",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->FX_Feedback=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Safety_colors",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Safety_colors=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Opening_message",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Opening_message=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Clear_with_stencil",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Clear_with_stencil=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Auto_discontinuous",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Auto_discontinuous=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Save_screen_size_in_GIF",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Screen_size_in_GIF=values[0]; if ((return_code=Load_INI_get_values (file,buffer,"Auto_nb_colors_used",1,values))) goto Erreur_Retour; if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Auto_nb_used=values[0]; // Optionnel, le mode video par dfaut ( partir de beta 97.0%) conf->Default_resolution=0; if (!Load_INI_get_string (file,buffer,"Default_video_mode",value_label, 0)) { int mode = Convert_videomode_arg(value_label); if (mode>=0) conf->Default_resolution=mode; } // Optionnel, les dimensions de la fentre ( partir de beta 97.0%) // Do that only if the first mode is actually windowed (not the case on gp2x for example) if(Video_mode[0].Fullscreen==0) { Video_mode[0].Width = 640; Video_mode[0].Height = 480; if (!Load_INI_get_values (file,buffer,"Default_window_size",2,values)) { if ((values[0]>=320)) Video_mode[0].Width = values[0]; if ((values[1]>=200)) Video_mode[0].Height = values[1]; } } conf->Mouse_merge_movement=100; // Optionnel, paramtre pour grouper les mouvements souris (>98.0%) if (!Load_INI_get_values (file,buffer,"Merge_movement",1,values)) { if ((values[0]<0) || (values[0]>1000)) goto Erreur_ERREUR_INI_CORROMPU; conf->Mouse_merge_movement=values[0]; } conf->Palette_cells_X=16; // Optionnel, nombre de colonnes dans la palette (>98.0%) if (!Load_INI_get_values (file,buffer,"Palette_cells_X",1,values)) { if ((values[0]<1) || (values[0]>256)) goto Erreur_ERREUR_INI_CORROMPU; conf->Palette_cells_X=values[0]; } conf->Palette_cells_Y=4; // Optionnel, nombre de lignes dans la palette (>98.0%) if (!Load_INI_get_values (file,buffer,"Palette_cells_Y",1,values)) { if (values[0]<1 || values[0]>16) goto Erreur_ERREUR_INI_CORROMPU; conf->Palette_cells_Y=values[0]; } // Optionnel, bookmarks (>98.0%) for (index=0;indexBookmark_directory[index]=NULL; conf->Bookmark_label[index][0]='\0'; } for (index=0;index8) { value_label[7]=ELLIPSIS_CHARACTER; value_label[8]='\0'; } strcpy(conf->Bookmark_label[index],value_label); } } else break; if (!Load_INI_get_string (file,buffer,"Bookmark_directory",value_label, 1)) { int size=strlen(value_label); if (size!=0) { conf->Bookmark_directory[index]=(char *)malloc(size+1); strcpy(conf->Bookmark_directory[index],value_label); } } else break; } conf->Palette_vertical=1; // Optional, vertical palette option (>98.0%) if (!Load_INI_get_values (file,buffer,"Palette_vertical",1,values)) { if ((values[0]<0) || (values[0]>1)) goto Erreur_ERREUR_INI_CORROMPU; conf->Palette_vertical=values[0]; } // Optional, the window position (>98.0%) conf->Window_pos_x=9999; conf->Window_pos_y=9999; if (!Load_INI_get_values (file,buffer,"Window_position",2,values)) { conf->Window_pos_x = values[0]; conf->Window_pos_y = values[1]; } conf->Double_click_speed=500; // Optional, speed of double-click (>2.0) if (!Load_INI_get_values (file,buffer,"Double_click_speed",1,values)) { if ((values[0]>0) || (values[0]<=2000)) conf->Double_click_speed=values[0]; } conf->Double_key_speed=500; // Optional, speed of double-keypress (>2.0) if (!Load_INI_get_values (file,buffer,"Double_key_speed",1,values)) { if ((values[0]>0) || (values[0]<=2000)) conf->Double_key_speed=values[0]; } // Optional, name of skin file. (>2.0) if(!Load_INI_get_string(file,buffer,"Skin_file",value_label,1)) { conf->Skin_file = strdup(value_label); } else conf->Skin_file = strdup("skin_DPaint.png"); // Optional, name of font file. (>2.0) if(!Load_INI_get_string(file,buffer,"Font_file",value_label,1)) conf->Font_file = strdup(value_label); else conf->Font_file = strdup("font_Dpaint.png"); // Optional, "fake hardware zoom" factor (>2.1) if (!Load_INI_get_values (file, buffer,"Pixel_ratio",1,values)) { Pixel_ratio = values[0]; switch(Pixel_ratio) { case PIXEL_WIDE: if(Video_mode[0].Width < 640) Pixel_ratio = PIXEL_SIMPLE; break; case PIXEL_TALL: if(Video_mode[0].Height < 400) Pixel_ratio = PIXEL_SIMPLE; break; case PIXEL_DOUBLE: if(Video_mode[0].Width < 640 || Video_mode[0].Height < 400) Pixel_ratio = PIXEL_SIMPLE; break; case PIXEL_TRIPLE: if(Video_mode[0].Width < 3*320 || Video_mode[0].Height < 3*200) Pixel_ratio = PIXEL_SIMPLE; break; case PIXEL_WIDE2: if(Video_mode[0].Width < 4*320 || Video_mode[0].Height < 2*200) Pixel_ratio = PIXEL_SIMPLE; break; case PIXEL_TALL2: if(Video_mode[0].Width < 2*320 || Video_mode[0].Height < 4*200) Pixel_ratio = PIXEL_SIMPLE; break; case PIXEL_TALL3: if(Video_mode[0].Width < 3*320 || Video_mode[0].Height < 4*200) Pixel_ratio = PIXEL_SIMPLE; break; case PIXEL_QUAD: if(Video_mode[0].Width < 4*320 || Video_mode[0].Height < 4*200) Pixel_ratio = PIXEL_SIMPLE; break; default: // Convert back unknown values to PIXEL_SIMPLE Pixel_ratio = PIXEL_SIMPLE; break; } } // Optional, Menu bars visibility (> 2.1) if (!Load_INI_get_values (file, buffer,"Menubars_visible",1,values)) { byte anim_visible = (values[0] & 2)!=0; byte tools_visible = (values[0] & 4)!=0; // Skip status bar, always enabled. Menu_bars[MENUBAR_LAYERS].Visible = anim_visible; Menu_bars[MENUBAR_ANIMATION].Visible = 0; Menu_bars[MENUBAR_TOOLS].Visible = tools_visible; } conf->Right_click_colorpick=0; // Optional, right mouse button to pick colors (>=2.3) if (!Load_INI_get_values (file,buffer,"Right_click_colorpick",1,values)) { conf->Right_click_colorpick=(values[0]!=0); } conf->Sync_views=1; // Optional, synced view of main and spare (>=2.3) if (!Load_INI_get_values (file,buffer,"Sync_views",1,values)) { conf->Sync_views=(values[0]!=0); } conf->Swap_buttons=0; // Optional, key for swap buttons (>=2.3) if (!Load_INI_get_values (file,buffer,"Swap_buttons",1,values)) { switch(values[0]) { case 1: conf->Swap_buttons=MOD_CTRL; break; case 2: conf->Swap_buttons=MOD_ALT; break; } } // Optional, Location of last directory used for Lua scripts browsing (>=2.3) conf->Scripts_directory[0]='\0'; if (!Load_INI_get_string (file,buffer,"Scripts_directory",value_label, 1)) { strcpy(conf->Scripts_directory,value_label); } if (conf->Scripts_directory[0]=='\0') { // Default when empty: Realpath(Data_directory, conf->Scripts_directory); Append_path(conf->Scripts_directory, SCRIPTS_SUBDIRECTORY, NULL); } conf->Allow_multi_shortcuts=0; // Optional, allow or disallow multiple shortcuts on same key (>=2.3) if (!Load_INI_get_values (file,buffer,"Allow_multi_shortcuts",1,values)) { conf->Allow_multi_shortcuts=(values[0]!=0); } conf->Tilemap_allow_flipped_x=0; // Optional, makes tilemap effect detect x-flipped tiles (>=2.4) if (!Load_INI_get_values (file,buffer,"Tilemap_detect_mirrored_x",1,values)) { conf->Tilemap_allow_flipped_x=(values[0]!=0); } conf->Tilemap_allow_flipped_y=0; // Optional, makes tilemap effect detect y-flipped tiles (>=2.4) if (!Load_INI_get_values (file,buffer,"Tilemap_detect_mirrored_y",1,values)) { conf->Tilemap_allow_flipped_y=(values[0]!=0); } conf->Tilemap_show_count=0; // Optional, makes tilemap effect display tile count (>=2.4) if (!Load_INI_get_values (file,buffer,"Tilemap_count",1,values)) { conf->Tilemap_show_count=(values[0]!=0); } conf->Use_virtual_keyboard=0; // Optional, enables virtual keyboard (>=2.4) if (!Load_INI_get_values (file,buffer,"Use_virtual_keyboard",1,values)) { if (values[0]>=0 && values[0]<=2) conf->Use_virtual_keyboard=values[0]; } conf->Default_mode_layers=0; // Optional, remembers if the user last chose layers or anim (>=2.4) if (!Load_INI_get_values (file,buffer,"Default_mode_layers",1,values)) { conf->Default_mode_layers=(values[0]!=0); } // Insert new values here fclose(file); free(filename); free(buffer); return 0; // Gestion des erreurs: Erreur_Retour: fclose(file); free(filename); free(buffer); return return_code; Erreur_ERREUR_INI_CORROMPU: fclose(file); free(filename); free(buffer); return ERROR_INI_CORRUPTED; } grafx2_2.4+git20180105/src/readline.h0000664000000000000000000000575613223665306015500 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file readline.h /// Text input functions. ////////////////////////////////////////////////////////////////////////////// enum INPUT_TYPE { INPUT_TYPE_STRING=0, ///< Any string INPUT_TYPE_INTEGER=1, ///< Decimal integer INPUT_TYPE_FILENAME=2,///< Filename INPUT_TYPE_DECIMAL=3, ///< Decimal value INPUT_TYPE_HEXA=4, ///< Hexadecimal integer }; /// /// Lets the user input a line of text, exit by Esc or Return. /// @param x_pos Coordinates of input, in window coordinates before scaling. /// @param y_pos Coordinates of input, in window coordinates before scaling. /// @param str The original string value (will be modified, unless user cancels. /// @param visible_size Number of characters visible and editable. /// @param input_type one of enum ::INPUT_TYPE /// @return 0 if user cancelled (esc), 1 if accepted (return) byte Readline(word x_pos,word y_pos,char * str,byte visible_size,byte input_type); /// /// Lets the user input a line of text, exit by Esc or Return. /// @param x_pos Coordinates of input, in window coordinates before scaling. /// @param y_pos Coordinates of input, in window coordinates before scaling. /// @param str The original string value (will be modified, unless user cancels. /// @param visible_size Number of characters visible. /// @param max_size Number of characters editable. /// @param input_type one of enum ::INPUT_TYPE /// @param decimal_places Number of decimal places (used only with decimal type) /// @return 0 if user cancelled (esc), 1 if accepted (return) byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_size, byte input_type, byte decimal_places); /// /// Converts a double to string. /// @param str Target string, should be pre-allocated and at least 40 characters, to be safe. /// @param value The number to convert /// @param decimal_places Number of decimal places to keep. 15 seems the maximum. /// @param min_positions Minimum number of characters: Will pad spaces on the left to meet this minimum. void Sprint_double(char *str, double value, byte decimal_places, byte min_positions); grafx2_2.4+git20180105/src/mountlist.h0000664000000000000000000000356313223665306015745 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* mountlist.h -- declarations for list of mounted file systems Copyright (C) 1991, 1992, 1998, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ ////////////////////////////////////////////////////////////////////////////// ///@file mountlist.h /// A function to enumerate the mounting points in the filesystem. /// Used to display them in fileselectors. ////////////////////////////////////////////////////////////////////////////// #ifndef MOUNTLIST_H_ # define MOUNTLIST_H_ #if !defined(__VBCC__) # include #else #define bool char #endif #include /* A mount table entry. */ struct mount_entry { char *me_devname; /* Device node name, including "/dev/". */ char *me_mountdir; /* Mount point directory name. */ char *me_type; /* "nfs", "4.2", etc. */ dev_t me_dev; /* Device number of me_mountdir. */ unsigned int me_dummy : 1; /* Nonzero for dummy file systems. */ unsigned int me_remote : 1; /* Nonzero for remote fileystems. */ unsigned int me_type_malloced : 1; /* Nonzero if me_type was malloced. */ struct mount_entry *me_next; }; struct mount_entry *read_file_system_list (bool need_fs_type); #endif grafx2_2.4+git20180105/src/help.c0000664000000000000000000006435313223665306014636 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #if defined(__WIN32__) #include #elif defined(__macosx__) || defined(__FreeBSD__) #include #include #elif defined (__linux__) || defined(__SYLLABLE__) #include #elif defined (__HAIKU__) #include "haiku.h" #elif defined (__MINT__) #include #include #include #elif defined(__AROS__) #include #endif #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "engine.h" #include "helpfile.h" #include "help.h" #include "sdlscreen.h" #include "text.h" #include "keyboard.h" #include "windows.h" #include "input.h" #include "hotkeys.h" #include "errors.h" #include "pages.h" #include "factory.h" extern char Program_version[]; // generated in pversion.c extern char SVN_revision[]; // generated in pversion.c // Recherche un raccourci clavier: word * Shortcut(word shortcut_number) { if (shortcut_number & 0x100) return &(Buttons_Pool[shortcut_number & 0xFF].Left_shortcut[0]); if (shortcut_number & 0x200) return &(Buttons_Pool[shortcut_number & 0xFF].Right_shortcut[0]); return &(Config_Key[shortcut_number & 0xFF][0]); } // Nom de la touche actuallement assigne un raccourci d'aprs son numro // de type 0x100+BOUTON_* ou SPECIAL_* const char * Keyboard_shortcut_value(word shortcut_number) { static char shortcuts_name[80]; word * pointer = Shortcut(shortcut_number); if (pointer == NULL) return "(Problem)"; else { if (pointer[0] == 0 && pointer[1] == 0) return "None"; if (pointer[0] != 0 && pointer[1] == 0) return Key_name(pointer[0]); if (pointer[0] == 0 && pointer[1] != 0) return Key_name(pointer[1]); strcpy(shortcuts_name, Key_name(pointer[0])); strcat(shortcuts_name, " or "); strcat(shortcuts_name, Key_name(pointer[1])); return shortcuts_name; } } void Redefine_control(word *shortcut, int x_pos, int y_pos) { Hide_cursor(); Print_in_window(x_pos,y_pos,"*PRESS KEY OR BUTTON*",MC_Black,MC_Light); Display_cursor(); while (1) { Get_input(20); if (Key==KEY_ESC) return; if (Key!=0) { *shortcut=Key; return; } } } void Window_set_shortcut(int action_id) { short clicked_button; short order_index; short config_index; short redraw_controls=1; word * shortcut_ptr=NULL; word backup_shortcut[2]; shortcut_ptr=Shortcut(action_id); backup_shortcut[0]=shortcut_ptr[0]; backup_shortcut[1]=shortcut_ptr[1]; // Recherche dans hotkeys order_index=0; while (Ordering[order_index]!=action_id) { order_index++; if (order_index>=NB_SHORTCUTS) { Error(0); return; } } /* config_index=0; while (ConfigKey[config_index].Number!=order_index) { config_index++; if (config_index>=NB_SHORTCUTS) { Error(0); return; } } */ config_index=order_index; // Comprends pas... a devrait pas marcher Open_window(302,131,"Keyboard shortcut"); Window_set_normal_button(181,111,55,14,"Cancel",0,1,KEY_ESC); // 1 Window_set_normal_button(241,111,55,14,"OK",0,1,SDLK_RETURN); // 2 Window_set_normal_button(6,111,111,14,"Reset default",0,1,KEY_NONE); // 3 // Titre Window_rectangle(5,16,292,11,MC_Black); Print_in_window(7,18,ConfigKey[config_index].Label,MC_White,MC_Black); // Zone de description Window_display_frame_in(5,68,292,37); Print_in_window(8,70,ConfigKey[config_index].Explanation1,MC_Black,MC_Light); Print_in_window(8,78,ConfigKey[config_index].Explanation2,MC_Black,MC_Light); Print_in_window(8,86,ConfigKey[config_index].Explanation3,MC_Black,MC_Light); // Shortcut 0 Window_set_normal_button(27,30,177,14,"",0,1,KEY_NONE); // 4 Window_set_normal_button(209,30,56,14,"Remove",0,1,KEY_NONE); // 5 // Shortcut 1 Window_set_normal_button(27,49,177,14,"",0,1,KEY_NONE); // 6 Window_set_normal_button(209,49,56,14,"Remove",0,1,KEY_NONE); // 7 Display_cursor(); do { if (redraw_controls) { Hide_cursor(); Window_rectangle(32,33,21*8,8,MC_Light); Print_in_window_limited(32,33,Key_name(shortcut_ptr[0]),21,MC_Black,MC_Light); Window_rectangle(32,52,21*8,8,MC_Light); Print_in_window_limited(32,52,Key_name(shortcut_ptr[1]),21,MC_Black,MC_Light); Update_window_area(0,0,302,131); Display_cursor(); redraw_controls=0; } clicked_button=Window_clicked_button(); switch (clicked_button) { case -1: case 0: break; case 4: // Change 0 Redefine_control(&shortcut_ptr[0], 32, 33); redraw_controls=1; break; case 6: // Change 1 Redefine_control(&shortcut_ptr[1], 32, 52); redraw_controls=1; break; case 5: // Remove 0 shortcut_ptr[0]=0; redraw_controls=1; break; case 7: // Remove 1 shortcut_ptr[1]=0; redraw_controls=1; break; case 3: // Defaults shortcut_ptr[0]=ConfigKey[config_index].Key; shortcut_ptr[1]=ConfigKey[config_index].Key2; redraw_controls=1; break; case 1: // Cancel shortcut_ptr[0]=backup_shortcut[0]; shortcut_ptr[1]=backup_shortcut[1]; case 2: // OK // Replace twice by single if (shortcut_ptr[0]==shortcut_ptr[1]) shortcut_ptr[1]=0; // Remove all other shortcuts that use same keys if (!Config.Allow_multi_shortcuts) { int n; for (n=0; n<2; n++) { if (shortcut_ptr[n]!=0) { int i; for(i=0; i0; action_1--) { int n; word *shortcut_1 = Shortcut(Ordering[action_1]); for (n=0; n<2; n++) { int action_2; for (action_2=0; action_2'_' || line[char_index/2]<' ') char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Caractre pas gr else if (char_index & 1) char_pixel=&(Gfx->Help_font_t2[(unsigned char)(line[char_index/2])-' '][0][0]); else char_pixel=&(Gfx->Help_font_t1[(unsigned char)(line[char_index/2])-' '][0][0]); } else if (line_type=='-') { if (line[char_index/2]>'_' || line[char_index/2]<' ') char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Caractre pas gr else if (char_index & 1) char_pixel=&(Gfx->Help_font_t4[(unsigned char)(line[char_index/2])-' '][0][0]); else char_pixel=&(Gfx->Help_font_t3[(unsigned char)(line[char_index/2])-' '][0][0]); } else if (line_type=='S') char_pixel=&(Gfx->Bold_font[(unsigned char)(line[char_index])][0][0]); else if (line_type=='N' || line_type=='K') char_pixel=&(Gfx->Help_font_norm[(unsigned char)(line[char_index])][0][0]); else char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Un garde-fou en cas de probleme for (x=0;x<6;x++) for (repeat_menu_x_factor=0;repeat_menu_x_factor=link_position && char_index<(link_position+link_size)) { if (color == MC_Light) color=MC_White; else if (color == MC_Dark) color=MC_Light; else if (y<7) color=MC_Dark; } Horizontal_line_buffer[x_position++]=color; while (repetition--) Horizontal_line_buffer[x_position++]=color; } } // On la splotche for (repeat_menu_y_factor=0;repeat_menu_y_factor= Help_section[Current_help_section].Length) { Window_rectangle (x_pos, y_pos + line_index*8, 44*6, // 44 = Nb max de char (+1 pour viter les plantages en mode X // causs par une largeur = 0) (16 - line_index)*8, MC_Black); break; } // On affiche la ligne line = Help_section[Current_help_section].Help_table[start_line + line_index].Text; line_type = Help_section[Current_help_section].Help_table[start_line + line_index].Line_type; // Si c'est une sous-ligne de titre, on utilise le texte de la ligne prcdente if (line_type == '-' && (start_line + line_index > 0)) line = Help_section[Current_help_section].Help_table[start_line + line_index - 1].Text; else if (line_type == 'K') { const char *hyperlink; const char * escaped_percent_pos; // Determine link position: link_position = strstr(line,"%s") - line; // Adjust for any escaped %% that would precede it. escaped_percent_pos = line; do { escaped_percent_pos = strstr(escaped_percent_pos,"%%"); if (escaped_percent_pos && escaped_percent_pos - line < link_position) { link_position--; escaped_percent_pos+=2; } } while (escaped_percent_pos); // hyperlink=Keyboard_shortcut_value(Help_section[Current_help_section].Help_table[start_line + line_index].Line_parameter); link_size=strlen(hyperlink); snprintf(buffer, 44, line, hyperlink); if (strlen(line)+link_size-2>44) { buffer[43]=ELLIPSIS_CHARACTER; buffer[44]='\0'; } line = buffer; } width=Print_help(x_pos, y_pos+(line_index<<3), line, line_type, link_position, link_size); // On efface la fin de la ligne: if (width<44) Window_rectangle (x_pos+width*6, y_pos+(line_index<<3), (44-width)*6, 8, MC_Black); } Update_window_area(x_pos,y_pos,44*6,16*8); } void Scroll_help(T_Scroller_button * scroller) { Hide_cursor(); scroller->Position=Help_position; Compute_slider_cursor_length(scroller); Window_draw_slider(scroller); Display_help(); Display_cursor(); } void Button_Help(void) { short btn_number; // Aide contextuelle if (Key!=0) { btn_number = Button_under_mouse(); if (btn_number != -1) { Window_help(btn_number, NULL); return; } } Window_help(-1, NULL); } // Ouvre l'ecran d'aide. Passer -1 pour la section par dfaut (ou derniere,) // Ou un nombre de l'enumration BUTTON_NUMBERS pour l'aide contextuelle. void Window_help(int section, const char *sub_section) { short clicked_button; short nb_lines; T_Scroller_button * scroller; if (section!=-1) { Current_help_section = 4 + section; Help_position = 0; } nb_lines=Help_section[Current_help_section].Length; if (section!=-1 && sub_section!=NULL) { int index=0; for (index=0; index2) { Current_help_section=clicked_button-3; Help_position=0; nb_lines=Help_section[Current_help_section].Length; scroller->Position=0; scroller->Nb_elements=nb_lines; Compute_slider_cursor_length(scroller); Window_draw_slider(scroller); } else Help_position=Window_attribute2; Display_help(); Display_cursor(); } // Gestion des touches de dplacement dans la liste switch (Key) { case SDLK_UP : // Haut if (Help_position>0) Help_position--; Scroll_help(scroller); Key=0; break; case SDLK_DOWN : // Bas if (Help_position15) Help_position-=15; else Help_position=0; Scroll_help(scroller); Key=0; break; case (KEY_MOUSEWHEELUP) : // WheelUp if (Help_position>3) Help_position-=3; else Help_position=0; Scroll_help(scroller); Key=0; break; case SDLK_PAGEDOWN : // PageDown if (nb_lines>16) { if (Help_position16) { if (Help_position16) { Help_position=nb_lines-16; Scroll_help(scroller); Key=0; } break; } if (Is_shortcut(Key,0x100+BUTTON_HELP)) clicked_button=1; } while ((clicked_button!=1) && (Key!=SDLK_RETURN)); Key=0; Close_window(); Unselect_button(BUTTON_HELP); Display_cursor(); } #define STATS_TITLE_COLOR MC_White #define STATS_DATA_COLOR MC_Light void Button_Stats(void) { short clicked_button; char buffer[37]; dword color_usage[256]; unsigned long long freeRam; qword mem_size = 0; int y; #if defined (__MINT__) _DISKINFO drvInfo; unsigned long STRAM=0,TTRAM=0; char helpBuf[64]={0}; #endif Open_window(310,174,"Statistics"); // Dessin de la fenetre ou va s'afficher le texte Window_display_frame_in(8,17,294,132); Window_rectangle(9,18,292,130,MC_Black); Window_set_normal_button(120,153,70,14,"OK",0,1,KEY_ESC); // 1 y=19; // row for first line Print_in_window(10,y,"Program version:",STATS_TITLE_COLOR,MC_Black); sprintf(buffer,"%s.%s",Program_version, SVN_revision); Print_in_window(146,y,buffer,STATS_DATA_COLOR,MC_Black); y+=16; Print_in_window(10,y,"Build options:",STATS_TITLE_COLOR,MC_Black); Print_in_window(146,y,TrueType_is_supported()?"TTF fonts":"no TTF fonts",STATS_DATA_COLOR,MC_Black); y+=8; Print_in_window(10,y,"Lua version:",STATS_TITLE_COLOR,MC_Black); Print_in_window_limited(146,y,Lua_version(),10,STATS_DATA_COLOR,MC_Black); y+=16; Print_in_window(10,y,"Free memory: ",STATS_TITLE_COLOR,MC_Black); y+=8; #if defined (__MINT__) // Display free TT/ST RAM freeRam=0; Atari_Memory_free(&STRAM,&TTRAM); freeRam=STRAM+TTRAM; buffer[0]='\0'; if(STRAM > (100*1024*1024)) sprintf(helpBuf,"ST:%u Mb ",(unsigned int)(STRAM/(1024*1024))); else if(freeRam > 100*1024) sprintf(helpBuf,"ST:%u Kb ",(unsigned int)(STRAM/1024)); else sprintf(helpBuf,"ST:%u b ",(unsigned int)STRAM); strncat(buffer,helpBuf,sizeof(char)*37); if(TTRAM > (100ULL*1024*1024*1024)) sprintf(helpBuf,"TT:%u Gb",(unsigned int)(TTRAM/(1024*1024*1024))); else if(TTRAM > (100*1024*1024)) sprintf(helpBuf,"TT:%u Mb",(unsigned int)(TTRAM/(1024*1024))); else if(freeRam > 100*1024) sprintf(helpBuf,"TT:%u Kb",(unsigned int)(TTRAM/1024)); else sprintf(helpBuf,"TT:%u b",(unsigned int)TTRAM); strncat(buffer,helpBuf,sizeof(char)*37); if(freeRam > (100ULL*1024*1024*1024)) sprintf(helpBuf,"(%u Gb)",(unsigned int)(freeRam/(1024*1024*1024))); else if(freeRam > (100*1024*1024)) sprintf(helpBuf,"(%u Mb)",(unsigned int)(freeRam/(1024*1024))); else if(freeRam > 100*1024) sprintf(helpBuf,"(%u Kb)",(unsigned int)(freeRam/1024)); else sprintf(helpBuf,"(%u b)",(unsigned int)freeRam); strncat(buffer,helpBuf,sizeof(char)*37); Print_in_window(18,y,buffer,STATS_DATA_COLOR,MC_Black); #else // Display free RAM (generic) freeRam = Memory_free(); if(freeRam > (100ULL*1024*1024*1024)) sprintf(buffer,"%u Gigabytes",(unsigned int)(freeRam/(1024*1024*1024))); else if(freeRam > (100*1024*1024)) sprintf(buffer,"%u Megabytes",(unsigned int)(freeRam/(1024*1024))); else if(freeRam > 100*1024) sprintf(buffer,"%u Kilobytes",(unsigned int)(freeRam/1024)); else sprintf(buffer,"%u bytes",(unsigned int)freeRam); Print_in_window(114,y,buffer,STATS_DATA_COLOR,MC_Black); #endif y+=8; // Used memory Print_in_window(10,y,"Used memory pages: ",STATS_TITLE_COLOR,MC_Black); if(Stats_pages_memory > (100LL*1024*1024*1024)) sprintf(buffer,"%ld (%lld Gb)",Stats_pages_number, Stats_pages_memory/(1024*1024*1024)); else if(Stats_pages_memory > (100*1024*1024)) sprintf(buffer,"%ld (%lld Mb)",Stats_pages_number, Stats_pages_memory/(1024*1024)); else sprintf(buffer,"%ld (%lld Kb)",Stats_pages_number, Stats_pages_memory/1024); Print_in_window(162,y,buffer,STATS_DATA_COLOR,MC_Black); y+=8; #if defined(__WIN32__) { ULARGE_INTEGER tailleU; GetDiskFreeSpaceEx(Main_selector.Directory,&tailleU,NULL,NULL); mem_size = tailleU.QuadPart; } #elif defined(__linux__) || defined(__macosx__) || defined(__FreeBSD__) || defined(__SYLLABLE__) || defined(__AROS__) { struct statfs disk_info; statfs(Main_selector.Directory,&disk_info); mem_size=(qword) disk_info.f_bfree * (qword) disk_info.f_bsize; } #elif defined(__HAIKU__) mem_size = haiku_get_free_space(Main_selector.Directory); #elif defined (__MINT__) mem_size=0; Dfree(&drvInfo,0); //number of free clusters*sectors per cluster*bytes per sector; // reports current drive mem_size=drvInfo.b_free*drvInfo.b_clsiz*drvInfo.b_secsiz; #else #define NODISKSPACESUPPORT // Free disk space is only for shows. Other platforms can display 0. #warning "Missing code for your platform !!! Check and correct please :)" mem_size=0; #endif // Display free space if (mem_size != 0) { #if defined(__AROS__) char *colon = strchr(Main_selector.Directory, ':'); int len = strlen(Main_selector.Directory); if (colon) { len = (long)colon - (long)Main_selector.Directory; } if (len > 8) len = 8; sprintf(buffer,"Free space on %.*s:",len,Main_selector.Directory); #else sprintf(buffer,"Free space on %c:",Main_selector.Directory[0]); #endif Print_in_window(10,y,buffer,STATS_TITLE_COLOR,MC_Black); if(mem_size > (100ULL*1024*1024*1024)) sprintf(buffer,"%u Gigabytes",(unsigned int)(mem_size/(1024*1024*1024))); else if(mem_size > (100*1024*1024)) sprintf(buffer,"%u Megabytes",(unsigned int)(mem_size/(1024*1024))); else if(mem_size > (100*1024)) sprintf(buffer,"%u Kilobytes",(unsigned int)(mem_size/1024)); else sprintf(buffer,"%u bytes",(unsigned int)mem_size); #if defined(__AROS__) Print_in_window(192,y,buffer,STATS_DATA_COLOR,MC_Black); #else Print_in_window(146,y,buffer,STATS_DATA_COLOR,MC_Black); #endif } else { #ifndef NODISKSPACESUPPORT Print_in_window(10,y,"Disk full!",STATS_TITLE_COLOR,MC_Black); #endif #undef NODISKSPACESUPPORT } y+=16; // Affichage des informations sur l'image Print_in_window(10,y,"Picture info.:",STATS_TITLE_COLOR,MC_Black); y+=8; // Affichage des dimensions de l'image Print_in_window(18,y,"Dimensions :",STATS_TITLE_COLOR,MC_Black); sprintf(buffer,"%dx%d",Main_image_width,Main_image_height); Print_in_window(122,y,buffer,STATS_DATA_COLOR,MC_Black); y+=8; // Affichage du nombre de couleur utilis Print_in_window(18,y,"Colors used:",STATS_TITLE_COLOR,MC_Black); memset(color_usage,0,sizeof(color_usage)); sprintf(buffer,"%d",Count_used_colors(color_usage)); Print_in_window(122,y,buffer,STATS_DATA_COLOR,MC_Black); y+=16; // Affichage des dimensions de l'cran Print_in_window(10,y,"Resolution:",STATS_TITLE_COLOR,MC_Black); sprintf(buffer,"%dx%d",Screen_width,Screen_height); Print_in_window(106,y,buffer,STATS_DATA_COLOR,MC_Black); Update_window_area(0,0,310,174); Display_cursor(); do { clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x200+BUTTON_HELP)) clicked_button=1; } while ( (clicked_button!=1) && (Key!=SDLK_RETURN) ); if(Key==SDLK_RETURN)Key=0; Close_window(); Unselect_button(BUTTON_HELP); Display_cursor(); } grafx2_2.4+git20180105/src/transform.h0000664000000000000000000000215513223665307015717 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2009 Yves Rizoud Copyright 2009 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file transform.h /// Screen and functions for picture transform. ////////////////////////////////////////////////////////////////////////////// /// Opens and handles the Picture transform screen. void Button_Transform_menu(void); grafx2_2.4+git20180105/src/readline.c0000664000000000000000000006436513223665306015474 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2014 Sergii Pylypenko Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ /************************************************************************ * * * READLINE (procdure permettant de saisir une chane de caractres) * * * ************************************************************************/ #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "errors.h" #include "const.h" #include "sdlscreen.h" #include "readline.h" #include "windows.h" #include "input.h" #include "engine.h" #ifdef __WIN32__ #include #include #elif defined __HAIKU__ #include "haiku.h" #elif defined(__AROS__) #include #include #endif #if defined(__ANDROID__) #include #endif // Virtual keyboard is ON by default on these platforms: #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(GCWZERO) #define VIRT_KEY_DEFAULT_ON 1 #else #define VIRT_KEY_DEFAULT_ON 0 #endif #define TEXT_COLOR MC_Black #define BACKGROUND_COLOR MC_Light #define CURSOR_COLOR MC_Black #define CURSOR_BACKGROUND_COLOR MC_Dark // Suppresion d'un caractre une certaine POSITION dans une CHAINE. void Remove_character(char * str, byte position) { for (;str[position]!='\0';position++) str[position]=str[position+1]; } void Insert_character(char * str, char letter, byte position) // Insertion d'une LETTRE une certaine POSITION // dans une CHAINE d'une certaine TAILLE. { char temp_char; for (;letter!='\0';position++) { // On mmorise le caractre qui se trouve en "position" temp_char=str[position]; // On splotch la lettre insrer str[position]=letter; // On place le caractre mmoris dans "letter" comme nouvelle lettre insrer letter=temp_char; } // On termine la chaine str[position]='\0'; } int Prepend_string(char* dest, char* src, int max) // Insert a string at the start of another. Up to MAX characters only // Returns actual number of chars inserted { // Insert src before dest int sized = strlen(dest); int sizes = strlen(src); if (sized + sizes >= max) { sizes = max - sized; } memmove(dest+sizes, dest, sized+1); memcpy(dest, src, sizes); return sizes; } int Valid_character(word c, int input_type) // returns 0 = Not allowed // returns 1 = Allowed // returns 2 = Allowed only once at start of string (for - sign in numbers) { // On va regarder si l'utilisateur le droit de se servir de cette touche switch(input_type) { case INPUT_TYPE_STRING : if ((c>=' ' && c<= 255) || c=='\n') return 1; break; case INPUT_TYPE_INTEGER : if ( (c>='0') && (c<='9') ) return 1; break; case INPUT_TYPE_DECIMAL: if ( (c>='0') && (c<='9') ) return 1; else if (c=='-') return 2; else if (c=='.') return 1; break; case INPUT_TYPE_FILENAME: { // On regarde si la touche est autorise // Sous Linux: Seul le / est strictement interdit, mais beaucoup // d'autres poseront des problmes au shell, alors on vite. // Sous Windows : c'est moins grave car le fopen() chouerait de toutes faons. // AmigaOS4: Pas de ':' car utilis pour les volumes. #if defined(__WIN32__) char forbidden_char[] = {'/', '|', '?', '*', '<', '>', ':', '\\'}; #elif defined (__amigaos4__) || defined(__AROS__) char forbidden_char[] = {'/', '|', '?', '*', '<', '>', ':'}; #else char forbidden_char[] = {'/', '|', '?', '*', '<', '>'}; #endif int position; if (c < ' ' || c > 255) return 0; for (position=0; position<(long)sizeof(forbidden_char); position++) if (c == forbidden_char[position]) return 0; return 1; } case INPUT_TYPE_HEXA: if ( (c>='0') && (c<='9') ) return 1; else if ( (c>='A') && (c<='F') ) return 1; else if ( (c>='a') && (c<='f') ) return 1; break; } // End du "switch(input_type)" return 0; } void Cleanup_string(char* str, int input_type) { int i,j=0; for(i=0; str[i]!='\0'; i++) { if (Valid_character((unsigned char)(str[i]), input_type)) { str[j]=str[i]; j++; } } str[j] = '\0'; } void Display_whole_string(word x_pos,word y_pos,char * str,byte position) { char cursor[2]; Print_general(x_pos,y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); cursor[0]=str[position] ? str[position] : ' '; cursor[1]='\0'; Print_general(x_pos+(position<<3)*Menu_factor_X,y_pos,cursor,CURSOR_COLOR,CURSOR_BACKGROUND_COLOR); } void Init_virtual_keyboard(word y_pos, word keyboard_width, word keyboard_height) { int h_pos; int v_pos; int parent_window_x=Window_pos_X+2; h_pos= Window_pos_X+(keyboard_width-Window_width)*Menu_factor_X/-2; if (h_pos<0) h_pos=0; else if (h_pos+keyboard_width*Menu_factor_X>Screen_width) h_pos=Screen_width-keyboard_width*Menu_factor_X; v_pos=Window_pos_Y+(y_pos+9)*Menu_factor_Y; if (v_pos+(keyboard_height*Menu_factor_Y)>Screen_height) v_pos=Window_pos_Y+(y_pos-keyboard_height-4)*Menu_factor_Y; Hide_cursor(); Open_popup(h_pos,v_pos,keyboard_width,keyboard_height); Window_rectangle(1,0,Window_width-1, Window_height-1, MC_Light); Window_rectangle(0,0,1,Window_height-2, MC_White); // white border on top left angle, when it exceeds border. if (parent_window_x>Window_pos_X) Window_rectangle(0,0,(parent_window_x-Window_pos_X)/Menu_factor_X, 1, MC_White); Window_rectangle(2,Window_height-2,Window_width-2, 2, MC_Black); if(keyboard_width<320) { Window_rectangle(Window_width-2,2,2,Window_height-2, MC_Black); } } // Inspired from http://www.libsdl.org/projects/scrap/ // TODO X11 and others char* getClipboard() { #ifdef __WIN32__ char* dst = NULL; SDL_SysWMinfo info; HWND SDL_Window; SDL_VERSION(&info.version); if ( SDL_GetWMInfo(&info) ) { SDL_Window = info.window; if ( IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(SDL_Window) ) { HANDLE hMem; char *src; hMem = GetClipboardData(CF_TEXT); if ( hMem != NULL ) { src = (char *)GlobalLock(hMem); dst = strdup(src); GlobalUnlock(hMem); } CloseClipboard(); } } return dst; #elif defined(__AROS__) struct IFFHandle *iff = NULL; struct ContextNode *cn; long error=0, unitnumber=0; char *dst = NULL; if (!(iff = AllocIFF ())) { goto bye; } if (!(iff->iff_Stream = (IPTR) OpenClipboard (unitnumber))) { goto bye; } InitIFFasClip (iff); if ((error = OpenIFF (iff, IFFF_READ)) != 0) { goto bye; } if ((error = StopChunk(iff, ID_FTXT, ID_CHRS)) != 0) { goto bye; } while(1) { error = ParseIFF(iff,IFFPARSE_SCAN); if (error) break; // we're reading only the 1st chunk cn = CurrentChunk(iff); if (cn && (cn->cn_Type == ID_FTXT) && (cn->cn_ID == ID_CHRS)) { if ((dst = malloc(cn->cn_Size + 1)) != NULL) { dst[0] = '\0'; if ((ReadChunkBytes(iff,dst,cn->cn_Size)) > 0) { dst[cn->cn_Size] = '\0'; } } } } bye: if (iff) { CloseIFF (iff); if (iff->iff_Stream) CloseClipboard ((struct ClipboardHandle *)iff->iff_Stream); FreeIFF (iff); } return dst; #elif defined __HAIKU__ return haiku_get_clipboard(); #else // Not implemented (no standard) on Linux systems. Maybe someday... return NULL; #endif } /**************************************************************************** * Enhanced super scanf deluxe pro plus giga mieux :-) * ****************************************************************************/ byte Readline(word x_pos,word y_pos,char * str,byte visible_size,byte input_type) // Paramtres: // x_pos, y_pos : Coordonnes de la saisie dans la fentre // str : Chane recevant la saisie (et contenant ventuellement une valeur initiale) // max_size : Nombre de caractres logeant dans la zone de saisie // input_type : 0=Chane, 1=Nombre, 2=Nom de fichier // Sortie: // 0: Sortie par annulation (Esc.) / 1: sortie par acceptation (Return) { byte max_size; // Grosse astuce pour les noms de fichiers: La taille affiche est diffrente // de la taille maximum gre. if (input_type == 2) max_size = 255; else max_size = visible_size; return Readline_ex(x_pos,y_pos,str,visible_size,max_size,input_type,0); } /**************************************************************************** * Enhanced super scanf deluxe pro plus giga mieux :-) * ****************************************************************************/ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_size, byte input_type, byte decimal_places) // Paramtres: // x_pos, y_pos : Coordonnes de la saisie dans la fentre // str : Chane recevant la saisie (et contenant ventuellement une valeur initiale) // max_size : Nombre de caractres logeant dans la zone de saisie // input_type : 0=String, 1=Unsigned int, 2=Filename 3=Signed Double // decimal_places: Number of decimal places for a double // Sortie: // 0: Sortie par annulation (Esc.) / 1: sortie par acceptation (Return) { char initial_string[256]; char display_string[256]; byte position; byte size; word input_key=0; word window_x=Window_pos_X; word window_y=Window_pos_Y; byte offset=0; // index du premier caractre affich // Virtual keyboard byte use_virtual_keyboard=0; static byte caps_lock=0; word keymapping[] = { SDLK_CLEAR,SDLK_BACKSPACE,SDLK_RETURN,KEY_ESC, '0','1','2','3','4','5','6','7','8','9','.',',', 'Q','W','E','R','T','Y','U','I','O','P', 'A','S','D','F','G','H','J','K','L', SDLK_CAPSLOCK,'Z','X','C','V','B','N','M',' ', '-','+','*','/','|','\\', '(',')','{','}','[',']', '_','=','<','>','%','@', ':',';','`','\'','"','~', '!','?','^','&','#','$' }; // Si on a commenc editer par un clic-droit, on vide la chaine. if (Mouse_K==RIGHT_SIDE) str[0]='\0'; else if (input_type==INPUT_TYPE_INTEGER && str[0]!='\0') snprintf(str,10,"%d",atoi(str)); // On tasse la chaine gauche else if (input_type==INPUT_TYPE_DECIMAL) { // Nothing. The caller should have used Sprint_double, with min_positions // at zero, so there's no spaces on the left and no useless 0s on the right. } else if (input_type==INPUT_TYPE_HEXA) { // Nothing. The caller should have initialized a valid hexa number. } #if defined(__ANDROID__) SDL_ANDROID_GetScreenKeyboardTextInput(str, max_size); input_key = SDLK_RETURN; #else // Virtual keyboards if (Config.Use_virtual_keyboard==1 || (VIRT_KEY_DEFAULT_ON && Config.Use_virtual_keyboard==0)) { if (input_type == INPUT_TYPE_STRING || input_type == INPUT_TYPE_FILENAME ) { int x,y; Init_virtual_keyboard(y_pos, 320, 87); use_virtual_keyboard=1; // The order is important, see the array Window_set_normal_button( 7,67,43,15,"Clr", 0,1,KEY_NONE); Window_set_normal_button( 51,67,43,15,"Del", 0,1,KEY_NONE); Window_set_normal_button( 95,67,43,15,"OK", 0,1,KEY_NONE); Window_set_normal_button(139,67,43,15,"Esc", 0,1,KEY_NONE); Window_display_frame_in(5,65,179,19); Window_set_normal_button(193,63,17,19,"0", 0,1,KEY_NONE); Window_set_normal_button(193,43,17,19,"1", 0,1,KEY_NONE); Window_set_normal_button(211,43,17,19,"2", 0,1,KEY_NONE); Window_set_normal_button(229,43,17,19,"3", 0,1,KEY_NONE); Window_set_normal_button(193,23,17,19,"4", 0,1,KEY_NONE); Window_set_normal_button(211,23,17,19,"5", 0,1,KEY_NONE); Window_set_normal_button(229,23,17,19,"6", 0,1,KEY_NONE); Window_set_normal_button(193, 3,17,19,"7", 0,1,KEY_NONE); Window_set_normal_button(211, 3,17,19,"8", 0,1,KEY_NONE); Window_set_normal_button(229, 3,17,19,"9", 0,1,KEY_NONE); Window_set_normal_button(211,63,17,19,".", 0,1,KEY_NONE); Window_set_normal_button(229,63,17,19,",", 0,1,KEY_NONE); Window_set_normal_button( 3, 3,18,19,"Q", 0,1,KEY_NONE); Window_set_normal_button( 22, 3,18,19,"W", 0,1,KEY_NONE); Window_set_normal_button( 41, 3,18,19,"E", 0,1,KEY_NONE); Window_set_normal_button( 60, 3,18,19,"R", 0,1,KEY_NONE); Window_set_normal_button( 79, 3,18,19,"T", 0,1,KEY_NONE); Window_set_normal_button( 98, 3,18,19,"Y", 0,1,KEY_NONE); Window_set_normal_button(117, 3,18,19,"U", 0,1,KEY_NONE); Window_set_normal_button(136, 3,18,19,"I", 0,1,KEY_NONE); Window_set_normal_button(155, 3,18,19,"O", 0,1,KEY_NONE); Window_set_normal_button(174, 3,18,19,"P", 0,1,KEY_NONE); Window_set_normal_button( 12,23,18,19,"A", 0,1,KEY_NONE); Window_set_normal_button( 31,23,18,19,"S", 0,1,KEY_NONE); Window_set_normal_button( 50,23,18,19,"D", 0,1,KEY_NONE); Window_set_normal_button( 69,23,18,19,"F", 0,1,KEY_NONE); Window_set_normal_button( 88,23,18,19,"G", 0,1,KEY_NONE); Window_set_normal_button(107,23,18,19,"H", 0,1,KEY_NONE); Window_set_normal_button(126,23,18,19,"J", 0,1,KEY_NONE); Window_set_normal_button(145,23,18,19,"K", 0,1,KEY_NONE); Window_set_normal_button(164,23,18,19,"L", 0,1,KEY_NONE); Window_set_normal_button( 3,43,18,19,caps_lock?"\036":"\037", 0,1,KEY_NONE); Window_set_normal_button( 22,43,18,19,"Z", 0,1,KEY_NONE); Window_set_normal_button( 41,43,18,19,"X", 0,1,KEY_NONE); Window_set_normal_button( 60,43,18,19,"C", 0,1,KEY_NONE); Window_set_normal_button( 79,43,18,19,"V", 0,1,KEY_NONE); Window_set_normal_button( 98,43,18,19,"B", 0,1,KEY_NONE); Window_set_normal_button(117,43,18,19,"N", 0,1,KEY_NONE); Window_set_normal_button(136,43,18,19,"M", 0,1,KEY_NONE); Window_set_normal_button(155,43,18,19," ", 0,1,KEY_NONE); for (y=0; y<5; y++) { for (x=0; x<6; x++) { char label[2]=" "; label[0]=keymapping[x+y*6+44]; Window_set_normal_button(247+x*12, 3+y*16,11,15,label, 0,1,KEY_NONE); } } Update_window_area(0,0,Window_width, Window_height); Display_cursor(); } else if (input_type == INPUT_TYPE_INTEGER || input_type == INPUT_TYPE_DECIMAL ) { Init_virtual_keyboard(y_pos, 215, 47); use_virtual_keyboard=1; // The order is important, see the array Window_set_normal_button( 7,27,43,15,"Clr", 0,1,KEY_NONE); Window_set_normal_button( 51,27,43,15,"Del", 0,1,KEY_NONE); Window_set_normal_button( 95,27,43,15,"OK", 0,1,KEY_NONE); Window_set_normal_button(139,27,43,15,"Esc", 0,1,KEY_NONE); Window_display_frame_in(5,25,179,19); Window_set_normal_button(174, 3,18,19,"0", 0,1,KEY_NONE); Window_set_normal_button( 3, 3,18,19,"1", 0,1,KEY_NONE); Window_set_normal_button( 22, 3,18,19,"2", 0,1,KEY_NONE); Window_set_normal_button( 41, 3,18,19,"3", 0,1,KEY_NONE); Window_set_normal_button( 60, 3,18,19,"4", 0,1,KEY_NONE); Window_set_normal_button( 79, 3,18,19,"5", 0,1,KEY_NONE); Window_set_normal_button( 98, 3,18,19,"6", 0,1,KEY_NONE); Window_set_normal_button(117, 3,18,19,"7", 0,1,KEY_NONE); Window_set_normal_button(136, 3,18,19,"8", 0,1,KEY_NONE); Window_set_normal_button(155, 3,18,19,"9", 0,1,KEY_NONE); Window_set_normal_button(193, 3,18,19,".", 0,1,KEY_NONE); Update_window_area(0,0,Window_width, Window_height); Display_cursor(); } } #ifdef GCWZERO //we cannot enter text into a field without using the virtual mouse otherwise so no saving etc Keyboard_click_allowed = 1; #else Keyboard_click_allowed = 0; #endif Hide_cursor(); // Effacement de la chane Window_rectangle(x_pos,y_pos,visible_size<<3,8,BACKGROUND_COLOR); Update_window_area(x_pos,y_pos,visible_size<<3,8); // Mise jour des variables se rapportant la chane en fonction de la chane initiale strcpy(initial_string,str); size=strlen(str); position=(size=visible_size) offset=position-visible_size+1; // Formatage d'une partie de la chaine (si trop longue pour tenir) strncpy(display_string, str + offset, visible_size); display_string[visible_size]='\0'; if (offset>0) display_string[0]=LEFT_TRIANGLE_CHARACTER; if (visible_size + offset + 1 < size ) display_string[visible_size-1]=RIGHT_TRIANGLE_CHARACTER; Display_whole_string(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y),display_string,position - offset); Update_window_area(x_pos,y_pos,visible_size<<3,8); Flush_update(); if (Mouse_K) { Display_cursor(); Wait_end_of_click(); Hide_cursor(); } while ((input_key!=SDLK_RETURN) && (input_key!=KEY_ESC)) { Display_cursor(); if (use_virtual_keyboard) { int clicked_button; clicked_button=Window_clicked_button(); input_key=Key_ANSI; if (clicked_button==-1) input_key=SDLK_RETURN; else if (clicked_button>0) { input_key=keymapping[clicked_button-1]; if (input_key==SDLK_CAPSLOCK) { // toggle uppercase caps_lock=!caps_lock; Hide_cursor(); Print_in_window(8, 49,caps_lock?"\036":"\037", MC_Black,MC_Light); Display_cursor(); } else if (input_key==SDLK_BACKSPACE) { // A little hack: the button for backspace will: // - backspace if the cursor is at end of string // - delete otherwise // It's needed for those input boxes that are completely full. if (position='A' && input_key<='Z' && !caps_lock) { input_key+='a'-'A'; } } } else { do { Get_input(20); input_key=Key_ANSI; if (Mouse_K) input_key=SDLK_RETURN; // Handle paste request on CTRL+v if (Key == SHORTCUT_PASTE) { int nb_added; char* data = getClipboard(); if (data == NULL) continue; // No clipboard data Cleanup_string(data, input_type); // Insert it at the cursor position nb_added = Prepend_string(str + position, data, max_size - position); while (nb_added) { size++; if (size=visible_size) offset++; } nb_added--; } free(data); Hide_cursor(); goto affichage; } } while(input_key==0); } Hide_cursor(); switch (input_key) { case SDLK_DELETE : // Suppr. if (position0) { // Effacement de la chane if (position==size) Window_rectangle(x_pos,y_pos,visible_size<<3,8,BACKGROUND_COLOR); position--; if (offset > 0 && (position == 0 || position < (offset + 1))) offset--; goto affichage; } break; case SDLK_RIGHT : // Droite if ((position visible_size + offset - 2) //if (offset + visible_size < max_size && (position == size || (position > visible_size + offset - 2))) if (display_string[position-offset]==RIGHT_TRIANGLE_CHARACTER || position-offset>=visible_size) offset++; goto affichage; } break; case SDLK_HOME : // Home if (position) { // Effacement de la chane if (position==size) Window_rectangle(x_pos,y_pos,visible_size<<3,8,BACKGROUND_COLOR); position = 0; offset = 0; goto affichage; } break; case SDLK_END : // End if ((position=visible_size) offset=position-visible_size+1; goto affichage; } break; case SDLK_BACKSPACE : // Backspace : combinaison de gauche + suppr if (position) { position--; if (offset > 0 && (position == 0 || position < (offset + 1))) offset--; Remove_character(str,position); size--; // Effacement de la chane Window_rectangle(x_pos,y_pos,visible_size<<3,8,BACKGROUND_COLOR); goto affichage; } break; case SDLK_CLEAR : // Clear str[0]='\0'; position=offset=0; // Effacement de la chane Window_rectangle(x_pos,y_pos,visible_size<<3,8,BACKGROUND_COLOR); goto affichage; case SDLK_RETURN : break; case KEY_ESC : // On restaure la chaine initiale strcpy(str,initial_string); size=strlen(str); break; default : if (size=visible_size) offset++; } // Enfin, on raffiche la chaine goto affichage; } // End du test d'autorisation de touche } // End du test de place libre break; affichage: size=strlen(str); // Formatage d'une partie de la chaine (si trop longue pour tenir) strncpy(display_string, str + offset, visible_size); display_string[visible_size]='\0'; if (offset>0) display_string[0]=LEFT_TRIANGLE_CHARACTER; if (visible_size + offset + 0 < size ) display_string[visible_size-1]=RIGHT_TRIANGLE_CHARACTER; Display_whole_string(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y),display_string,position - offset); Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); } // End du "switch(input_key)" Flush_update(); } // End du "while" Keyboard_click_allowed = 1; if (use_virtual_keyboard) { byte old_mouse_k = Mouse_K; Close_popup(); Mouse_K=old_mouse_k; Input_sticky_control=0; } #endif // defined(__ANDROID__) // Effacement de la chane Window_rectangle(x_pos,y_pos,visible_size<<3,8,BACKGROUND_COLOR); // On raffiche la chaine correctement if (input_type==INPUT_TYPE_INTEGER) { if (str[0]=='\0') { strcpy(str,"0"); size=1; } Print_in_window(x_pos+((max_size-size)<<3),y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); } else if (input_type==INPUT_TYPE_DECIMAL) { double value; // Discard extra digits value = Fround(atof(str), decimal_places); Sprint_double(str,value,decimal_places,visible_size); // Recompute updated size size = strlen(str); if (size<=visible_size) Print_in_window(x_pos+((visible_size-size)<<3),y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); else Print_in_window_limited(x_pos,y_pos,str,visible_size,TEXT_COLOR,BACKGROUND_COLOR); } else { Print_in_window_limited(x_pos,y_pos,str,visible_size,TEXT_COLOR,BACKGROUND_COLOR); } Update_window_area(x_pos,y_pos,visible_size<<3,8); return (input_key==SDLK_RETURN); } void Sprint_double(char *str, double value, byte decimal_places, byte min_positions) { int i; int length; sprintf(str,"%.*f",decimal_places, value); length=strlen(str); for (i=0; i= 0 && decimals[j]=='0'; j--) { decimals[j] = '\0'; } // If all decimals were removed, remove the dot too if (str[i+1]=='\0') str[i]='\0'; // Update string length length=strlen(str); // Ends the parent loop break; } } // Now try add spaces at beginning if (length */ ////////////////////////////////////////////////////////////////////////////// ///@file op_c.h /// Color reduction and color conversion (24b->8b, RGB<->HSL). /// This is called op_c because half of the process was originally /// coded in op_asm, in assembler. ////////////////////////////////////////////////////////////////////////////// #ifndef _OP_C_H_ #define _OP_C_H_ #include "struct.h" #include "colorred.h" //////////////////////////////////////////////// Dfinition des types de base typedef T_Components * T_Bitmap24B; typedef byte * T_Bitmap256; ///////////////////////////////////////// Dfinition d'une table d'occurences typedef struct { int nbb_r; // Nb de bits de prcision sur les rouges int nbb_g; // Nb de bits de prcision sur les verts int nbb_b; // Nb de bits de prcision sur les bleu int rng_r; // Nb de valeurs sur les rouges (= 1< */ #include #include #include #include #include #include "struct.h" #include "global.h" #include "errors.h" #include "misc.h" #include "palette.h" #include "pages.h" #include "windows.h" #include "layers.h" void Pixel_in_layer(word x,word y, byte layer, byte color) { *((y)*Main_image_width+(x)+Main_backups->Pages->Image[layer].Pixels)=color; } byte C64_FLI(byte *bitmap, byte *screen_ram, byte *color_ram, byte *background) { word used_colors[200][40]; word block_used_colors[25][40]; word line_used_colors[200]; byte used_colors_count[200][40]; dword usage[16]; word x,y,row,col; int i; byte line_color[200]; byte block_color[25][40]; word best_color_count; byte best_color; const byte no_color=16; // Prerequisites if (Main_backups->Pages->Nb_layers < 3) return 1; if (Main_image_width != 160 || Main_image_height != 200) return 2; memset(used_colors,0,200*40*sizeof(word)); memset(block_used_colors,0,25*40*sizeof(word)); memset(line_used_colors,0,200*sizeof(word)); memset(used_colors_count,0,200*40*sizeof(byte)); // Initialize these as "unset" memset(line_color,no_color,200*sizeof(byte)); memset(block_color,no_color,25*40*sizeof(byte)); // Examine all 4-pixel blocks to fill used_colors[][] for (row=0;row<200;row++) { for (col=0;col<40;col++) { for (x=0;x<4;x++) { byte c=*((row)*Main_image_width+(col*4+x)+Main_backups->Pages->Image[2].Pixels); used_colors[row][col] |= 1<Pages->Image[0].Pixels); if (c<16) { line_color[row]=c; for (col=0;col<40;col++) { // Remove that color from the sets used_colors[row][col] &= ~(1<Pages->Image[1].Pixels); if (c<16) { block_color[row/8][col]=c; // Remove that color from the sets for (y=0; y<8;y++) used_colors[row+y][col] &= ~(1<best_color_count) { best_color_count=usage[i]; best_color=i; } } line_color[row]=best_color; // Remove that color from the sets for (col=0;col<40;col++) { if (used_colors[row][col] & (1<2) { filter &= used_colors[row+y][col]; for (i=0; i<16; i++) { if (used_colors[row+y][col] & (1<best_color_count) { best_color_count=usage[i]; best_color=i; } } } } block_color[row/8][col]=best_color; // Remove that color from the sets for (y=0;y<8;y++) { if (used_colors[row+y][col] & (1<15) c1=16; if (c2>15) c2=16; // Output Screen RAMs if (screen_ram!=NULL) screen_ram[y*1024+row*40+col] = (c1&15) | ((c2&15)<<4); // Output bitmap if (bitmap!=NULL) { for(x=0; x<4; x++) { byte bits; byte c=*((row*8+y)*Main_image_width+(col*4+x)+Main_backups->Pages->Image[2].Pixels); if (c==line_color[row*8+y]) // BG color bits=0; else if (c==block_color[row][col]) // block color bits=3; else if (c==c1) // Color 1 bits=2; else if (c==c2) // Color 2 bits=1; else // problem bits=0; // clear target bits //bitmap[row*320+col*8+y] &= ~(3<<((3-x)*2)); // set them bitmap[row*320+col*8+y] |= bits<<((3-x)*2); } } } } } //memset(background,3,200); //memset(color_ram,5,8000); //memset(screen_ram,(9<<4) | 7,8192); return 0; } byte C64_FLI_enforcer(void) { byte background[200]; byte bitmap[8000]; byte screen_ram[8192]; byte color_ram[1000]; int row, col, x, y; byte c[4]; // Checks if (Main_image_width != 160) return 1; if (Main_image_height != 200) return 1; if (Main_backups->Pages->Nb_layers != 4) return 2; Backup_layers(3); memset(bitmap,0,8000); memset(background,0,200); memset(color_ram,0,1000); memset(screen_ram,0,8192); C64_FLI(bitmap, screen_ram, color_ram, background); for(row=0; row<25; row++) { for(col=0; col<40; col++) { c[3]=color_ram[row*40+col]&15; for(y=0; y<8; y++) { int pixel=bitmap[row*320+col*8+y]; c[0]=background[row*8+y]&15; c[1]=screen_ram[y*1024+row*40+col]>>4; c[2]=screen_ram[y*1024+row*40+col]&15; for(x=0; x<4; x++) { int color=c[(pixel&3)]; pixel>>=2; Pixel_in_layer(col*4+(3-x),row*8+y,3,color); } } } } End_of_modification(); // Visible feedback: // If the "check" layer was visible, manually update the whole thing if (Main_layers_visible & (1<<3)) { Hide_cursor(); Redraw_layered_image(); Display_all_screen(); Display_layerbar(); Display_cursor(); } else // Otherwise, simply toggle the layer visiblity Layer_activate(3,RIGHT_SIDE); return 0; } grafx2_2.4+git20180105/src/sdlscreen.c0000664000000000000000000002346313223665306015665 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2014 Sergii Pylypenko Copyright 2011 Pawel Gralski Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include #if defined(__WIN32__) #include #endif // There is no WM on the GP2X... #ifndef __GP2X__ #include #endif #include "global.h" #include "sdlscreen.h" #include "errors.h" #include "misc.h" // Update method that does a large number of small rectangles, aiming // for a minimum number of total pixels updated. #define UPDATE_METHOD_MULTI_RECTANGLE 1 // Intermediate update method, does only one update with the smallest // rectangle that includes all modified pixels. #define UPDATE_METHOD_CUMULATED 2 // Total screen update, for platforms that impose a Vsync on each SDL update. #define UPDATE_METHOD_FULL_PAGE 3 // UPDATE_METHOD can be set from makefile, otherwise it's selected here // depending on the platform : #ifndef UPDATE_METHOD #if defined(__macosx__) #define UPDATE_METHOD UPDATE_METHOD_FULL_PAGE #elif defined(__MINT__) #define UPDATE_METHOD UPDATE_METHOD_CUMULATED #elif defined(GCWZERO) #define UPDATE_METHOD UPDATE_METHOD_FULL_PAGE #elif defined(__ANDROID__) #define UPDATE_METHOD UPDATE_METHOD_FULL_PAGE #else #define UPDATE_METHOD UPDATE_METHOD_CUMULATED #endif #endif volatile int Allow_colorcycling=1; /// Sets the new screen/window dimensions. void Set_mode_SDL(int *width, int *height, int fullscreen) { static SDL_Cursor* cur = NULL; static byte cursorData = 0; #ifdef GCWZERO Screen_SDL=SDL_SetVideoMode(*width,*height,8,SDL_HWSURFACE|SDL_TRIPLEBUF|(fullscreen?SDL_FULLSCREEN:0)|SDL_RESIZABLE); #else Screen_SDL=SDL_SetVideoMode(*width,*height,8,(fullscreen?SDL_FULLSCREEN:0)|SDL_RESIZABLE); #endif if(Screen_SDL != NULL) { // Check the mode we got, in case it was different from the one we requested. if (Screen_SDL->w != *width || Screen_SDL->h != *height) { DEBUG("Error: Got a different video mode than the requested one!",0); *width = Screen_SDL->w; *height = Screen_SDL->h; } Screen_pixels=Screen_SDL->pixels; } else { DEBUG("Error: Unable to change video mode!",0); } // Trick borrowed to Barrage (http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg737265.html) : // Showing the cursor but setting it to fully transparent allows us to get absolute mouse coordinates, // this means we can use tablet in fullscreen mode. SDL_ShowCursor(1); // Hide the SDL mouse cursor, we use our own SDL_FreeCursor(cur); cur = SDL_CreateCursor(&cursorData, &cursorData, 1,1,0,0); SDL_SetCursor(cur); } #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) short Min_X=0; short Min_Y=0; short Max_X=10000; short Max_Y=10000; short Status_line_dirty_begin=0; short Status_line_dirty_end=0; #endif #if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE) int update_is_required=0; #endif void Flush_update(void) { #if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE) // Do a full screen update if (update_is_required) { #ifdef GCWZERO SDL_Flip(Screen_SDL); #else SDL_UpdateRect(Screen_SDL, 0, 0, 0, 0); #endif update_is_required=0; } #endif #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) if (Min_X>=Max_X || Min_Y>=Max_Y) { ; // Nothing to do } else { if (Min_X<0) Min_X=0; if (Min_Y<0) Min_Y=0; SDL_UpdateRect(Screen_SDL, Min_X*Pixel_width, Min_Y*Pixel_height, Min(Screen_width-Min_X, Max_X-Min_X)*Pixel_width, Min(Screen_height-Min_Y, Max_Y-Min_Y)*Pixel_height); Min_X=Min_Y=10000; Max_X=Max_Y=0; } if (Status_line_dirty_end) { SDL_UpdateRect(Screen_SDL, (18+(Status_line_dirty_begin*8))*Menu_factor_X*Pixel_width,Menu_status_Y*Pixel_height,(Status_line_dirty_end-Status_line_dirty_begin)*8*Menu_factor_X*Pixel_width,8*Menu_factor_Y*Pixel_height); } Status_line_dirty_begin=25; Status_line_dirty_end=0; #endif } void Update_rect(short x, short y, unsigned short width, unsigned short height) { #if (UPDATE_METHOD == UPDATE_METHOD_MULTI_RECTANGLE) SDL_UpdateRect(Screen_SDL, x*Pixel_width, y*Pixel_height, width*Pixel_width, height*Pixel_height); #endif #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) if (width==0 || height==0) { Min_X=Min_Y=0; Max_X=Max_Y=10000; } else { if (x < Min_X) Min_X = x; if (y < Min_Y) Min_Y = y; if (x+width>Max_X) Max_X=x+width; if (y+height>Max_Y) Max_Y=y+height; } #endif #if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE) (void)x; (void)y; (void)width; (void)height; // unused update_is_required=1; #endif } void Update_status_line(short char_pos, short width) { #if (UPDATE_METHOD == UPDATE_METHOD_MULTI_RECTANGLE) SDL_UpdateRect(Screen_SDL, (18+char_pos*8)*Menu_factor_X*Pixel_width,Menu_status_Y*Pixel_height,width*8*Menu_factor_X*Pixel_width,8*Menu_factor_Y*Pixel_height); #endif #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) // Merge the ranges if (Status_line_dirty_end < char_pos+width) Status_line_dirty_end=char_pos+width; if (Status_line_dirty_begin > char_pos) Status_line_dirty_begin=char_pos; #endif #if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE) (void)char_pos; // unused parameter (void)width; // unused parameter update_is_required=1; #endif } /// /// Converts a SDL_Surface (indexed colors or RGB) into an array of bytes /// (indexed colors). /// If dest is NULL, it's allocated by malloc(). Otherwise, be sure to /// pass a buffer of the right dimensions. byte * Surface_to_bytefield(SDL_Surface *source, byte * dest) { byte *src; byte *dest_ptr; int y; int remainder; // Support seulement des images 256 couleurs if (source->format->BytesPerPixel != 1) return NULL; if (source->w & 3) remainder=4-(source->w&3); else remainder=0; if (dest==NULL) dest=(byte *)malloc(source->w*source->h); dest_ptr=dest; src=(byte *)(source->pixels); for(y=0; y < source->h; y++) { memcpy(dest_ptr, src,source->w); dest_ptr += source->w; src += source->w + remainder; } return dest; } /// Gets the RGB 24-bit color currently associated with a palette index. SDL_Color Color_to_SDL_color(byte index) { SDL_Color color; color.r = Main_palette[index].R; color.g = Main_palette[index].G; color.b = Main_palette[index].B; color.unused = 255; return color; } /// Reads a pixel in a 8-bit SDL surface. byte Get_SDL_pixel_8(SDL_Surface *bmp, int x, int y) { return ((byte *)(bmp->pixels))[(y*bmp->pitch+x)]; } /// Writes a pixel in a 8-bit SDL surface. void Set_SDL_pixel_8(SDL_Surface *bmp, int x, int y, byte color) { ((byte *)(bmp->pixels))[(y*bmp->pitch+x)]=color; } /// Reads a pixel in a multi-byte SDL surface. dword Get_SDL_pixel_hicolor(SDL_Surface *bmp, int x, int y) { byte * ptr; switch(bmp->format->BytesPerPixel) { case 4: default: return *((dword *)((byte *)bmp->pixels+(y*bmp->pitch+x*4))); case 3: // Reading a 4-byte number starting at an address that isn't a multiple // of 2 (or 4?) is not supported on Caanoo console at least (ARM CPU) // So instead, we will read the 3 individual bytes, and re-construct the // "dword" expected by SDL. ptr = ((byte *)bmp->pixels)+(y*bmp->pitch+x*3); #ifdef SDL_LIL_ENDIAN // Read ABC, output _CBA : Most Significant Byte is zero. return (*ptr) | (*(ptr+1)<<8) | (*(ptr+2)<<16); #else // Read ABC, output ABC_ : Least Significant Byte is zero. return ((*ptr)<<24) | (*(ptr+1)<<16) | (*(ptr+2)<<8); #endif case 2: return *((word *)((byte *)bmp->pixels+(y*bmp->pitch+x*2))); } } /// Convert a SDL Palette to a grafx2 palette void Get_SDL_Palette(const SDL_Palette * sdl_palette, T_Palette palette) { int i; for (i=0; i<256; i++) { palette[i].R=sdl_palette->colors[i].r; palette[i].G=sdl_palette->colors[i].g; palette[i].B=sdl_palette->colors[i].b; } } void Clear_border(byte color) { int width; int height; // This function can be called before the graphics mode is set. // Nothing to do then. if (!Screen_SDL) return; width = Screen_SDL->w - Screen_width*Pixel_width; height = Screen_SDL->h - Screen_height*Pixel_height; if (width) { SDL_Rect r; r.x=Screen_SDL->w - width; r.y=0; r.h=Screen_SDL->h; r.w=width; SDL_FillRect(Screen_SDL,&r,color); SDL_UpdateRect(Screen_SDL, r.x, r.y, r.w, r.h); } if (height) { SDL_Rect r; r.x=0; r.y=Screen_SDL->h - height; r.h=height; r.w=Screen_SDL->w - height; SDL_FillRect(Screen_SDL,&r,color); SDL_UpdateRect(Screen_SDL, r.x, r.y, r.w, r.h); } } /// Activates or desactivates file drag-dropping in program window. void Allow_drag_and_drop(int flag) { // Inform Windows that we accept drag-n-drop events or not #ifdef __WIN32__ SDL_SysWMinfo wminfo; HWND hwnd; SDL_VERSION(&wminfo.version); SDL_GetWMInfo(&wminfo); hwnd = wminfo.window; DragAcceptFiles(hwnd,flag?TRUE:FALSE); SDL_EventState (SDL_SYSWMEVENT,flag?SDL_ENABLE:SDL_DISABLE ); #else (void)flag; // unused #endif } grafx2_2.4+git20180105/src/graph.c0000664000000000000000000030465313223665306015007 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Franck Charlet Copyright 2007-2017 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see ******************************************************************************** Drawing functions and effects. */ #include #include #include #include "global.h" #include "struct.h" #include "engine.h" #include "buttons.h" #include "pages.h" #include "errors.h" #include "sdlscreen.h" #include "graph.h" #include "misc.h" #include "pxsimple.h" #include "pxtall.h" #include "pxwide.h" #include "pxdouble.h" #include "pxtriple.h" #include "pxwide2.h" #include "pxtall2.h" #include "pxtall3.h" #include "pxquad.h" #include "windows.h" #include "input.h" #include "brush.h" #include "tiles.h" #if defined(__VBCC__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) #define M_PI 3.141592653589793238462643 #endif // Generic pixel-drawing function. Func_pixel Pixel_figure; /** Update the picture on screen, for the area passed in parameters. * * Takes into account the X/Y scrolling and zoom, and performs all safety checks so no updates will * go outside the display area. */ void Update_part_of_screen(short x, short y, short width, short height) { short effective_w, effective_h; short effective_X; short effective_Y; short diff; // First make sure the zone is in forward direction (positive width/height) if (width < 0) { x += width; width = - width; } if (height < 0) { y += height; height = - height; } // Round up to a multiple of 8 pixels, because some special modes (ZX, Thomson, ...) can change // more pixels than expected (attribute clash) x &= 0xFFF8; y &= 0xFFF8; width = ((width - 1) | 0x7) + 1; height = ((height - 1) | 0x7) + 1; // Update "normal" view diff = x-Main_offset_X; if (diff<0) { effective_w = width + diff; effective_X = 0; } else { effective_w = width; effective_X = diff; } diff = y-Main_offset_Y; if (diff<0) { effective_h = height + diff; effective_Y = 0; } else { effective_h = height; effective_Y = diff; } // Clamp to actually visible area. All tools are normally constrained to this, but there are some // exceptions: // - Brush preview requests updates outside the visible screen, // - ZX/Thomson constraints can lead to pixel changes outside the visible area. if(Main_magnifier_mode && effective_X + effective_w > Main_separator_position) effective_w = Main_separator_position - effective_X; else if(effective_X + effective_w > Screen_width) effective_w = Screen_width - effective_X; if(effective_Y + effective_h > Menu_Y) effective_h = Menu_Y - effective_Y; /* (for debug purposes, highlight the rectangle that is updated) SDL_Rect r; r.x=effective_X; r.y=effective_Y; r.h=effective_h; r.w=effective_w; SDL_FillRect(Screen_SDL,&r,3); */ Update_rect(effective_X,effective_Y,effective_w,effective_h); // Now update the "zoomed" part of the display if(Main_magnifier_mode) { // Convert picture to zoomed-screen coordinates effective_X = (x-Main_magnifier_offset_X)*Main_magnifier_factor; effective_Y = (y-Main_magnifier_offset_Y)*Main_magnifier_factor; effective_w = width * Main_magnifier_factor; effective_h = height * Main_magnifier_factor; // Apply horizontal clipping if (effective_X < 0) { effective_w+=effective_X; if (effective_w<0) return; effective_X = Main_separator_position + SEPARATOR_WIDTH*Menu_factor_X; } else effective_X += Main_separator_position + SEPARATOR_WIDTH*Menu_factor_X; diff = effective_X+effective_w-Min(Screen_width, Main_X_zoom+(Main_image_width-Main_magnifier_offset_X)*Main_magnifier_factor); if (diff>0) { effective_w -=diff; if (effective_w<0) return; } // Vertical clipping if (effective_Y < 0) { effective_h+=effective_Y; if (effective_h<0) return; effective_Y = 0; } diff = effective_Y+effective_h-Min(Menu_Y, (Main_image_height-Main_magnifier_offset_Y)*Main_magnifier_factor); if (diff>0) { effective_h -=diff; if (effective_h<0) return; } // Again, for debugging purposes, display the touched rectangle /*SDL_Rect r; r.x=effective_X; r.y=effective_Y; r.h=effective_h; r.w=effective_w; SDL_FillRect(Screen_SDL,&r,3);*/ // When the grid is displayed in Tilemap mode, this tests if // one edge of the grid has been touched : // In this case, the whole magnified area requires a refreshed grid. // This could be optimized further, but at the moment this seemed // fast enough. if (Show_grid && Main_tilemap_mode && ( x/Snap_width <(x+width )/Snap_width || y/Snap_height<(y+height)/Snap_height)) { short w,h; w=Min(Screen_width-Main_X_zoom, (Main_image_width-Main_magnifier_offset_X)*Main_magnifier_factor); h=Min(Menu_Y, (Main_image_height-Main_magnifier_offset_Y)*Main_magnifier_factor); Redraw_grid(Main_X_zoom,0,w,h); Update_rect(Main_X_zoom,0,w,h); } else { Redraw_grid(effective_X,effective_Y,effective_w,effective_h); Update_rect(effective_X,effective_Y,effective_w,effective_h); } } } void Transform_point(short x, short y, float cos_a, float sin_a, short * rx, short * ry) { *rx=Round(((float)x*cos_a)+((float)y*sin_a)); *ry=Round(((float)y*cos_a)-((float)x*sin_a)); } //--------------------- Initialisation d'un mode vido ----------------------- int Init_mode_video(int width, int height, int fullscreen, int pix_ratio) { int index; int factor; int pix_width; int pix_height; byte screen_changed; byte pixels_changed; int absolute_mouse_x=Mouse_X*Pixel_width; int absolute_mouse_y=Mouse_Y*Pixel_height; static int Wrong_resize; try_again: switch (pix_ratio) { default: case PIXEL_SIMPLE: pix_width=1; pix_height=1; break; case PIXEL_TALL: pix_width=1; pix_height=2; break; case PIXEL_WIDE: pix_width=2; pix_height=1; break; case PIXEL_DOUBLE: pix_width=2; pix_height=2; break; case PIXEL_TRIPLE: pix_width=3; pix_height=3; break; case PIXEL_WIDE2: pix_width=4; pix_height=2; break; case PIXEL_TALL2: pix_width=2; pix_height=4; break; case PIXEL_TALL3: pix_width=3; pix_height=4; break; case PIXEL_QUAD: pix_width=4; pix_height=4; break; } screen_changed = (Screen_width*Pixel_width!=width || Screen_height*Pixel_height!=height || Video_mode[Current_resolution].Fullscreen != fullscreen); // Valeurs raisonnables: minimum 320x200 if (!fullscreen) { if (Wrong_resize>20 && (width < 320*pix_width || height < 200*pix_height)) { if(pix_ratio != PIXEL_SIMPLE) { pix_ratio = PIXEL_SIMPLE; Verbose_message("Error!", "Your WM is forcing GrafX2 to resize to something " "smaller than the minimal resolution.\n" "GrafX2 switched to a smaller\npixel scaler to avoid problems "); goto try_again; } } if (width > 320*pix_width && height > 200*pix_height) Wrong_resize = 0; if (width < 320*pix_width) { width = 320*pix_width; screen_changed=1; Wrong_resize++; } if (height < 200*pix_height) { height = 200*pix_height; screen_changed=1; Wrong_resize++; } Video_mode[0].Width = width; Video_mode[0].Height = height; } else { if (width < 320*pix_width || height < 200*pix_height) return 1; } // La largeur doit tre un multiple de 4 #ifdef __amigaos4__ // On AmigaOS the systems adds some more constraints on that ... width = (width + 15) & 0xFFFFFFF0; #else //width = (width + 3 ) & 0xFFFFFFFC; #endif pixels_changed = (Pixel_ratio!=pix_ratio); if (!screen_changed && !pixels_changed) { Resize_width=0; Resize_height=0; return 0; } if (screen_changed) { Set_mode_SDL(&width, &height,fullscreen); } if (screen_changed || pixels_changed) { Pixel_ratio=pix_ratio; Pixel_width=pix_width; Pixel_height=pix_height; switch (Pixel_ratio) { default: case PIXEL_SIMPLE: #define Display_line_on_screen_fast_simple Display_line_on_screen_simple #define SETPIXEL(x) \ Pixel = Pixel_##x ; \ Read_pixel= Read_pixel_##x ; \ Display_screen = Display_part_of_screen_##x ; \ Block = Block_##x ; \ Pixel_preview_normal = Pixel_preview_normal_##x ; \ Pixel_preview_magnifier = Pixel_preview_magnifier_##x ; \ Horizontal_XOR_line = Horizontal_XOR_line_##x ; \ Vertical_XOR_line = Vertical_XOR_line_##x ; \ Display_brush_color = Display_brush_color_##x ; \ Display_brush_mono = Display_brush_mono_##x ; \ Clear_brush = Clear_brush_##x ; \ Remap_screen = Remap_screen_##x ; \ Display_line = Display_line_on_screen_##x ; \ Display_line_fast = Display_line_on_screen_fast_##x ; \ Read_line = Read_line_screen_##x ; \ Display_zoomed_screen = Display_part_of_screen_scaled_##x ; \ Display_brush_color_zoom = Display_brush_color_zoom_##x ; \ Display_brush_mono_zoom = Display_brush_mono_zoom_##x ; \ Clear_brush_scaled = Clear_brush_scaled_##x ; \ Display_brush = Display_brush_##x ; SETPIXEL(simple) break; case PIXEL_TALL: #define Display_line_on_screen_fast_tall Display_line_on_screen_tall SETPIXEL(tall) break; case PIXEL_WIDE: SETPIXEL(wide) break; case PIXEL_DOUBLE: SETPIXEL(double) break; case PIXEL_TRIPLE: SETPIXEL(triple) break; case PIXEL_WIDE2: SETPIXEL(wide2) break; case PIXEL_TALL2: SETPIXEL(tall2) break; case PIXEL_TALL3: SETPIXEL(tall3) break; case PIXEL_QUAD: SETPIXEL(quad) break; } } Screen_width = width/Pixel_width; Screen_height = height/Pixel_height; Clear_border(MC_Black); // Requires up-to-date Screen_* and Pixel_* // Set menu size (software zoom) if (Screen_width/320 > Screen_height/200) factor=Screen_height/200; else factor=Screen_width/320; switch (Config.Ratio) { case 1: // Always the biggest possible Menu_factor_X=factor; Menu_factor_Y=factor; break; case 2: // Only keep the aspect ratio Menu_factor_X=factor-1; if (Menu_factor_X<1) Menu_factor_X=1; Menu_factor_Y=factor-1; if (Menu_factor_Y<1) Menu_factor_Y=1; break; case 0: // Always smallest possible Menu_factor_X=1; Menu_factor_Y=1; break; default: // Stay below some reasonable size if (factor>Max(Pixel_width,Pixel_height)) factor/=Max(Pixel_width,Pixel_height); Menu_factor_X=Min(factor,abs(Config.Ratio)); Menu_factor_Y=Min(factor,abs(Config.Ratio)); } if (Pixel_height>Pixel_width && Screen_width>=Menu_factor_X*2*320) Menu_factor_X*=2; else if (Pixel_width>Pixel_height && Screen_height>=Menu_factor_Y*2*200) Menu_factor_Y*=2; free(Horizontal_line_buffer); Horizontal_line_buffer=(byte *)malloc(Pixel_width * ((Screen_width>Main_image_width)?Screen_width:Main_image_width)); Set_palette(Main_palette); Current_resolution=0; if (fullscreen) { for (index=1; index=Screen_width) Mouse_X=Screen_width-1; Mouse_Y=absolute_mouse_y/Pixel_height; if (Mouse_Y>=Screen_height) Mouse_Y=Screen_height-1; if (fullscreen) Set_mouse_position(); Spare_offset_X=0; // | Il faut penser viter les incohrences Spare_offset_Y=0; // |- de dcalage du brouillon par rapport Spare_magnifier_mode=0; // | la rsolution. if (Main_magnifier_mode) { Pixel_preview=Pixel_preview_magnifier; } else { Pixel_preview=Pixel_preview_normal; // Recaler la vue (meme clipping que dans Scroll_screen()) if (Main_offset_X+Screen_width>Main_image_width) Main_offset_X=Main_image_width-Screen_width; if (Main_offset_X<0) Main_offset_X=0; if (Main_offset_Y+Menu_Y>Main_image_height) Main_offset_Y=Main_image_height-Menu_Y; if (Main_offset_Y<0) Main_offset_Y=0; } Compute_magnifier_data(); if (Main_magnifier_mode) Position_screen_according_to_zoom(); Compute_limits(); Compute_paintbrush_coordinates(); Resize_width=0; Resize_height=0; return 0; } // -- Redimentionner l'image (nettoie l'cran virtuel) -- void Resize_image(word chosen_width,word chosen_height) { word old_width=Main_image_width; word old_height=Main_image_height; int i; // +-+-+ // |C| | A+B+C = Ancienne image // +-+A| // |B| | C = Nouvelle image // +-+-+ Upload_infos_page_main(Main_backups->Pages); if (Backup_with_new_dimensions(chosen_width,chosen_height)) { // La nouvelle page a pu tre alloue, elle est pour l'instant pleine de // 0s. Elle fait Main_image_width de large. Main_image_is_modified=1; // On copie donc maintenant la partie C dans la nouvelle image. for (i=0; iPages->Nb_layers; i++) { Copy_part_of_image_to_another( Main_backups->Pages->Next->Image[i].Pixels,0,0,Min(old_width,Main_image_width), Min(old_height,Main_image_height),old_width, Main_backups->Pages->Image[i].Pixels,0,0,Main_image_width); } Redraw_layered_image(); } else { // Afficher un message d'erreur Display_cursor(); Message_out_of_memory(); Hide_cursor(); } } void Remap_spare(void) { short x_pos; // Variable de balayage de la brosse short y_pos; // Variable de balayage de la brosse byte used[256]; // Tableau de boolens "La couleur est utilise" int color; int layer; // On commence par initialiser le tableau de boolens faux for (color=0;color<=255;color++) used[color]=0; // On calcule la table d'utilisation des couleurs for (layer=0; layerPages->Nb_layers; layer++) for (y_pos=0;y_posPages->Image[layer].Pixels+(y_pos*Spare_image_width+x_pos))]=1; // On va maintenant se servir de la table "used" comme table de // conversion: pour chaque indice, la table donne une couleur de // remplacement. // Note : Seules les couleurs utilises on besoin d'tres recalcules: les // autres ne seront jamais consultes dans la nouvelle table de // conversion puisque elles n'existent pas dans l'image, donc elles // ne seront pas utilises par Remap_general_lowlevel. for (color=0;color<=255;color++) if (used[color]) used[color]=Best_color_perceptual(Spare_palette[color].R,Spare_palette[color].G,Spare_palette[color].B); // Maintenant qu'on a une super table de conversion qui n'a que le nom // qui craint un peu, on peut faire l'change dans la brosse de toutes les // teintes. for (layer=0; layerPages->Nb_layers; layer++) Remap_general_lowlevel(used,Spare_backups->Pages->Image[layer].Pixels,Spare_backups->Pages->Image[layer].Pixels,Spare_image_width,Spare_image_height,Spare_image_width); // Change transparent color index Spare_backups->Pages->Transparent_color=used[Spare_backups->Pages->Transparent_color]; } void Get_colors_from_brush(void) { short x_pos; // Variable de balayage de la brosse short y_pos; // Variable de balayage de la brosse byte brush_used[256]; // Tableau de boolens "La couleur est utilise" dword usage[256]; int color; int image_color; //if (Confirmation_box("Modify current palette ?")) // Backup with unchanged layers, only palette is modified Backup_layers(LAYER_NONE); // Init array of new colors for (color=0;color<=255;color++) brush_used[color]=0; // Tag used colors for (y_pos=0;y_posLimit_left) && (Read_pixel_from_current_layer(start_x-1,line)==2)) || // Test de la prsence d'un point droite du segment ((end_x-1Limit_top)) for (x_pos=start_x;x_pos*right_reached) *right_reached=end_x; // On remplit le segment de start_x end_x-1. for (x_pos=start_x;x_posLimit_top) current_limit_top--; for (line=current_limit_bottom;line>=current_limit_top;line--) { line_is_modified=0; // On va traiter le cas de la ligne n line. // On commence le traitement la gauche de l'cran start_x=Limit_left; // Pour chaque segment de couleur 1 que peut contenir la ligne while (start_x<=Limit_right) { // On cherche son dbut for (;(start_x<=Limit_right) && (Read_pixel_from_current_layer(start_x,line)!=1);start_x++); if (start_x<=Limit_right) { // Un segment de couleur 1 existe et commence la position start_x. // On va donc en chercher la fin. for (end_x=start_x+1;(end_x<=Limit_right) && (Read_pixel_from_current_layer(end_x,line)==1);end_x++); // On sait qu'il existe un segment de couleur 1 qui commence en // start_x et qui se termine en end_x-1. // On va maintenant regarder si une couleur sur la priphrie // permet de colorier ce segment avec la couleur 2. can_propagate=( // Test de la prsence d'un point gauche du segment ((start_x>Limit_left) && (Read_pixel_from_current_layer(start_x-1,line)==2)) || // Test de la prsence d'un point droite du segment ((end_x-1*right_reached) *right_reached=end_x; // On remplit le segment de start_x end_x-1. for (x_pos=start_x;x_posLimit_top) ) current_limit_top--; // On monte cette limite vers le haut } } *top_reached=current_limit_top; *bottom_reached =current_limit_bottom; (*right_reached)--; } // end de la routine de remplissage "Fill" byte Read_pixel_from_backup_layer(word x,word y) { return *((y)*Main_image_width+(x)+Main_backups->Pages->Next->Image[Main_current_layer].Pixels); } void Fill_general(byte fill_color) // // Cette fonction fait un remplissage qui gre tous les effets. Elle fait // appel "Fill()". // { byte cursor_shape_before_fill; short x_pos,y_pos; short top_reached ,bottom_reached; short left_reached,right_reached; byte replace_table[256]; int old_limit_right=Limit_right; int old_limit_left=Limit_left; int old_limit_top=Limit_top; int old_limit_bottom=Limit_bottom; // Avant toute chose, on vrifie que l'on n'est pas en train de remplir // en dehors de l'image: if ( (Paintbrush_X>=Limit_left) && (Paintbrush_X<=Limit_right) && (Paintbrush_Y>=Limit_top) && (Paintbrush_Y<=Limit_bottom) ) { // If tilemap mode is ON, ignore action if it's outside grid limits if (Main_tilemap_mode) { if (Paintbrush_X= (Main_image_width-Snap_offset_X)/Snap_width*Snap_width+Snap_offset_X) return; if (Paintbrush_Y= (Main_image_height-Snap_offset_Y)/Snap_height*Snap_height+Snap_offset_Y) return; } // On suppose que le curseur est dj cach. // Hide_cursor(); // On va faire patienter l'utilisateur en lui affichant un joli petit // sablier: cursor_shape_before_fill=Cursor_shape; Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); // On commence par effectuer un backup de l'image. Backup(); // On fait attention au Feedback qui DOIT se faire avec le backup. Update_FX_feedback(0); // If tilemap mode is ON, adapt limits to current tile only if (Main_tilemap_mode) { Limit_right = Min(Limit_right, (Paintbrush_X-Snap_offset_X)/Snap_width*Snap_width+Snap_width-1+Snap_offset_X); Limit_left = Max(Limit_left, (Paintbrush_X-Snap_offset_X)/Snap_width*Snap_width+Snap_offset_X); Limit_bottom = Min(Limit_bottom, (Paintbrush_Y-Snap_offset_Y)/Snap_height*Snap_height+Snap_height-1+Snap_offset_Y); Limit_top = Max(Limit_top, (Paintbrush_Y-Snap_offset_Y)/Snap_height*Snap_height+Snap_offset_Y); } // On va maintenant "purer" la zone visible de l'image: memset(replace_table,0,256); replace_table[Read_pixel_from_backup_layer(Paintbrush_X,Paintbrush_Y)]=1; Replace_colors_within_limits(replace_table); // On fait maintenant un remplissage classique de la couleur 1 avec la 2 Fill(&top_reached ,&bottom_reached, &left_reached,&right_reached); // On s'apprte faire des oprations qui ncessitent un affichage. Il // faut donc retirer de l'cran le curseur: Hide_cursor(); Cursor_shape=cursor_shape_before_fill; // Il va maintenant falloir qu'on "turn" ce gros caca "into" un truc qui // ressemble un peu plus ce quoi l'utilisateur peut s'attendre. if (top_reached>Limit_top) Copy_part_of_image_to_another(Main_backups->Pages->Next->Image[Main_current_layer].Pixels, // source Limit_left,Limit_top, // Pos X et Y dans source (Limit_right-Limit_left)+1, // width copie top_reached-Limit_top,// height copie Main_image_width, // width de la source Main_backups->Pages->Image[Main_current_layer].Pixels, // Destination Limit_left,Limit_top, // Pos X et Y destination Main_image_width); // width destination if (bottom_reachedPages->Next->Image[Main_current_layer].Pixels, Limit_left,bottom_reached+1, (Limit_right-Limit_left)+1, Limit_bottom-bottom_reached, Main_image_width,Main_backups->Pages->Image[Main_current_layer].Pixels, Limit_left,bottom_reached+1,Main_image_width); if (left_reached>Limit_left) Copy_part_of_image_to_another(Main_backups->Pages->Next->Image[Main_current_layer].Pixels, Limit_left,top_reached, left_reached-Limit_left, (bottom_reached-top_reached)+1, Main_image_width,Main_backups->Pages->Image[Main_current_layer].Pixels, Limit_left,top_reached,Main_image_width); if (right_reachedPages->Next->Image[Main_current_layer].Pixels, right_reached+1,top_reached, Limit_right-right_reached, (bottom_reached-top_reached)+1, Main_image_width,Main_backups->Pages->Image[Main_current_layer].Pixels, right_reached+1,top_reached,Main_image_width); // Restore image limits : this is needed by the tilemap effect, // otherwise it will not display other modified tiles. Limit_right=old_limit_right; Limit_left=old_limit_left; Limit_top=old_limit_top; Limit_bottom=old_limit_bottom; for (y_pos=top_reached;y_pos<=bottom_reached;y_pos++) { for (x_pos=left_reached;x_pos<=right_reached;x_pos++) { byte filled = Read_pixel_from_current_layer(x_pos,y_pos); // First, restore the color. Pixel_in_current_screen(x_pos,y_pos,Read_pixel_from_backup_layer(x_pos,y_pos)); if (filled==2) { // Update the color according to the fill color and all effects Display_pixel(x_pos,y_pos,fill_color); } } } // Restore original feedback value Update_FX_feedback(Config.FX_Feedback); // A la fin, on n'a pas besoin de rafficher le curseur puisque c'est // l'appelant qui s'en charge, et on n'a pas besoin de rafficher l'image // puisque les seuls points qui ont chang dans l'image ont t raffichs // par l'utilisation de "Display_pixel()", et que les autres... eh bein // on n'y a jamais touch l'cran les autres: ils sont donc corrects. if(Main_magnifier_mode) { short w,h; w=Min(Screen_width-Main_X_zoom, (Main_image_width-Main_magnifier_offset_X)*Main_magnifier_factor); h=Min(Menu_Y, (Main_image_height-Main_magnifier_offset_Y)*Main_magnifier_factor); Redraw_grid(Main_X_zoom,0,w,h); } Update_rect(0,0,0,0); End_of_modification(); } } ////////////////////////////////////////////////////////////////////////////// ////////////////// TRACS DE FIGURES GOMTRIQUES STANDARDS ////////////////// ////////////////////////// avec gestion de previews ////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Data used by ::Init_permanent_draw() and ::Pixel_figure_permanent() static Uint32 Permanent_draw_next_refresh=0; static int Permanent_draw_count=0; void Init_permanent_draw(void) { Permanent_draw_count = 0; Permanent_draw_next_refresh = SDL_GetTicks() + 100; } // Affichage d'un point de faon dfinitive (utilisation du pinceau) void Pixel_figure_permanent(word x_pos,word y_pos,byte color) { Draw_paintbrush(x_pos,y_pos,color); Permanent_draw_count ++; // Check every 8 pixels if (! (Permanent_draw_count&7)) { Uint32 now = SDL_GetTicks(); SDL_PumpEvents(); if (now>= Permanent_draw_next_refresh) { Permanent_draw_next_refresh = now+100; Flush_update(); } } } // Affichage d'un point de faon dfinitive void Pixel_clipped(word x_pos,word y_pos,byte color) { if ( (x_pos>=Limit_left) && (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) Display_pixel(x_pos,y_pos,color); } // Affichage d'un point pour une preview void Pixel_figure_preview(word x_pos,word y_pos,byte color) { if ( (x_pos>=Limit_left) && (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) Pixel_preview(x_pos,y_pos,color); } // Affichage d'un point pour une preview, avec sa propre couleur void Pixel_figure_preview_auto(word x_pos,word y_pos) { if ( (x_pos>=Limit_left) && (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) Pixel_preview(x_pos,y_pos,Read_pixel_from_current_screen(x_pos,y_pos)); } // Affichage d'un point pour une preview en xor void Pixel_figure_preview_xor(short x_pos,short y_pos,byte color) { (void)color; // unused if ( (x_pos>=Limit_left) && (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) Pixel_preview(x_pos,y_pos,xor_lut[Read_pixel(x_pos-Main_offset_X, y_pos-Main_offset_Y)]); } // Affichage d'un point pour une preview en xor additif // (Il lit la couleur depuis la page backup) void Pixel_figure_preview_xorback(word x_pos,word y_pos,byte color) { (void)color; // unused if ( (x_pos>=Limit_left) && (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) Pixel_preview(x_pos,y_pos,xor_lut[Main_screen[x_pos+y_pos*Main_image_width]]); } // Effacement d'un point de preview void Pixel_figure_clear_preview(word x_pos,word y_pos,byte color) { (void)color; // unused if ( (x_pos>=Limit_left) && (x_pos<=Limit_right) && (y_pos>=Limit_top) && (y_pos<=Limit_bottom) ) Pixel_preview(x_pos,y_pos,Read_pixel_from_current_screen(x_pos,y_pos)); } // Affichage d'un point dans la brosse void Pixel_figure_in_brush(word x_pos,word y_pos,byte color) { x_pos-=Brush_offset_X; y_pos-=Brush_offset_Y; if ( (x_posLimit_bottom) end_y=Limit_bottom; if (start_xLimit_right) end_x=Limit_right; // Affichage du cercle for (y_pos=start_y,Circle_cursor_Y=(long)start_y-center_y;y_pos<=end_y;y_pos++,Circle_cursor_Y++) for (x_pos=start_x,Circle_cursor_X=(long)start_x-center_x;x_pos<=end_x;x_pos++,Circle_cursor_X++) if (Pixel_in_circle()) Display_pixel(x_pos,y_pos,color); Update_part_of_screen(start_x,start_y,end_x+1-start_x,end_y+1-start_y); } int Circle_squared_diameter(int diameter) { int result = diameter*diameter; // Trick to make some circles rounder, even though // mathematically incorrect. if (diameter==3 || diameter==9) return result-2; if (diameter==11) return result-6; if (diameter==14) return result-4; return result; } // -- Tracer gnral d'une ellipse vide ----------------------------------- void Draw_empty_ellipse_general(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color) { short start_x; short start_y; short x_pos; short y_pos; start_x=center_x-horizontal_radius; start_y=center_y-vertical_radius; // Calcul des limites de l'ellipse Ellipse_compute_limites(horizontal_radius+1,vertical_radius+1); // Affichage des extremites de l'ellipse sur chaque quart de l'ellipse: for (y_pos=start_y,Ellipse_cursor_Y=-vertical_radius;y_posLimit_bottom) end_y=Limit_bottom; if (start_xLimit_right) end_x=Limit_right; // Affichage de l'ellipse for (y_pos=start_y,Ellipse_cursor_Y=start_y-center_y;y_pos<=end_y;y_pos++,Ellipse_cursor_Y++) for (x_pos=start_x,Ellipse_cursor_X=start_x-center_x;x_pos<=end_x;x_pos++,Ellipse_cursor_X++) if (Pixel_in_ellipse()) Display_pixel(x_pos,y_pos,color); Update_part_of_screen(center_x-horizontal_radius,center_y-vertical_radius,2*horizontal_radius+1,2*vertical_radius+1); } /****************** * TRAC DE LIGNES * ******************/ /// Alters bx and by so the (AX,AY)-(BX,BY) segment becomes either horizontal, /// vertical, 45degrees, or isometrical for pixelart (ie 2:1 ratio) void Clamp_coordinates_regular_angle(short ax, short ay, short* bx, short* by) { int dx, dy; float angle; dx = *bx-ax; dy = *by-ay; // No mouse move: no need to clamp anything if (dx==0 || dy == 0) return; // Determine angle (heading) angle = atan2(dx, dy); // Get absolute values, useful from now on: //dx=abs(dx); //dy=abs(dy); // Negative Y if (angle < M_PI*(-15.0/16.0) || angle > M_PI*(15.0/16.0)) { *bx=ax; *by=ay + dy; } // Iso close to negative Y else if (angle < M_PI*(-13.0/16.0)) { dy=dy | 1; // Round up to next odd number *bx=ax + dy/2; *by=ay + dy; } // 45deg else if (angle < M_PI*(-11.0/16.0)) { *by = (*by + ay + dx)/2; *bx = ax - ay + *by; } // Iso close to negative X else if (angle < M_PI*(-9.0/16.0)) { dx=dx | 1; // Round up to next odd number *bx=ax + dx; *by=ay + dx/2; } // Negative X else if (angle < M_PI*(-7.0/16.0)) { *bx=ax + dx; *by=ay; } // Iso close to negative X else if (angle < M_PI*(-5.0/16.0)) { dx=dx | 1; // Round up to next odd number *bx=ax + dx; *by=ay - dx/2; } // 45 degrees else if (angle < M_PI*(-3.0/16.0)) { *by = (*by + ay - dx)/2; *bx = ax + ay - *by; } // Iso close to positive Y else if (angle < M_PI*(-1.0/16.0)) { dy=dy | 1; // Round up to next odd number *bx=ax - dy/2; *by=ay + dy; } // Positive Y else if (angle < M_PI*(1.0/16.0)) { *bx=ax; *by=ay + dy; } // Iso close to positive Y else if (angle < M_PI*(3.0/16.0)) { dy=dy | 1; // Round up to next odd number *bx=ax + dy/2; *by=ay + dy; } // 45 degrees else if (angle < M_PI*(5.0/16.0)) { *by = (*by + ay + dx)/2; *bx = ax - ay + *by; } // Iso close to positive X else if (angle < M_PI*(7.0/16.0)) { dx=dx | 1; // Round up to next odd number *bx=ax + dx; *by=ay + dx/2; } // Positive X else if (angle < M_PI*(9.0/16.0)) { *bx=ax + dx; *by=ay; } // Iso close to positive X else if (angle < M_PI*(11.0/16.0)) { dx=dx | 1; // Round up to next odd number *bx=ax + dx; *by=ay - dx/2; } // 45 degrees else if (angle < M_PI*(13.0/16.0)) { *by = (*by + ay - dx)/2; *bx = ax + ay - *by; } // Iso close to negative Y else //if (angle < M_PI*(15.0/16.0)) { dy=dy | 1; // Round up to next odd number *bx=ax - dy/2; *by=ay + dy; } return; } // -- Tracer gnral d'une ligne ------------------------------------------ void Draw_line_general(short start_x,short start_y,short end_x,short end_y, byte color) { short x_pos,y_pos; short incr_x,incr_y; short i,cumul; short delta_x,delta_y; x_pos=start_x; y_pos=start_y; if (start_xdelta_x) { cumul=delta_y>>1; for (i=1; i=delta_y) { cumul-=delta_y; x_pos+=incr_x; } Pixel_figure(x_pos,y_pos,color); } } else { cumul=delta_x>>1; for (i=1; i=delta_x) { cumul-=delta_x; y_pos+=incr_y; } Pixel_figure(x_pos,y_pos,color); } } if ( (start_x!=end_x) || (start_y!=end_y) ) Pixel_figure(end_x,end_y,color); } // -- Tracer dfinitif d'une ligne -- void Draw_line_permanent(short start_x,short start_y,short end_x,short end_y, byte color) { int w = end_x-start_x, h = end_y - start_y; Pixel_figure=Pixel_figure_permanent; Init_permanent_draw(); Draw_line_general(start_x,start_y,end_x,end_y,color); Update_part_of_screen((start_xend_x) { temp=start_x; start_x=end_x; end_x=temp; } if (start_y>end_y) { temp=start_y; start_y=end_y; end_y=temp; } // On trace le rectangle: Init_permanent_draw(); for (x_pos=start_x;x_pos<=end_x;x_pos++) { Pixel_figure_permanent(x_pos,start_y,color); Pixel_figure_permanent(x_pos, end_y,color); } for (y_pos=start_y+1;y_posend_x) { temp=start_x; start_x=end_x; end_x=temp; } if (start_y>end_y) { temp=start_y; start_y=end_y; end_y=temp; } // Correction en cas de dpassement des limites de l'image if (end_x>Limit_right) end_x=Limit_right; if (end_y>Limit_bottom) end_y=Limit_bottom; // On trace le rectangle: for (y_pos=start_y;y_pos<=end_y;y_pos++) for (x_pos=start_x;x_pos<=end_x;x_pos++) // Display_pixel traite chaque pixel avec tous les effets ! (smear, ...) // Donc on ne peut pas otimiser en traant ligne par ligne avec memset :( Display_pixel(x_pos,y_pos,color); Update_part_of_screen(start_x,start_y,end_x-start_x,end_y-start_y); } // -- Tracer une courbe de Bzier -- void Draw_curve_general(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color) { float delta,t,t2,t3; short x,y,old_x,old_y; word i; int cx[4]; int cy[4]; // Calcul des vecteurs de coefficients cx[0]= - x1 + 3*x2 - 3*x3 + x4; cx[1]= + 3*x1 - 6*x2 + 3*x3; cx[2]= - 3*x1 + 3*x2; cx[3]= + x1; cy[0]= - y1 + 3*y2 - 3*y3 + y4; cy[1]= + 3*y1 - 6*y2 + 3*y3; cy[2]= - 3*y1 + 3*y2; cy[3]= + y1; // Traage de la courbe old_x=x1; old_y=y1; Pixel_figure(old_x,old_y,color); delta=0.05; // 1.0/20 t=0; for (i=1; i<=20; i++) { t=t+delta; t2=t*t; t3=t2*t; x=Round(t3*cx[0] + t2*cx[1] + t*cx[2] + cx[3]); y=Round(t3*cy[0] + t2*cy[1] + t*cy[2] + cy[3]); Draw_line_general(old_x,old_y,x,y,color); old_x=x; old_y=y; } x = Min(Min(x1,x2),Min(x3,x4)); y = Min(Min(y1,y2),Min(y3,y4)); old_x = Max(Max(x1,x2),Max(x3,x4)) - x; old_y = Max(Max(y1,y2),Max(y3,y4)) - y; Update_part_of_screen(x,y,old_x+1,old_y+1); } // -- Tracer une courbe de Bzier dfinitivement -- void Draw_curve_permanent(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color) { Pixel_figure=Pixel_figure_permanent; Init_permanent_draw(); Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color); } // -- Tracer la preview d'une courbe de Bzier -- void Draw_curve_preview(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color) { Pixel_figure=Pixel_figure_preview; Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color); } // -- Effacer la preview d'une courbe de Bzier -- void Hide_curve_preview(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color) { Pixel_figure=Pixel_figure_clear_preview; Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color); } // -- Spray : un petit coup de Pschiitt! -- void Airbrush(short clicked_button) { short x_pos,y_pos; short radius=Airbrush_size>>1; long radius_squared=(long)radius*radius; short index,count; byte color_index; byte direction; Hide_cursor(); if (Airbrush_mode) { for (count=1; count<=Airbrush_mono_flow; count++) { x_pos=(rand()%Airbrush_size)-radius; y_pos=(rand()%Airbrush_size)-radius; if ( (x_pos*x_pos)+(y_pos*y_pos) <= radius_squared ) { x_pos+=Paintbrush_X; y_pos+=Paintbrush_Y; if (clicked_button==1) Draw_paintbrush(x_pos,y_pos,Fore_color); else Draw_paintbrush(x_pos,y_pos,Back_color); } } } else { // On essaye de se balader dans la table des flux de faon ce que ce // ne soit pas toujours la dernire couleur qui soit affiche en dernier // Pour a, on part d'une couleur au pif dans une direction alatoire. direction=rand()&1; for (index=0,color_index=rand()/*%256*/; index<256; index++) { for (count=1; count<=Airbrush_multi_flow[color_index]; count++) { x_pos=(rand()%Airbrush_size)-radius; y_pos=(rand()%Airbrush_size)-radius; if ( (x_pos*x_pos)+(y_pos*y_pos) <= radius_squared ) { x_pos+=Paintbrush_X; y_pos+=Paintbrush_Y; if (clicked_button==LEFT_SIDE) Draw_paintbrush(x_pos,y_pos,color_index); else Draw_paintbrush(x_pos,y_pos,Back_color); } } if (direction) color_index++; else color_index--; } } Display_cursor(); } ////////////////////////////////////////////////////////////////////////// ////////////////////////// GESTION DES DEGRADES ////////////////////////// ////////////////////////////////////////////////////////////////////////// // -- Gestion d'un dgrad de base (le plus moche) -- void Gradient_basic(long index,short x_pos,short y_pos) { long position; // On fait un premier calcul partiel position=(index*Gradient_bounds_range); // On gre un dplacement au hasard position+=(Gradient_total_range*(rand()%Gradient_random_factor)) >>6; position-=(Gradient_total_range*Gradient_random_factor) >>7; position/=Gradient_total_range; // On va vrifier que nos petites idioties n'ont pas ject la valeur hors // des valeurs autorises par le dgrad dfini par l'utilisateur. if (position<0) position=0; else if (position>=Gradient_bounds_range) position=Gradient_bounds_range-1; // On ramne ensuite la position dans le dgrad vers un numro de couleur if (Gradient_is_inverted) Gradient_pixel(x_pos,y_pos,Gradient_upper_bound-position); else Gradient_pixel(x_pos,y_pos,Gradient_lower_bound+position); } // -- Gestion d'un dgrad par trames simples -- void Gradient_dithered(long index,short x_pos,short y_pos) { long position_in_gradient; long position_in_segment; // // But de l'opration: en plus de calculer la position de base (dsigne // dans cette procdure par "position_in_gradient", on calcule la position // de l'indice dans le schma suivant: // // | Les indices qui tranent de ce ct du segment se voient subir // | une incrmentation conditionnelle leur position dans l'cran. // v // |---|---|---|---- - - - // ^ // |_ Les indices qui tranent de ce ct du segment se voient subir une // dcrmentation conditionnelle leur position dans l'cran. // On fait d'abord un premier calcul partiel position_in_gradient=(index*Gradient_bounds_range); // On gre un dplacement au hasard... position_in_gradient+=(Gradient_total_range*(rand()%Gradient_random_factor)) >>6; position_in_gradient-=(Gradient_total_range*Gradient_random_factor) >>7; if (position_in_gradient<0) position_in_gradient=0; // ... qui nous permet de calculer la position dans le segment position_in_segment=((position_in_gradient<<2)/Gradient_total_range)&3; // On peut ensuite terminer le calcul de l'indice dans le dgrad position_in_gradient/=Gradient_total_range; // On va pouvoir discuter de la valeur de position_in_gradient en fonction // de la position dans l'cran et de la position_in_segment. switch (position_in_segment) { case 0 : // On est sur la gauche du segment if (((x_pos+y_pos)&1)==0) position_in_gradient--; break; // On n'a pas traiter les cas 1 et 2 car ils reprsentent des valeurs // suffisament au centre du segment pour ne pas avoir subir la trame case 3 : // On est sur la droite du segment if (((x_pos+y_pos)&1)!=0) // Note: on doit faire le test inverse au cas gauche pour synchroniser les 2 cts de la trame. position_in_gradient++; } // On va vrifier que nos petites idioties n'ont pas ject la valeur hors // des valeurs autorises par le dgrad dfini par l'utilisateur. if (position_in_gradient<0) position_in_gradient=0; else if (position_in_gradient>=Gradient_bounds_range) position_in_gradient=Gradient_bounds_range-1; // On ramne ensuite la position dans le dgrad vers un numro de couleur if (Gradient_is_inverted) position_in_gradient=Gradient_upper_bound-position_in_gradient; else position_in_gradient=Gradient_lower_bound+position_in_gradient; Gradient_pixel(x_pos,y_pos,position_in_gradient); } // -- Gestion d'un dgrad par trames tendues -- void Gradient_extra_dithered(long index,short x_pos,short y_pos) { long position_in_gradient; long position_in_segment; // // But de l'opration: en plus de calculer la position de base (dsigne // dans cette procdure par "position_in_gradient", on calcule la position // de l'indice dans le schma suivant: // // | Les indices qui tranent de ce ct du segment se voient subir // | une incrmentation conditionnelle leur position dans l'cran. // v // |---|---|---|---- - - - // ^ // |_ Les indices qui tranent de ce ct du segment se voient subir une // dcrmentation conditionnelle leur position dans l'cran. // On fait d'abord un premier calcul partiel position_in_gradient=(index*Gradient_bounds_range); // On gre un dplacement au hasard position_in_gradient+=(Gradient_total_range*(rand()%Gradient_random_factor)) >>6; position_in_gradient-=(Gradient_total_range*Gradient_random_factor) >>7; if (position_in_gradient<0) position_in_gradient=0; // Qui nous permet de calculer la position dans le segment position_in_segment=((position_in_gradient<<3)/Gradient_total_range)&7; // On peut ensuite terminer le calcul de l'indice dans le dgrad position_in_gradient/=Gradient_total_range; // On va pouvoir discuter de la valeur de position_in_gradient en fonction // de la position dans l'cran et de la position_in_segment. switch (position_in_segment) { case 0 : // On est sur l'extrme gauche du segment if (((x_pos+y_pos)&1)==0) position_in_gradient--; break; case 1 : // On est sur la gauche du segment case 2 : // On est sur la gauche du segment if (((x_pos & 1)==0) && ((y_pos & 1)==0)) position_in_gradient--; break; // On n'a pas traiter les cas 3 et 4 car ils reprsentent des valeurs // suffisament au centre du segment pour ne pas avoir subir la trame case 5 : // On est sur la droite du segment case 6 : // On est sur la droite du segment if (((x_pos & 1)==0) && ((y_pos & 1)!=0)) position_in_gradient++; break; case 7 : // On est sur l'extreme droite du segment if (((x_pos+y_pos)&1)!=0) // Note: on doit faire le test inverse au cas gauche pour synchroniser les 2 cts de la trame. position_in_gradient++; } // On va vrifier que nos petites idioties n'ont pas ject la valeur hors // des valeurs autorises par le dgrad dfini par l'utilisateur. if (position_in_gradient<0) position_in_gradient=0; else if (position_in_gradient>=Gradient_bounds_range) position_in_gradient=Gradient_bounds_range-1; // On ramne ensuite la position dans le dgrad vers un numro de couleur if (Gradient_is_inverted) position_in_gradient=Gradient_upper_bound-position_in_gradient; else position_in_gradient=Gradient_lower_bound+position_in_gradient; Gradient_pixel(x_pos,y_pos,position_in_gradient); } // -- Tracer un cercle degrad (une sphre) -- void Draw_grad_circle(short center_x,short center_y,short radius,short spot_x,short spot_y) { long start_x; long start_y; long x_pos; long y_pos; long end_x; long end_y; long distance_x; // Distance (au carr) sur les X du point en cours au centre d'clairage long distance_y; // Distance (au carr) sur les Y du point en cours au centre d'clairage start_x=center_x-radius; start_y=center_y-radius; end_x=center_x+radius; end_y=center_y+radius; // Correction des bornes d'aprs les limites if (start_yLimit_bottom) end_y=Limit_bottom; if (start_xLimit_right) end_x=Limit_right; Gradient_total_range=Circle_limit+ ((center_x-spot_x)*(center_x-spot_x))+ ((center_y-spot_y)*(center_y-spot_y))+ (2L*radius*sqrt( ((center_x-spot_x)*(center_x-spot_x))+ ((center_y-spot_y)*(center_y-spot_y)))); if (Gradient_total_range==0) Gradient_total_range=1; // Affichage du cercle for (y_pos=start_y,Circle_cursor_Y=(long)start_y-center_y;y_pos<=end_y;y_pos++,Circle_cursor_Y++) { distance_y =(y_pos-spot_y); distance_y*=distance_y; for (x_pos=start_x,Circle_cursor_X=(long)start_x-center_x;x_pos<=end_x;x_pos++,Circle_cursor_X++) if (Pixel_in_circle()) { distance_x =(x_pos-spot_x); distance_x*=distance_x; Gradient_function(distance_x+distance_y,x_pos,y_pos); } } Update_part_of_screen(center_x-radius,center_y-radius,2*radius+1,2*radius+1); } // -- Tracer une ellipse degrade -- void Draw_grad_ellipse(short center_x,short center_y,short horizontal_radius,short vertical_radius,short spot_x,short spot_y) { long start_x; long start_y; long x_pos; long y_pos; long end_x; long end_y; long distance_x; // Distance (au carr) sur les X du point en cours au centre d'clairage long distance_y; // Distance (au carr) sur les Y du point en cours au centre d'clairage start_x=center_x-horizontal_radius; start_y=center_y-vertical_radius; end_x=center_x+horizontal_radius; end_y=center_y+vertical_radius; // Calcul des limites de l'ellipse Ellipse_compute_limites(horizontal_radius+1,vertical_radius+1); // On calcule la distance maximale: Gradient_total_range=(horizontal_radius*horizontal_radius)+ (vertical_radius*vertical_radius)+ ((center_x-spot_x)*(center_x-spot_x))+ ((center_y-spot_y)*(center_y-spot_y))+ (2L *sqrt( (horizontal_radius*horizontal_radius)+ (vertical_radius *vertical_radius )) *sqrt( ((center_x-spot_x)*(center_x-spot_x))+ ((center_y-spot_y)*(center_y-spot_y)))); if (Gradient_total_range==0) Gradient_total_range=1; // Correction des bornes d'aprs les limites if (start_yLimit_bottom) end_y=Limit_bottom; if (start_xLimit_right) end_x=Limit_right; // Affichage de l'ellipse for (y_pos=start_y,Ellipse_cursor_Y=start_y-center_y;y_pos<=end_y;y_pos++,Ellipse_cursor_Y++) { distance_y =(y_pos-spot_y); distance_y*=distance_y; for (x_pos=start_x,Ellipse_cursor_X=start_x-center_x;x_pos<=end_x;x_pos++,Ellipse_cursor_X++) if (Pixel_in_ellipse()) { distance_x =(x_pos-spot_x); distance_x*=distance_x; Gradient_function(distance_x+distance_y,x_pos,y_pos); } } Update_part_of_screen(start_x,start_y,end_x-start_x+1,end_y-start_y+1); } // Trac d'un rectangle (rax ray - rbx rby) dgrad selon le vecteur (vax vay - vbx - vby) void Draw_grad_rectangle(short rax,short ray,short rbx,short rby,short vax,short vay, short vbx, short vby) { short y_pos, x_pos; // On commence par s'assurer que le rectangle est l'endroit if(rbx < rax) { x_pos = rbx; rbx = rax; rax = x_pos; } if(rby < ray) { y_pos = rby; rby = ray; ray = y_pos; } // Correction des bornes d'aprs les limites if (rayLimit_bottom) rby=Limit_bottom; if (raxLimit_right) rbx=Limit_right; if(vbx == vax) { // Le vecteur est vertical, donc on vite la partie en dessous qui foirerait avec une division par 0... if (vby == vay) return; // L'utilisateur fait n'importe quoi Gradient_total_range = abs(vby - vay); for(y_pos=ray;y_pos<=rby;y_pos++) for(x_pos=rax;x_pos<=rbx;x_pos++) Gradient_function(abs(vby - y_pos),x_pos,y_pos); } else { float a; float b; float distance_x, distance_y; Gradient_total_range = sqrt(pow(vby - vay,2)+pow(vbx - vax,2)); a = (float)(vby - vay)/(float)(vbx - vax); b = vay - a*vax; for (y_pos=ray;y_pos<=rby;y_pos++) for (x_pos = rax;x_pos<=rbx;x_pos++) { // On calcule ou on en est dans le dgrad distance_x = pow((y_pos - vay),2)+pow((x_pos - vax),2); distance_y = pow((-a * x_pos + y_pos - b),2)/(a*a+1); Gradient_function((int)sqrt(distance_x - distance_y),x_pos,y_pos); } } Update_part_of_screen(rax,ray,rbx,rby); } // -- Tracer un polygne plein -- typedef struct T_Polygon_edge /* an active edge */ { short top; /* top y position */ short bottom; /* bottom y position */ float x, dx; /* floating point x position and gradient */ float w; /* width of line segment */ struct T_Polygon_edge *prev; /* doubly linked list */ struct T_Polygon_edge *next; } T_Polygon_edge; /* Fill_edge_structure: * Polygon helper function: initialises an edge structure for the 2d * rasteriser. */ void Fill_edge_structure(T_Polygon_edge *edge, short *i1, short *i2) { short *it; if (i2[1] < i1[1]) { it = i1; i1 = i2; i2 = it; } edge->top = i1[1]; edge->bottom = i2[1] - 1; edge->dx = ((float) i2[0] - (float) i1[0]) / ((float) i2[1] - (float) i1[1]); edge->x = i1[0] + 0.4999999; edge->prev = NULL; edge->next = NULL; if (edge->dx+1 < 0.0) edge->x += edge->dx+1; if (edge->dx >= 0.0) edge->w = edge->dx; else edge->w = -(edge->dx); if (edge->w-1.0<0.0) edge->w = 0.0; else edge->w = edge->w-1; } /* Add_edge: * Adds an edge structure to a linked list, returning the new head pointer. */ T_Polygon_edge * Add_edge(T_Polygon_edge *list, T_Polygon_edge *edge, int sort_by_x) { T_Polygon_edge *pos = list; T_Polygon_edge *prev = NULL; if (sort_by_x) { while ( (pos) && ((pos->x+((pos->w+pos->dx)/2)) < (edge->x+((edge->w+edge->dx)/2))) ) { prev = pos; pos = pos->next; } } else { while ((pos) && (pos->top < edge->top)) { prev = pos; pos = pos->next; } } edge->next = pos; edge->prev = prev; if (pos) pos->prev = edge; if (prev) { prev->next = edge; return list; } else return edge; } /* Remove_edge: * Removes an edge structure from a list, returning the new head pointer. */ T_Polygon_edge * Remove_edge(T_Polygon_edge *list, T_Polygon_edge *edge) { if (edge->next) edge->next->prev = edge->prev; if (edge->prev) { edge->prev->next = edge->next; return list; } else return edge->next; } /* polygon: * Draws a filled polygon with an arbitrary number of corners. Pass the * number of vertices, then an array containing a series of x, y points * (a total of vertices*2 values). */ void Polyfill_general(int vertices, short * points, int color) { short c; short top; short bottom; short *i1, *i2; short x_pos,end_x; T_Polygon_edge *edge, *next_edge, *initial_edge; T_Polygon_edge *active_edges = NULL; T_Polygon_edge *inactive_edges = NULL; if (vertices < 1) return; top = bottom = points[1]; /* allocate some space and fill the edge table */ initial_edge=edge=(T_Polygon_edge *) malloc(sizeof(T_Polygon_edge) * vertices); i1 = points; i2 = points + ((vertices-1)<<1); for (c=0; cbottom >= edge->top) { if (edge->top < top) top = edge->top; if (edge->bottom > bottom) bottom = edge->bottom; inactive_edges = Add_edge(inactive_edges, edge, 0); edge++; } } i2 = i1; i1 += 2; } /* for each scanline in the polygon... */ for (c=top; c<=bottom; c++) { /* check for newly active edges */ edge = inactive_edges; while ((edge) && (edge->top == c)) { next_edge = edge->next; inactive_edges = Remove_edge(inactive_edges, edge); active_edges = Add_edge(active_edges, edge, 1); edge = next_edge; } /* draw horizontal line segments */ if ((c>=Limit_top) && (c<=Limit_bottom)) { edge = active_edges; while ((edge) && (edge->next)) { x_pos=/*Round*/(edge->x); end_x=/*Round*/(edge->next->x+edge->next->w); if (x_posLimit_right) end_x=Limit_right; for (; x_pos<=end_x; x_pos++) Pixel_figure(x_pos,c,color); edge = edge->next->next; } } /* update edges, sorting and removing dead ones */ edge = active_edges; while (edge) { next_edge = edge->next; if (c >= edge->bottom) active_edges = Remove_edge(active_edges, edge); else { edge->x += edge->dx; while ((edge->prev) && ( (edge->x+(edge->w/2)) < (edge->prev->x+(edge->prev->w/2))) ) { if (edge->next) edge->next->prev = edge->prev; edge->prev->next = edge->next; edge->next = edge->prev; edge->prev = edge->prev->prev; edge->next->prev = edge; if (edge->prev) edge->prev->next = edge; else active_edges = edge; } } edge = next_edge; } } free(initial_edge); initial_edge = NULL; // On ne connait pas simplement les xmin et xmax ici, mais de toutes faon ce n'est pas utilis en preview Update_part_of_screen(0,top,Main_image_width,bottom-top+1); } void Polyfill(int vertices, short * points, int color) { int index; Pixel_clipped(points[0],points[1],color); if (vertices==1) { Update_part_of_screen(points[0],points[1],1,1); return; } // Comme pour le Fill, cette operation fait un peu d'"overdraw" // (pixels dessins plus d'une fois) alors on force le FX Feedback OFF Update_FX_feedback(0); Pixel_figure=Pixel_clipped; Polyfill_general(vertices,points,color); // Remarque: pour dessiner la bordure avec la brosse en cours au lieu // d'un pixel de couleur premier-plan, il suffit de mettre ici: // Pixel_figure=Pixel_figure_permanent; // Dessin du contour for (index=0; index255)) index++; // On note la position de la premire case de la squence first=index; // On recherche la position de la dernire case de la squence for (last=first;list[last+1]<256;last++); // Pour toutes les cases non vides (et non inhibes) qui suivent switch (mode) { case SHADE_MODE_NORMAL : for (;(index<512) && (list[index]<256);index++) { // On met jour les tables de conversion color=list[index]; table_inc[color]=list[(index+step<=last)?index+step:last]; table_dec[color]=list[(index-step>=first)?index-step:first]; } break; case SHADE_MODE_LOOP : temp=1+last-first; for (;(index<512) && (list[index]<256);index++) { // On met jour les tables de conversion color=list[index]; table_inc[color]=list[first+((step+index-first)%temp)]; table_dec[color]=list[first+(((temp-step)+index-first)%temp)]; } break; default : // SHADE_MODE_NOSAT for (;(index<512) && (list[index]<256);index++) { // On met jour les tables de conversion color=list[index]; if (index+step<=last) table_inc[color]=list[index+step]; if (index-step>=first) table_dec[color]=list[index-step]; } } } } // -- Interface avec l'image, affecte par le facteur de grossissement ------- // fonction d'affichage "Pixel" utilise pour les oprations dfinitivement // Ne doit aucune condition tre appele en dehors de la partie visible // de l'image dans l'cran (a pourrait tre grave) void Display_pixel(word x,word y,byte color) // x & y sont la position d'un point dans l'IMAGE // color est la couleur du point // Le Stencil est gr. // Les effets sont grs par appel Effect_function(). // La Loupe est gre par appel Pixel_preview(). { if ( ( (!Sieve_mode) || (Effect_sieve(x,y)) ) && (!((Stencil_mode) && (Stencil[Read_pixel_from_current_layer(x,y)]))) && (!((Mask_mode) && (Mask_table[Read_pixel_from_spare_screen(x,y)]))) ) { color=Effect_function(x,y,color); if (Main_tilemap_mode) { Tilemap_draw(x,y, color); } else Pixel_in_current_screen_with_preview(x,y,color); } } // -- Calcul des diffrents effets ------------------------------------------- // -- Aucun effet en cours -- byte No_effect(word x, word y, byte color) { (void)x; // unused (void)y; // unused return color; } // -- Effet de Shading -- byte Effect_shade(word x,word y,byte color) { (void)color; // unused return Shade_table[Read_pixel_from_feedback_screen(x,y)]; } byte Effect_quick_shade(word x,word y,byte color) { int c=color=Read_pixel_from_feedback_screen(x,y); int direction=(Fore_color<=Back_color); byte start,end; int width; if (direction) { start=Fore_color; end =Back_color; } else { start=Back_color; end =Fore_color; } if ((c>=start) && (c<=end) && (start!=end)) { width=1+end-start; if ( ((Shade_table==Shade_table_left) && direction) || ((Shade_table==Shade_table_right) && (!direction)) ) c-=Quick_shade_step%width; else c+=Quick_shade_step%width; if (cend) switch (Quick_shade_loop) { case SHADE_MODE_NORMAL : return end; case SHADE_MODE_LOOP : return (c-width); default : return color; } } return c; } // -- Effet de Tiling -- byte Effect_tiling(word x,word y,byte color) { (void)color; // unused return Read_pixel_from_brush((x+Brush_width-Tiling_offset_X)%Brush_width, (y+Brush_height-Tiling_offset_Y)%Brush_height); } // -- Effet de Smooth -- byte Effect_smooth(word x,word y,byte color) { int r,g,b; byte c; int weight,total_weight; byte x2=((x+1)Pages->Nb_layers) { return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[color].Pixels); } return Read_pixel_from_feedback_screen(x,y); } void Horizontal_grid_line(word x_pos,word y_pos,word width) { int x; for (x=!(x_pos&1);xPages->Image_mode == IMAGE_MODE_ANIMATION) { return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer].Pixels); } if (Main_backups->Pages->Image_mode == IMAGE_MODE_MODE5) if (Main_current_layer==4) return *(Main_backups->Pages->Image[Main_current_layer].Pixels + x+y*Main_image_width); color = *(Main_screen+y*Main_image_width+x); if (color != Main_backups->Pages->Transparent_color) // transparent color return color; depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width); return *(Main_backups->Pages->Image[depth].Pixels + x+y*Main_image_width); } /// Paint a a single pixel in image only : as-is. void Pixel_in_screen_direct(word x,word y,byte color) { *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer].Pixels)=color; } /// Paint a a single pixel in image and on screen: as-is. void Pixel_in_screen_direct_with_preview(word x,word y,byte color) { *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer].Pixels)=color; Pixel_preview(x,y,color); } /// Paint a a single pixel in image only : using layered display. void Pixel_in_screen_layered(word x,word y,byte color) { byte depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width); *(Main_backups->Pages->Image[Main_current_layer].Pixels + x+y*Main_image_width)=color; if ( depth <= Main_current_layer) { if (color == Main_backups->Pages->Transparent_color) // transparent color // fetch pixel color from the topmost visible layer color=*(Main_backups->Pages->Image[depth].Pixels + x+y*Main_image_width); *(x+y*Main_image_width+Main_screen)=color; } } /// Paint a a single pixel in image and on screen : using layered display. void Pixel_in_screen_layered_with_preview(word x,word y,byte color) { byte depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width); *(Main_backups->Pages->Image[Main_current_layer].Pixels + x+y*Main_image_width)=color; if ( depth <= Main_current_layer) { if (color == Main_backups->Pages->Transparent_color) // transparent color // fetch pixel color from the topmost visible layer color=*(Main_backups->Pages->Image[depth].Pixels + x+y*Main_image_width); *(x+y*Main_image_width+Main_screen)=color; Pixel_preview(x,y,color); } } void Pixel_in_screen_egx(word x,word y,byte color) { uint8_t mask; if (Main_backups->Pages->Image_mode == IMAGE_MODE_EGX) { mask = 0xF3; } else { mask = 0xFD; } if (y & 1) { Pixel_in_screen_layered(x & ~1,y,color); Pixel_in_screen_layered(x | 1,y,color); } else Pixel_in_screen_layered(x,y,color & mask); } void Pixel_in_screen_egx_with_preview(word x,word y,byte color) { uint8_t mask; if (Main_backups->Pages->Image_mode == IMAGE_MODE_EGX) { mask = 0xF3; } else { mask = 0xFD; } if (y & 1) { Pixel_in_screen_layered_with_preview(x & ~1,y,color); Pixel_in_screen_layered_with_preview(x | 1,y,color); } else Pixel_in_screen_layered_with_preview(x,y,color & mask); } void Pixel_in_screen_thomson(word x,word y,byte color) { word start = x & 0xFFF8; word x2; uint8_t c1, c2; // The color we are going to replace c1 = *(Main_backups->Pages->Image[Main_current_layer].Pixels + x+y*Main_image_width); if (c1 == color) return; for (x2 = 0; x2 < 8; x2++) { c2 = *(Main_backups->Pages->Image[Main_current_layer].Pixels + (x2+start)+y*Main_image_width); if (c2 == color) continue; if (c2 != c1) break; } if (c2 == c1 || c2 == color) { // There was only one color, so we can add a second one. Pixel_in_screen_layered(x,y,color); return; } for (x2 = 0; x2 < 8; x2++) { c2 = *(Main_backups->Pages->Image[Main_current_layer].Pixels + (x2+start)+y*Main_image_width); if (c2 == c1) { Pixel_in_screen_layered(x2+start,y,color); } } } void Pixel_in_screen_thomson_with_preview(word x,word y,byte color) { word start = x & 0xFFF8; word x2; uint8_t c1, c2; // The color we are going to replace c1 = *(Main_backups->Pages->Image[Main_current_layer].Pixels + x+y*Main_image_width); if (c1 == color) return; for (x2 = 0; x2 < 8; x2++) { c2 = *(Main_backups->Pages->Image[Main_current_layer].Pixels + (x2+start)+y*Main_image_width); if (c2 == color) continue; if (c2 != c1) break; } if (c2 == c1 || c2 == color) { // There was only one color, so we can add a second one. Pixel_in_screen_layered_with_preview(x,y,color); return; } for (x2 = 0; x2 < 8; x2++) { c2 = *(Main_backups->Pages->Image[Main_current_layer].Pixels + (x2+start)+y*Main_image_width); if (c2 == c1) { Pixel_in_screen_layered_with_preview(x2+start,y,color); } } } void Pixel_in_screen_zx(word x,word y,byte color) { word start = x & 0xFFF8; word starty = y & 0xFFF8; word x2, y2; uint8_t c1, c2; // The color we are going to replace c1 = *(Main_backups->Pages->Image[Main_current_layer].Pixels + x + y * Main_image_width); if (c1 == color) return; // find if there is another color in the cell for (x2 = 0; x2 < 8; x2++) for (y2 = 0; y2 < 8; y2++) { c2 = *(Main_backups->Pages->Image[Main_current_layer].Pixels + (x2 + start) + (y2 + starty) * Main_image_width); // Pixel is already of the color we are going to add, it is no problem if (c2 == color) continue; // We have found another color, which is the one we will keep from the cell if (c2 != c1) goto done; } done: if ((c2 == c1 || c2 == color)) { // There was only one color, so we can add a second one // First make sure we have a single brightness if ((c2 & 8) != (color & 8)) { for (x2 = 0; x2 < 8; x2++) for (y2 = 0; y2 < 8; y2++) { Pixel_in_screen_layered(x2+start,y2+starty,c2 ^ 8); } } Pixel_in_screen_layered(x,y,color); return; } // Now replace all pixels which are of color c1, with color c2 for (x2 = 0; x2 < 8; x2++) for (y2 = 0; y2 < 8; y2++) { c2 = *(Main_backups->Pages->Image[Main_current_layer].Pixels + (x2 + start) + (y2 + starty) * Main_image_width); if (c2 == c1) { Pixel_in_screen_layered(x2+start,y2+starty,color); } else { // Force the brightness bit Pixel_in_screen_layered(x2+start,y2+starty,(c2 & ~8) | (color & 8)); } } } void Pixel_in_screen_zx_with_preview(word x,word y,byte color) { word start = x & 0xFFF8; word starty = y & 0xFFF8; word x2,y2; uint8_t c1, c2; // The color we are going to replace c1 = *(Main_backups->Pages->Image[Main_current_layer].Pixels + x + y * Main_image_width); // Pixel is already of the wanted color: nothing to do if (c1 == color) return; // Check the whole cell for (x2 = 0; x2 < 8; x2++) for (y2 = 0; y2 < 8; y2++) { c2 = *(Main_backups->Pages->Image[Main_current_layer].Pixels + (x2 + start) + (y2 + starty) * Main_image_width); // Pixel is already of the color we are going to add, it is no problem if (c2 == color) continue; // We have found another color, which is the one we will keep from the cell if (c2 != c1) goto done; } done: if ((c2 == c1 || c2 == color)) { // There was only one color, so we can add a second one // First make sure we have a single brightness if ((c2 & 8) != (color & 8)) { for (x2 = 0; x2 < 8; x2++) for (y2 = 0; y2 < 8; y2++) { Pixel_in_screen_layered_with_preview(x2+start,y2+starty,c2 ^ 8); } } Pixel_in_screen_layered_with_preview(x,y,color); return; } // Replace all C1 with color for (x2 = 0; x2 < 8; x2++) for (y2 = 0; y2 < 8; y2++) { c2 = *(Main_backups->Pages->Image[Main_current_layer].Pixels + (x2 + start) + (y2 + starty) * Main_image_width); if (c2 == c1) { Pixel_in_screen_layered_with_preview(x2+start,y2+starty,color); } else { // Force the brightness bit Pixel_in_screen_layered_with_preview(x2+start,y2+starty,(c2 & ~8) | (color & 8)); } } } /// Paint a a single pixel in image only : in a layer under one that acts as a layer-selector (mode 5). void Pixel_in_screen_underlay(word x,word y,byte color) { byte depth; // Paste in layer *(Main_backups->Pages->Image[Main_current_layer].Pixels + x+y*Main_image_width)=color; // Search depth depth = *(Main_backups->Pages->Image[4].Pixels + x+y*Main_image_width); if ( depth == Main_current_layer) { // Draw that color on the visible image buffer *(x+y*Main_image_width+Main_screen)=color; } } /// Paint a a single pixel in image and on screen : in a layer under one that acts as a layer-selector (mode 5). void Pixel_in_screen_underlay_with_preview(word x,word y,byte color) { byte depth; // Paste in layer *(Main_backups->Pages->Image[Main_current_layer].Pixels + x+y*Main_image_width)=color; // Search depth depth = *(Main_backups->Pages->Image[4].Pixels + x+y*Main_image_width); if ( depth == Main_current_layer) { // Draw that color on the visible image buffer *(x+y*Main_image_width+Main_screen)=color; Pixel_preview(x,y,color); } } /// Paint a a single pixel in image only : in a layer that acts as a layer-selector (mode 5). void Pixel_in_screen_overlay(word x,word y,byte color) { if (color<4) { // Paste in layer *(Main_backups->Pages->Image[Main_current_layer].Pixels + x+y*Main_image_width)=color; // Paste in depth buffer *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width)=color; // Fetch pixel color from the target raster layer if (Main_layers_visible & (1 << color)) color=*(Main_backups->Pages->Image[color].Pixels + x+y*Main_image_width); // Draw that color on the visible image buffer *(x+y*Main_image_width+Main_screen)=color; } } /// Paint a a single pixel in image and on screen : in a layer that acts as a layer-selector (mode 5). void Pixel_in_screen_overlay_with_preview(word x,word y,byte color) { if (color<4) { // Paste in layer *(Main_backups->Pages->Image[Main_current_layer].Pixels + x+y*Main_image_width)=color; // Paste in depth buffer *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width)=color; // Fetch pixel color from the target raster layer if (Main_layers_visible & (1 << color)) color=*(Main_backups->Pages->Image[color].Pixels + x+y*Main_image_width); // Draw that color on the visible image buffer *(x+y*Main_image_width+Main_screen)=color; Pixel_preview(x,y,color); } } Func_pixel Pixel_in_current_screen=Pixel_in_screen_direct; Func_pixel Pixel_in_current_screen_with_preview=Pixel_in_screen_direct_with_preview; void Pixel_in_spare(word x,word y, byte color) { *((y)*Spare_image_width+(x)+Spare_backups->Pages->Image[Spare_current_layer].Pixels)=color; } void Pixel_in_current_layer(word x,word y, byte color) { *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer].Pixels)=color; } byte Read_pixel_from_current_layer(word x,word y) { return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer].Pixels); } void Update_pixel_renderer(void) { if (Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION) { // direct Pixel_in_current_screen = Pixel_in_screen_direct; Pixel_in_current_screen_with_preview = Pixel_in_screen_direct_with_preview; } else if (Main_backups->Pages->Image_mode == IMAGE_MODE_LAYERED) { // layered Pixel_in_current_screen = Pixel_in_screen_layered; Pixel_in_current_screen_with_preview = Pixel_in_screen_layered_with_preview; } else if (Main_backups->Pages->Image_mode == IMAGE_MODE_EGX || Main_backups->Pages->Image_mode == IMAGE_MODE_EGX2) { // special "EGX" mode Pixel_in_current_screen = Pixel_in_screen_egx; Pixel_in_current_screen_with_preview = Pixel_in_screen_egx_with_preview; } else if (Main_backups->Pages->Image_mode == IMAGE_MODE_THOMSON) { Pixel_in_current_screen = Pixel_in_screen_thomson; Pixel_in_current_screen_with_preview = Pixel_in_screen_thomson_with_preview; } else if (Main_backups->Pages->Image_mode == IMAGE_MODE_ZX) { Pixel_in_current_screen = Pixel_in_screen_zx; Pixel_in_current_screen_with_preview = Pixel_in_screen_zx_with_preview; } // Implicit else : Image_mode must be IMAGE_MODE_MODE5 else if ( Main_current_layer == 4) { // overlay Pixel_in_current_screen = Pixel_in_screen_overlay; Pixel_in_current_screen_with_preview = Pixel_in_screen_overlay_with_preview; } else if (Main_current_layer<4 && (Main_layers_visible & (1<<4))) { // underlay Pixel_in_current_screen = Pixel_in_screen_underlay; Pixel_in_current_screen_with_preview = Pixel_in_screen_underlay_with_preview; } else { // layered (again, for layers > 4 in MODE5) Pixel_in_current_screen = Pixel_in_screen_layered; Pixel_in_current_screen_with_preview = Pixel_in_screen_layered_with_preview; } } grafx2_2.4+git20180105/src/sdlscreen.h0000664000000000000000000000555113223665307015671 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file sdlscreen.h /// Screen update (refresh) system, and some SDL-specific graphic functions. ////////////////////////////////////////////////////////////////////////////// #ifndef SDLSCREEN_H_INCLUDED #define SDLSCREEN_H_INCLUDED #include #include "struct.h" /// /// This is the number of bytes in a video line for the current mode. /// On many platforms it will be the video mode's width (in pixels), rounded up /// to be a multiple of 4. #define VIDEO_LINE_WIDTH (Screen_SDL->pitch) void Set_mode_SDL(int *,int *,int); SDL_Rect ** List_SDL_video_modes; byte* Screen_pixels; void Update_rect(short x, short y, unsigned short width, unsigned short height); void Flush_update(void); void Update_status_line(short char_pos, short width); /// /// Converts a SDL_Surface (indexed colors or RGB) into an array of bytes /// (indexed colors). /// If dest is NULL, it's allocated by malloc(). Otherwise, be sure to /// pass a buffer of the right dimensions. byte * Surface_to_bytefield(SDL_Surface *source, byte * dest); /// Gets the RGB 24-bit color currently associated with a palette index. SDL_Color Color_to_SDL_color(byte); /// Reads a pixel in a 8-bit SDL surface. byte Get_SDL_pixel_8(SDL_Surface *bmp, int x, int y); /// Reads a pixel in a multi-byte SDL surface. dword Get_SDL_pixel_hicolor(SDL_Surface *bmp, int x, int y); /// Writes a pixel in a 8-bit SDL surface. void Set_SDL_pixel_8(SDL_Surface *bmp, int x, int y, byte color); /// Convert a SDL Palette to a grafx2 palette void Get_SDL_Palette(const SDL_Palette * sdl_palette, T_Palette palette); /// /// Clears the parts of screen that are outside of the editing area. /// There is such area only if the screen mode is not a multiple of the pixel /// size, eg: 3x3 pixels in 1024x768 leaves 1 column on the right, 0 rows on bottom. void Clear_border(byte color); extern volatile int Allow_colorcycling; /// Activates or desactivates file drag-dropping in program window. void Allow_drag_and_drop(int flag); #endif // SDLSCREEN_H_INCLUDED grafx2_2.4+git20180105/src/loadsave.h0000664000000000000000000002145113223665306015501 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file loadsave.h /// Saving and loading different picture formats. /// Also handles showing the preview in fileselectors. ////////////////////////////////////////////////////////////////////////////// #ifndef __LOADSAVE_H__ #define __LOADSAVE_H__ #include #include enum CONTEXT_TYPE { CONTEXT_MAIN_IMAGE, CONTEXT_BRUSH, CONTEXT_PREVIEW, CONTEXT_SURFACE, CONTEXT_PALETTE }; /// Data for a cycling color series. Heavily cloned from T_Gradient_array. typedef struct { byte Start; ///< First color byte End; ///< Last color byte Inverse; ///< Boolean, true if the gradient goes in descending order byte Speed; ///< Frequency of cycling, from 1 (slow) to 64 (fast) } T_Color_cycle; typedef struct { /// Kind of context. Internally used to differentiate the "sub-classes" enum CONTEXT_TYPE Type; // File properties char * File_name; char * File_directory; byte Format; // Image properties T_Palette Palette; short Width; short Height; int Nb_layers; char Comment[COMMENT_SIZE+1]; byte Background_transparent; byte Transparent_color; /// Pixel ratio of the image enum PIXEL_RATIO Ratio; /// Load/save address of first pixel byte *Target_address; /// Pitch: Difference of addresses between one pixel and the one just "below" it long Pitch; /// Original file name, stored in GIF file char * Original_file_name; /// Original file directory, stored in GIF file char * Original_file_directory; byte Color_cycles; T_Color_cycle Cycle_range[16]; /// Internal: during load, marks which layer is being loaded. int Current_layer; /// Internal: Used to mark truecolor images on loading. Only used by preview. //byte Is_truecolor; /// Internal: Temporary RGB buffer when loading 24bit images T_Components *Buffer_image_24b; /// Internal: Temporary buffer when saving the flattened copy of something byte *Buffer_image; // Internal: working data for preview case short Preview_factor_X; short Preview_factor_Y; short Preview_pos_X; short Preview_pos_Y; byte *Preview_bitmap; byte Preview_usage[256]; // Internal: returned surface for SDL_Surface case SDL_Surface * Surface; } T_IO_Context; #define PREVIEW_WIDTH 120 #define PREVIEW_HEIGHT 80 /// Type of a function that can be called for a T_IO_Context. Kind of a method. typedef void (* Func_IO) (T_IO_Context *); /* void Pixel_load_in_current_screen (word x_pos, word y_pos, byte color); void Pixel_load_in_preview (word x_pos, word y_pos, byte color); void Pixel_load_in_brush (word x_pos, word y_pos, byte color); */ // Setup for loading a preview in fileselector void Init_context_preview(T_IO_Context * context, char *file_name, char *file_directory); // Setup for loading/saving the current main image void Init_context_layered_image(T_IO_Context * context, char *file_name, char *file_directory); // Setup for loading/saving an intermediate backup void Init_context_backup_image(T_IO_Context * context, char *file_name, char *file_directory); // Setup for loading/saving the flattened version of current main image void Init_context_flat_image(T_IO_Context * context, char *file_name, char *file_directory); // Setup for loading/saving the user's brush void Init_context_brush(T_IO_Context * context, char *file_name, char *file_directory); // Setup for saving an arbitrary undo/redo step, from either the main or spare page. void Init_context_history_step(T_IO_Context * context, T_Page *page); // Setup for loading an image into a new SDL surface. void Init_context_surface(T_IO_Context * context, char *file_name, char *file_directory); // Cleans up resources (currently: the 24bit buffer) void Destroy_context(T_IO_Context *context); /// /// High-level picture loading function. void Load_image(T_IO_Context *context); /// /// High-level picture saving function. void Save_image(T_IO_Context *context); /// /// Checks if there are any pending safety backups, and then opens them. /// Returns 0 if there were none /// Returns non-zero if some backups were loaded. int Check_recovery(void); /// Makes a safety backup periodically. void Rotate_safety_backups(void); /// Remove safety backups. Need to call on normal program exit. void Delete_safety_backups(void); /// Data for an image file format. typedef struct { byte Identifier; ///< Identifier for this format in enum :FILE_FORMATS char *Label; ///< Five-letter label Func_IO Test; ///< Function which tests if the file is of this format Func_IO Load; ///< Function which loads an image of this format Func_IO Save; ///< Function which saves an image of this format byte Palette_only; ///< Boolean, true if this format saves/loads only the palette. byte Comment; ///< This file format allows a text comment byte Supports_layers; ///< Boolean, true if this format preserves layers on saving char *Default_extension; ///< Default file extension char *Extensions; ///< List of semicolon-separated file extensions } T_Format; /// Array of the known file formats extern T_Format File_formats[]; /// /// Function which attempts to save backups of the images (main and spare), /// called in case of SIGSEGV. /// It will save an image only if it has just one layer... otherwise, /// the risk of flattening a layered image (or saving just one detail layer) /// is too high. void Image_emergency_backup(void); /// /// Load an arbitrary SDL_Surface. /// @param gradients Pass the address of a target T_Gradient_array if you want the gradients, NULL otherwise SDL_Surface * Load_surface(char *full_name, T_Gradient_array *gradients); /* /// Pixel ratio of last loaded image: one of :PIXEL_SIMPLE, :PIXEL_WIDE or :PIXEL_TALL extern enum PIXEL_RATIO Ratio_of_loaded_image; */ T_Format * Get_fileformat(byte format); // -- File formats /// Total number of known file formats unsigned int Nb_known_formats(void); // Internal use /// Generic allocation and similar stuff, done at beginning of image load, as soon as size is known. void Pre_load(T_IO_Context *context, short width, short height, long file_size, int format, enum PIXEL_RATIO ratio, byte truecolor); /// Fill the entire current layer/frame of an image being loaded with a color. void Fill_canvas(T_IO_Context *context, byte color); /// Query the color of a pixel (to save) byte Get_pixel(T_IO_Context *context, short x, short y); /// Set the color of a pixel (on load) void Set_pixel(T_IO_Context *context, short x, short y, byte c); /// Set the color of a 24bit pixel (on load) void Set_pixel_24b(T_IO_Context *context, short x, short y, byte r, byte g, byte b); /// Function to call when need to switch layers. void Set_loading_layer(T_IO_Context *context, int layer); /// Function to call when need to switch layers. void Set_saving_layer(T_IO_Context *context, int layer); /// Function to call when loading an image's duration void Set_frame_duration(T_IO_Context *context, int duration); /// Function to call to get an image's duration for saving int Get_frame_duration(T_IO_Context *context); // ================================================================= // What follows here are the definitions of functions and data // useful for fileformats.c, miscfileformats.c etc. // ================================================================= // This is here and not in fileformats.c because the emergency save uses it... typedef struct { byte Filler1[6]; word Width; word Height; byte Filler2[118]; T_Palette Palette; } T_IMG_Header; // Data for 24bit loading /* typedef void (* Func_24b_display) (short,short,byte,byte,byte); extern int Image_24b; extern T_Components * Buffer_image_24b; extern Func_24b_display Pixel_load_24b; void Init_preview_24b(short width,short height,long size,int format); void Pixel_load_in_24b_preview(short x_pos,short y_pos,byte r,byte g,byte b); */ // void Set_file_error(int value); /* void Init_preview(short width,short height,long size,int format,enum PIXEL_RATIO ratio); */ void Write_one_byte(FILE *file, byte b); #endif grafx2_2.4+git20180105/src/pxtall3.c0000664000000000000000000004321213223665306015264 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxtall3.h" #define ZOOMX 3 #define ZOOMY 4 void Pixel_tall3 (word x,word y,byte color) /* Affiche un pixel de la color aux coords x;y l'cran */ { *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 2)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 2)=color; } byte Read_pixel_tall3 (word x,word y) /* On retourne la couleur du pixel aux coords donnes */ { return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); } void Block_tall3 (word start_x,word start_y,word width,word height,byte color) /* On affiche un rectangle de la couleur donne */ { SDL_Rect rectangle; rectangle.x=start_x*ZOOMX; rectangle.y=start_y*ZOOMY; rectangle.w=width*ZOOMX; rectangle.h=height*ZOOMY; SDL_FillRect(Screen_SDL,&rectangle,color); } void Display_part_of_screen_tall3 (word width,word height,word image_width) /* Afficher une partie de l'image telle quelle sur l'cran */ { byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'cran (dest) byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de dpart ds la source (src) int y; int dy; for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne for (dy=width;dy>0;dy--) { *(dest+2)=*(dest+1)=*dest=*src; src++; dest+=ZOOMX; } // On double la ligne qu'on vient de copier memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On la triple memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On la quadruple memcpy(dest-width*ZOOMX+3*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } //Update_rect(0,0,width,height); } void Pixel_preview_normal_tall3 (word x,word y,byte color) /* Affichage d'un pixel dans l'cran, par rapport au dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure Pixel_Preview_Loupe_SDL. */ { // if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) Pixel_tall3(x-Main_offset_X,y-Main_offset_Y,color); } void Pixel_preview_magnifier_tall3 (word x,word y,byte color) { // Affiche le pixel dans la partie non zoome Pixel_tall3(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) { // On est dedans int height; int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_tall3( Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, y_zoom, Main_magnifier_factor, height, color ); } } void Horizontal_XOR_line_tall3(word x_pos,word y_pos,word width) { //On calcule la valeur initiale de dest: byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; int x; for (x=0;x0;i--) { *(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*(dest)=xor_lut[*(dest)]; dest+=VIDEO_LINE_WIDTH*ZOOMY; } } void Display_brush_color_tall3(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = Brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+3*VIDEO_LINE_WIDTH+2) =*(dest+3*VIDEO_LINE_WIDTH+1) = *(dest+3*VIDEO_LINE_WIDTH) = *(dest+2*VIDEO_LINE_WIDTH+2) =*(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+2) =*(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+2) =*(dest+1) = *dest = *src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } Update_rect(x_pos,y_pos,width,height); } void Display_brush_mono_tall3(word x_pos, word y_pos, word x_offset, word y_offset, word width, word height, byte transp_color, byte color, word brush_width) /* On affiche la brosse en monochrome */ { byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination // l'cran byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds // la brosse int x,y; for(y=height;y!=0;y--) //Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { if (*src!=transp_color) *(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*(dest)=color; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=brush_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Clear_brush_tall3(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width) { byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'cran (dest) byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de dpart ds la source (src) int y; int x; (void)x_offset; // unused (void)y_offset; // unused (void)transp_color; // unused for(y=height;y!=0;y--) // Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { *(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*(dest)=*src; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } // Affiche une brosse (arbitraire) l'cran void Display_brush_tall3(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*(dest)=*src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } } void Remap_screen_tall3(word x_pos,word y_pos,word width,word height,byte * conversion_table) { // dest = coords a l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; int x,y; // Pour chaque ligne for(y=height;y>0;y--) { // Pour chaque pixel for(x=width;x>0;x--) { *(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*(dest)= conversion_table[*dest]; dest +=ZOOMX; } dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Display_line_on_screen_fast_tall3(word x_pos,word y_pos,word width,byte * line) /* On affiche toute une ligne de pixels telle quelle. */ /* Utilise si le buffer contient dja des pixel doubls. */ { memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+3)*VIDEO_LINE_WIDTH,line,width*ZOOMX); } void Display_line_on_screen_tall3(word x_pos,word y_pos,word width,byte * line) /* On affiche une ligne de pixels en les doublant. */ { int x; byte *dest; dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; for(x=width;x>0;x--) { *(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*(dest)=*line; dest+=ZOOMX; line++; } } void Display_transparent_mono_line_on_screen_tall3( word x_pos, word y_pos, word width, byte* line, byte transp_color, byte color) // Affiche une ligne l'cran avec une couleur + transparence. // Utilis par les brosses en mode zoom { byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; int x; // Pour chaque pixel for(x=0;x 0); src += image_width; } // ATTENTION on n'arrive jamais ici ! } // Affiche une partie de la brosse couleur zoome void Display_brush_color_zoom_tall3(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle de la brosse byte * buffer) { byte* src = Brush+y_offset*brush_width + x_offset; word y = y_pos; byte bx; // Pour chaque ligne while(1) { Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche facteur fois la ligne zoome for(bx=Main_magnifier_factor;bx>0;bx--) { byte* line_src = buffer; byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; word x; // Pour chaque pixel de la ligne for(x = width*Main_magnifier_factor;x > 0;x--) { if(*line_src!=transp_color) { *(dest+2)=*(dest+1)=*dest = *line_src; } line_src++; dest+=ZOOMX; } // Double the line memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); // Triple the line memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); // Quadruple it memcpy(Screen_pixels + (y*ZOOMY+3)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); y++; if(y==end_y_pos) { return; } } src += brush_width; } // ATTENTION zone jamais atteinte } void Display_brush_mono_zoom_tall3(word x_pos, word y_pos, word x_offset, word y_offset, word width, // width non zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle de la brosse byte * buffer ) { byte* src = Brush + y_offset * brush_width + x_offset; int y=y_pos*ZOOMY; //Pour chaque ligne zoomer : while(1) { int bx; // src = Ligne originale // On clate la ligne Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche la ligne Facteur fois l'cran (sur des // lignes conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome Display_transparent_mono_line_on_screen_tall3( x_pos, y, width * Main_magnifier_factor, buffer, transp_color, color ); // On passe la ligne suivante y++; // On vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); Update_rect( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); return; } bx --; } while (bx > 0); // Passage la ligne suivante dans la brosse aussi src+=brush_width; } } void Clear_brush_scaled_tall3(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer) { // En fait on va recopier l'image non zoome dans la partie zoome ! byte* src = Main_screen + y_offset * image_width + x_offset; int y = y_pos; int bx; (void)transp_color; // unused // Pour chaque ligne zoomer while(1){ Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); bx=Main_magnifier_factor; // Pour chaque ligne do{ // TODO a verifier Display_line_on_screen_fast_tall3(x_pos,y, width * Main_magnifier_factor,buffer); // Ligne suivante y++; if(y==end_y_pos) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); Update_rect(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); return; } bx--; }while(bx!=0); src+= image_width; } } grafx2_2.4+git20180105/src/helpfile.h0000664000000000000000000037653013223665306015506 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2009 Franck Charlet Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file helpfile.h /// This is all the text that appears in contextual help and credits. /// /// Note: The source code is kept on a public website, so keep this in mind /// if you're thinking of putting an e-mail address in there. At least, use /// "\100" instead of @, to help against the most basic email address harvesters. ////////////////////////////////////////////////////////////////////////////// #include "const.h" // Uses enumerations BUTTON_NUMBERS and SPECIAL_ACTIONS // Some magic formulas: #define HELP_TEXT(x) {'N', x, 0}, // Generates a 'N' line (Normal) #define HELP_LINK(x,y) {'K', x, y}, // Generates a 'K' line (Key) #define HELP_BOLD(x) {'S', x, 0}, // Generates a 'S' line (BOLD) #define HELP_TITLE(x) {'T', x, 0}, {'-', x, 0}, // Generates a 'T' line (Title, upper half) // and a second '-' line (Title, lower half), with the same text. static const T_Help_table helptable_about[] = /* Do not exceed 44 characters for normal lines: HELP_TEXT ("--------------------------------------------") Do not exceed 22 characters for title lines: HELP_TITLE("======================") */ { HELP_TEXT ("") // Leave enough room for a hard-coded logo, eventually. HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE(" GRAFX 2 ") HELP_BOLD (" \"Dragon's Layers\" Edition") HELP_BOLD (" THE ULTIMATE MULTI-RESOLUTION GFX EDITOR") HELP_TEXT (" http://grafx2.org") #if defined(__MINT__) HELP_TEXT (" atari build ") #else HELP_TEXT ("") #endif HELP_TEXT ("Copyright 2007-2016, the Grafx2 project team") HELP_TEXT (" Copyright 1996-2001, SUNSET DESIGN") }; static const T_Help_table helptable_licence[] = { HELP_TITLE(" LICENSE") HELP_TEXT ("") HELP_TEXT ("Grafx2 is FREE SOFTWARE, you can") HELP_TEXT ("redistribute it and/or modify it under the") HELP_TEXT ("terms of the GNU General Public License as") HELP_TEXT ("published by the Free Software Foundation;") HELP_TEXT ("version 2 of the License.") HELP_TEXT ("") HELP_TEXT ("Grafx2 is distributed in the hope that it") HELP_TEXT ("will be useful, but WITHOUT ANY WARRANTY;") HELP_TEXT ("without even the implied warranty of") HELP_TEXT ("MERCHANTABILITY or FITNESS FOR A PARTICULAR") HELP_TEXT ("PURPOSE. See the GNU General Public License") HELP_TEXT ("for more details.") HELP_TEXT ("") HELP_TEXT ("You should have received a copy of the GNU") HELP_TEXT ("General Public License along with Grafx2;") HELP_TEXT ("if not, see http://www.gnu.org/licenses/ or") HELP_TEXT ("write to the Free Software Foundation, Inc.") HELP_TEXT (" 59 Temple Place - Suite 330, Boston,") HELP_TEXT (" MA 02111-1307, USA.") }; static const T_Help_table helptable_help[] = { HELP_TITLE(" HELP") HELP_TEXT ("") HELP_TEXT (" Contextual help is available by pressing") HELP_LINK (" the %s key",0x100+BUTTON_HELP) HELP_TEXT (" You can do it while hovering a menu icon,") HELP_TEXT (" or while a window is open.") HELP_TEXT (" When a keyboard shortcut is displayed it's") HELP_TEXT (" your current configuration and you can") HELP_TEXT (" change it by clicking it.") HELP_TEXT ("") HELP_TITLE(" KEYBOARD SHORTCUTS") HELP_TEXT ("") HELP_TEXT ("Scroll visible area") HELP_LINK (" up: %s", SPECIAL_SCROLL_UP) HELP_LINK (" down: %s", SPECIAL_SCROLL_DOWN) HELP_LINK (" left: %s", SPECIAL_SCROLL_LEFT) HELP_LINK (" right: %s", SPECIAL_SCROLL_RIGHT) HELP_LINK (" up faster: %s", SPECIAL_SCROLL_UP_FAST) HELP_LINK (" down faster: %s", SPECIAL_SCROLL_DOWN_FAST) HELP_LINK (" left faster: %s", SPECIAL_SCROLL_LEFT_FAST) HELP_LINK (" right faster: %s", SPECIAL_SCROLL_RIGHT_FAST) HELP_LINK (" up slower: %s", SPECIAL_SCROLL_UP_SLOW) HELP_LINK (" down slower: %s", SPECIAL_SCROLL_DOWN_SLOW) HELP_LINK (" left slower: %s", SPECIAL_SCROLL_LEFT_SLOW) HELP_LINK (" right slower: %s", SPECIAL_SCROLL_RIGHT_SLOW) HELP_LINK ("Mouse pan: %s", SPECIAL_HOLD_PAN) HELP_TEXT ("Emulate mouse") HELP_LINK (" Up: %s", SPECIAL_MOUSE_UP) HELP_LINK (" Down: %s", SPECIAL_MOUSE_DOWN) HELP_LINK (" Left: %s", SPECIAL_MOUSE_LEFT) HELP_LINK (" Right: %s", SPECIAL_MOUSE_RIGHT) HELP_LINK (" Left click: %s", SPECIAL_CLICK_LEFT) HELP_LINK (" Right click: %s", SPECIAL_CLICK_RIGHT) HELP_LINK ("Show / Hide menu: %s", 0x100+BUTTON_HIDE) HELP_LINK ("Show / Hide cursor: %s", SPECIAL_SHOW_HIDE_CURSOR) HELP_LINK ("Paintbrush = \".\": %s", SPECIAL_DOT_PAINTBRUSH) HELP_LINK ("Paintbrush choice: %s", 0x100+BUTTON_PAINTBRUSHES) HELP_LINK ("Monochrome brush: %s", 0x200+BUTTON_PAINTBRUSHES) HELP_LINK ("Freehand drawing: %s", 0x100+BUTTON_DRAW) HELP_TEXT ("Switch freehand") HELP_LINK (" drawing mode: %s", 0x200+BUTTON_DRAW) HELP_TEXT ("Continuous freehand") HELP_LINK (" drawing: %s", SPECIAL_CONTINUOUS_DRAW) HELP_LINK ("Line: %s", 0x100+BUTTON_LINES) HELP_LINK ("Knotted lines: %s", 0x200+BUTTON_LINES) HELP_LINK ("Spray: %s", 0x100+BUTTON_AIRBRUSH) HELP_LINK ("Spray menu: %s", 0x200+BUTTON_AIRBRUSH) HELP_LINK ("Floodfill: %s", 0x100+BUTTON_FLOODFILL) HELP_LINK ("Replace color: %s", 0x200+BUTTON_FLOODFILL) HELP_LINK ("Bezier's curves: %s", 0x100+BUTTON_CURVES) HELP_TEXT ("Bezier's curve with") HELP_LINK (" 3 or 4 points %s", 0x200+BUTTON_CURVES) HELP_LINK ("Empty rectangle: %s", 0x100+BUTTON_RECTANGLES) HELP_LINK ("Filled rectangle: %s", 0x100+BUTTON_FILLRECT) HELP_LINK ("Empty circle: %s", 0x100+BUTTON_CIRCLES) HELP_LINK ("Empty ellipse: %s", 0x200+BUTTON_CIRCLES) HELP_LINK ("Filled circle: %s", 0x100+BUTTON_FILLCIRC) HELP_LINK ("Filled ellipse: %s", 0x200+BUTTON_FILLCIRC) HELP_LINK ("Empty polygon: %s", 0x100+BUTTON_POLYGONS) HELP_LINK ("Empty polyform: %s", 0x200+BUTTON_POLYGONS) HELP_LINK ("Polyfill: %s", 0x100+BUTTON_POLYFILL) HELP_LINK ("Filled polyform: %s", 0x200+BUTTON_POLYFILL) HELP_LINK ("Gradient rectangle: %s", 0x100+BUTTON_GRADRECT) HELP_LINK ("Gradation menu: %s", 0x200+BUTTON_GRADRECT) HELP_LINK ("Toggle color cycling:%s", SPECIAL_CYCLE_MODE) HELP_LINK ("Spheres: %s", 0x100+BUTTON_SPHERES) HELP_LINK ("Gradient ellipses: %s", 0x200+BUTTON_SPHERES) HELP_LINK ("Adjust picture: %s", 0x100+BUTTON_ADJUST) HELP_LINK ("Flip picture menu: %s", 0x200+BUTTON_ADJUST) HELP_LINK ("Effects menu: %s", 0x100+BUTTON_EFFECTS) HELP_LINK ("Effects all off %s", SPECIAL_EFFECTS_OFF) HELP_LINK ("Shade mode: %s", SPECIAL_SHADE_MODE) HELP_LINK ("Shade menu: %s", SPECIAL_SHADE_MENU) HELP_LINK ("Quick-shade mode: %s", SPECIAL_QUICK_SHADE_MODE) HELP_LINK ("Quick-shade menu: %s", SPECIAL_QUICK_SHADE_MENU) HELP_LINK ("Stencil mode: %s", SPECIAL_STENCIL_MODE) HELP_LINK ("Stencil menu: %s", SPECIAL_STENCIL_MENU) HELP_LINK ("Mask mode: %s", SPECIAL_MASK_MODE) HELP_LINK ("Mask menu: %s", SPECIAL_MASK_MENU) HELP_LINK ("Grid mode: %s", SPECIAL_GRID_MODE) HELP_LINK ("Grid menu: %s", SPECIAL_GRID_MENU) HELP_LINK ("Grid view: %s", SPECIAL_SHOW_GRID) HELP_LINK ("Sieve mode: %s", SPECIAL_SIEVE_MODE) HELP_LINK ("Sieve menu: %s", SPECIAL_SIEVE_MENU) HELP_LINK ("Invert Sieve: %s", SPECIAL_INVERT_SIEVE) HELP_LINK ("Colorize mode: %s", SPECIAL_COLORIZE_MODE) HELP_LINK (" At opacity 10%%: %s", SPECIAL_TRANSPARENCY_1) HELP_LINK (" At opacity 20%%: %s", SPECIAL_TRANSPARENCY_2) HELP_LINK (" At opacity 30%%: %s", SPECIAL_TRANSPARENCY_3) HELP_LINK (" At opacity 40%%: %s", SPECIAL_TRANSPARENCY_4) HELP_LINK (" At opacity 50%%: %s", SPECIAL_TRANSPARENCY_5) HELP_LINK (" At opacity 60%%: %s", SPECIAL_TRANSPARENCY_6) HELP_LINK (" At opacity 70%%: %s", SPECIAL_TRANSPARENCY_7) HELP_LINK (" At opacity 80%%: %s", SPECIAL_TRANSPARENCY_8) HELP_LINK (" At opacity 90%%: %s", SPECIAL_TRANSPARENCY_9) HELP_LINK (" At opacity 100%%: %s", SPECIAL_TRANSPARENCY_0) HELP_LINK ("Colorize menu: %s", SPECIAL_COLORIZE_MENU) HELP_LINK ("Smooth mode: %s", SPECIAL_SMOOTH_MODE) HELP_LINK ("Smooth menu: %s", SPECIAL_SMOOTH_MENU) HELP_LINK ("Smear mode: %s", SPECIAL_SMEAR_MODE) HELP_LINK ("Tiling mode: %s", SPECIAL_TILING_MODE) HELP_LINK ("Tiling menu: %s", SPECIAL_TILING_MENU) HELP_LINK ("Tilemap mode: %s", SPECIAL_TILEMAP_MODE) HELP_LINK ("Tilemap menu: %s", SPECIAL_TILEMAP_MENU) HELP_LINK ("Pick brush: %s", 0x100+BUTTON_BRUSH) HELP_LINK ("Pick polyform brush: %s", 0x100+BUTTON_POLYBRUSH) HELP_LINK ("Restore brush: %s", 0x200+BUTTON_BRUSH) HELP_LINK ("Flip brush X: %s", SPECIAL_FLIP_X) HELP_LINK ("Flip brush Y: %s", SPECIAL_FLIP_Y) HELP_LINK ("90 brush rotation: %s", SPECIAL_ROTATE_90) HELP_LINK ("180 brush rotation: %s", SPECIAL_ROTATE_180) HELP_LINK ("Stretch brush: %s", SPECIAL_STRETCH) HELP_LINK ("Distort brush: %s", SPECIAL_DISTORT) HELP_LINK ("Outline brush: %s", SPECIAL_OUTLINE) HELP_LINK ("Nibble brush: %s", SPECIAL_NIBBLE) HELP_LINK ("Double brush size: %s", SPECIAL_BRUSH_DOUBLE) HELP_LINK ("Halve brush size: %s", SPECIAL_BRUSH_HALVE) HELP_LINK ("Double brush width: %s", SPECIAL_BRUSH_DOUBLE_WIDTH) HELP_LINK ("Double brush height: %s", SPECIAL_BRUSH_DOUBLE_HEIGHT) HELP_LINK ("Get brush colors: %s", SPECIAL_GET_BRUSH_COLORS) HELP_LINK ("Recolorize brush: %s", SPECIAL_RECOLORIZE_BRUSH) HELP_LINK ("Rotate brush: %s", SPECIAL_ROTATE_ANY_ANGLE) HELP_LINK ("Pipette: %s", 0x100+BUTTON_COLORPICKER) HELP_LINK ("Swap fore/back color:%s", 0x200+BUTTON_COLORPICKER) HELP_TEXT ("Magnifier mode") HELP_LINK (" Toggle: %s", 0x100+BUTTON_MAGNIFIER) HELP_LINK (" Zoom factor menu: %s", 0x200+BUTTON_MAGNIFIER) HELP_LINK (" Zoom in: %s", SPECIAL_ZOOM_IN) HELP_LINK (" Zoom out: %s", SPECIAL_ZOOM_OUT) HELP_LINK (" 1:1 (off) %s", SPECIAL_ZOOM_1) HELP_LINK (" 2:1 %s", SPECIAL_ZOOM_2) HELP_LINK (" 3:1 %s", SPECIAL_ZOOM_3) HELP_LINK (" 4:1 %s", SPECIAL_ZOOM_4) HELP_LINK (" 5:1 %s", SPECIAL_ZOOM_5) HELP_LINK (" 6:1 %s", SPECIAL_ZOOM_6) HELP_LINK (" 8:1 %s", SPECIAL_ZOOM_8) HELP_LINK (" 10:1 %s", SPECIAL_ZOOM_10) HELP_LINK (" 12:1 %s", SPECIAL_ZOOM_12) HELP_LINK (" 14:1 %s", SPECIAL_ZOOM_14) HELP_LINK (" 16:1 %s", SPECIAL_ZOOM_16) HELP_LINK (" 18:1 %s", SPECIAL_ZOOM_18) HELP_LINK (" 20:1 %s", SPECIAL_ZOOM_20) HELP_LINK ("Brush effects menu: %s", 0x100+BUTTON_BRUSH_EFFECTS) HELP_LINK ("Brush factory: %s", 0x200+BUTTON_BRUSH_EFFECTS) HELP_LINK ("Repeat last script: %s", SPECIAL_REPEAT_SCRIPT) HELP_LINK ("Run script #1: %s", SPECIAL_RUN_SCRIPT_1) HELP_LINK ("Run script #2: %s", SPECIAL_RUN_SCRIPT_2) HELP_LINK ("Run script #3: %s", SPECIAL_RUN_SCRIPT_3) HELP_LINK ("Run script #4: %s", SPECIAL_RUN_SCRIPT_4) HELP_LINK ("Run script #5: %s", SPECIAL_RUN_SCRIPT_5) HELP_LINK ("Run script #6: %s", SPECIAL_RUN_SCRIPT_6) HELP_LINK ("Run script #7: %s", SPECIAL_RUN_SCRIPT_7) HELP_LINK ("Run script #8: %s", SPECIAL_RUN_SCRIPT_8) HELP_LINK ("Run script #9: %s", SPECIAL_RUN_SCRIPT_9) HELP_LINK ("Run script #10: %s", SPECIAL_RUN_SCRIPT_10) HELP_LINK ("Text: %s", 0x100+BUTTON_TEXT) HELP_LINK ("Resolution menu: %s", 0x100+BUTTON_RESOL) HELP_LINK ("Safety resolution: %s", 0x200+BUTTON_RESOL) HELP_LINK ("Help: %s", 0x100+BUTTON_HELP) HELP_LINK ("Statistics: %s", 0x200+BUTTON_HELP) HELP_LINK ("Go to spare page: %s", 0x100+BUTTON_PAGE) HELP_LINK ("Copy to spare page: %s", 0x200+BUTTON_PAGE) HELP_LINK ("Save as: %s", 0x100+BUTTON_SAVE) HELP_LINK ("Save: %s", 0x200+BUTTON_SAVE) HELP_LINK ("Load: %s", 0x100+BUTTON_LOAD) HELP_LINK ("Re-load: %s", 0x200+BUTTON_LOAD) HELP_LINK ("Save brush: %s", SPECIAL_SAVE_BRUSH) HELP_LINK ("Load brush: %s", SPECIAL_LOAD_BRUSH) HELP_LINK ("Larger brush size: %s", SPECIAL_BIGGER_PAINTBRUSH) HELP_LINK ("Smaller brush size: %s", SPECIAL_SMALLER_PAINTBRUSH) HELP_LINK ("Settings: %s", 0x100+BUTTON_SETTINGS) HELP_LINK ("Undo: %s", 0x100+BUTTON_UNDO) HELP_LINK ("Redo: %s", 0x200+BUTTON_UNDO) HELP_LINK ("Kill page: %s", 0x100+BUTTON_KILL) HELP_LINK ("Clear: %s", 0x100+BUTTON_CLEAR) HELP_LINK ("Clear with BG color: %s", 0x200+BUTTON_CLEAR) HELP_LINK ("Quit: %s", 0x100+BUTTON_QUIT) HELP_LINK ("Palette menu: %s", 0x100+BUTTON_PALETTE) HELP_LINK ("2nd Palette menu: %s", 0x200+BUTTON_PALETTE) HELP_LINK ("Exclude colors menu: %s", SPECIAL_EXCLUDE_COLORS_MENU) HELP_TEXT ("") HELP_TEXT ("Scroll palette") HELP_LINK (" Back: %s", 0x100+BUTTON_PAL_LEFT) HELP_LINK (" Forward: %s", 0x100+BUTTON_PAL_RIGHT) HELP_LINK (" Back faster: %s", 0x200+BUTTON_PAL_LEFT) HELP_LINK (" Forward faster: %s", 0x200+BUTTON_PAL_RIGHT) HELP_TEXT ("") HELP_TEXT ("Change brush attachement") HELP_LINK (" Center : %s", SPECIAL_CENTER_ATTACHMENT) HELP_LINK (" Top-left : %s", SPECIAL_TOP_LEFT_ATTACHMENT) HELP_LINK (" Top-right : %s", SPECIAL_TOP_RIGHT_ATTACHMENT) HELP_LINK (" Bottom-left : %s", SPECIAL_BOTTOM_LEFT_ATTACHMENT) HELP_LINK (" Bottom-right: %s", SPECIAL_BOTTOM_RIGHT_ATTACHMENT) HELP_TEXT ("") HELP_TEXT ("Select foreground color") HELP_TEXT ("") HELP_LINK (" Next : %s", SPECIAL_NEXT_FORECOLOR) HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_FORECOLOR) HELP_TEXT ("") HELP_TEXT ("Select background color") HELP_LINK (" Next : %s", SPECIAL_NEXT_BACKCOLOR) HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_BACKCOLOR) HELP_TEXT ("") HELP_TEXT ("Select user-defined foreground color") HELP_TEXT ("") HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_FORECOLOR) HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_FORECOLOR) HELP_TEXT ("") HELP_TEXT ("Select user-defined background color") HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_BACKCOLOR) HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_BACKCOLOR) HELP_TEXT ("") HELP_TEXT ("LAYERS / ANIMATION FRAMES") HELP_TEXT ("") HELP_LINK (" Menu : %s", 0x100+BUTTON_LAYER_MENU) HELP_LINK (" Add new : %s", 0x100+BUTTON_LAYER_ADD) HELP_LINK (" Duplicate : %s", 0x200+BUTTON_LAYER_ADD) HELP_LINK (" Delete : %s", 0x100+BUTTON_LAYER_REMOVE) HELP_LINK (" Merge : %s", 0x100+BUTTON_LAYER_MERGE) HELP_LINK (" Move up : %s", 0x100+BUTTON_LAYER_UP) HELP_LINK (" Move down : %s", 0x100+BUTTON_LAYER_DOWN) //HELP_LINK (" Set transp: %s", 0x100+BUTTON_LAYER_COLOR) HELP_TEXT (" Select :") HELP_LINK (" 1 : %s", SPECIAL_LAYER1_SELECT) HELP_LINK (" 2 : %s", SPECIAL_LAYER2_SELECT) HELP_LINK (" 3 : %s", SPECIAL_LAYER3_SELECT) HELP_LINK (" 4 : %s", SPECIAL_LAYER4_SELECT) HELP_LINK (" 5 : %s", SPECIAL_LAYER5_SELECT) HELP_LINK (" 6 : %s", SPECIAL_LAYER6_SELECT) HELP_LINK (" 7 : %s", SPECIAL_LAYER7_SELECT) HELP_LINK (" 8 : %s", SPECIAL_LAYER8_SELECT) HELP_TEXT (" Toggle :") HELP_LINK (" 1 : %s", SPECIAL_LAYER1_TOGGLE) HELP_LINK (" 2 : %s", SPECIAL_LAYER2_TOGGLE) HELP_LINK (" 3 : %s", SPECIAL_LAYER3_TOGGLE) HELP_LINK (" 4 : %s", SPECIAL_LAYER4_TOGGLE) HELP_LINK (" 5 : %s", SPECIAL_LAYER5_TOGGLE) HELP_LINK (" 6 : %s", SPECIAL_LAYER6_TOGGLE) HELP_LINK (" 7 : %s", SPECIAL_LAYER7_TOGGLE) HELP_LINK (" 8 : %s", SPECIAL_LAYER8_TOGGLE) HELP_LINK (" Go to first: %s", 0x100+BUTTON_ANIM_FIRST_FRAME) HELP_LINK (" Go to previous: %s", 0x100+BUTTON_ANIM_PREV_FRAME) HELP_LINK (" Go to next: %s", 0x100+BUTTON_ANIM_NEXT_FRAME) HELP_LINK (" Go to last: %s", 0x100+BUTTON_ANIM_LAST_FRAME) HELP_LINK (" Set duration: %s", 0x100+BUTTON_ANIM_TIME) HELP_TEXT ("") HELP_LINK (" Format check : %s", SPECIAL_FORMAT_CHECKER) HELP_LINK (" Format check menu: %s", SPECIAL_FORMAT_CHECKER_MENU) HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("") }; static const T_Help_table helptable_credits[] = { //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") HELP_TITLE(" GRAFX2 IS CREATED BY") HELP_TEXT ("") HELP_BOLD (" THE GRAFX2 PROJECT TEAM") HELP_TEXT ("") HELP_TEXT (" Adrien Destugues (pulkomandy)") HELP_TEXT (" Yves Rizoud (yrizoud)") HELP_TEXT ("") HELP_TEXT (" Got the source back to life in 2006") HELP_TEXT ("") HELP_BOLD (" SUNSET DESIGN") HELP_BOLD (" AUTHORS OF GRAFX2.0 BETA 96.5%") HELP_TEXT ("") HELP_TEXT (" Guillaume Dorme alias \"Robinson\" (code)") HELP_TEXT (" Karl Maritaud alias \"X-Man\" (code&gfx)") //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") HELP_TEXT ("") HELP_TEXT (" Re-licensed GrafX2 under the GPL in 2001") HELP_TEXT (" Huge thanks to them for their work !") HELP_TEXT ("") HELP_BOLD (" OTHER CODE CONTRIBUTORS") HELP_TEXT ("") HELP_TEXT (" Karl Bartel") HELP_TEXT (" SFont: bitmap fonts rendering") HELP_TEXT ("") HELP_TEXT (" Petter Lindquist") HELP_TEXT (" C64 file and image formats") HELP_TEXT ("") HELP_TEXT (" Pasi Kallinen") HELP_TEXT (" Better command-line handling") HELP_TEXT ("") HELP_TEXT (" Nic Soudee (zoner / xylem)") HELP_TEXT (" 3:4 pixel mode") HELP_TEXT ("") HELP_TEXT (" DawnBringer") HELP_TEXT (" Lua scripts, image effects") HELP_TEXT ("") HELP_TEXT (" Nitrofurano") HELP_TEXT (" Lua scripts") HELP_TEXT ("") HELP_TITLE(" ART") HELP_TEXT ("") HELP_TEXT (" Made (www.m4de.com)") HELP_TEXT (" Logo (classic)") HELP_TEXT ("") HELP_TEXT (" X-Man") HELP_TEXT (" Buttons and fonts (classic)") HELP_TEXT ("") HELP_TEXT (" iLKke (ilkke.blogspot.com)") HELP_TEXT (" Buttons and logo (modern, scenish)") HELP_TEXT (" Several fonts") HELP_TEXT ("") HELP_TEXT (" Jamon") HELP_TEXT (" Buttons, logo and font (DPaint tribute)") HELP_TEXT ("") HELP_TEXT (" Hatch") HELP_TEXT (" Vectorized icon") HELP_TEXT ("") HELP_TEXT (" ...Pixelled all the graphics") HELP_TEXT ("") HELP_TITLE(" OTHER MACHINES PORTS") HELP_TEXT ("") //HELP_TEXT ("0----5----0----5----0X---5----0----5----0--X") HELP_BOLD (" ATARI PORT") HELP_TEXT ("") HELP_TEXT (" Pawel Goralski (Saulot)") HELP_TEXT ("") HELP_BOLD (" AMIGA OS 3 PORT") HELP_TEXT ("") HELP_TEXT (" Artur Jarosik") HELP_TEXT ("") HELP_BOLD (" AMIGA OS 4 PORT") HELP_TEXT ("") HELP_TEXT (" Peter Gordon (www.petergordon.org.uk)") HELP_TEXT ("") //HELP_TEXT ("0----5----0----5----0X---5----0----5----0--X") HELP_BOLD (" AROS PORT") HELP_TEXT ("") HELP_TEXT (" Yannick") HELP_TEXT (" Fernando Mastandrea (masta.uy)") HELP_TEXT (" Markus Weiss") HELP_TEXT (" Mazze") HELP_TEXT ("") HELP_BOLD (" MORPHOS PORT") HELP_TEXT ("") HELP_TEXT (" Rusback") HELP_TEXT (" OffseT") HELP_BOLD (" SKYOS PORT") HELP_TEXT ("") HELP_TEXT (" Luc Schrijvers (Begasus)") HELP_TEXT ("") HELP_BOLD (" SYLLABLE PORT") HELP_TEXT ("") HELP_TEXT (" Syllable Software") HELP_TEXT ("") //HELP_TEXT ("0----5----0----5----0X---5----0----5----0--X") HELP_BOLD (" HAIKU OS AND BEOS PORT") HELP_TEXT ("") HELP_TEXT (" Luc Schrijvers (Begasus)") HELP_TEXT ("") HELP_BOLD (" FREEBSD PORT") HELP_TEXT ("") HELP_TEXT (" Jean-Baptiste Berlioz (Tob)") HELP_TEXT ("") HELP_BOLD (" OPENBSD PORT") HELP_TEXT ("") HELP_TEXT (" Luc Schrijvers (Begasus)") HELP_TEXT ("") HELP_BOLD (" NETBSD PORT") HELP_TEXT ("") HELP_TEXT (" Jeff Read") HELP_TEXT ("") //HELP_TEXT ("0----5----0----5----0X---5----0----5----0--X") HELP_BOLD (" LINUX BINARIES") HELP_TEXT ("") HELP_TEXT (" Gentoo : Matteo 'Peach' Pescarin") HELP_TEXT (" Debian : Grkan Sengn") HELP_TEXT (" Android : pelya") HELP_TEXT ("") HELP_BOLD (" WIZ & CAANOO PORT") HELP_TEXT ("") HELP_TEXT (" Alexander Filyanov (PheeL)") HELP_TEXT ("") HELP_BOLD (" MAC OS X PORT") HELP_TEXT ("") HELP_TEXT (" Franck Charlet (hitchhikr)") HELP_TEXT (" Per Olofsson (MagerValp)") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT (" ... made it work on your favourite toaster") HELP_TEXT ("") HELP_TITLE(" BUGFINDERS") HELP_TEXT ("") //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") HELP_TEXT (" Akira anibiqme antdzeryn ") HELP_TEXT (" blumunkee BDCIron Ced ") HELP_TEXT (" DarkDefende DawnBringer El Topo ") HELP_TEXT (" falenblood fanickbux fano ") HELP_TEXT (" finticemo fogbot121 freehand ") HELP_TEXT (" Frost Grimmy Grkan Sengn") HELP_TEXT (" Hatch HoraK-FDF iLKke ") HELP_TEXT (" Iw2evk jackfrost128 Jamon ") HELP_TEXT (" keito kusma lmemsm ") HELP_TEXT (" Lord Graga Lorenzo Gatti MagerValp ") HELP_TEXT (" maymunbeyin Michael Ilsaas mind ") HELP_TEXT (" MooZ m.zubrov Pasi Kallinen") HELP_TEXT (" the Peach petter PheeL ") HELP_TEXT (" Ravey1138 richienyhus rixard ") HELP_TEXT (" sm4tik spratek Surt ") HELP_TEXT (" tape.yrm TeeEmCee tempest ") HELP_TEXT (" Timo Kurrpa titus^Rab Tob ") HELP_TEXT (" yakumo2975 00ai99") HELP_TEXT (" ... posted the annoying bug reports.") HELP_TEXT ("") HELP_TITLE(" FILE FORMATS CREDITS") HELP_TEXT ("") HELP_TEXT (" BMP : Microsoft") HELP_TEXT (" CEL,KCF : K.O.S. (KISekae Set system)") HELP_TEXT (" CM5 : SyX") HELP_TEXT (" EGX : Targhan & Supersly / Cargosoft") HELP_TEXT (" GIF : Compuserve") HELP_TEXT (" GPL : The GIMP") HELP_TEXT (" IMG : Bivas (W. Wiedmann?)") HELP_TEXT (" IFF : Electronic Arts") HELP_TEXT (" KOA : Koala Technologies") HELP_TEXT (" NEO : Atari Corporation") HELP_TEXT (" PAL : ermmh... nobody (?)") HELP_TEXT (" PCX : Z-Soft") HELP_TEXT (" PI1,PC1 : Degas Elite") HELP_TEXT (" PKM : Sunset Design") HELP_TEXT (" PNG : W3C") HELP_TEXT (" PPH : Rhino / Batman Group") HELP_TEXT (" SCx : Colorix (?)") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE(" OUR HOMEPAGE") HELP_TEXT ("") HELP_BOLD (" http://grafx2.tk") HELP_TEXT ("") HELP_TEXT (" Link to us!") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE(" GREETINGS") HELP_TEXT ("") HELP_BOLD ("Pulkomandy:") HELP_TEXT ("") HELP_TEXT (" To the Pouet.net BBS posters, the #CPC") HELP_TEXT (" trolls and the bitfellas") HELP_TEXT (" To every people who makes the scene alive!") HELP_TEXT (" To all guys making nice pixelled pictures") HELP_TEXT (" (with or without GrafX2)") HELP_TEXT ("") HELP_BOLD ("Sunset Designs:") HELP_TEXT ("") HELP_TEXT (" We send our best regards to...") HELP_TEXT ("") HELP_TEXT (" Access Filter Pink") HELP_TEXT (" Ace Fiver Pixel") HELP_TEXT (" AcidJam Flan Profil") HELP_TEXT (" Acryl Fred Prowler") HELP_TEXT (" Alexel FreddyV Puznik") HELP_TEXT (" Alias Frost Quick") HELP_TEXT (" Amiral Gal(GDC) Ra") HELP_TEXT (" Arrakis GainX Raster") HELP_TEXT (" Avocado Gandalf Ravian") HELP_TEXT (" Baloo Goblin RedBug") HELP_TEXT (" Barti Greenpix7 Rem") HELP_TEXT (" Bat Grid Rez") HELP_TEXT (" Biro GrosQuick Roudoudou") HELP_TEXT (" Bisounours HackerCroll Sacrilege") HELP_TEXT (" BlackAxe Haplo Sam") HELP_TEXT (" Bonnie Hof SandMan") HELP_TEXT (" Boo Hornet Scape") HELP_TEXT (" Boz Hulud Sbastien") HELP_TEXT (" Carine Java Shodan") HELP_TEXT (" Chandra JBT Skal") HELP_TEXT (" Cheetah Jrme Skyfire") HELP_TEXT (" Chill Julien(JCA) Sphair") HELP_TEXT (" Cougar KalMinDo Sprocket") HELP_TEXT (" Cremax KaneWood Stef") HELP_TEXT (" Cyclone Karma Stony") HELP_TEXT (" Dake Keith303 Sumaleth") HELP_TEXT (" Danny Lazur Sunday") HELP_TEXT (" Danube LightShow Suny") HELP_TEXT (" Darjul Lluvia Sybaris") HELP_TEXT (" Darwin Louie TBF") HELP_TEXT (" DarkAngel Luk Tempest") HELP_TEXT (" Das Made Thor") HELP_TEXT (" Decker Mamos TMK") HELP_TEXT (" DerPiipo Mandrixx TwoFace") HELP_TEXT (" Destop Mangue Underking") HELP_TEXT (" Diabolo Mars Unreal") HELP_TEXT (" DineS Mephisto VaeVictis") HELP_TEXT (" Drac Mercure Vastator") HELP_TEXT (" DrYes Mirec Vatin") HELP_TEXT (" Edyx Moa Veckman") HELP_TEXT (" Eller Moxica Wain") HELP_TEXT (" Ellyn MRK Wally") HELP_TEXT (" EOF Nitch WillBe") HELP_TEXT (" Fall Noal Xoomie") HELP_TEXT (" Fame Nytrik Xtrm") HELP_TEXT (" Fantom Optic YannSulu") HELP_TEXT (" Fear Orome Z") HELP_TEXT (" Feather Pahladin Zeb") HELP_TEXT (" Fennec Phar Zebig") HELP_TEXT ("") HELP_TEXT (" and all #pixel, #demofr and #coders.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT (" Some information taken from several docs") HELP_TEXT (" (PCGPE, Intervue, PC Interdit...)") HELP_TEXT (" gave us an invaluable help.") HELP_TEXT ("") HELP_TEXT (" Thanks to Shawn Hargreaves for his filled") HELP_TEXT (" polygon routine from Allegro v2.2.") HELP_TEXT ("") HELP_TEXT (" Thanks to Carlos \"Made\" Pardo for his") HELP_TEXT (" great GrafX2 logo.") HELP_TEXT ("") HELP_TEXT (" This is our very first program compiled") HELP_TEXT (" with the Gnu C Compiler.") HELP_TEXT (" A thousand thanks to the authors of") HELP_TEXT (" this compiler.") HELP_TEXT ("") HELP_TEXT (" We also would like to thank all the") HELP_TEXT (" people who gave us ideas to improve") HELP_TEXT (" GrafX2.") HELP_TEXT ("") }; static const T_Help_table helptable_paintbrush[] = { HELP_TITLE("PAINTBRUSHES") HELP_TEXT ("") HELP_BOLD (" LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_PAINTBRUSHES) HELP_TEXT ("") HELP_TEXT ("Displays a menu where you can choose the") HELP_TEXT ("shape of your paintbrush.") HELP_TEXT ("") HELP_TEXT ("Paintbrushes are sorted by family. You can") HELP_TEXT ("see some paintbrushes of the same family but") HELP_TEXT ("with different sizes. There is at least one") HELP_TEXT ("paint-brush from each family displayed in") HELP_TEXT ("this menu.") HELP_TEXT ("Here is the list of all the different") HELP_TEXT ("paintbrush families:") HELP_TEXT ("") HELP_TEXT ("******* *** * * * * * * ") HELP_TEXT ("******* ***** * * * * * * ") HELP_TEXT ("******* ******* * * * * * * * * ") HELP_TEXT ("******* ******* * * * * * * ") HELP_TEXT ("******* ******* * * * * * * * * ") HELP_TEXT ("******* ***** * * * * * * ") HELP_TEXT ("******* *** * * * * * * ") HELP_TEXT ("") HELP_TEXT ("Square Disc Sieve Sieve ") HELP_TEXT (" square disc ") HELP_TEXT (" ") HELP_TEXT (" * * * ") HELP_TEXT (" *** * * * ") HELP_TEXT (" ***** * * ") HELP_TEXT ("******* ******* * ") HELP_TEXT (" ***** * * * * ") HELP_TEXT (" *** * ") HELP_TEXT (" * * * * ") HELP_TEXT (" ") HELP_TEXT ("Diamond Random Horiz. Vertical") HELP_TEXT (" bar bar ") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT (" * * * * *") HELP_TEXT (" * * * * *") HELP_TEXT (" * * * * *") HELP_TEXT (" * * * *******") HELP_TEXT (" * * * * *") HELP_TEXT (" * * * * *") HELP_TEXT ("* * * * *") HELP_TEXT ("") HELP_TEXT (" Slash Back- Cross X Cross +") HELP_TEXT (" slash") HELP_TEXT ("") HELP_TEXT ("When using one of these, you can change the") HELP_TEXT ("brush size by using the keys:") HELP_LINK ("Reduce : %s", SPECIAL_SMALLER_PAINTBRUSH) HELP_LINK ("Increase : %s", SPECIAL_BIGGER_PAINTBRUSH) HELP_TEXT ("") HELP_TEXT ("Other brushes are bitmaps, their size can't") HELP_TEXT ("be adjusted.") HELP_TEXT ("") HELP_TEXT ("Click with left mouse button to choose a ") HELP_TEXT ("paintbrush, and right mouse button to store") HELP_TEXT ("your current brush in the slot. If your") HELP_TEXT ("current brush is a grabbed brush, it will") HELP_TEXT ("store a monochrome version of it, maximum") HELP_TEXT ("15x15. (See below 'Brush container' to store") HELP_TEXT ("backups of a big brush)") HELP_TEXT ("The stored brushes are saved when you exit") HELP_TEXT ("the program.") HELP_TEXT ("") HELP_TEXT ("The 'Preset' button allows you to pick a") HELP_TEXT ("brush from any family. It's useful if you've") HELP_TEXT ("overwritten all normal slots with brushes") HELP_TEXT ("that you use more often.") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD ("BRUSH CONTAINER") HELP_TEXT ("") HELP_TEXT ("The bottom row, initially showing empty") HELP_TEXT ("buttons, is the brush container. You can") HELP_TEXT ("right-click a button to store the current") HELP_TEXT ("brush in it, and then whenever you need the") HELP_TEXT ("brush back, open this menu again and") HELP_TEXT ("left-click the button.") HELP_TEXT ("The container can memorize resizable brushes") HELP_TEXT ("as well as brushes grabbed from the image.") HELP_TEXT ("Brushes are lost when you exit the program.") HELP_TEXT ("") HELP_BOLD (" RIGHT CLICK ") HELP_LINK ("(Key:%s)",0x200+BUTTON_PAINTBRUSHES) HELP_TEXT ("") HELP_TEXT ("Transforms your current user-defined brush") HELP_TEXT ("into a paintbrush. This is actually a") HELP_TEXT ("\"monochromisation\" of your user-defined") HELP_TEXT ("brush. This means that every color of the") HELP_TEXT ("brush that aren't the Back-color will be") HELP_TEXT ("set to the Fore-color. But this option") HELP_TEXT ("doesn't alter the brush: you'll just have") HELP_TEXT ("to right-click on the \"Get brush\" buttons") HELP_TEXT ("to get your brush back.") HELP_TEXT ("") HELP_TEXT ("Note: When you press (not in the menu) the") HELP_LINK ("key %s, the current",SPECIAL_DOT_PAINTBRUSH) HELP_TEXT ("paintbrush becomes the smallest member of") HELP_TEXT ("the \"Disc\" family: i.e one pixel.") }; static const T_Help_table helptable_adjust[] = { HELP_TITLE("ADJUST OR TRANSFORM") HELP_TITLE(" PICTURE") HELP_TEXT ("") HELP_BOLD (" LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_ADJUST) HELP_TEXT ("") HELP_TEXT ("Allows you to scroll the picture to") HELP_TEXT ("re-center your graph for example.") HELP_TEXT ("") HELP_TEXT ("Any part of the picture that goes out of") HELP_TEXT ("the image by a side comes back by the") HELP_TEXT ("opposite one.") HELP_TEXT ("") HELP_TEXT ("Left clicking the picture will scroll only") HELP_TEXT ("the active layer. Right-clicking will scroll") HELP_TEXT ("all of them.") HELP_TEXT ("") HELP_TEXT ("It is assimilated to the drawing tools") HELP_TEXT ("family.") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_ADJUST) HELP_TEXT ("") HELP_TEXT ("Opens the Picture Transform menu.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("PICTURE TRANSFORM") HELP_TEXT ("") HELP_BOLD ("RESCALE") HELP_TEXT ("") HELP_TEXT ("Allows you to change the image's size,") HELP_TEXT ("rescaling it accordingly. Enter new size") HELP_TEXT ("and press RESIZE to confirm.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("When 'Lock proportions' is checked and you") HELP_TEXT ("change one dimension, the other one is") HELP_TEXT ("automatically adjusted to preserve the") HELP_TEXT ("proportions of the original image.") HELP_TEXT ("") HELP_TEXT ("You can use the dropdown button to choose") HELP_TEXT ("between three ways to enter the dimensions:") HELP_TEXT ("") HELP_TEXT ("In 'Pixels' mode, the column 'old' shows") HELP_TEXT ("the original dimensions, and you can set") HELP_TEXT ("the new size in pixels.") HELP_TEXT ("") HELP_TEXT ("In 'Percent' mode, you set a percentage") HELP_TEXT ("compared to the original image.") HELP_TEXT ("") HELP_TEXT ("In 'Ratio' mode, you can set 2 numbers for") HELP_TEXT ("each dimension, and the resizing factor will") HELP_TEXT ("be of 'new''old'. For example you can use") HELP_TEXT ("1:3 to divide the image by three, 2:1 to") HELP_TEXT ("double it, and any fraction like 15:16.") HELP_TEXT ("") HELP_TEXT ("Be careful that moving from one mode to the") HELP_TEXT ("next can lose precision, if the selected") HELP_TEXT ("dimensions cannot be represented exactly in") HELP_TEXT ("the new mode.") HELP_TEXT ("") HELP_BOLD ("MIRROR") HELP_TEXT ("") HELP_TEXT ("- X: Flip the picture horizontally.") HELP_TEXT ("") HELP_TEXT ("- Y: Flip the picture vertically.") HELP_TEXT ("") HELP_BOLD ("ROTATE") HELP_TEXT ("") HELP_TEXT ("-90: Rotates the image by 90") HELP_TEXT (" clockwise.") HELP_TEXT ("") HELP_TEXT ("+90: Rotates the image by 90") HELP_TEXT (" counter-clockwise.") HELP_TEXT ("180: Rotates the image by 180") HELP_TEXT ("") HELP_TEXT ("") }; static const T_Help_table helptable_draw[] = { HELP_TITLE("HAND-DRAWING") HELP_TEXT ("") HELP_BOLD (" LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_DRAW) HELP_TEXT ("") HELP_TEXT ("Selects the current hand-drawing mode as the") HELP_TEXT ("active drawing tool. There are 4") HELP_TEXT ("hand-drawing modes:") HELP_TEXT ("") HELP_TEXT ("Continuous hand-drawing: as you move the") HELP_TEXT ("mouse, the paintbrush is regularily pasted") HELP_TEXT ("on the picture. This drawing tool allows to") HELP_TEXT ("change the fore and back colors when being") HELP_TEXT ("in use.") HELP_TEXT ("") HELP_TEXT ("Discontinuous hand-drawing: as you move the") HELP_TEXT ("mouse, the paintbrush is pasted on the") HELP_TEXT ("picture every time a delay is passed") HELP_TEXT ("(actually, the delay is 1 VBL") HELP_TEXT ("(vertical blanking)). This drawing tool") HELP_TEXT ("allows to change the fore and back colors") HELP_TEXT ("when being in use.") HELP_TEXT ("") HELP_TEXT ("Dot by dot hand-drawing: the paintbrush is") HELP_TEXT ("only pasted at the position where you first") HELP_TEXT ("clicked.") HELP_TEXT ("") HELP_TEXT ("Contour fill: Draws pixels like continuous") HELP_TEXT ("mode, but when you release the button Grafx2") HELP_TEXT ("draws a line back to your starting position,") HELP_TEXT ("and fills the area. This tool doesn't use") HELP_TEXT ("the current brush, but single pixels.") HELP_TEXT ("") HELP_BOLD (" RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_DRAW) HELP_TEXT ("") HELP_TEXT ("Toggles the different hand-drawing modes") HELP_TEXT ("and activates, at the same time, the") HELP_TEXT ("hand-drawing tool.") }; static const T_Help_table helptable_curves[] = { HELP_TITLE("SPLINES") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_CURVES) HELP_TEXT ("") HELP_TEXT ("Selects the current curve-drawing mode as") HELP_TEXT ("the active drawing tool. There are 2") HELP_TEXT ("different curve-drawing modes:") HELP_TEXT ("") HELP_TEXT ("* 4 control points curves: define the basic") HELP_TEXT ("line like a classical line, then move, with") HELP_TEXT ("the left mouse button, the inner control") HELP_TEXT ("points to choose the shape of your curve.") HELP_TEXT ("When the curve has the shape you want, click") HELP_TEXT ("with the right mouse button to draw it") HELP_TEXT ("definitively.") HELP_TEXT ("") HELP_TEXT ("* 3 control points curves: the same as") HELP_TEXT ("above, but you'll have only one inner") HELP_TEXT ("control point to place. Moreover, the spline") HELP_TEXT ("will be traced just after placing this") HELP_TEXT ("point.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_CURVES) HELP_TEXT ("") HELP_TEXT ("Toggles the different curve-drawing modes") HELP_TEXT ("and activates, at the same time, the") HELP_TEXT ("curve-drawing tool.") }; static const T_Help_table helptable_lines[] = { HELP_TITLE("LINES") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_LINES) HELP_TEXT ("") HELP_TEXT ("Selects the current line-drawing mode as the") HELP_TEXT ("active drawing tool. There are 3") HELP_TEXT ("line-drawing modes:") HELP_TEXT ("") HELP_TEXT ("* Classical lines: when first clicking on") HELP_TEXT ("the picture, you'll define the start of the") HELP_TEXT ("line. Maintain your click to choose the end") HELP_TEXT ("of the line and release the mouse button to") HELP_TEXT ("set it.") HELP_TEXT ("If you hold SHIFT when drawing, the line") HELP_TEXT ("will be constrained to horizonal, vertical") HELP_TEXT ("or diagonal.") HELP_TEXT ("") HELP_TEXT ("* Knotted lines: works like classical lines,") HELP_TEXT ("but the end of your line will automatically") HELP_TEXT ("become the start of the next one. When you") HELP_TEXT ("want to stop chaining lines, use the") HELP_TEXT ("opposite mouse button. \"The opposite button\"") HELP_TEXT ("means that if you started to draw lignes") HELP_TEXT ("with the left button (Fore-color), you'll") HELP_TEXT ("have to stop the procedure with the right") HELP_TEXT ("button; and conversely.") HELP_TEXT ("") HELP_TEXT ("* Concentric lines: when first clicking on") HELP_TEXT ("the picture, you'll define center of the") HELP_TEXT ("lines. In fact, the center is defined by the") HELP_TEXT ("the position of the mouse when you release") HELP_TEXT ("the mouse button. Then you can draw lines") HELP_TEXT ("from the center to the current mouse") HELP_TEXT ("position by clicking. To stop drawing") HELP_TEXT ("concentric lines, use the opposite mouse") HELP_TEXT ("button. This drawing tool allows to change") HELP_TEXT ("the fore and back colors when being in use.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_LINES) HELP_TEXT ("") HELP_TEXT ("Toggles the different line-drawing modes and") HELP_TEXT ("activates, at the same time, the") HELP_TEXT ("line-drawing tool.") }; static const T_Help_table helptable_airbrush[] = { HELP_TITLE("SPRAY") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_AIRBRUSH) HELP_TEXT ("") HELP_TEXT ("Selects the spray as the active drawing") HELP_TEXT ("tool. This drawing tool allows to change the") HELP_TEXT ("fore and back colors when being in use.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_AIRBRUSH) HELP_TEXT ("") HELP_TEXT ("Displays a menu where you can configure the") HELP_TEXT ("spray:") HELP_TEXT ("") HELP_TEXT ("- Size: Defines the diameter of the circle") HELP_TEXT ("in which will effectively fit the spray.") HELP_TEXT ("") HELP_TEXT ("- Delay: Defines the number of VBLs that") HELP_TEXT ("will be waited for between two flows of") HELP_TEXT ("spray.") HELP_TEXT ("") HELP_TEXT ("- Mode: Defines whether you want to use a") HELP_TEXT ("monochrome spray or a multi- colored one.") HELP_TEXT ("") HELP_TEXT ("- Mono-flow: Defines the number of") HELP_TEXT ("paintbrushes that will be pasted in the") HELP_TEXT ("circle of the spray at each cycle.") HELP_TEXT ("") HELP_TEXT ("- Palette: Left-click on a color of the") HELP_TEXT ("palette to see how much it will be used in") HELP_TEXT ("the multicolored flow, and modify it by") HELP_TEXT ("using the gauge on the right. If the flow of") HELP_TEXT ("this color was equal to 0, then the \"Init\"") HELP_TEXT ("value will be applied. Or set the flow of a") HELP_TEXT ("color to 0 by clicking on it with the right") HELP_TEXT ("mouse button.") HELP_TEXT ("") HELP_TEXT ("- Clear: Removes all the colors from the") HELP_TEXT ("multicolored flow. Actually, this puts a 0") HELP_TEXT ("value in the use of each color.") HELP_TEXT ("") HELP_TEXT ("- Init: Allows you to define a value that") HELP_TEXT ("will be set to the color you click on in the") HELP_TEXT ("palette if its value is equal to 0. This") HELP_TEXT ("permits to tag a set of colors more quickly.") HELP_TEXT ("") HELP_TEXT ("- +1,-1,x2,/2: Modify the values of all the") HELP_TEXT ("tagged colors (and only them).") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("Tip: If you often use the Shade mode, and") HELP_TEXT ("are bored to click many times on a color to") HELP_TEXT ("reach the color you want, you can define a") HELP_TEXT ("spray with \"Size\"=1, \"Mono-flow\"=1, and") HELP_TEXT ("\"Delay\"=2 (or more, according to your") HELP_TEXT ("reflexes). And then, you'll just have to") HELP_TEXT ("click a few hundredths of second to modify a") HELP_TEXT ("color.") }; static const T_Help_table helptable_floodfill[] = { HELP_TITLE("FLOODFILL") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_FLOODFILL) HELP_TEXT ("") HELP_TEXT ("Selects the filler as the active drawing") HELP_TEXT ("tool. The filler, as any drawing tool, will") HELP_TEXT ("be affected by all the effects!") HELP_TEXT ("") HELP_TEXT ("Note that only the visible part of the") HELP_TEXT ("picture will be filled (as every other") HELP_TEXT ("drawing tools, the floodfill only alters the") HELP_TEXT ("visible part of the picture; this avoids") HELP_TEXT ("unwanted effects that wouldn't be controlled") HELP_TEXT ("by the user).") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_FLOODFILL) HELP_TEXT ("") HELP_TEXT ("Selects the color replacement as the active") HELP_TEXT ("drawing tool.") HELP_TEXT ("") HELP_TEXT ("Any rule has its exceptions and this one") HELP_TEXT ("doesn't depart from that. Indeed, this tool") HELP_TEXT ("is the only one to be affected by no effect") HELP_TEXT ("(except Stencil) and to be able to modify") HELP_TEXT ("non visible parts of the picture.") HELP_TEXT ("The function of this tool being replacing") HELP_TEXT ("all the occurences of a color in the picture") HELP_TEXT ("by another, if would have been a shame to") HELP_TEXT ("limit modifications only to the visible part") HELP_TEXT ("of the picture.") }; static const T_Help_table helptable_polygons[] = { HELP_TITLE("POLYGONS") HELP_TITLE("POLYFORMS") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYGONS) HELP_TEXT ("") HELP_TEXT ("Selects the polygons as the active drawing") HELP_TEXT ("tool.") HELP_TEXT ("") HELP_TEXT ("This works just like knotted-lines but loops") HELP_TEXT ("the extremities when you're finished.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_POLYGONS) HELP_TEXT ("") HELP_TEXT ("Selects the polyforms as the active drawing") HELP_TEXT ("tool.") HELP_TEXT ("") HELP_TEXT ("This works like a combination of free-hand") HELP_TEXT ("drawing and knotted-lines. If you keep the") HELP_TEXT ("mouse button pressed, you'll draw as if you") HELP_TEXT ("were in free-hand drawing mode. And, if you") HELP_TEXT ("release the mouse button, it will work like") HELP_TEXT ("knotted lines.") HELP_TEXT ("") HELP_TEXT ("Click on the opposite mouse button (i.e.:") HELP_TEXT ("click right if you started to draw with the") HELP_TEXT ("left mouse button, and vice versa) to") HELP_TEXT ("terminate the operation. The two extremities") HELP_TEXT ("will be linked automatically.") }; static const T_Help_table helptable_polyfill[] = { HELP_TITLE("FILLED POLY") HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYFILL) HELP_LINK ("(Key:%s)",0x200+BUTTON_POLYFILL) HELP_TEXT (" Work exactly the same way as the polygons") HELP_TEXT ("et polyforms above, but fill in the interior") HELP_TEXT ("of the drawn shapes.") }; static const T_Help_table helptable_rectangles[] = { HELP_TITLE("RECTANGLES") HELP_LINK ("(Key:%s)",0x100+BUTTON_RECTANGLES) HELP_TEXT ("") HELP_TEXT ("Selects the empty rectangles as the active") HELP_TEXT ("drawing tool.") HELP_TEXT ("") HELP_TEXT ("Set a corner of a rectangle. Maintain the") HELP_TEXT ("click to move the opposite corner and") HELP_TEXT ("release the mouse button to set it") HELP_TEXT ("definitively.") }; static const T_Help_table helptable_filled_rectangles[] = { HELP_TITLE("FILLED RECT") HELP_LINK ("(Key:%s)",0x100+BUTTON_FILLRECT) HELP_TEXT ("") HELP_TEXT ("Selects the filled rectangles as the active") HELP_TEXT ("drawing tool.") HELP_TEXT ("") HELP_TEXT ("Works like an empty rectangle.") }; static const T_Help_table helptable_circles[] = { HELP_TITLE("CIRCLES") HELP_TITLE("ELLIPSES") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_CIRCLES) HELP_TEXT ("") HELP_TEXT ("Selects the empty circles as the active") HELP_TEXT ("drawing tool.") HELP_TEXT ("") HELP_TEXT ("Position the center of the cercle and") HELP_TEXT ("maintain the mouse button to select its") HELP_TEXT ("radius.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_CIRCLES) HELP_TEXT ("") HELP_TEXT ("Selects the empty ellipses as the active") HELP_TEXT ("drawing tool.") HELP_TEXT ("") HELP_TEXT ("Position the center of the cercle and") HELP_TEXT ("maintain the mouse button to select its") HELP_TEXT ("dimensions.") }; static const T_Help_table helptable_filled_circles[] = { HELP_TITLE("FILLED CIRCLES") HELP_TITLE(" AND ELLIPSES") HELP_TEXT ("") HELP_BOLD ("FILLED CIRCLES") HELP_LINK ("(Key:%s)",0x100+BUTTON_FILLCIRC) HELP_TEXT ("") HELP_TEXT ("Works like empty circles.") HELP_TEXT ("") HELP_BOLD ("FILLED ELLIPSES") HELP_LINK ("(Key:%s)",0x200+BUTTON_FILLCIRC) HELP_TEXT ("") HELP_TEXT ("Works like empty ellipses.") }; static const T_Help_table helptable_grad_rect[] = { HELP_TITLE("GRAD RECTANGLE") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_GRADRECT) HELP_TEXT ("") HELP_TEXT ("Selects the rectangle with gradations as") HELP_TEXT ("the active drawing tool.") HELP_TEXT ("") HELP_TEXT ("Set a corner of a rectangle. Maintain the") HELP_TEXT ("click to move the opposite corner and") HELP_TEXT ("release the mouse button to set it") HELP_TEXT ("definitively.") HELP_TEXT ("") HELP_TEXT ("If you don't like what you have done and") HELP_TEXT ("want to restart, you can use the right") HELP_TEXT ("click to cancel everything at this point.") HELP_TEXT (" If you think it's nice, then click and hold") HELP_TEXT ("the mouse in a point you want to have the") HELP_TEXT ("starting color, drag to a point where you") HELP_TEXT ("want the ending color, and release the") HELP_TEXT ("button. You can press SHIFT to enforce your") HELP_TEXT ("line to be vertical, horizontal, or") HELP_TEXT ("diagonal.") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_GRADRECT) HELP_TEXT ("") HELP_TEXT ("Opens a window where you can define the way") HELP_TEXT ("gradations are processed. The different") HELP_TEXT ("sections of this menu are:") HELP_TEXT ("") HELP_TEXT ("- Direction (arrow): Switches the direction") HELP_TEXT ("of the gradation.") HELP_TEXT ("") HELP_TEXT ("- Dithering method: Toggles the 3 following") HELP_TEXT ("methods:") HELP_TEXT (" - No dithering") HELP_TEXT (" - Basical dithering") HELP_TEXT (" - Enhanced dithering") HELP_TEXT ("") HELP_TEXT ("- Mix: Mixes the gradation with a more or") HELP_TEXT ("less random factor.") HELP_TEXT ("") HELP_TEXT ("- Palette: Select a color range to build a") HELP_TEXT ("gradation.") HELP_TEXT ("") HELP_TEXT ("- Index scroller: Defines the current") HELP_TEXT ("gradation among a set of 16 that will be") HELP_TEXT ("memorised.") HELP_TEXT ("") HELP_BOLD ("COLOR CYCLING") HELP_TEXT ("") HELP_TEXT ("These options allow you to use animation of") HELP_TEXT ("colors: Grafx2 will shift palette entries") HELP_TEXT ("at real-time. Note that only the IFF file") HELP_TEXT ("format can record these settings, and very") HELP_TEXT ("few image viewers will play it back.") HELP_TEXT ("") HELP_TEXT ("- Cycling: Activates or desactivates the") HELP_TEXT ("cycling of colors when you're in the editor.") HELP_LINK ("Key: %s", SPECIAL_CYCLE_MODE) HELP_TEXT ("") HELP_TEXT ("- Speed: Sets the speed for the cycling of") HELP_TEXT ("this range. Zero means this range doesn't") HELP_TEXT ("cycle. With 1, the range shifts 0.2856 times") HELP_TEXT ("per second; at speed 64 it's 18.28 times") HELP_TEXT ("per second. The program activates cycling") HELP_TEXT ("while you hold the speed slider, so you can") HELP_TEXT ("preview the speed.") HELP_TEXT ("") }; static const T_Help_table helptable_spheres[] = { HELP_TITLE("GRAD SPHERE") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_SPHERES) HELP_TEXT ("") HELP_TEXT ("Selects the spheres as the active drawing") HELP_TEXT ("tool.") HELP_TEXT ("") HELP_TEXT ("Position the center of the sphere and") HELP_TEXT ("maintain the mouse button to select its") HELP_TEXT ("radius. Then place the spot-light.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_SPHERES) HELP_TEXT ("") HELP_TEXT ("Selects the ellipses with gradation as the") HELP_TEXT ("active drawing tool.") HELP_TEXT ("") HELP_TEXT ("Draw the shape like a normal ellipse, and") HELP_TEXT ("then position the spot-light and click the") HELP_TEXT ("left mouse button to finish the shape.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("If you trace a sphere or an ellipse with") HELP_TEXT ("gradation with the right mouse button, the") HELP_TEXT ("result will be the same figure filled with") HELP_TEXT ("the Back-color.") }; static const T_Help_table helptable_brush[] = { HELP_TITLE("GRAB BRUSH") HELP_BOLD (" OR RESTORE BRUSH") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_BRUSH) HELP_TEXT ("") HELP_TEXT ("Engages a brush grabbing.") HELP_TEXT ("") HELP_TEXT ("Click on a corner of the rectangle") HELP_TEXT ("containing the brush then maintain the click") HELP_TEXT ("to define the opposite corner of the") HELP_TEXT ("rectangle. Release the mouse button to grab") HELP_TEXT ("the brush. Performing this operation with") HELP_TEXT ("the right mouse button will erase the area") HELP_TEXT ("where the brush was grabbed with the") HELP_TEXT ("Back-color.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH) HELP_TEXT ("") HELP_TEXT ("Restores the old brush.") }; static const T_Help_table helptable_polybrush[] = { HELP_TITLE("POLY GRAB") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYBRUSH) HELP_TEXT ("") HELP_TEXT ("Grabs a brush of any shape by defining a") HELP_TEXT ("polyform (please refer to section 8 for more") HELP_TEXT ("explanations).") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH) HELP_TEXT ("") HELP_TEXT ("Restores the old brush (same as above).") }; static const T_Help_table helptable_brush_fx[] = { HELP_TITLE("BRUSH FX") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_BRUSH_EFFECTS) HELP_TEXT ("") HELP_TEXT ("Displays a menu where the following options") HELP_TEXT ("are available:") HELP_TEXT ("") HELP_LINK ("- X: (Key:%s)",SPECIAL_FLIP_X) HELP_TEXT ("Flip horizontally.") HELP_TEXT ("") HELP_LINK ("- Y: (Key:%s)",SPECIAL_FLIP_Y) HELP_TEXT ("Flip vertically.") HELP_TEXT ("") HELP_LINK ("- Rotate by 90: (Key:%s)",SPECIAL_ROTATE_90) HELP_TEXT ("Rotates the brush by an angle of 90 degrees.") HELP_TEXT ("") HELP_LINK ("- Rotate by 180: (Key:%s)",SPECIAL_ROTATE_180) HELP_TEXT ("Rotates the brush by an angle of 180") HELP_TEXT ("degrees.") HELP_TEXT ("") HELP_TEXT ("- Rotate by any angle:") HELP_LINK ("(Key:%s)",SPECIAL_ROTATE_ANY_ANGLE) HELP_TEXT ("Triggers an interactive operation that") HELP_TEXT ("allows you to rotate the brush. For this,") HELP_TEXT ("start by placing the center or rotation with") HELP_TEXT ("the left mouse button (if, at this moment,") HELP_TEXT ("you press the right button, the operation") HELP_TEXT ("with be cancelled). After that, you can") HELP_TEXT ("define the angle of rotation as many times") HELP_TEXT ("as you want by moving the mouse and") HELP_TEXT ("left-clicking. Then validate with the right") HELP_TEXT ("button when you are satisfied. Meanwhile,") HELP_TEXT ("you can press on the 8 outer digits of the") HELP_TEXT ("numeric pad for defining angles multiple of") HELP_TEXT ("45 degrees:") HELP_TEXT ("") HELP_TEXT (" 135 90 45") HELP_TEXT (" \\ | /") HELP_TEXT (" '7' '8' '9'") HELP_TEXT (" 180 -'4' '6'- 0") HELP_TEXT (" '1' '2' '3'") HELP_TEXT (" / | \\") HELP_TEXT (" 225 270 315") HELP_TEXT ("") HELP_LINK ("- Stretch: (Key:%s)",SPECIAL_STRETCH) HELP_TEXT ("Triggers an interactive operation") HELP_TEXT ("that enables you to stretch the brush. For") HELP_TEXT ("this, start by placing the upper-left") HELP_TEXT ("cornerof the brush with the left mouse") HELP_TEXT ("button (if, at this moment, you press the") HELP_TEXT ("right button, the operation will be") HELP_TEXT ("cancelled). after that, you can place the") HELP_TEXT ("opposite corner as many times as you need,") HELP_TEXT ("then validate with the right mouse button") HELP_TEXT ("when you are satisfied. If you place this") HELP_TEXT ("point at coordinates inferior to the ones of") HELP_TEXT ("the first point, the brush will be inverted.") HELP_TEXT ("Meanwhile, you can press the following keys") HELP_TEXT ("whose effects are:") HELP_TEXT (" 'D' : Double the brush") HELP_TEXT (" 'H' : Reduce the brush by half") HELP_TEXT (" 'X' : Double the brush in X") HELP_TEXT (" 'Shift+X': Reduce the brush by half in X") HELP_TEXT (" 'Y' : Double the brush in Y") HELP_TEXT (" 'Shift+Y': Reduce the brush by half in Y") HELP_TEXT (" 'N' : Restore the normal size of the") HELP_TEXT (" brush (can be useful because") HELP_TEXT (" it's the only way for") HELP_TEXT (" cancelling)") HELP_TEXT ("") HELP_LINK ("- Distort: (Key:%s)",SPECIAL_DISTORT) HELP_TEXT ("Triggers an interactive operation") HELP_TEXT ("that allows you to distort your brush.") HELP_TEXT ("Start by placing the brush somewhere on the") HELP_TEXT ("screen and left-click. The brush will") HELP_TEXT ("appear, with a little peg at each corner.") HELP_TEXT ("Use the left mouse button to displace the") HELP_TEXT ("corners, which will deform the brush.") HELP_TEXT ("When you're done, click the right mouse") HELP_TEXT ("button.") HELP_TEXT ("") HELP_LINK ("- Outline: (Key:%s)",SPECIAL_OUTLINE) HELP_TEXT ("This option permits to draw the") HELP_TEXT ("outlines of the brush with the Fore- color.") HELP_TEXT ("") HELP_LINK ("- Nibble: (Key:%s)",SPECIAL_NIBBLE) HELP_TEXT ("This option \"nibbles\" the outlines") HELP_TEXT ("of the brush. It's in some way the opposite") HELP_TEXT ("effect of the Outline option.") HELP_TEXT ("") HELP_LINK ("- Recolorize: (Key:%s)",SPECIAL_RECOLORIZE_BRUSH) HELP_TEXT ("Remaps the brush so that it") HELP_TEXT ("looks like it would in the spare page, using") HELP_TEXT ("the current palette.") HELP_TEXT ("") HELP_LINK ("- Get brush colors: (Key:%s)",SPECIAL_GET_BRUSH_COLORS) HELP_TEXT ("Transfers the spare") HELP_TEXT ("page's colors used by the brush to the") HELP_TEXT ("current palette.") HELP_TEXT ("") HELP_TEXT ("- Brush handle:") HELP_TEXT ("Allows you to choose where to place the") HELP_TEXT ("handle of the brush. Shortcuts are :") HELP_LINK (" Center : %s", SPECIAL_CENTER_ATTACHMENT) HELP_LINK (" Top-left : %s", SPECIAL_TOP_LEFT_ATTACHMENT) HELP_LINK (" Top-right : %s", SPECIAL_TOP_RIGHT_ATTACHMENT) HELP_LINK (" Bottom-left : %s", SPECIAL_BOTTOM_LEFT_ATTACHMENT) HELP_LINK (" Bottom-right: %s", SPECIAL_BOTTOM_RIGHT_ATTACHMENT) HELP_TEXT ("") HELP_LINK ("- Load : (Key:%s)",SPECIAL_LOAD_BRUSH) HELP_TEXT ("Load a brush from disk.") HELP_TEXT ("") HELP_LINK ("- Save : (Key:%s)",SPECIAL_SAVE_BRUSH) HELP_TEXT ("Save a brush to disk.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("BRUSH FACTORY") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH_EFFECTS) HELP_TEXT ("") HELP_TEXT ("This menu allows you to run scripts. Scripts") HELP_TEXT ("are written in the Lua language, and allow") HELP_TEXT ("you to modify the brush (hence the name") HELP_TEXT ("'Brush factory'), or even modify the image") HELP_TEXT ("or palette, like a Photoshop filter. See") HELP_TEXT ("the online documentation for more help") HELP_TEXT ("on scripting.") HELP_TEXT ("") HELP_TEXT ("You can select a script with the selector,") HELP_TEXT ("the bottom panel shows a short description") HELP_TEXT ("of what it does, and you can click Run to") HELP_TEXT ("launch it.") HELP_TEXT ("") HELP_TEXT ("The scripts are located in the application's") HELP_TEXT ("data folder, under the '/scripts'") HELP_TEXT ("subdirectory. The list is refreshed each") HELP_TEXT ("time you open the window. Scripts are loaded") HELP_TEXT ("from disk when you run them.") HELP_TEXT ("") HELP_LINK ("- Repeat last script: %s", SPECIAL_REPEAT_SCRIPT) HELP_TEXT ("") }; static const T_Help_table helptable_effects[] = { HELP_TITLE("DRAW MODES") HELP_LINK ("(Key:%s)",0x100+BUTTON_EFFECTS) HELP_TEXT ("") HELP_TEXT (" This button opens a menu where you can") HELP_TEXT ("switch on or off the different drawing") HELP_TEXT ("modes.") HELP_TEXT (" In this menu, the \"All off\" button switches") HELP_TEXT ("all the drawing modes off. The [Del] key") HELP_TEXT ("is the keyboard shortcut for this button.") HELP_TEXT (" The \"Feedback\" button is only used in") HELP_TEXT ("\"Shade\", \"Quick-shade, \"Transparency\"") HELP_TEXT ("and \"Smooth\" modes. When it is set, it means") HELP_TEXT ("that the _current_ state of the picture") HELP_TEXT ("has to be taken into account for the effect") HELP_TEXT ("instead of the state in which the image") HELP_TEXT ("was when you started to click for drawing.") HELP_TEXT ("The best, as often, is that you try by") HELP_TEXT ("yourself with and without Feedback to see") HELP_TEXT ("the difference.") HELP_TEXT (" The other buttons are the following:") HELP_TEXT ("") HELP_TITLE("SHADE") HELP_TEXT (" It consists in increasing or decreasing the") HELP_TEXT ("color number within a user-defined range.") HELP_TEXT ("This shows its real dimension when used with") HELP_TEXT ("a range of colors that shade off. Then,") HELP_TEXT ("you can work on a part of your picture where") HELP_TEXT ("colors belong to the same range without") HELP_TEXT ("having to change your brush color all the") HELP_TEXT ("time. You can choose the incrementation or") HELP_TEXT ("decrementation of the color by pressing") HELP_TEXT ("the left or right mouse button while") HELP_TEXT ("drawing. If you click on a color that does") HELP_TEXT ("not belong to the range, it will remain") HELP_TEXT ("unchanged.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key : %s)", SPECIAL_SHADE_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Shade mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_SHADE_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define one table") HELP_TEXT ("of shades within a range of 8 memorised by") HELP_TEXT ("the program. The different sections of this") HELP_TEXT ("menu are:") HELP_TEXT ("") HELP_TEXT ("- Palette: You can define in it the color") HELP_TEXT ("blocks that will be inserted") HELP_TEXT ("into the table of shades.") HELP_TEXT ("") HELP_TEXT ("- Scroller: Used to change flick through the") HELP_TEXT ("tables of shades.") HELP_TEXT ("") HELP_TEXT ("- Table of shades definition area: The 512") HELP_TEXT ("squares should be widely") HELP_TEXT ("sufficient to define the different shades") HELP_TEXT ("since every 256 colors of") HELP_TEXT ("the palette cannot be present more than once") HELP_TEXT ("in each table.") HELP_TEXT ("") HELP_TEXT ("- A window (on the top-right side) permits") HELP_TEXT ("to visualize the different") HELP_TEXT ("shades defined in he current table.") HELP_TEXT ("") HELP_TEXT ("- Copy: Copy the contents of the table in a") HELP_TEXT ("buffer.") HELP_TEXT ("(Each time you open this menu, the current") HELP_TEXT ("table is automatically") HELP_TEXT ("transfered into this buffer).") HELP_TEXT ("") HELP_TEXT ("- Paste: Copy the contents of the buffer") HELP_TEXT ("above in the current table.") HELP_TEXT ("") HELP_TEXT ("- Clear: Reset the \"shades\" table.") HELP_TEXT ("") HELP_TEXT ("- Insert: Used to insert the block selected") HELP_TEXT ("in the palette at the") HELP_TEXT ("cursor's position in the table of shades.") HELP_TEXT ("IF you click with the left mouse button on") HELP_TEXT ("this button THEN IF a block of more than one") HELP_TEXT ("color is selected in the table THEN It is") HELP_TEXT ("deleted and the block defined in the palette") HELP_TEXT ("is inserted. ELSE The block defined in the") HELP_TEXT ("palette is inserted at the postion just") HELP_TEXT ("before the selected square. END IF") HELP_TEXT ("ELSE The block defined in the palette is") HELP_TEXT ("inserted by erasing the colors following the") HELP_TEXT ("beginning of the bloc selected in the table.") HELP_TEXT ("END IF") HELP_TEXT ("") HELP_TEXT ("- Delete: Delete the block selected in the") HELP_TEXT ("table.") HELP_TEXT ("") HELP_TEXT ("- Blank: Follows this algorithm:") HELP_TEXT ("IF you click with the left mouse button on") HELP_TEXT ("this button THEN Replace the block selected") HELP_TEXT ("in the table by blank squares.") HELP_TEXT ("ELSE IF a block of more than one color is") HELP_TEXT ("selected in the table THEN Insert blank") HELP_TEXT ("squares to the left and to the right of the") HELP_TEXT ("block. (this is useful for isolating a") HELP_TEXT ("shade quickly) ELSE Insert blank squares") HELP_TEXT ("to the left of the selected square. END IF") HELP_TEXT ("END IF") HELP_TEXT ("") HELP_TEXT ("- Invert: Invert the order of the block") HELP_TEXT ("selected in the table.") HELP_TEXT ("") HELP_TEXT ("- Swap: Allows you you move a block (this") HELP_TEXT ("exchanges it with what is") HELP_TEXT ("where you want to move it).") HELP_TEXT ("") HELP_TEXT ("- Undo: Cancel the last modification of the") HELP_TEXT ("table.") HELP_TEXT ("") HELP_TEXT ("- The 2 numbers displayed on the right of") HELP_TEXT ("these buttons are: (above) - the number of") HELP_TEXT ("the color selected in the palette if only") HELP_TEXT ("one color is selected. (below) - the number") HELP_TEXT ("of the color contained in a square in the") HELP_TEXT ("shades table if this square is the only one") HELP_TEXT ("selected.") HELP_TEXT ("") HELP_TEXT ("- The \"mode\" button displays 3 different") HELP_TEXT ("modes:") HELP_TEXT ("\"Normal\": Shades in the range and saturates") HELP_TEXT ("to its boundaries.") HELP_TEXT ("\"Loop\": Shades in the range and loops if") HELP_TEXT ("boundaries are passed.") HELP_TEXT ("\"No saturation\": Shades in the range and") HELP_TEXT ("doesn't saturate if boundaries are passed.") HELP_TEXT ("If the Step (see below) is set to 1, this") HELP_TEXT ("option does exactly the same as the Normal") HELP_TEXT ("mode.") HELP_TEXT ("") HELP_TEXT ("- Set/Disable: If you want to define several") HELP_TEXT ("shades in the same table") HELP_TEXT ("but you'd like these shades not to be") HELP_TEXT ("effective at the same time, you") HELP_TEXT ("can mask (disable) some parts of the table") HELP_TEXT ("so that they will be") HELP_TEXT ("interpreted a blank squares.") HELP_TEXT ("To do that, select a block in the table of") HELP_TEXT ("shades and click on \"Set\".") HELP_TEXT ("The block will be underlined with a white") HELP_TEXT ("line; this means that it is") HELP_TEXT ("disabled.") HELP_TEXT ("") HELP_TEXT ("- Clear/Enable: This does exactly the") HELP_TEXT ("opposite as the button above.") HELP_TEXT ("") HELP_TEXT ("- Step: Defines the step of incrementation") HELP_TEXT ("of the shade. The bigger,") HELP_TEXT ("the faster you run through the colors of the") HELP_TEXT ("shade.") HELP_TEXT ("For example: if the step is 2 and that you") HELP_TEXT ("have defined a shade with") HELP_TEXT ("the colors 0,1,4,5,9 and that you click on a") HELP_TEXT ("pixel of color 1, it will") HELP_TEXT ("take the value 5 which is 2 positions next") HELP_TEXT ("in the la table.") HELP_TEXT ("") HELP_TEXT ("(We are sorry for these technical") HELP_TEXT ("considerations quite far from a purely") HELP_TEXT ("artistic point of view; but know that this") HELP_TEXT ("effect is really very useful and it is") HELP_TEXT ("preferable that you understand its whole") HELP_TEXT ("functionment if you want to fully take") HELP_TEXT ("advantage of it).") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("QUICK SHADE") HELP_TEXT (" This drawing mode has about the same effect") HELP_TEXT ("as Shade mode's except that it is faster") HELP_TEXT ("to configurate but a little bit less") HELP_TEXT ("powerful. When you draw on a color of the") HELP_TEXT ("image which is between the fore- and the") HELP_TEXT ("back-color in the palette, the color tends") HELP_TEXT ("towards the fore-color (according to the") HELP_TEXT ("step defined) if you draw with the left") HELP_TEXT ("mouse button, or it tends towards the") HELP_TEXT ("back-color if you are using the right mouse") HELP_TEXT ("button.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_QUICK_SHADE_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Quick-shade mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_QUICK_SHADE_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu with a few parameters that mean") HELP_TEXT ("exactly the same as in the menu of Shade") HELP_TEXT ("mode. These parameters are the step and the") HELP_TEXT ("loop/satu- ration mode (normal, loop, no") HELP_TEXT ("saturation).") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("STENCIL") HELP_TEXT (" It is used to prevent some colors from") HELP_TEXT ("being modified if you draw on them. The") HELP_TEXT ("main application of the stencil is when you") HELP_TEXT ("want to change one color or more into") HELP_TEXT ("another.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_STENCIL_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Stencil mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_STENCIL_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define a stencil.") HELP_TEXT ("The different sections of this menu are:") HELP_TEXT ("") HELP_TEXT ("- Clear: No color is protected.") HELP_TEXT ("") HELP_TEXT ("- Invert: Colors that were protected are") HELP_TEXT ("unprotected and vice versa.") HELP_TEXT ("") HELP_TEXT ("- Palette: Select colors that should be") HELP_TEXT ("protected with the left mouse button or") HELP_TEXT ("unprotect colors with the right mouse") HELP_TEXT ("button.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("MASK") HELP_TEXT (" This effect could have been called \"True") HELP_TEXT ("stencil\" because it protects some parts of") HELP_TEXT ("the picture instead of some colors. The") HELP_TEXT ("colors you tag represent the pixels in the") HELP_TEXT ("spare page, corresponding to the pixels in") HELP_TEXT ("the current page, that you don't want to") HELP_TEXT ("alter. For example, draw a simple white") HELP_TEXT ("figure on a black background in the spare") HELP_TEXT ("page. Then, tag the black color in the menu") HELP_TEXT ("of the Mask mode. When you'll draw in the") HELP_TEXT ("current page, only the pixels corresponding") HELP_TEXT ("to the white (non-black) ones in the spare") HELP_TEXT ("page will be modified.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_MASK_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Mask mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_MASK_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can set the colors of") HELP_TEXT ("the Mask.") HELP_TEXT ("This menu works the same way as the one of") HELP_TEXT ("the Stencil, so please refer to the Stencil") HELP_TEXT ("paragraph to know how to use it.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("GRID") HELP_TEXT (" This is useful to snap the cursor to the") HELP_TEXT ("cross-points of a grid. It's generally") HELP_TEXT ("used to draw a grid before drawing sprites") HELP_TEXT ("of the same size such as a font or tiles,") HELP_TEXT ("or for drawing figures or grabbing brushes") HELP_TEXT ("with their dimensions multiple of the step") HELP_TEXT ("of the grid.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_GRID_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Snap-to-grid mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_GRID_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define the grid") HELP_TEXT ("parameters. These parameters are:") HELP_TEXT ("") HELP_TEXT ("- X,Y: Steps of the grid.") HELP_TEXT ("") HELP_TEXT ("- dX,dY: Offsets of the grid.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("The following shortcut hides or shows the") HELP_TEXT ("grid in the magnified view:") HELP_LINK ("%s", SPECIAL_SHOW_GRID) HELP_TEXT ("The grid size will be according to your") HELP_TEXT ("snap-to-grid settings.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("SIEVE") HELP_TEXT (" This effect allows you, by defining a") HELP_TEXT ("pattern, to draw only on particular points") HELP_TEXT ("of the picture. If you are a Manga drawer,") HELP_TEXT ("you might find this useful to make patterned") HELP_TEXT ("shades or color transitions.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_SIEVE_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Sieve mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_SIEVE_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define the Sieve") HELP_TEXT ("parameters. This menu consists in:") HELP_TEXT ("") HELP_TEXT ("- 16x16 drawing area: You can define a") HELP_TEXT ("pattern in it (left click => white pixel /") HELP_TEXT ("right click => black pixel). All the white") HELP_TEXT ("pixels indicate that, when you'll draw,") HELP_TEXT ("pixels will be applied on the picture at the") HELP_TEXT ("corresponding positions whereas black pixels") HELP_TEXT ("won't modify the picture: whites pixels are") HELP_TEXT ("the \"holes of the sieve\".") HELP_TEXT ("") HELP_TEXT ("- 12 default patterns: They can be copied to") HELP_TEXT ("the drawing area.") HELP_TEXT ("") HELP_TEXT ("- \"Transfer to brush\": Copies the pattern to") HELP_TEXT ("the brush (white pixels => Fore-color /") HELP_TEXT ("black pixels => Back-color).") HELP_TEXT ("") HELP_TEXT ("- \"Get from brush\": Puts the brush into the") HELP_TEXT ("drawing area (back-color => black pixels /") HELP_TEXT ("others => white pixels).") HELP_TEXT ("") HELP_TEXT ("- Scrolling 4-arrows pad: Scrolls the") HELP_TEXT ("pattern in the drawing area.") HELP_TEXT ("") HELP_TEXT ("- Resizing 4-arrows pad: Defines the") HELP_TEXT ("dimensions of the pattern.") HELP_TEXT ("") HELP_TEXT ("- Default-value (black or white square):") HELP_TEXT ("Indicates which value must be inserted when") HELP_TEXT ("you increase the dimensions of the pattern.") HELP_TEXT ("") HELP_TEXT ("- \"Clear\": Sets the whole pattern with the") HELP_TEXT ("default value (see above).") HELP_TEXT ("") HELP_TEXT ("- \"Invert\": It... inverts :) ... black and") HELP_TEXT ("white pixels.") HELP_LINK ("(Key: %s)", SPECIAL_INVERT_SIEVE) HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("TRANSPARENCY") HELP_TEXT (" This allows to mix the color(s) of the") HELP_TEXT ("paintbrush with the colors of the picture.") HELP_TEXT ("It's used to make transparency effects like") HELP_TEXT ("with watercolors.") HELP_TEXT ("") HELP_TEXT ("You can also use the following shortcuts to") HELP_TEXT ("activate transparency mode and assign an") HELP_TEXT ("amount of opacity:") HELP_LINK (" 10%% : %s", SPECIAL_TRANSPARENCY_1) HELP_LINK (" 20%% : %s", SPECIAL_TRANSPARENCY_2) HELP_LINK (" 30%% : %s", SPECIAL_TRANSPARENCY_3) HELP_LINK (" 40%% : %s", SPECIAL_TRANSPARENCY_4) HELP_LINK (" 50%% : %s", SPECIAL_TRANSPARENCY_5) HELP_LINK (" 60%% : %s", SPECIAL_TRANSPARENCY_6) HELP_LINK (" 70%% : %s", SPECIAL_TRANSPARENCY_7) HELP_LINK (" 80%% : %s", SPECIAL_TRANSPARENCY_8) HELP_LINK (" 90%% : %s", SPECIAL_TRANSPARENCY_9) HELP_LINK (" 100%% : %s", SPECIAL_TRANSPARENCY_0) HELP_TEXT ("If you use two of these shortcuts quickly,") HELP_TEXT ("the second will set the units for finer") HELP_TEXT ("control. Ie: 4 5 makes 45%, 0 9 makes 9%.") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_COLORIZE_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Transparency mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_COLORIZE_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define the") HELP_TEXT ("Transparency parameters. These parameters") HELP_TEXT ("are:") HELP_TEXT ("") HELP_TEXT ("- Interpolation rate: Indicates the") HELP_TEXT ("percentage of the applied color that will be") HELP_TEXT ("considered upon the replaced color.") HELP_TEXT ("") HELP_TEXT ("- Interpolation method: Uses an") HELP_TEXT ("interpolation algorithm to compute the") HELP_TEXT ("color, according to the interpolation rate.") HELP_TEXT ("") HELP_TEXT ("- Additive method: Uses the lightest colors") HELP_TEXT ("to choose the color to apply. For example:") HELP_TEXT ("if you want to apply a color RGB:30,20,40 on") HELP_TEXT ("a color RGB:10,50,20, the color applied will") HELP_TEXT ("be the one, in the palette, that is the") HELP_TEXT ("closest to the theoretic color RGB:30,50,40.") HELP_TEXT ("") HELP_TEXT ("- Subtractive method: uses the darkest") HELP_TEXT ("colors to choose the color to apply. For") HELP_TEXT ("example: if you want to apply a color") HELP_TEXT ("RGB:30,20,40 on a color RGB:10,50,20, the") HELP_TEXT ("color applied will be the one, in the") HELP_TEXT ("palette, that is the closest to the") HELP_TEXT ("theoretic color RGB:10,20,20.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("SMOOTH") HELP_TEXT (" It provides an easy but not as efficient") HELP_TEXT ("anti-aliasing as any artist's touch.") HELP_TEXT ("Anyway this effect finds a better use in") HELP_TEXT ("making a blurry aspect.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_SMOOTH_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Smooth mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_SMOOTH_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define the Smooth") HELP_TEXT ("matrix or choose one among the 4 ones") HELP_TEXT ("predefined.") HELP_TEXT ("The middle square represents the pixel on") HELP_TEXT ("which you draw and the 8 others represent") HELP_TEXT ("the neighbour pixels. Then, the point on") HELP_TEXT ("which one draw will be replaced by the") HELP_TEXT ("weighted average (according to values of") HELP_TEXT ("each squares) of the 9 defined points.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("SMEAR") HELP_TEXT (" It smears pixels in the direction you are") HELP_TEXT ("moving your paintbrush, just as if you") HELP_TEXT ("wanted to spread fresh paint with your") HELP_TEXT ("fingers. You can combine this effect with") HELP_TEXT ("the transparency effect.") HELP_TEXT ("") HELP_LINK ("(Key: %s)", SPECIAL_SMEAR_MODE) HELP_TEXT ("Switches the Smear mode.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("TILING") HELP_TEXT (" It consists in displaying parts of the") HELP_TEXT ("brush that are adjusted on a tiling when") HELP_TEXT ("you are drawing. It's mainly used for") HELP_TEXT ("quickly drawing a background with a") HELP_TEXT ("pattern, but there is a great number of") HELP_TEXT ("other possibilities.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_TILING_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Tiling mode.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_TILING_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define the Tiling") HELP_TEXT ("parameters. These parameters are the offsets") HELP_TEXT ("of the tiling.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("TILEMAP") HELP_TEXT (" This mode analyses the current image to") HELP_TEXT ("define identical rectangular tiles. After") HELP_TEXT ("that, anything you draw is repeated on all") HELP_TEXT ("other occurrences of the same tile. The tile") HELP_TEXT ("dimensions are defined by the Grid settings") HELP_TEXT ("(but the grid mode doesn't have to be") HELP_TEXT ("active). ") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_TILEMAP_MODE) HELP_TEXT ("") HELP_TEXT ("Switches the Tilemap mode. Note that it is") HELP_TEXT ("set separately for the main and spare page.") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_TILEMAP_MENU) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can define the") HELP_TEXT ("following options for the tilemap mode:") HELP_TEXT ("") HELP_TEXT ("* Detect mirrored : When this is active,") HELP_TEXT ("Grafx2 detects tiles that are exact mirrored") HELP_TEXT ("versions of another. It can be set") HELP_TEXT ("separately for X and Y.") HELP_TEXT ("") HELP_TEXT ("* Show count : Briefly displays the number") HELP_TEXT ("of unique tiles after each analysis.") HELP_TEXT ("") }; static const T_Help_table helptable_text[] = { HELP_TITLE("TEXT") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_TEXT) HELP_TEXT ("") HELP_TEXT ("The text menu allows you to enter some text") HELP_TEXT ("and render it as a brush.") HELP_TEXT ("The current background and foreground colors") HELP_TEXT ("are very important, they determine the text") HELP_TEXT ("color, the transparent color, and also the") HELP_TEXT ("color range to use for antialiasing.") HELP_TEXT ("GrafX2 can use 'bitmap' fonts as long as") HELP_TEXT ("they are in the special layout supported ") HELP_TEXT ("by SFont.") HELP_TEXT ("TrueType fonts can also be used if this") HELP_TEXT ("version of GrafX2 was compiled with") HELP_TEXT ("TrueType support.") HELP_TEXT ("") HELP_TEXT ("- Txt: Click and enter your text here, a") HELP_TEXT ("line of up to 250 characters.") HELP_TEXT ("") HELP_TEXT ("- Clear txt: Empties the current text.") HELP_TEXT ("When the text is empty, a standard string") HELP_TEXT ("is shown instead in the preview area.") HELP_TEXT ("") HELP_TEXT ("- Antialias: Click to enable or disable") HELP_TEXT ("Antialiasing. Only affects TrueType fonts.") HELP_TEXT ("") HELP_TEXT ("- Size: Determine the font height. Only") HELP_TEXT ("affects TrueType fonts.") HELP_TEXT ("") HELP_TEXT ("- Font selector: Choose a font. You can") HELP_TEXT ("use the arrow keys (up and down) to quickly") HELP_TEXT ("browse your fonts.") HELP_TEXT ("TrueType fonts are indicated by 'TT'.") HELP_TEXT ("") HELP_TEXT ("- Preview area: Shows what the brush will") HELP_TEXT ("look like.") }; static const T_Help_table helptable_magnifier[] = { HELP_TITLE("MAGNIFIER") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_MAGNIFIER) HELP_TEXT ("") HELP_TEXT ("Engages/Disengages the choice of the zoomed") HELP_TEXT ("window. If you're already in magnifier mode,") HELP_TEXT ("you'll return to normal mode.") HELP_LINK ("Zoom in : %s",SPECIAL_ZOOM_IN) HELP_LINK ("Zoom out: %s",SPECIAL_ZOOM_OUT) HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_MAGNIFIER) HELP_TEXT ("") HELP_TEXT ("Displays a menu where you can choose the") HELP_TEXT ("magnifying factor.") HELP_TEXT ("") HELP_TEXT (" Note: When you are in Zoom mode, you can") HELP_TEXT ("move the \"split\" bar by clicking on it and") HELP_TEXT ("moving your mouse left or right while") HELP_TEXT ("holding the mouse button down.") }; static const T_Help_table helptable_colorpicker[] = { HELP_TITLE("PIPETTE") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_COLORPICKER) HELP_TEXT ("") HELP_TEXT ("Engages a color grabbing.") HELP_TEXT ("") HELP_TEXT ("Click on the picture to get the color of the") HELP_TEXT ("pixel you're on. You can either get a new") HELP_TEXT ("Fore-color or Back-color with respectively") HELP_TEXT ("left or right mouse button.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_COLORPICKER) HELP_TEXT ("") HELP_TEXT ("Swap Fore-color and Back-color.") HELP_TEXT ("") HELP_TEXT (" The color currently pointed will be") HELP_TEXT ("displayed in the tool-bar right after the") HELP_TEXT ("coordinates. If you click outside the") HELP_TEXT ("picture, the color 0 will be returned.") }; static const T_Help_table helptable_resolution[] = { HELP_TITLE("RESOLUTION AND") HELP_TITLE(" IMAGE SIZE") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_RESOL) HELP_TEXT ("") HELP_TEXT ("Displays a menu where you can define the") HELP_TEXT ("size of your picture and choose the") HELP_TEXT ("screen resolution.") HELP_TEXT ("") HELP_TEXT ("- Image size") HELP_TEXT ("Click in the boxes named \"Width\" and") HELP_TEXT ("\"Height\" to change the size of the image") HELP_TEXT ("you're editing, up to 9999x9999.") HELP_TEXT ("You can also right-click a video mode to") HELP_TEXT ("copy its dimensions to the image's.") HELP_TEXT ("") HELP_TEXT ("- Pixel size") HELP_TEXT ("If you choose any Pixel size other than") HELP_TEXT ("Normal, Grafx2 will emulate a lower") HELP_TEXT ("resolution by scaling up everything it") HELP_TEXT ("displays, including the menus and mouse") HELP_TEXT ("cursor. In Double, Triple and Quadruple") HELP_TEXT ("mode, the image will appear zoomed x2, x3 or") HELP_TEXT ("x4, keeping the original proportions. The") HELP_TEXT ("scaling is done in software, with no linear") HELP_TEXT ("interpolation, so it can't cause blur. This") HELP_TEXT ("setting is especially useful if your") HELP_TEXT ("hardware or drivers don't support the low") HELP_TEXT ("resolutions you need, but it also allows you") HELP_TEXT ("to draw in low-resolution while staying in") HELP_TEXT ("window mode.") HELP_TEXT ("If you choose one of the scalers called") HELP_TEXT ("Wide, Tall, Wide2 and Tall2, this will") HELP_TEXT ("emulate a video mode which has rectangular") HELP_TEXT ("pixels (longer horizontally or vertically),") HELP_TEXT ("like some video modes of the C64, Amstrad") HELP_TEXT ("CPC, and Commodore Amiga.") HELP_TEXT ("") HELP_TEXT ("- Video mode") HELP_TEXT ("Click on a video mode to select it.") HELP_TEXT ("Grafx2 only lists modes that are detected") HELP_TEXT ("as available on your computer. Depending on") HELP_TEXT ("your video card and drivers, there can be") HELP_TEXT ("a huge difference in the number of modes") HELP_TEXT ("it can propose.") HELP_TEXT ("The small buttons on the left-hand side of") HELP_TEXT ("the lines in the list of modes have been") HELP_TEXT ("designed to allow you to disable some modes") HELP_TEXT ("that are not supported by your card. So, the") HELP_TEXT ("modes that you will disable won't be used") HELP_TEXT ("when loading pictures with \"Auto-set") HELP_TEXT ("resolution\" ON.") HELP_TEXT ("") HELP_TEXT ("When you click on one of these buttons, its") HELP_TEXT ("color changes to one of the 4 following. The") HELP_TEXT ("signification for each color of these") HELP_TEXT ("buttons is:") HELP_TEXT ("") HELP_TEXT ("- Light gray: The video mode is OK. It can") HELP_TEXT ("be used by the auto-set resolution option") HELP_TEXT ("when you load picture, and you can select it") HELP_TEXT ("in the menu of resolutions.") HELP_TEXT ("") HELP_TEXT ("- White: It works exactly the same as above.") HELP_TEXT ("Moreover, it allows you to tag your") HELP_TEXT ("favourite modes. Indeed, the huge number of") HELP_TEXT ("video modes makes it more difficult to find") HELP_TEXT ("the mode your want in the list; so you can") HELP_TEXT ("tag your favoutite ones in white, so that it") HELP_TEXT ("will be easier to locate them. (Note: you") HELP_TEXT ("cannot disable the standard windowed mode)") HELP_TEXT ("") HELP_TEXT ("- Dark gray: It allows you to indicate which") HELP_TEXT ("modes are not really perfect (flickering,") HELP_TEXT ("not centered, etc...) but which can be used") HELP_TEXT ("even so. The difference with the light grey") HELP_TEXT ("button is that these modes won't be used by") HELP_TEXT ("the auto-set resolution option.") HELP_TEXT ("") HELP_TEXT ("- Black: Use it for totally unsupported") HELP_TEXT ("modes. Thus, these modes won't be selected") HELP_TEXT ("the \"auto-set res.\" and the program will") HELP_TEXT ("not let you select them from the list of") HELP_TEXT ("resolutions.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_RESOL) HELP_TEXT ("") HELP_TEXT (" Automatically switches to the 640x400 window") HELP_TEXT ("mode.") }; static const T_Help_table helptable_page[] = { HELP_TITLE("SPARE") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_PAGE) HELP_TEXT ("") HELP_TEXT ("Jumps to spare page. The current page is") HELP_TEXT ("then considered as the new spare page, and") HELP_TEXT ("the spare page considered as the new current") HELP_TEXT ("page.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_PAGE) HELP_TEXT ("") HELP_TEXT ("Opens a menu where you can choose whether") HELP_TEXT ("you want to copy the whole picture (keyboard") HELP_TEXT ("short-cut in this menu is [Return]), only") HELP_TEXT ("the pixels, only the palette, or only some") HELP_TEXT ("colors.") HELP_TEXT ("In this last case, a second menu") HELP_TEXT ("(stencil-like) will propose you to tag the") HELP_TEXT ("colors you want to copy (they are all") HELP_TEXT ("selected by default).") HELP_TEXT ("Please refer to section \"Stencil\" to know") HELP_TEXT ("how to use this last menu.") HELP_TEXT ("The last option the menu (\"Copy palette and") HELP_TEXT ("remap\"), remaps the spare page with the") HELP_TEXT ("current palette and replicates this palette") HELP_TEXT ("to the spare page. This option is useful to") HELP_TEXT ("quickly remap a picture with the palette of") HELP_TEXT ("another.") }; static const T_Help_table helptable_save[] = { HELP_TITLE("SAVE") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_SAVE) HELP_TEXT ("") HELP_TEXT ("Displays a fileselector where the following") HELP_TEXT ("options are available:") HELP_TEXT ("") HELP_TEXT ("- Select drive: Allow you to change the") HELP_TEXT ("current drive.or volume (depending on your") HELP_TEXT ("operating system") HELP_TEXT ("") HELP_TEXT ("- Format: Allows you to choose the file") HELP_TEXT ("format you want. (PAL and KCF file formats") HELP_TEXT ("are \"palette\" files).") HELP_TEXT ("") HELP_TEXT ("- Filename: Allows you to give a new name to") HELP_TEXT ("the picture. If no extension is given, the") HELP_TEXT ("default (according to the format) will be") HELP_TEXT ("used.") HELP_TEXT ("") HELP_TEXT ("- Bookmarks: The four dropdown buttons allow") HELP_TEXT ("you to bookmark frequently used directories.") HELP_TEXT ("Use right-click to open a contextual menu") HELP_TEXT ("to Set it (memorize current directory),") HELP_TEXT ("Rename it to change its label, and Clear it") HELP_TEXT ("if you no longer need it. Use left-click to") HELP_TEXT ("change to the memorized directory.") HELP_TEXT ("") HELP_TEXT ("- File-list: Allows you to flick through the") HELP_TEXT ("disk tree or to overwrite an existing file.") HELP_TEXT ("") HELP_TEXT ("- Delete: Allows you to delete the item") HELP_TEXT ("under the selection bar. If the item is a") HELP_TEXT ("directory, it must be empty to be removed.") HELP_TEXT ("") HELP_TEXT ("- Save: Saves the picture with the current") HELP_TEXT ("filename, with the chosen format. If the ") HELP_TEXT ("current filename represents a directory,") HELP_TEXT ("you'll enter it.") HELP_TEXT ("") HELP_TEXT ("- Comment (Txt): If you're using the PKM") HELP_TEXT ("or PNG format, you can type in a comment on") HELP_TEXT ("your picture. It will be memorized in the") HELP_TEXT ("image.") HELP_TEXT ("") HELP_TEXT ("Note: The Backspace key brings you directly") HELP_TEXT ("to the parent directory. You can also type") HELP_TEXT ("the first letters of a filename you are") HELP_TEXT ("looking for, to access it faster.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_SAVE) HELP_TEXT ("") HELP_TEXT ("Save the current picture with its current") HELP_TEXT ("filename, format and comment.") HELP_TEXT ("") HELP_TEXT ("If the file already exists, a confirmation") HELP_TEXT ("box will appear.") }; static const T_Help_table helptable_load[] = { HELP_TITLE("LOAD") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_LOAD) HELP_TEXT ("") HELP_TEXT ("This works the same way as Save.") HELP_TEXT ("") HELP_TEXT ("You'll have access in the format selector to") HELP_TEXT ("a \"*.*\" filter. And of course, you won't be") HELP_TEXT ("able to type in any comment.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_LOAD) HELP_TEXT ("") HELP_TEXT ("Reloads the picture.") HELP_TEXT ("") HELP_TEXT ("If you want to load a picture and that you") HELP_TEXT ("haven't saved the last modifications of the") HELP_TEXT ("current picture, a confirmation box will") HELP_TEXT ("appear.") }; static const T_Help_table helptable_settings[] = { HELP_TITLE("SETTINGS") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_SETTINGS) HELP_TEXT ("") HELP_TEXT ("Displays a menu where you can configure some") HELP_TEXT ("miscellaneous elements of the program.") HELP_TEXT ("Detailed description of each setting is") HELP_TEXT ("available when this screen is open (Use the") HELP_LINK ("%s key.",0x100+BUTTON_HELP) HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("SKINS") HELP_TEXT ("") HELP_TEXT ("This window allow you to change the look and") HELP_TEXT ("feel of the program.") HELP_TEXT ("") HELP_TEXT ("- Font: determines whether you want to use") HELP_TEXT ("GrafX2 with a classical font, or another one") HELP_TEXT ("a bit funnier.") HELP_TEXT ("") HELP_TEXT ("- Cursor: Allows you to choose the graphic") HELP_TEXT ("mouse cursor: Solid and Thin are solid black") HELP_TEXT ("and white cursors defined by the skin file,") HELP_TEXT (" Transparent is a 1-pixel wide XOR cross.") HELP_TEXT ("") HELP_TEXT ("- Graphic file: you can change the whole") HELP_TEXT ("interface by selecting where the sprites for") HELP_TEXT ("all buttons are. Look at the files in the") HELP_TEXT ("\"skin\" directory if you want to create your") HELP_TEXT ("own. There are two skins available, the") HELP_TEXT ("default for 2.1 is called modern. Classic is") HELP_TEXT ("for nostalgics who wish to remember the old") HELP_TEXT ("days of Sunset Design. If you create a good") HELP_TEXT ("skin, feel free to share it with us! We may") HELP_TEXT ("include it in a future release...") HELP_TEXT ("") HELP_TEXT ("- Separate colors: Draws a squaring around") HELP_TEXT ("the colors of the tool-bar.") HELP_TEXT ("") HELP_TEXT ("- Show/Hide picture limits: Indicates if the") HELP_TEXT ("picture boundaries must be displayed when") HELP_TEXT ("you are in a resolution bigger than the") HELP_TEXT ("picture.") HELP_TEXT ("") }; static const T_Help_table helptable_settings_details[] = { HELP_TITLE("DETAILED SETTINGS") HELP_TEXT ("") HELP_TITLE("FILE SELECTOR") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" Show hidden files") HELP_TEXT ("Hidden files appear.") HELP_TEXT ("") HELP_BOLD (" Show hidden directories") HELP_TEXT ("Hidden directories appear.") HELP_TEXT ("") HELP_BOLD (" Preview delay") HELP_TEXT ("Delay before displaying a preview in file-") HELP_TEXT ("selectors (in 18.2th of second). Possible") HELP_TEXT ("values range from 1 to 256.") HELP_TEXT ("") HELP_BOLD (" Maximize preview") HELP_TEXT ("Maximize the preview of the pictures so that") HELP_TEXT ("it is as big as possible. If you're not in") HELP_TEXT ("the same resolution as the picture's one, it") HELP_TEXT ("can try to correct the aspect ratio, but if") HELP_TEXT ("the picture does not fill the whole screen,") HELP_TEXT ("it can be worse.") HELP_TEXT ("") HELP_BOLD (" Find file fast") HELP_TEXT ("This option is used to place the selection") HELP_TEXT ("bar on a filename by typing its first") HELP_TEXT ("letters. For example, if you want to find") HELP_TEXT ("the 'PICTURE.PKM' in a directory that also") HELP_TEXT ("contains 'PALETTE.PAL', you'll just have to") HELP_TEXT ("type P and I. The different values of 'FFF'") HELP_TEXT ("indicate if you want to find the name in") HELP_TEXT ("both files and directories or just in only") HELP_TEXT ("one of these:") HELP_TEXT ("0: files and directories") HELP_TEXT ("1: files only") HELP_TEXT ("2: directories only") HELP_TEXT ("") HELP_BOLD (" Auto set resolution") HELP_TEXT ("Automatically set the resolution when") HELP_TEXT ("loading a picture. You should set this value") HELP_TEXT ("to 'yes' after disabling the video modes") HELP_TEXT ("that are notsupported by your video card or") HELP_TEXT ("monitor.") HELP_TEXT ("") HELP_BOLD (" Set resolution according to") HELP_TEXT ("If the variable above is set to 'yes', this") HELP_TEXT ("one tells if you want to set the resolution") HELP_TEXT ("according to:") HELP_TEXT ("1: the internal 'original screen' dimensions") HELP_TEXT (" of the picture") HELP_TEXT ("2: the actual dimensions of the picture") HELP_TEXT (" ") HELP_BOLD (" Backup") HELP_TEXT ("Create a backup file when saving.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("FILE FORMAT OPTIONS") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" Save screen size in GIF") HELP_TEXT ("Save the screen dimensions in GIF files. If") HELP_TEXT ("you want to read these files with Photoshop") HELP_TEXT ("or Alchemy, and maybe some other programs,") HELP_TEXT ("you must set this option to 'no'.") HELP_TEXT ("") HELP_BOLD (" Clear palette") HELP_TEXT ("If you load a picture with a palette of less") HELP_TEXT ("than 256 colors, this option defines if you") HELP_TEXT ("want to clear the palette or to keep the") HELP_TEXT ("colors of the previous picture that are over") HELP_TEXT ("the number of colors of the new picture.") HELP_TEXT ("For example, if you load a 32-color picture,") HELP_TEXT ("the colors 32 to 255 will be set to black if") HELP_TEXT ("this option is set to 'yes', or they will be") HELP_TEXT ("kept unchanged if this option is set to 'no'") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("GUI") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" Opening message") HELP_TEXT ("Display a message at startup telling the") HELP_TEXT ("version number of the program.") HELP_TEXT ("") HELP_BOLD (" Menu ratio") HELP_TEXT ("Aspect ratio and size of the menus and the") HELP_TEXT ("tool-bar.") HELP_TEXT ("Possible values:") HELP_TEXT ("0: Do not adapt (pixels are not stretched)") HELP_TEXT ("1: Adapt the menus and the tool-bar") HELP_TEXT (" according to the resolution") HELP_TEXT ("2: Slightly adapt the ratio of the menus and") HELP_TEXT (" tool-bar") HELP_TEXT ("-1:Do not adapt (like 0)") HELP_TEXT ("-2:Stretch by x2 maximum") HELP_TEXT ("-3:Stretch by x3 maximum") HELP_TEXT ("-4:Stretch by x4 maximum") HELP_TEXT ("") HELP_BOLD (" Draw limits") HELP_TEXT ("Draw the limits of the picture.") HELP_TEXT ("") HELP_BOLD (" Coordinates") HELP_TEXT ("Coordinates:") HELP_TEXT ("1: Relative") HELP_TEXT ("2: Absolute") HELP_TEXT ("") HELP_BOLD (" Separate colors") HELP_TEXT ("Separate the colors in the tool-bar by a") HELP_TEXT ("black squaring.") HELP_TEXT ("") HELP_BOLD (" Safety colors") HELP_TEXT ("When you reduce the palette or 'zap' some") HELP_TEXT ("colors out of it, it is possible that there") HELP_TEXT ("are not enough colors left to draw the") HELP_TEXT ("menus. Switching the following variable on") HELP_TEXT ("will bring back the colors of the menu if") HELP_TEXT ("there are less than 4 colors left after") HELP_TEXT ("'reducing' or 'zapping'.") HELP_TEXT ("") HELP_BOLD (" Grid XOR color") HELP_TEXT ("This determines the color value for the") HELP_TEXT ("grid. Each pixel of the grid will be") HELP_TEXT ("displayed by XOR-ing the original color with") HELP_TEXT ("the value of this setting.") HELP_TEXT ("For example, if you always paint 16-color") HELP_TEXT ("images, you can set it to 16 so the color of") HELP_TEXT ("the grid are 16 for 0, 17 for 1, etc. Then") HELP_TEXT ("you can set colors 16-31 as lighter/darker") HELP_TEXT ("variants of your original palette, resulting") HELP_TEXT ("in a pretty grid !") HELP_TEXT ("") HELP_BOLD (" Sync views") HELP_TEXT ("When this mode is active, scrolling the view") HELP_TEXT ("(and the magnifier view) affects both the") HELP_TEXT ("main image and the spare page - as long as") HELP_TEXT ("they have the same dimensions.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("INPUT") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" Gauges scrolling speed Left") HELP_TEXT ("Speed of the scroll-bars (in VBLs waited)") HELP_TEXT ("while clicking with the left or right button") HELP_TEXT ("of the mouse.") HELP_TEXT ("Values can be between 1 and 255. The bigger") HELP_TEXT ("values, the slower.") HELP_TEXT ("") HELP_BOLD (" Gauges scrolling speed Right") HELP_TEXT ("Speed of the scroll-bars (in VBLs waited)") HELP_TEXT ("while clicking with the left or right button") HELP_TEXT ("of the mouse.") HELP_TEXT ("Values can be between 1 and 255. The bigger") HELP_TEXT ("values, the slower.") HELP_TEXT ("") HELP_BOLD (" Merge movement") HELP_TEXT ("This setting allows you merge successive") HELP_TEXT ("mouse movements into a single mouse") HELP_TEXT ("movement. You should only use it if you are") HELP_TEXT ("using a mouse which reports at 200Hz or") HELP_TEXT ("more, and you experience lag when using") HELP_TEXT ("discontinuous hand-drawing with large") HELP_TEXT ("brushes (this tool tries to paste the brush") HELP_TEXT ("and update the screen on each new mouse") HELP_TEXT ("position) In this case, set this to 2 or") HELP_TEXT ("more, to ignore some intermediate mouse") HELP_TEXT ("reports when a more recent one is present.") HELP_TEXT ("Note that with a value superior to 1, you") HELP_TEXT ("lose precision with continuous hand-drawing,") HELP_TEXT ("as intermediate mouse positions are skipped.") HELP_TEXT ("") HELP_BOLD (" Double click speed") HELP_TEXT ("This is the time (in milliseconds) between") HELP_TEXT ("two clicks for Grafx2 to recognize a") HELP_TEXT ("double-click. Double-click is used mostly in") HELP_TEXT ("the palette area of the menu: double-click a") HELP_TEXT ("color to open the palette.") HELP_TEXT ("") HELP_BOLD (" Double key speed") HELP_TEXT ("When you press two digit keys in rapid") HELP_TEXT ("succession (ex: 3 8), Grafx2 sets") HELP_TEXT ("transparency to 38% (instead of 30% then") HELP_TEXT ("80%). This setting allows you to set the") HELP_TEXT ("maximum delay between two keypresses for") HELP_TEXT ("GrafX2 to recognize them as a combo.") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" Swap buttons") HELP_TEXT ("This setting determines which key inverts") HELP_TEXT ("the mouse buttons when it's held : A left") HELP_TEXT ("click is then interpreted as a right-click.") HELP_TEXT ("It's especially useful for one-button") HELP_TEXT ("controllers, such as touchscreens and") HELP_TEXT ("tablets.") HELP_TEXT ("") HELP_BOLD (" Virtual keyboard") HELP_TEXT ("This setting activates a graphical 'virtual") HELP_TEXT ("keyboard' whenever you have to type text in") HELP_TEXT ("a menu. It's designed for devices that don't") HELP_TEXT ("provide a physical keyboard, such as tablet") HELP_TEXT ("PCs and portable consoles. The default") HELP_TEXT ("setting 'auto' means ON for a portable") HELP_TEXT ("console and OFF for all others.") HELP_TEXT ("") HELP_TITLE("EDITING") HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD (" Adjust brush pick") HELP_TEXT ("Adjust the brush grabbing in 'grid' mode.") HELP_TEXT ("") HELP_BOLD (" Undo pages") HELP_TEXT ("Number of pages stored in memory for") HELP_TEXT ("'undoing'.") HELP_TEXT ("Values are between 1 and 99.") HELP_TEXT ("") HELP_BOLD (" Vertices per polygon") HELP_TEXT ("Maximum number of vertices used in filled") HELP_TEXT ("polygons and polyforms, and lasso. Possible") HELP_TEXT ("values range from 2 to 16384.") HELP_TEXT ("") HELP_BOLD (" Fast zoom") HELP_TEXT ("Automatically zoom into the pointed area") HELP_TEXT ("when you press the short-key of the") HELP_TEXT ("Magnifier button while being above the") HELP_TEXT ("picture.") HELP_TEXT ("") HELP_BOLD (" Clear with stencil") HELP_TEXT ("Take the Stencil into account when clearing") HELP_TEXT ("the image.") HELP_TEXT ("") HELP_BOLD (" Auto discontinuous") HELP_TEXT ("Directly set the discontinuous freehand") HELP_TEXT ("drawing mode after brush grabbing.") HELP_TEXT ("") HELP_BOLD (" Auto nb colors used") HELP_TEXT ("Automaticaly count the number of different") HELP_TEXT ("colors used when opening the palette editor") HELP_TEXT ("window. (Set it to 'no' if you have a slow") HELP_TEXT ("computer or if you edit huge pictures)") HELP_TEXT ("") HELP_BOLD (" Right click colorpick") HELP_TEXT ("This enables a mode where the right mouse") HELP_TEXT ("buttons acts as a color picker until") HELP_TEXT ("it's released, and selects Foreground color.") HELP_TEXT ("This mode prevents you from painting with") HELP_TEXT ("Background color.") HELP_TEXT ("This option is ignored when the Shade,") HELP_TEXT ("Quick-shade, or Tiling mode is used.") HELP_TEXT ("") HELP_TEXT (" Multi shortcuts") HELP_TEXT ("When this setting is disabled, and you") HELP_TEXT ("create a shortcut with a key that is already") HELP_TEXT ("associated to another shortcut, Grafx2 will") HELP_TEXT ("unset the latter. If you enable this mode,") HELP_TEXT ("Grafx2 will not make such check, so you can") HELP_TEXT ("design shortcuts that trigger several") HELP_TEXT ("actions at once.") HELP_TEXT ("") }; static const T_Help_table helptable_clear[] = { HELP_TITLE("CLEAR") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_CLEAR) HELP_TEXT ("") HELP_TEXT ("Clears the picture with the color number 0,") HELP_TEXT ("or the transparent color of the picture.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_CLEAR) HELP_TEXT ("") HELP_TEXT ("Clears the picture with the Back-color.") }; static const T_Help_table helptable_general[] = { HELP_TITLE("HELP STATS") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_HELP) HELP_TEXT ("") HELP_TEXT ("Displays an info window where you'll find") HELP_TEXT ("some credits, help about the credits,") HELP_TEXT ("different effects, greetings, registering...") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_HELP) HELP_TEXT ("") HELP_TEXT ("Displays a window where you'll find") HELP_TEXT ("miscellaneous information about the system.") HELP_TEXT (" Note: you should take care to keep more") HELP_TEXT ("than 128 Kb in order to let the program") HELP_TEXT ("run in a proper way.") }; static const T_Help_table helptable_undo[] = { HELP_TITLE("OOPS") HELP_TEXT ("(UNDO/REDO)") HELP_TEXT ("LEFT CLICK Allows you to undo the last") HELP_TEXT ("modification on the picture.") HELP_LINK ("(Key:%s)",0x100+BUTTON_UNDO) HELP_TEXT ("") HELP_TEXT ("RIGHT CLICK Allows you to redo the last") HELP_TEXT ("modification undone on the picture.") HELP_TEXT ("The maximum number of UNDO that you can") HELP_TEXT ("perform can be defined in the settings") HELP_TEXT ("menu.") HELP_TEXT ("Undo/Redo aren't effective after page") HELP_TEXT ("switching, picture loading and picture") HELP_TEXT ("size modifications.") HELP_LINK ("(Key:%s)",0x200+BUTTON_UNDO) }; static const T_Help_table helptable_kill[] = { HELP_TITLE("KILL") HELP_TEXT ("KILL CURRENT PAGE") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_KILL) HELP_TEXT ("") HELP_TEXT ("Removes the current page from the list of") HELP_TEXT ("\"Undo\" pages. This allows you to free some") HELP_TEXT ("memory if you need it. For instance, this") HELP_TEXT ("will allow you to delete the start-up page") HELP_TEXT ("after having loaded an image. A message will") HELP_TEXT ("appear if you've already erased all the") HELP_TEXT ("pages except the last one.") HELP_TEXT (" Note: Another way to free some memory is to") HELP_TEXT ("decrease the number of \"Undo\" pages. Or") HELP_TEXT ("else, if you have recentlt grabbed a very") HELP_TEXT ("big brush that you don't use any more, you") HELP_TEXT ("can grab a new smaller one. The memory") HELP_TEXT ("allocated by the big brush will be thus") HELP_TEXT ("freed.") }; static const T_Help_table helptable_quit[] = { HELP_TITLE("QUIT") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_QUIT) HELP_TEXT ("") HELP_TEXT ("Allows you to leave GrafX2. If there are") HELP_TEXT ("unsaved modifications in the current or") HELP_TEXT ("spare page, a confirmation box will ask you") HELP_TEXT ("if you really want to quit GrafX2, if you") HELP_TEXT ("want to save (Auto-save, no fileselector) or") HELP_TEXT ("if you want to stay in GrafX2.") }; static const T_Help_table helptable_palette[] = { HELP_TITLE("PAL MENU") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_PALETTE) HELP_TEXT ("") HELP_TEXT ("Displays a menu where the following options") HELP_TEXT ("are available:") HELP_TEXT ("") HELP_TEXT ("- Palette: Allows you to choose a") HELP_TEXT ("color-block to edit. If you click with the") HELP_TEXT ("right mouse button, you'll choose a new") HELP_TEXT ("Back-color.") HELP_TEXT ("") HELP_TEXT ("- Gauges: Allow you to modify the") HELP_TEXT ("current selection.") HELP_TEXT ("") HELP_TEXT ("- RGB or HSL above the gauges: Switches") HELP_TEXT ("between RGB and HSL color spaces. In HSL") HELP_TEXT ("mode, the three sliders allow you to set the") HELP_TEXT ("Hue (tint), Saturation (from grayscale to") HELP_TEXT ("pure color) and Lightness (from black to") HELP_TEXT ("white).") HELP_TEXT ("") HELP_TEXT ("- numbers below the gauges: Allows you to") HELP_TEXT ("type in a new color in hexadecimal RRGGBB") HELP_TEXT ("or RGB: ie. to get blue, you can type either") HELP_TEXT ("0000ff or 00f.") HELP_TEXT ("") HELP_TEXT ("- \"+\" and \"-\": Allow you to lighten or") HELP_TEXT ("darken the current selection.") HELP_TEXT ("") HELP_TEXT ("- Swap: Swaps the current selection with") HELP_TEXT ("another color-block. Click on the beginning") HELP_TEXT ("of the new color-block.") HELP_TEXT ("") HELP_TEXT ("- X-Swap: Works as above but modifies the") HELP_TEXT ("picture so that it looks the same. This may") HELP_TEXT ("be useful if you want to sort your palette.") HELP_TEXT ("") HELP_TEXT ("- Copy: Copies the current selection to") HELP_TEXT ("another color-block. Click on the beginning") HELP_TEXT ("of the new color-block.") HELP_TEXT ("") HELP_TEXT ("- Histo: Opens a screen showing how much of") HELP_TEXT ("each color is used in your image. Clicking a") HELP_TEXT ("color selects it and closes the screen.") HELP_TEXT ("") HELP_TEXT ("- Flip: Swaps the colors of the current") HELP_TEXT ("selection so that the first colors become") HELP_TEXT ("the last ones.") HELP_TEXT ("") HELP_TEXT ("- X-Flip: Works as above but modifies the") HELP_TEXT ("picture so that it looks the same.") HELP_TEXT ("") HELP_TEXT ("- Sort: Sorts the colors :") HELP_TEXT (" * Hue/Light : By H then L, in the HSL") HELP_TEXT (" color space.") HELP_TEXT (" * Lightness : By descending perceptual") HELP_TEXT (" lightness. The calculation is not the") HELP_TEXT (" same as the L of HSL space, it more") HELP_TEXT (" precisely represents how the human eye") HELP_TEXT (" find the color 'luminous'.") HELP_TEXT (" * Histogram : How much the color is used") HELP_TEXT (" in the image (descending)") HELP_TEXT ("") HELP_TEXT ("Note that you can choose a range of") HELP_TEXT ("colors before sorting, and instead of the") HELP_TEXT ("whole palette it will sort this range.") HELP_TEXT ("") HELP_TEXT ("- Used: Toggle small white indicators next") HELP_TEXT ("to each color which are actually used, i.e.") HELP_TEXT ("if there's at least one pixel of the image") HELP_TEXT ("which is painted in this color.") HELP_TEXT ("") HELP_TEXT ("- Neg: Transforms the current selection") HELP_TEXT ("into its reverse video equivalent.") HELP_TEXT ("") HELP_TEXT ("- Gray: Transforms the current selection") HELP_TEXT ("into its gray-scaled equivalent.") HELP_TEXT ("") HELP_TEXT ("- Spread: Computes a gradation between two") HELP_TEXT ("colors. If your selection is only made up of") HELP_TEXT ("one color, select the second color in the") HELP_TEXT ("palette. Otherwise, the two colors used will") HELP_TEXT ("be its extremities.") HELP_TEXT ("") HELP_TEXT ("- Merge: The selected range of colors") HELP_TEXT ("becomes an average, weighted according to") HELP_TEXT ("how many pixels use this color. Then all the") HELP_TEXT ("pixels get replaced by the first color of") HELP_TEXT ("the range. This function is generally used") HELP_TEXT ("on colors which are too similar, then you") HELP_TEXT ("can recycle the unused palette entries, or") HELP_TEXT ("use 'Reduce to - Unique' to clean up.") HELP_TEXT ("") HELP_TEXT ("- Zap unused: Erases the unused colors with") HELP_TEXT ("copies of the current selection. (The") HELP_TEXT ("keyboard shortcut for this button is ).") HELP_TEXT ("") HELP_TEXT ("- Reduce: Allows you to reduce the palette") HELP_TEXT ("to the number of colors you want (and") HELP_TEXT ("modifies the picture).") HELP_TEXT ("") HELP_TEXT ("- Undo: Allows you to recover the last") HELP_TEXT ("modifications made on the palette. Note that") HELP_TEXT ("it can't undo the changes that affect the") HELP_TEXT ("pixels (remapping), you'll need to Cancel") HELP_TEXT ("them.") HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("If you press , the program will") HELP_TEXT ("replace, as well as possible, some unused") HELP_TEXT ("colors by the four default colors of the") HELP_TEXT ("menu. The image won't look altered because") HELP_TEXT ("the modified colors (in the case they were") HELP_TEXT ("used on a few points) will be replaced by") HELP_TEXT ("the closest colors in the rest of the") HELP_TEXT ("palette. This option is really useful when") HELP_TEXT ("you modify the palette so that there are no") HELP_TEXT ("colors that fit for the menu (eg: \"Zap") HELP_TEXT ("unused\" while very little colors are used in") HELP_TEXT ("the picture; or \"Reduce\" with a very small") HELP_TEXT ("number of colors).") HELP_TEXT ("") HELP_TEXT ("If you press the key below or <,>") HELP_TEXT ("(QWERTY), the menu will disappear and you") HELP_TEXT ("will be able to pick up a color from the") HELP_TEXT ("picture easily. Press to cancel.") HELP_TEXT ("") HELP_TEXT ("If only one color is selected (not a block),") HELP_TEXT ("the <[> and <]> keys can be used to select") HELP_TEXT ("the previous or next Forecolor (Backcolor if") HELP_TEXT ("you press at the same time).") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("PALETTE OPTIONS") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_PALETTE) HELP_TEXT ("") HELP_TEXT ("Opens a menu from where you have the") HELP_TEXT ("following options:") HELP_TEXT ("") HELP_TEXT ("- Colors for best match:") HELP_TEXT ("A menu in which you can select the colors") HELP_TEXT ("that have not to be used for smoothing, for") HELP_TEXT ("the transparency mode, and for remapping.") HELP_TEXT ("") HELP_TEXT ("- User's color series:") HELP_TEXT ("A menu in which you can define color series") HELP_TEXT ("for next/previous user color shortcuts.") HELP_TEXT ("It's the same settings than the shade mode.") HELP_TEXT ("After you have some color ranges defined in") HELP_TEXT ("this screen, you can use those shortcuts to") HELP_TEXT ("move to the next or previous color according") HELP_TEXT ("to your ranges:") HELP_TEXT ("") HELP_TEXT ("Foreground color") HELP_TEXT ("") HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_FORECOLOR) HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_FORECOLOR) HELP_TEXT ("") HELP_TEXT ("Background color") HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_BACKCOLOR) HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_BACKCOLOR) HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT ("- Palette layout:") HELP_TEXT ("Lets you customize the palette that appears") HELP_TEXT ("on the right of the menu. You can choose the") HELP_TEXT ("number of lines and columns.") HELP_TEXT ("If you want the colors to run top to bottom,") HELP_TEXT ("check the 'Vertical' button, otherwise the") HELP_TEXT ("colors runs left to right.") HELP_TEXT ("") HELP_TEXT ("- RGB Scale:") HELP_TEXT ("Lets you set the scale of the R G B sliders") HELP_TEXT ("in the palette screen. You should normally") HELP_TEXT ("leave it at 256 to get the full 0-255 range,") HELP_TEXT ("but if you want to constrain the palette") HELP_TEXT ("to the capabilities of some specific") HELP_TEXT ("computers and consoles, you can choose eg:") HELP_TEXT (" 64 : VGA") HELP_TEXT (" 16 : Amiga") HELP_TEXT (" 4 : MSX2") HELP_TEXT (" 2 : Amstrad CPC") }; static const T_Help_table helptable_pal_scroll[] = { HELP_TITLE("SCROLL PAL") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_TEXT ("") HELP_TEXT ("Scrolls the palette window in the right of") HELP_TEXT ("the menu.") HELP_LINK ("Key for back: %s", 0x100+BUTTON_PAL_LEFT) HELP_LINK ("Key for forward: %s", 0x100+BUTTON_PAL_RIGHT) HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_TEXT ("") HELP_TEXT ("Same as above, but faster.") HELP_LINK ("Key for back: %s", 0x200+BUTTON_PAL_LEFT) HELP_LINK ("Key for forward: %s", 0x200+BUTTON_PAL_RIGHT) HELP_TEXT ("") }; static const T_Help_table helptable_color_select[] = { HELP_TITLE("PALETTE") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_TEXT ("") HELP_TEXT ("Defines the Fore-color.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_TEXT ("") HELP_TEXT ("Defines the Back-color.") }; static const T_Help_table helptable_hide[] = { HELP_TITLE("HIDE MENU") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_HIDE) HELP_TEXT ("") HELP_TEXT ("Allows you to hide all toolbars, leaving") HELP_TEXT ("only the status bar.") HELP_TEXT ("Click again to show them again.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_TEXT ("") HELP_TEXT ("Opens a drop-down menu where you can choose") HELP_TEXT ("Which toolbars are going to be visible in") HELP_TEXT ("the menu.") }; static const T_Help_table helptable_layermenu[] = { HELP_TITLE("LAYERS MENU") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_MENU) HELP_TEXT ("") HELP_TEXT ("In this menu you can set the following") HELP_TEXT ("options:") HELP_TEXT ("") HELP_TEXT ("* Transparent color : This determines which") HELP_TEXT ("color index is considered transparent when") HELP_TEXT ("using layers. Click the button and then") HELP_TEXT ("click on the image to pick the right color,") HELP_TEXT ("or use ESC to cancel.") HELP_TEXT ("") HELP_TEXT ("* Transparent background : When this option") HELP_TEXT ("is checked, all pixels of the transparent") HELP_TEXT ("color on layer 1 (background layer) will") HELP_TEXT ("be tagged as transparent in the final image.") HELP_TEXT ("Check this option if you want to make a") HELP_TEXT ("transparent GIF or PNG. These are the only") HELP_TEXT ("file formats that support this option.") }; static const T_Help_table helptable_layertrans[] = { HELP_TITLE("LAYERS TRANSPARENCY") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_TEXT ("") HELP_TEXT ("Sets the transparent color as background pen") HELP_TEXT ("color.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_TEXT ("") HELP_TEXT ("The current Background color becomes the") HELP_TEXT ("color considered transparent for the layers.") }; static const T_Help_table helptable_layermerge[] = { HELP_TITLE("LAYERS MERGE") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_MERGE) HELP_TEXT ("") HELP_TEXT ("Merges the current layer with the one below") HELP_TEXT ("it, and sets the resulting layer as current") HELP_TEXT ("one for editing.") HELP_TEXT ("This function has no effect if you're") HELP_TEXT ("editing the lowest layer.") }; static const T_Help_table helptable_layeradd[] = { HELP_TITLE("ADD LAYER") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_ADD) HELP_TEXT ("") HELP_TEXT ("Add a new layer above the current one,") HELP_TEXT ("and selects this new (empty) layer for") HELP_TEXT ("editing.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_LINK ("(Key:%s)",0x200+BUTTON_LAYER_ADD) HELP_TEXT ("") HELP_TEXT ("Add a new layer, as a copy of the current") HELP_TEXT ("layer.") }; static const T_Help_table helptable_layerdel[] = { HELP_TITLE("DROP LAYER") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_REMOVE) HELP_TEXT ("") HELP_TEXT ("Deletes the current layer.") }; static const T_Help_table helptable_layerup[] = { HELP_TITLE("MOVE LAYER UP") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_UP) HELP_TEXT ("") HELP_TEXT ("Swaps the current layer with the one") HELP_TEXT ("above it. This has no effect if this") HELP_TEXT ("layer is already on top.") }; static const T_Help_table helptable_layerdown[] = { HELP_TITLE("MOVE LAYER DOWN") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_DOWN) HELP_TEXT ("") HELP_TEXT ("Swaps the current layer with the one") HELP_TEXT ("below it. This has no effect if this") HELP_TEXT ("layer is already on the bottom.") }; static const T_Help_table helptable_animtime[] = { HELP_TITLE("ANIMATION SPEED") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_ANIM_TIME) HELP_TEXT ("") HELP_TEXT ("Opens the 'animation speed' window.") HELP_TEXT ("This window displays the duration of the") HELP_TEXT ("current animation frame, in milliseconds.") HELP_TEXT ("You can:") HELP_TEXT ("* Change this frame's duration.") HELP_TEXT ("* Change the duration of all frames.") HELP_TEXT ("* Alter the duration of all frames by adding") HELP_TEXT ("a number of milliseconds. You can use") HELP_TEXT ("negative numbers to reduce the durations") HELP_TEXT ("instead.") }; static const T_Help_table helptable_firstframe[] = { HELP_TITLE("FIRST FRAME") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_ANIM_FIRST_FRAME) HELP_TEXT ("") HELP_TEXT ("Goes to the first frame of animation.") }; static const T_Help_table helptable_prevframe[] = { HELP_TITLE("PREVIOUS FRAME") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_ANIM_PREV_FRAME) HELP_TEXT ("") HELP_TEXT ("Selects the previous frame of animation") HELP_TEXT ("for editing. If the first frame was already") HELP_TEXT ("selected, this wraps back to the last frame.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_TEXT ("") HELP_TEXT ("Hold a right-click on this button to run the") HELP_TEXT ("animation continuously backwards. This can") HELP_TEXT ("be used to preview the animation at its") HELP_TEXT ("intended speed, or to quickly navigate in") HELP_TEXT ("a long animation with many frames.") }; static const T_Help_table helptable_nextframe[] = { HELP_TITLE("NEXT FRAME") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_ANIM_NEXT_FRAME) HELP_TEXT ("") HELP_TEXT ("Selects the last frame of animation") HELP_TEXT ("for editing. If the last frame was already") HELP_TEXT ("selected, this wraps back to the first") HELP_TEXT ("frame.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_TEXT ("") HELP_TEXT ("Hold a right-click on this button to run the") HELP_TEXT ("animation continuously forward. This can") HELP_TEXT ("be used to preview the animation at its") HELP_TEXT ("intended speed, or to quickly navigate in") HELP_TEXT ("a long animation with many frames.") }; static const T_Help_table helptable_lastframe[] = { HELP_TITLE("LAST FRAME") HELP_TEXT ("") HELP_LINK ("(Key:%s)",0x100+BUTTON_ANIM_LAST_FRAME) HELP_TEXT ("") HELP_TEXT ("Goes to the last frame of animation.") }; static const T_Help_table helptable_layerselect[] = { HELP_TITLE("LAYER SELECTION") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_TEXT ("") HELP_TEXT ("Choose a layer as the current one for") HELP_TEXT ("drawing.") HELP_TEXT ("") HELP_BOLD ("RIGHT CLICK") HELP_TEXT ("") HELP_TEXT ("Makes a layer visible or invisible.") HELP_TEXT ("If you click the current layer, this toggles") HELP_TEXT ("the visibility of all other layers instead.") }; #define HELP_TABLE_DECLARATION(x) {x, sizeof(x)/sizeof(const T_Help_table)}, T_Help_section Help_section[] = { HELP_TABLE_DECLARATION(helptable_about) HELP_TABLE_DECLARATION(helptable_licence) HELP_TABLE_DECLARATION(helptable_help) HELP_TABLE_DECLARATION(helptable_credits) // Attention, keep the same order as BUTTON_NUMBERS: HELP_TABLE_DECLARATION(helptable_hide) HELP_TABLE_DECLARATION(helptable_layermenu) HELP_TABLE_DECLARATION(helptable_animtime) HELP_TABLE_DECLARATION(helptable_firstframe) HELP_TABLE_DECLARATION(helptable_prevframe) HELP_TABLE_DECLARATION(helptable_nextframe) HELP_TABLE_DECLARATION(helptable_lastframe) HELP_TABLE_DECLARATION(helptable_layeradd) HELP_TABLE_DECLARATION(helptable_layerdel) HELP_TABLE_DECLARATION(helptable_layerup) HELP_TABLE_DECLARATION(helptable_layerdown) HELP_TABLE_DECLARATION(helptable_animtime) // reserved for future button HELP_TABLE_DECLARATION(helptable_layermenu) HELP_TABLE_DECLARATION(helptable_layertrans) HELP_TABLE_DECLARATION(helptable_layermerge) HELP_TABLE_DECLARATION(helptable_layeradd) HELP_TABLE_DECLARATION(helptable_layerdel) HELP_TABLE_DECLARATION(helptable_layerup) HELP_TABLE_DECLARATION(helptable_layerdown) HELP_TABLE_DECLARATION(helptable_layerselect) HELP_TABLE_DECLARATION(helptable_paintbrush) HELP_TABLE_DECLARATION(helptable_adjust) HELP_TABLE_DECLARATION(helptable_draw) HELP_TABLE_DECLARATION(helptable_curves) HELP_TABLE_DECLARATION(helptable_lines) HELP_TABLE_DECLARATION(helptable_airbrush) HELP_TABLE_DECLARATION(helptable_floodfill) HELP_TABLE_DECLARATION(helptable_polygons) HELP_TABLE_DECLARATION(helptable_polyfill) HELP_TABLE_DECLARATION(helptable_rectangles) HELP_TABLE_DECLARATION(helptable_filled_rectangles) HELP_TABLE_DECLARATION(helptable_circles) HELP_TABLE_DECLARATION(helptable_filled_circles) HELP_TABLE_DECLARATION(helptable_grad_rect) HELP_TABLE_DECLARATION(helptable_spheres) HELP_TABLE_DECLARATION(helptable_brush) HELP_TABLE_DECLARATION(helptable_polybrush) HELP_TABLE_DECLARATION(helptable_brush_fx) HELP_TABLE_DECLARATION(helptable_effects) HELP_TABLE_DECLARATION(helptable_text) HELP_TABLE_DECLARATION(helptable_magnifier) HELP_TABLE_DECLARATION(helptable_colorpicker) HELP_TABLE_DECLARATION(helptable_resolution) HELP_TABLE_DECLARATION(helptable_page) HELP_TABLE_DECLARATION(helptable_save) HELP_TABLE_DECLARATION(helptable_load) HELP_TABLE_DECLARATION(helptable_settings) HELP_TABLE_DECLARATION(helptable_clear) HELP_TABLE_DECLARATION(helptable_general) HELP_TABLE_DECLARATION(helptable_undo) HELP_TABLE_DECLARATION(helptable_kill) HELP_TABLE_DECLARATION(helptable_quit) HELP_TABLE_DECLARATION(helptable_palette) HELP_TABLE_DECLARATION(helptable_pal_scroll) HELP_TABLE_DECLARATION(helptable_pal_scroll) HELP_TABLE_DECLARATION(helptable_color_select) // End of buttons list // NB_BUTTONS+0 HELP_TABLE_DECLARATION(helptable_settings_details) // NB_BUTTONS+1 // HELP_TABLE_DECLARATION() // NB_BUTTONS+2 // HELP_TABLE_DECLARATION() // ... }; grafx2_2.4+git20180105/src/text.c0000664000000000000000000004232513223665307014666 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2014 Sergii Pylypenko Copyright 2011 Pawel Gralski Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2008 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ // Pour dsactiver le support TrueType, dfinir NOTTF // To disable TrueType support, define NOTTF #include #include #include // tolower() // TrueType #ifndef NOTTF #if defined(__macosx__) #include #else #include #endif #if defined(__CAANOO__) || defined(__WIZ__) || defined(__GP2X__) // No fontconfig #elif defined(USE_FC) && !defined(NOTTF) #include #endif #endif #if defined(__macosx__) #import #import #endif #include #include "SFont.h" #include "struct.h" #include "global.h" #include "sdlscreen.h" #include "io.h" #include "errors.h" #include "windows.h" #include "misc.h" #include "setup.h" typedef struct T_Font { char * Name; int Is_truetype; int Is_bitmap; char Label[22]; // Liste chaine simple struct T_Font * Next; struct T_Font * Previous; } T_Font; // Liste chaine des polices de texte T_Font * font_list_start; int Nb_fonts; // Inspir par Allegro #define EXTID(a,b,c) ((((a)&255)<<16) | (((b)&255)<<8) | (((c)&255))) #define EXTID4(a,b,c,d) ((((a)&255)<<24) | (((b)&255)<<16) | (((c)&255)<<8) | (((d)&255))) int Compare_fonts(T_Font * font_1, T_Font * font_2) { if (font_1->Is_bitmap && !font_2->Is_bitmap) return -1; if (font_2->Is_bitmap && !font_1->Is_bitmap) return 1; return strcmp(font_1->Label, font_2->Label); } // Ajout d'une fonte la liste. void Add_font(const char *name) { char * font_name; T_Font * font; int size=strlen(name)+1; int index; // Dtermination du type: #if defined(__macosx__) char strFontName[512]; CFStringRef CFSFontName;// = CFSTR(name); if (size < 6) return; CFSFontName = CFStringCreateWithBytes(NULL, (UInt8 *) name, size - 1, kCFStringEncodingASCII, false); // Fix some funny names CFStringGetCString(CFSFontName, strFontName, 512, kCFStringEncodingASCII); // Now we have a printable font name, use it name = strFontName; #else if (size<5 || name[size-5]!='.') return; #endif font = (T_Font *)malloc(sizeof(T_Font)); switch (EXTID(tolower(name[size-4]), tolower(name[size-3]), tolower(name[size-2]))) { case EXTID('t','t','f'): case EXTID('f','o','n'): case EXTID('o','t','f'): case EXTID('p','f','b'): font->Is_truetype = 1; font->Is_bitmap = 0; break; case EXTID('b','m','p'): case EXTID('g','i','f'): case EXTID('j','p','g'): case EXTID('l','b','m'): case EXTID('p','c','x'): case EXTID('p','n','g'): case EXTID('t','g','a'): case EXTID('t','i','f'): case EXTID('x','c','f'): case EXTID('x','p','m'): case EXTID('.','x','v'): font->Is_truetype = 0; font->Is_bitmap = 1; break; default: #if defined(__macosx__) if(strcasecmp(&name[size-6], "dfont") == 0) { font->Is_truetype = 1; font->Is_bitmap = 0; } else { free(font); return; } #else free(font); return; #endif } font->Name = (char *)malloc(size); strcpy(font->Name, name); // Label strcpy(font->Label, " "); if (font->Is_truetype) font->Label[17]=font->Label[18]='T'; // Logo TT font_name=Find_last_separator(font->Name); if (font_name==NULL) font_name=font->Name; else font_name++; for (index=0; index < 17 && font_name[index]!='\0' && font_name[index]!='.'; index++) font->Label[index]=font_name[index]; // Gestion Liste font->Next = NULL; font->Previous = NULL; if (font_list_start==NULL) { // Premiere (liste vide) font_list_start = font; Nb_fonts++; } else { int compare; compare = Compare_fonts(font, font_list_start); if (compare<=0) { if (compare==0 && !strcmp(font->Name, font_list_start->Name)) { // Doublon free(font->Name); free(font); return; } // Avant la premiere font->Next=font_list_start; font_list_start=font; Nb_fonts++; } else { T_Font *searched_font; searched_font=font_list_start; while (searched_font->Next && (compare=Compare_fonts(font, searched_font->Next))>0) searched_font=searched_font->Next; // Aprs searched_font if (compare==0 && strcmp(font->Name, searched_font->Next->Name)==0) { // Doublon free(font->Name); free(font); return; } font->Next=searched_font->Next; searched_font->Next=font; Nb_fonts++; } } } // Trouve le nom d'une fonte par son numro char * Font_name(int index) { T_Font *font = font_list_start; if (index<0 ||index>=Nb_fonts) return ""; while (index--) font = font->Next; return font->Name; } // Trouve le libell d'affichage d'une fonte par son numro // Renvoie un pointeur sur un buffer statique de 20 caracteres. char * Font_label(int index) { T_Font *font; static char label[20]; strcpy(label, " "); // Recherche de la fonte font = font_list_start; if (index<0 ||index>=Nb_fonts) return label; while (index--) font = font->Next; // Libell strcpy(label, font->Label); return label; } // Vrifie si une fonte donne est TrueType int TrueType_font(int index) { T_Font *font = font_list_start; if (index<0 ||index>=Nb_fonts) return 0; while (index--) font = font->Next; return font->Is_truetype; } // Initialisation faire une fois au dbut du programme void Init_text(void) { char directory_name[MAX_PATH_CHARACTERS]; #ifndef NOTTF // Initialisation de TTF TTF_Init(); #endif // Initialisation des fontes font_list_start = NULL; Nb_fonts=0; // Parcours du rpertoire "fonts" snprintf(directory_name, sizeof(directory_name), "%s%s", Data_directory,FONTS_SUBDIRECTORY); For_each_file(directory_name, Add_font); // fonts subdirectory in Config_directory snprintf(directory_name, sizeof(directory_name), "%s%s", Config_directory, "/fonts"); For_each_file(directory_name, Add_font); #if defined(__WIN32__) // Parcours du rpertoire systeme windows "fonts" #ifndef NOTTF { char * WindowsPath=getenv("windir"); if (WindowsPath) { sprintf(directory_name, "%s\\FONTS", WindowsPath); For_each_file(directory_name, Add_font); } } #endif #elif defined(__macosx__) // Rcupration de la liste des fonts avec fontconfig #ifndef NOTTF int i,number; char home_dir[MAXPATHLEN]; char *font_path_list[3] = { "/System/Library/Fonts", "/Library/Fonts" }; number = 3; // Make sure we also search into the user's fonts directory CFURLRef url = (CFURLRef) CFCopyHomeDirectoryURLForUser(NULL); CFURLGetFileSystemRepresentation(url, true, (UInt8 *) home_dir, MAXPATHLEN); strcat(home_dir, "/Library/Fonts"); font_path_list[2] = home_dir; for(i=0;iformat->palette, palette); if (antialias) { int black_col; // Shaded text: X-Swap the color that is pure black with the BG color number, // so that the brush is immediately 'transparent' // Find black (c) for (black_col=0; black_col<256; black_col++) { if (palette[black_col].R==0 && palette[black_col].G==0 && palette[black_col].B==0) break; } // If not found: c = 256 = 0 (byte) if (black_col != Back_color) { int c; byte colmap[256]; // Swap palette entries SWAP_BYTES(palette[black_col].R, palette[Back_color].R) SWAP_BYTES(palette[black_col].G, palette[Back_color].G) SWAP_BYTES(palette[black_col].B, palette[Back_color].B) // Define a colormap for (c=0; c<256; c++) colmap[c]=c; // The swap colmap[black_col]=Back_color; colmap[Back_color]=black_col; Remap_general_lowlevel(colmap, new_brush, new_brush, text_surface->w,text_surface->h, text_surface->w); // Also, make the BG color in brush palette have same RGB values as // the current BG color : this will help for remaps. palette[Back_color].R=Main_palette[Back_color].R; palette[Back_color].G=Main_palette[Back_color].G; palette[Back_color].B=Main_palette[Back_color].B; } } else { // Solid text: Was rendered as white on black. Now map colors: // White becomes FG color, black becomes BG. 2-color palette. // Exception: if BG==FG, FG will be set to black or white - any different color. long index; byte new_fore=Fore_color; if (Fore_color==Back_color) { new_fore=Best_color_perceptual_except(Main_palette[Back_color].R, Main_palette[Back_color].G, Main_palette[Back_color].B, Back_color); } for (index=0; index < text_surface->w * text_surface->h; index++) { if (palette[*(new_brush+index)].G < 128) *(new_brush+index)=Back_color; else *(new_brush+index)=new_fore; } // Now copy the current palette to brushe's, for consistency // with the indices. memcpy(palette, Main_palette, sizeof(T_Palette)); } *width=text_surface->w; *height=text_surface->h; SDL_FreeSurface(text_surface); TTF_CloseFont(font); return new_brush; } #endif byte *Render_text_SFont(const char *str, int font_number, int *width, int *height, T_Palette palette) { SFont_Font *font; SDL_Surface * text_surface; SDL_Surface *font_surface; byte * new_brush; SDL_Rect rectangle; // Chargement de la fonte font_surface=IMG_Load(Font_name(font_number)); if (!font_surface) { char buffer[256]; strcpy(buffer, "Error loading font.\n"); strcat(buffer,IMG_GetError()); Verbose_message("Warning",buffer); // TODO this leaves a non-erased cursor when the window closes. return NULL; } // Font is 24bit: Perform a color reduction if (font_surface->format->BitsPerPixel>8) { SDL_Surface * reduced_surface; int x,y,color; SDL_Color rgb; reduced_surface=SDL_CreateRGBSurface(SDL_SWSURFACE, font_surface->w, font_surface->h, 8, 0, 0, 0, 0); if (!reduced_surface) { SDL_FreeSurface(font_surface); return NULL; } // Set the quick palette for (color=0;color<256;color++) { rgb.r=((color & 0xE0)>>5)<<5; rgb.g=((color & 0x1C)>>2)<<5; rgb.b=((color & 0x03)>>0)<<6; SDL_SetColors(reduced_surface, &rgb, color, 1); } // Perform reduction for (y=0; yh; y++) for (x=0; xw; x++) { SDL_GetRGB(Get_SDL_pixel_hicolor(font_surface, x, y), font_surface->format, &rgb.r, &rgb.g, &rgb.b); color=((rgb.r >> 5) << 5) | ((rgb.g >> 5) << 2) | ((rgb.b >> 6)); Set_SDL_pixel_8(reduced_surface, x, y, color); } SDL_FreeSurface(font_surface); font_surface=reduced_surface; } font=SFont_InitFont(font_surface); if (!font) { DEBUG("Font init failed",1); SDL_FreeSurface(font_surface); return NULL; } // Calcul des dimensions *height=SFont_TextHeight(font, str); *width=SFont_TextWidth(font, str); // Allocation d'une surface SDL text_surface=SDL_CreateRGBSurface(SDL_SWSURFACE, *width, *height, 8, 0, 0, 0, 0); // Copy palette SDL_SetPalette(text_surface, SDL_LOGPAL, font_surface->format->palette->colors, 0, 256); // Fill with transparent color rectangle.x=0; rectangle.y=0; rectangle.w=*width; rectangle.h=*height; SDL_FillRect(text_surface, &rectangle, font->Transparent); // Rendu du texte SFont_Write(text_surface, font, 0, 0, str); if (!text_surface) { DEBUG("Rendering failed",2); SFont_FreeFont(font); return NULL; } new_brush=Surface_to_bytefield(text_surface, NULL); if (!new_brush) { DEBUG("Converting failed",3); SDL_FreeSurface(text_surface); SFont_FreeFont(font); return NULL; } Get_SDL_Palette(font_surface->format->palette, palette); // Swap current BG color with font's transparent color if (font->Transparent != Back_color) { int c; byte colmap[256]; // Swap palette entries SWAP_BYTES(palette[font->Transparent].R, palette[Back_color].R) SWAP_BYTES(palette[font->Transparent].G, palette[Back_color].G) SWAP_BYTES(palette[font->Transparent].B, palette[Back_color].B) // Define a colormap for (c=0; c<256; c++) colmap[c]=c; // The swap colmap[font->Transparent]=Back_color; colmap[Back_color]=font->Transparent; Remap_general_lowlevel(colmap, new_brush, new_brush, text_surface->w,text_surface->h, text_surface->w); } SDL_FreeSurface(text_surface); SFont_FreeFont(font); return new_brush; } // Cre une brosse partir des paramtres de texte demands. // Si cela russit, la fonction place les dimensions dans width et height, // et retourne l'adresse du bloc d'octets. byte *Render_text(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height, T_Palette palette) { T_Font *font = font_list_start; int index=font_number; #ifdef NOTTF (void) size; // unused (void) antialias; // unused (void) bold; // unused (void) italic; // unused #endif // Verification type de la fonte if (font_number<0 ||font_number>=Nb_fonts) return NULL; while (index--) font = font->Next; if (font->Is_truetype) { #ifndef NOTTF return Render_text_TTF(str, font_number, size, antialias, bold, italic, width, height, palette); #else return NULL; #endif } else { return Render_text_SFont(str, font_number, width, height, palette); } } grafx2_2.4+git20180105/src/mountlist.c0000664000000000000000000005731513223665306015744 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* mountlist.c -- return a list of mounted file systems Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ // This file is not used on some platforms, so don't do anything for them #if(!defined(__WIN32__))&&(!defined(__amigaos4__))&&(!defined(__AROS__))&&(!defined(__MORPHOS__))&&(!defined(__amigaos__)) // We don't use autoconf and all that in grafx2, so let's do the config here ... #if defined(__macosx__) || defined(__FreeBSD__) || defined(__OpenBSD__) // MacOS X is POSIX compliant #define MOUNTED_GETMNTINFO #if defined(__macosx__) || defined(__FreeBSD__) #include #endif #if defined(__OpenBSD__) #define HAVE_STRUCT_STATFS_F_FSTYPENAME 1 #include /* types.h needs this */ #include #endif #elif defined(__NetBSD__) #define MOUNTED_GETMNTINFO2 #elif defined(__BEOS__) || defined(__HAIKU__) #define MOUNTED_FS_STAT_DEV #elif defined(__TRU64__) #define MOUNTED_GETFSSTAT 1 #define HAVE_SYS_MOUNT_H 1 #include #elif defined(__SKYOS__)||defined(__ANDROID__) #warning "Your platform is missing some specific code here ! please check and fix :)" #else #define MOUNTED_GETMNTENT1 #endif #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 500 #endif // --- END GRAFX2 CUSTOM CONFIG --- #include "mountlist.h" #include #include #include #include #include #include #include #if HAVE_SYS_PARAM_H # include #endif #if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */ # if HAVE_SYS_UCRED_H # include /* needed on OSF V4.0 for definition of NGROUPS, NGROUPS is used as an array dimension in ucred.h */ # include /* needed by powerpc-apple-darwin1.3.7 */ # endif # if HAVE_SYS_MOUNT_H # include # endif # if HAVE_SYS_FS_TYPES_H # include /* needed by powerpc-apple-darwin1.3.7 */ # endif # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME # define FS_TYPE(Ent) ((Ent).f_fstypename) # else # define FS_TYPE(Ent) mnt_names[(Ent).f_type] # endif #endif /* MOUNTED_GETFSSTAT */ #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ # include # if !defined MOUNTED # if defined _PATH_MOUNTED /* GNU libc */ # define MOUNTED _PATH_MOUNTED # endif # if defined MNT_MNTTAB /* HP-UX. */ # define MOUNTED MNT_MNTTAB # endif # if defined MNTTABNAME /* Dynix. */ # define MOUNTED MNTTABNAME # endif # endif #endif #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ # include #endif #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ # include #endif #ifdef MOUNTED_GETMNT /* Ultrix. */ # include # include #endif #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */ # include # include #endif #ifdef MOUNTED_FREAD /* SVR2. */ # include #endif #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */ # include # include # include #endif #ifdef MOUNTED_LISTMNTENT # include #endif #ifdef MOUNTED_GETMNTENT2 /* SVR4. */ # include #endif #ifdef MOUNTED_VMOUNT /* AIX. */ # include # include #endif #ifdef DOLPHIN /* So special that it's not worth putting this in autoconf. */ # undef MOUNTED_FREAD_FSTYP # define MOUNTED_GETMNTTBL #endif #if HAVE_SYS_MNTENT_H /* This is to get MNTOPT_IGNORE on e.g. SVR4. */ # include #endif #undef MNT_IGNORE #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE) #else # define MNT_IGNORE(M) 0 #endif #if USE_UNLOCKED_IO # include "unlocked-io.h" #endif #ifndef SIZE_MAX # define SIZE_MAX ((size_t) -1) #endif /* The results of open() in this file are not used with fchdir, therefore save some unnecessary work in fchdir.c. */ #undef open #undef close /* The results of opendir() in this file are not used with dirfd and fchdir, therefore save some unnecessary work in fchdir.c. */ #undef opendir #undef closedir // gcc2 under haiku and beos don't like these macros for some reason. // As they are not used there anyways, we remove them and everyone is happy. #if !defined(__HAIKU__) && !defined(__BEOS__) #ifndef ME_DUMMY # define ME_DUMMY(Fs_name, Fs_type) \ (strcmp (Fs_type, "autofs") == 0 \ || strcmp (Fs_type, "none") == 0 \ || strcmp (Fs_type, "proc") == 0 \ || strcmp (Fs_type, "subfs") == 0 \ || strcmp (Fs_type, "sysfs") == 0 \ || strcmp (Fs_type, "usbfs") == 0 \ || strcmp (Fs_type, "devpts") == 0 \ || strcmp (Fs_type, "tmpfs") == 0 \ /* for NetBSD 3.0 */ \ || strcmp (Fs_type, "kernfs") == 0 \ /* for Irix 6.5 */ \ || strcmp (Fs_type, "ignore") == 0 \ /* for MacOSX */ \ || strcmp (Fs_type, "devfs") == 0 \ || strcmp (Fs_type, "fdesc") == 0 \ || strcmp (Fs_type, "nfs") == 0 \ || strcmp (Fs_type, "volfs") == 0) #endif #ifndef ME_REMOTE /* A file system is `remote' if its Fs_name contains a `:' or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */ # define ME_REMOTE(Fs_name, Fs_type) \ (strchr (Fs_name, ':') != NULL \ || ((Fs_name)[0] == '/' \ && (Fs_name)[1] == '/' \ && (strcmp (Fs_type, "smbfs") == 0 \ || strcmp (Fs_type, "cifs") == 0))) #endif #endif // HAIKU / BEOS #ifdef MOUNTED_VMOUNT /* AIX. */ static char * fstype_to_string (int t) { struct vfs_ent *e; e = getvfsbytype (t); if (!e || !e->vfsent_name) return "none"; else return e->vfsent_name; } #endif /* MOUNTED_VMOUNT */ #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2 /* Return the device number from MOUNT_OPTIONS, if possible. Otherwise return (dev_t) -1. */ static dev_t dev_from_mount_options (char const *mount_options) { /* GNU/Linux allows file system implementations to define their own meaning for "dev=" mount options, so don't trust the meaning here. */ # ifndef __linux__ static char const dev_pattern[] = ",dev="; char const *devopt = strstr (mount_options, dev_pattern); if (devopt) { char const *optval = devopt + sizeof dev_pattern - 1; char *optvalend; unsigned long int dev; errno = 0; dev = strtoul (optval, &optvalend, 16); if (optval != optvalend && (*optvalend == '\0' || *optvalend == ',') && ! (dev == ULONG_MAX && errno == ERANGE) && dev == (dev_t) dev) return dev; } #else (void)mount_options; // unused # endif return -1; } #endif /* Return a list of the currently mounted file systems, or NULL on error. Add each entry to the tail of the list so that they stay in order. If NEED_FS_TYPE is true, ensure that the file system type fields in the returned list are valid. Otherwise, they might not be. */ struct mount_entry * read_file_system_list (bool need_fs_type) { struct mount_entry *mount_list; struct mount_entry *me; struct mount_entry **mtail = &mount_list; (void)need_fs_type; // may be unused #ifdef MOUNTED_LISTMNTENT { struct tabmntent *mntlist, *p; struct mntent *mnt; struct mount_entry *me; /* the third and fourth arguments could be used to filter mounts, but Crays doesn't seem to have any mounts that we want to remove. Specifically, automount create normal NFS mounts. */ if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0) return NULL; for (p = mntlist; p; p = p->next) { mnt = p->ment; me = xmalloc (sizeof *me); me->me_devname = xstrdup (mnt->mnt_fsname); me->me_mountdir = xstrdup (mnt->mnt_dir); me->me_type = xstrdup (mnt->mnt_type); me->me_type_malloced = 1; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = -1; *mtail = me; mtail = &me->me_next; } freemntlist (mntlist); } #endif #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ { struct mntent *mnt; char *table = MOUNTED; FILE *fp; fp = setmntent (table, "r"); if (fp == NULL) return NULL; while ((mnt = getmntent (fp))) { me = malloc (sizeof *me); me->me_devname = strdup (mnt->mnt_fsname); me->me_mountdir = strdup (mnt->mnt_dir); me->me_type = strdup (mnt->mnt_type); me->me_type_malloced = 1; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = dev_from_mount_options (mnt->mnt_opts); /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } if (endmntent (fp) == 0) goto free_then_fail; } #endif /* MOUNTED_GETMNTENT1. */ #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ { struct statfs *fsp; int entries; entries = getmntinfo (&fsp, MNT_NOWAIT); if (entries < 0) return NULL; for (; entries-- > 0; fsp++) { me = malloc (sizeof *me); me->me_devname = strdup (fsp->f_mntfromname); me->me_mountdir = strdup (fsp->f_mntonname); #if defined(__macosx__) || defined(__OpenBSD__) || defined(__FreeBSD__) me->me_type = fsp->f_fstypename; #else me->me_type = fsp->fs_typename; #endif me->me_type_malloced = 0; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } } #endif /* MOUNTED_GETMNTINFO */ #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ { struct statvfs *fsp; int entries; entries = getmntinfo (&fsp, MNT_NOWAIT); if (entries < 0) return NULL; for (; entries-- > 0; fsp++) { me = malloc (sizeof *me); me->me_devname = strdup (fsp->f_mntfromname); me->me_mountdir = strdup (fsp->f_mntonname); me->me_type = strdup (fsp->f_fstypename); me->me_type_malloced = 1; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } } #endif /* MOUNTED_GETMNTINFO2 */ #ifdef MOUNTED_GETMNT /* Ultrix. */ { int offset = 0; int val; struct fs_data fsd; while (errno = 0, 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, (char *) 0))) { me = xmalloc (sizeof *me); me->me_devname = xstrdup (fsd.fd_req.devname); me->me_mountdir = xstrdup (fsd.fd_req.path); me->me_type = gt_names[fsd.fd_req.fstype]; me->me_type_malloced = 0; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = fsd.fd_req.dev; /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } if (val < 0) goto free_then_fail; } #endif /* MOUNTED_GETMNT. */ #if defined MOUNTED_FS_STAT_DEV /* BeOS */ { /* The next_dev() and fs_stat_dev() system calls give the list of all file systems, including the information returned by statvfs() (fs type, total blocks, free blocks etc.), but without the mount point. But on BeOS all file systems except / are mounted in the rootfs, directly under /. The directory name of the mount point is often, but not always, identical to the volume name of the device. We therefore get the list of subdirectories of /, and the list of all file systems, and match the two lists. */ DIR *dirp; struct rootdir_entry { char *name; dev_t dev; ino_t ino; struct rootdir_entry *next; }; struct rootdir_entry *rootdir_list; struct rootdir_entry **rootdir_tail; int32 pos; dev_t dev; fs_info fi; /* All volumes are mounted in the rootfs, directly under /. */ rootdir_list = NULL; rootdir_tail = &rootdir_list; dirp = opendir ("/"); if (dirp) { struct dirent *d; while ((d = readdir (dirp)) != NULL) { char *name; struct stat statbuf; if (strcmp (d->d_name, "..") == 0) continue; if (strcmp (d->d_name, ".") == 0) name = strdup ("/"); else { name = malloc (1 + strlen (d->d_name) + 1); name[0] = '/'; strcpy (name + 1, d->d_name); } if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode)) { struct rootdir_entry *re = malloc (sizeof *re); re->name = name; re->dev = statbuf.st_dev; re->ino = statbuf.st_ino; /* Add to the linked list. */ *rootdir_tail = re; rootdir_tail = &re->next; } else free (name); } closedir (dirp); } *rootdir_tail = NULL; for (pos = 0; (dev = next_dev (&pos)) >= 0; ) if (fs_stat_dev (dev, &fi) >= 0) { /* Note: fi.dev == dev. */ struct rootdir_entry *re; for (re = rootdir_list; re; re = re->next) if (re->dev == fi.dev && re->ino == fi.root) break; me = malloc (sizeof *me); me->me_devname = strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name); me->me_mountdir = strdup (re != NULL ? re->name : fi.fsh_name); me->me_type = strdup (fi.fsh_name); me->me_type_malloced = 1; me->me_dev = fi.dev; me->me_dummy = 0; me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0; /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } *mtail = NULL; while (rootdir_list != NULL) { struct rootdir_entry *re = rootdir_list; rootdir_list = re->next; free (re->name); free (re); } } #endif /* MOUNTED_FS_STAT_DEV */ #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */ { int numsys, counter; size_t bufsize; struct statfs *stats; numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT); if (numsys < 0) return (NULL); /* if (SIZE_MAX / sizeof *stats <= numsys) xalloc_die ();*/ bufsize = (1 + numsys) * sizeof *stats; stats = malloc (bufsize); numsys = getfsstat (stats, bufsize, MNT_NOWAIT); if (numsys < 0) { free (stats); return (NULL); } for (counter = 0; counter < numsys; counter++) { me = malloc (sizeof *me); me->me_devname = strdup (stats[counter].f_mntfromname); me->me_mountdir = strdup (stats[counter].f_mntonname); //me->me_type = strdup (FS_TYPE (stats[counter])); me->me_type_malloced = 1; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } free (stats); } #endif /* MOUNTED_GETFSSTAT */ #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */ { struct mnttab mnt; char *table = "/etc/mnttab"; FILE *fp; fp = fopen (table, "r"); if (fp == NULL) return NULL; while (fread (&mnt, sizeof mnt, 1, fp) > 0) { me = xmalloc (sizeof *me); # ifdef GETFSTYP /* SVR3. */ me->me_devname = xstrdup (mnt.mt_dev); # else me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6); strcpy (me->me_devname, "/dev/"); strcpy (me->me_devname + 5, mnt.mt_dev); # endif me->me_mountdir = xstrdup (mnt.mt_filsys); me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ me->me_type = ""; me->me_type_malloced = 0; # ifdef GETFSTYP /* SVR3. */ if (need_fs_type) { struct statfs fsd; char typebuf[FSTYPSZ]; if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1) { me->me_type = xstrdup (typebuf); me->me_type_malloced = 1; } } # endif me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } if (ferror (fp)) { /* The last fread() call must have failed. */ int saved_errno = errno; fclose (fp); errno = saved_errno; goto free_then_fail; } if (fclose (fp) == EOF) goto free_then_fail; } #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */ #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */ { struct mntent **mnttbl = getmnttbl (), **ent; for (ent=mnttbl;*ent;ent++) { me = xmalloc (sizeof *me); me->me_devname = xstrdup ( (*ent)->mt_resource); me->me_mountdir = xstrdup ( (*ent)->mt_directory); me->me_type = xstrdup ((*ent)->mt_fstype); me->me_type_malloced = 1; me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } endmnttbl (); } #endif #ifdef MOUNTED_GETMNTENT2 /* SVR4. */ { struct mnttab mnt; char *table = MNTTAB; FILE *fp; int ret; int lockfd = -1; # if defined F_RDLCK && defined F_SETLKW /* MNTTAB_LOCK is a macro name of our own invention; it's not present in e.g. Solaris 2.6. If the SVR4 folks ever define a macro for this file name, we should use their macro name instead. (Why not just lock MNTTAB directly? We don't know.) */ # ifndef MNTTAB_LOCK # define MNTTAB_LOCK "/etc/.mnttab.lock" # endif lockfd = open (MNTTAB_LOCK, O_RDONLY); if (0 <= lockfd) { struct flock flock; flock.l_type = F_RDLCK; flock.l_whence = SEEK_SET; flock.l_start = 0; flock.l_len = 0; while (fcntl (lockfd, F_SETLKW, &flock) == -1) if (errno != EINTR) { int saved_errno = errno; close (lockfd); errno = saved_errno; return NULL; } } else if (errno != ENOENT) return NULL; # endif errno = 0; fp = fopen (table, "r"); if (fp == NULL) ret = errno; else { while ((ret = getmntent (fp, &mnt)) == 0) { me = xmalloc (sizeof *me); me->me_devname = xstrdup (mnt.mnt_special); me->me_mountdir = xstrdup (mnt.mnt_mountp); me->me_type = xstrdup (mnt.mnt_fstype); me->me_type_malloced = 1; me->me_dummy = MNT_IGNORE (&mnt) != 0; me->me_remote = ME_REMOTE (me->me_devname, me->me_type); me->me_dev = dev_from_mount_options (mnt.mnt_mntopts); /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1; } if (0 <= lockfd && close (lockfd) != 0) ret = errno; if (0 <= ret) { errno = ret; goto free_then_fail; } } #endif /* MOUNTED_GETMNTENT2. */ #ifdef MOUNTED_VMOUNT /* AIX. */ { int bufsize; char *entries, *thisent; struct vmount *vmp; int n_entries; int i; /* Ask how many bytes to allocate for the mounted file system info. */ if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0) return NULL; entries = xmalloc (bufsize); /* Get the list of mounted file systems. */ n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries); if (n_entries < 0) { int saved_errno = errno; free (entries); errno = saved_errno; return NULL; } for (i = 0, thisent = entries; i < n_entries; i++, thisent += vmp->vmt_length) { char *options, *ignore; vmp = (struct vmount *) thisent; me = xmalloc (sizeof *me); if (vmp->vmt_flags & MNT_REMOTE) { char *host, *dir; me->me_remote = 1; /* Prepend the remote dirname. */ host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off; dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off; me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2); strcpy (me->me_devname, host); strcat (me->me_devname, ":"); strcat (me->me_devname, dir); } else { me->me_remote = 0; me->me_devname = xstrdup (thisent + vmp->vmt_data[VMT_OBJECT].vmt_off); } me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off); me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype)); me->me_type_malloced = 1; options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off; ignore = strstr (options, "ignore"); me->me_dummy = (ignore && (ignore == options || ignore[-1] == ',') && (ignore[sizeof "ignore" - 1] == ',' || ignore[sizeof "ignore" - 1] == '\0')); me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */ /* Add to the linked list. */ *mtail = me; mtail = &me->me_next; } free (entries); } #endif /* MOUNTED_VMOUNT. */ *mtail = NULL; return mount_list; #if defined(MOUNTED_GETMNTENT1) || defined(MOUNTED_GETMNTENT2) || defined(MOUNTED_GETMNT) || defined(MOUNTED_FREAD) || defined(MOUNTED_FREAD_FSTYP) free_then_fail: { int saved_errno = errno; *mtail = NULL; while (mount_list) { me = mount_list->me_next; free (mount_list->me_devname); free (mount_list->me_mountdir); if (mount_list->me_type_malloced) free (mount_list->me_type); free (mount_list); mount_list = me; } errno = saved_errno; return NULL; } #endif } #endif grafx2_2.4+git20180105/src/main.c0000664000000000000000000007765613223665306014644 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2009 Pasi Kallinen Copyright 2008 Peter Gordon Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #define GLOBAL_VARIABLES // time.h defines timeval which conflicts with the one in amiga SDK #ifdef __amigaos__ #include #else #include #endif #include #include #include #include #include #include #include // There is no WM on the GP2X... #if !defined(__GP2X__) && !defined(__WIZ__) && !defined(__CAANOO__) && !defined(GCWZERO) #include #endif #include "const.h" #include "struct.h" #include "global.h" #include "graph.h" #include "misc.h" #include "init.h" #include "buttons.h" #include "engine.h" #include "pages.h" #include "loadsave.h" #include "sdlscreen.h" #include "errors.h" #include "readini.h" #include "saveini.h" #include "io.h" #include "text.h" #include "setup.h" #include "windows.h" #include "brush.h" #include "palette.h" #include "realpath.h" #include "input.h" #include "help.h" #include "filesel.h" #if defined(__WIN32__) #include #include #define chdir(dir) SetCurrentDirectory(dir) #elif defined (__MINT__) #include #elif defined(__macosx__) #import #import #elif defined(__FreeBSD__) #include #endif #if defined (__WIN32__) // On Windows, SDL_putenv is not present in any compilable header. // It can be linked anyway, this declaration only avoids // a compilation warning. extern DECLSPEC int SDLCALL SDL_putenv(const char *variable); #endif extern char Program_version[]; // generated in pversion.c //--- Affichage de la syntaxe, et de la liste des modes vidos disponibles --- void Display_syntax(void) { int mode_index; printf("Syntax: grafx2 [] [] []\n\n"); printf(" can be:]\n"); printf("\t-? -h -H -help for this help screen\n"); printf("\t-wide to emulate a video mode with wide pixels (2x1)\n"); printf("\t-tall to emulate a video mode with tall pixels (1x2)\n"); printf("\t-double to emulate a video mode with double pixels (2x2)\n"); printf("\t-wide2 to emulate a video mode with double wide pixels (4x2)\n"); printf("\t-tall2 to emulate a video mode with double tall pixels (2x4)\n"); printf("\t-triple to emulate a video mode with triple pixels (3x3)\n"); printf("\t-quadruple to emulate a video mode with quadruple pixels (4x4)\n"); printf("\t-rgb n to reduce RGB precision (2 to 256, 256=max precision)\n"); printf("\t-gamma n to adjust Gamma correction (1 to 30, 10=no correction)\n"); printf("\t-skin to use an alternate file with the menu graphics\n"); printf("\t-mode to set a video mode\n"); printf("Arguments can be prefixed either by / - or --\n"); printf("They can also be abbreviated.\n\n"); printf("Available video modes:\n\n"); for (mode_index = 0; mode_index < Nb_video_modes; mode_index += 12) { int k; for (k = 0; k < 6; k++) { if (mode_index + k >= Nb_video_modes) break; printf("%12s",Mode_label(mode_index + k)); } puts(""); } } // ---------------------------- Sortie impromptue ---------------------------- void Warning_function(const char *message, const char *filename, int line_number, const char *function_name) { printf("Warning in file %s, line %d, function %s : %s\n", filename, line_number, function_name, message); } // ---------------------------- Sortie impromptue ---------------------------- void Error_function(int error_code, const char *filename, int line_number, const char *function_name) { T_Palette temp_palette; int index; printf("Error number %d occured in file %s, line %d, function %s.\n", error_code, filename,line_number,function_name); if (error_code==0) { // L'erreur 0 n'est pas une vraie erreur, elle fait seulement un flash rouge de l'cran pour dire qu'il y a un problme. // Toutes les autres erreurs dclenchent toujours une sortie en catastrophe du programme ! memcpy(temp_palette,Main_palette,sizeof(T_Palette)); for (index=0;index<=255;index++) temp_palette[index].R=255; Set_palette(temp_palette); Delay_with_active_mouse(50); // Half a second of red flash Set_palette(Main_palette); } else { switch (error_code) { case ERROR_GUI_MISSING : printf("Error: File containing the GUI graphics is missing!\n"); printf("This program cannot run without this file.\n"); break; case ERROR_GUI_CORRUPTED : printf("Error: File containing the GUI graphics couldn't be parsed!\n"); printf("This program cannot run without a correct version of this file.\n"); break; case ERROR_INI_MISSING : printf("Error: File gfx2def.ini is missing!\n"); printf("This program cannot run without this file.\n"); break; case ERROR_MEMORY : printf("Error: Not enough memory!\n\n"); printf("You should try exiting other programs to free some bytes for Grafx2.\n\n"); break; case ERROR_FORBIDDEN_MODE : printf("Error: The requested video mode has been disabled from the resolution menu!\n"); printf("If you want to run the program in this mode, you'll have to start it with an\n"); printf("enabled mode, then enter the resolution menu and enable the mode you want.\n"); printf("Check also if the 'Default_video_mode' parameter in gfx2.ini is correct.\n"); break; case ERROR_COMMAND_LINE : printf("Error: Invalid parameter or file not found.\n\n"); Display_syntax(); break; case ERROR_SAVING_CFG : printf("Error: Write error while saving settings!\n"); printf("Settings have not been saved correctly, and the gfx2.cfg file may have been\n"); printf("corrupt. If so, please delete it and Grafx2 will restore default settings.\n"); break; case ERROR_MISSING_DIRECTORY : printf("Error: Directory you ran the program from not found!\n"); break; case ERROR_INI_CORRUPTED : printf("Error: File gfx2.ini is corrupt!\n"); printf("It contains bad values at line %d.\n",Line_number_in_INI_file); printf("You can re-generate it by deleting the file and running GrafX2 again.\n"); break; case ERROR_SAVING_INI : printf("Error: Cannot rewrite file gfx2.ini!\n"); break; case ERROR_SORRY_SORRY_SORRY : printf("Error: Sorry! Sorry! Sorry! Please forgive me!\n"); break; } SDL_Quit(); exit(error_code); } } enum CMD_PARAMS { CMDPARAM_HELP, CMDPARAM_MODE, CMDPARAM_PIXELRATIO_TALL, CMDPARAM_PIXELRATIO_WIDE, CMDPARAM_PIXELRATIO_DOUBLE, CMDPARAM_PIXELRATIO_TRIPLE, CMDPARAM_PIXELRATIO_QUAD, CMDPARAM_PIXELRATIO_TALL2, CMDPARAM_PIXELRATIO_TALL3, CMDPARAM_PIXELRATIO_WIDE2, CMDPARAM_RGB, CMDPARAM_GAMMA, CMDPARAM_SKIN }; struct { const char *param; int id; } cmdparams[] = { {"?", CMDPARAM_HELP}, {"h", CMDPARAM_HELP}, {"H", CMDPARAM_HELP}, {"help", CMDPARAM_HELP}, {"mode", CMDPARAM_MODE}, {"tall", CMDPARAM_PIXELRATIO_TALL}, {"wide", CMDPARAM_PIXELRATIO_WIDE}, {"double", CMDPARAM_PIXELRATIO_DOUBLE}, {"triple", CMDPARAM_PIXELRATIO_TRIPLE}, {"quadruple", CMDPARAM_PIXELRATIO_QUAD}, {"tall2", CMDPARAM_PIXELRATIO_TALL2}, {"tall3", CMDPARAM_PIXELRATIO_TALL3}, {"wide2", CMDPARAM_PIXELRATIO_WIDE2}, {"rgb", CMDPARAM_RGB}, {"gamma", CMDPARAM_GAMMA}, {"skin", CMDPARAM_SKIN} }; #define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof(x[0])) // --------------------- Analyse de la ligne de commande --------------------- int Analyze_command_line(int argc, char * argv[], char *main_filename, char *main_directory, char *spare_filename, char *spare_directory) { char *buffer ; int index; int file_in_command_line; file_in_command_line = 0; Resolution_in_command_line = 0; Current_resolution = Config.Default_resolution; for (index = 1; index 256) { Error(ERROR_COMMAND_LINE); Display_syntax(); exit(0); } Set_palette_RGB_scale(scale); } else { Error(ERROR_COMMAND_LINE); Display_syntax(); exit(0); } break; case CMDPARAM_GAMMA: /* Gamma correction */ index++; if (index 30) { Error(ERROR_COMMAND_LINE); Display_syntax(); exit(0); } Set_palette_Gamma(scale); } else { Error(ERROR_COMMAND_LINE); Display_syntax(); exit(0); } break; case CMDPARAM_SKIN: // GUI skin file index++; if (index 1) { // Il y a dj 2 noms de fichiers et on vient d'en trouver un 3me Error(ERROR_COMMAND_LINE); Display_syntax(); exit(0); } else if (File_exists(argv[index])) { file_in_command_line ++; buffer = Realpath(argv[index], NULL); if (file_in_command_line == 1) { // Separate path from filename Extract_path(main_directory, buffer); Extract_filename(main_filename, buffer); } else { // Separate path from filename Extract_path(spare_directory, buffer); Extract_filename(spare_filename, buffer); } free(buffer); buffer = NULL; } else { Error(ERROR_COMMAND_LINE); Display_syntax(); exit(0); } break; } } return file_in_command_line; } // Compile-time assertions: #define CT_ASSERT(e) extern char (*ct_assert(void)) [sizeof(char[1 - 2*!(e)])] // This line will raise an error at compile time // when sizeof(T_Components) is not 3. CT_ASSERT(sizeof(T_Components)==3); // This line will raise an error at compile time // when sizeof(T_Palette) is not 768. CT_ASSERT(sizeof(T_Palette)==768); // ------------------------ Initialiser le programme ------------------------- // Returns 0 on fail int Init_program(int argc,char * argv[]) { int temp; int starting_videomode; enum IMAGE_MODES starting_image_mode; static char program_directory[MAX_PATH_CHARACTERS]; T_Gui_skin *gfx; int file_in_command_line; T_Gradient_array initial_gradients; static char main_filename [MAX_PATH_CHARACTERS]; static char main_directory[MAX_PATH_CHARACTERS]; static char spare_filename [MAX_PATH_CHARACTERS]; static char spare_directory[MAX_PATH_CHARACTERS]; #if defined(__MINT__) printf("===============================\n"); printf(" /|\\ GrafX2 %.19s\n", Program_version); printf(" compilation date: %.16s\n", __DATE__); printf("===============================\n"); #endif // On cre ds maintenant les descripteurs des listes de pages pour la page // principale et la page de brouillon afin que leurs champs ne soient pas // invalide lors des appels aux multiples fonctions manipules // l'initialisation du programme. Main_backups=(T_List_of_pages *)malloc(sizeof(T_List_of_pages)); Spare_backups=(T_List_of_pages *)malloc(sizeof(T_List_of_pages)); Init_list_of_pages(Main_backups); Init_list_of_pages(Spare_backups); // Determine the executable directory Set_program_directory(argv[0],program_directory); // Choose directory for data (read only) Set_data_directory(program_directory,Data_directory); // Choose directory for settings (read/write) Set_config_directory(program_directory,Config_directory); #if defined(__MINT__) strcpy(Main_selector.Directory,program_directory); #else // On dtermine le rpertoire courant: getcwd(Main_selector.Directory,MAX_PATH_CHARACTERS); #endif #ifdef ENABLE_FILENAMES_ICONV // Initialisation de iconv // utilis pour convertir les noms de fichiers cd = iconv_open(TOCODE, FROMCODE); // From UTF8 to ANSI cd_inv = iconv_open(FROMCODE, TOCODE); // From ANSI to UTF8 #endif /* ENABLE_FILENAMES_ICONV */ // On en profite pour le mmoriser dans le rpertoire principal: strcpy(Initial_directory,Main_selector.Directory); // On initialise les donnes sur le nom de fichier de l'image de brouillon: strcpy(Spare_selector.Directory,Main_selector.Directory); Main_fileformat=DEFAULT_FILEFORMAT; Spare_fileformat =Main_fileformat; strcpy(Brush_selector.Directory,Main_selector.Directory); strcpy(Brush_file_directory,Main_selector.Directory); strcpy(Brush_filename ,"NO_NAME.GIF"); Brush_fileformat =Main_fileformat; // On initialise ce qu'il faut pour que les fileselects ne plantent pas: Main_selector.Position=0; // Au dbut, le fileselect est en haut de la liste des fichiers Main_selector.Offset=0; // Au dbut, le fileselect est en haut de la liste des fichiers Main_selector.Format_filter=FORMAT_ALL_IMAGES; Main_current_layer=0; Main_layers_visible=0xFFFFFFFF; Spare_current_layer=0; Spare_layers_visible=0xFFFFFFFF; Spare_selector.Position=0; Spare_selector.Offset=0; Spare_selector.Format_filter=FORMAT_ALL_IMAGES; Brush_selector.Position=0; Brush_selector.Offset=0; Brush_selector.Format_filter=FORMAT_ALL_IMAGES; // On initialise d'ot' trucs Main_offset_X=0; Main_offset_Y=0; Main_separator_position=0; Main_X_zoom=0; Main_separator_proportion=INITIAL_SEPARATOR_PROPORTION; Main_magnifier_mode=0; Main_magnifier_factor=DEFAULT_ZOOM_FACTOR; Main_magnifier_height=0; Main_magnifier_width=0; Main_magnifier_offset_X=0; Main_magnifier_offset_Y=0; Spare_offset_X=0; Spare_offset_Y=0; Spare_separator_position=0; Spare_X_zoom=0; Spare_separator_proportion=INITIAL_SEPARATOR_PROPORTION; Spare_magnifier_mode=0; Spare_magnifier_factor=DEFAULT_ZOOM_FACTOR; Spare_magnifier_height=0; Spare_magnifier_width=0; Spare_magnifier_offset_X=0; Spare_magnifier_offset_Y=0; Keyboard_click_allowed = 1; Main_safety_backup_prefix = SAFETYBACKUP_PREFIX_A[0]; Spare_safety_backup_prefix = SAFETYBACKUP_PREFIX_B[0]; Main_time_of_safety_backup = 0; Spare_time_of_safety_backup = 0; // SDL if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_JOYSTICK) < 0) { // The program can't continue without that anyway printf("Couldn't initialize SDL.\n"); return(0); } Joystick = SDL_JoystickOpen(0); SDL_EnableKeyRepeat(250, 32); SDL_EnableUNICODE(SDL_ENABLE); SDL_WM_SetCaption("GrafX2","GrafX2"); Define_icon(); // Texte Init_text(); // On initialise tous les modes vido Set_all_video_modes(); Pixel_ratio=PIXEL_SIMPLE; // On initialise les donnes sur l'tat du programme: // Donne sur la sortie du programme: Quit_is_required=0; Quitting=0; // Donnes sur l'tat du menu: Menu_is_visible=1; // Donnes sur les couleurs et la palette: First_color_in_palette=0; // Donnes sur le curseur: Cursor_shape=CURSOR_SHAPE_TARGET; Cursor_hidden=0; // Donnes sur le pinceau: Paintbrush_X=0; Paintbrush_Y=0; Paintbrush_hidden=0; // On initialise tout ce qui concerne les oprations et les effets Operation_stack_size=0; Selected_freehand_mode=OPERATION_CONTINUOUS_DRAW; Selected_line_mode =OPERATION_LINE; Selected_curve_mode =OPERATION_3_POINTS_CURVE; Effect_function=No_effect; // On initialise les infos de la loupe: Main_magnifier_mode=0; Main_magnifier_factor=DEFAULT_ZOOM_FACTOR; Main_separator_proportion=INITIAL_SEPARATOR_PROPORTION; Spare_separator_proportion=INITIAL_SEPARATOR_PROPORTION; // On initialise les infos du mode smear: Smear_mode=0; Smear_brush_width=PAINTBRUSH_WIDTH; Smear_brush_height=PAINTBRUSH_HEIGHT; // On initialise les infos du mode smooth: Smooth_mode=0; // On initialise les infos du mode shade: Shade_mode=0; // Les autres infos du Shade sont charges avec la config Quick_shade_mode=0; // idem // On initialise les infos sur les dgrads: Gradient_pixel =Display_pixel; // Les autres infos sont charges avec la config // On initialise les infos de la grille: Snap_mode=0; Snap_width=8; Snap_height=8; Snap_offset_X=0; Snap_offset_Y=0; // On initialise les infos du mode Colorize: Colorize_mode=0; // Mode colorize inactif par dfaut Colorize_opacity=50; // Une interpolation de 50% par dfaut Colorize_current_mode=0; // Par dfaut, la mthode par interpolation Compute_colorize_table(); // On initialise les infos du mode Tiling: Tiling_mode=0; // Pas besoin d'initialiser les dcalages car a se fait // en prenant une brosse (toujours mis 0). // On initialise les infos du mode Mask: Mask_mode=0; // Infos du Spray Airbrush_mode=1; // Mode Mono Airbrush_size=31; Airbrush_delay=1; Airbrush_mono_flow=10; memset(Airbrush_multi_flow,0,256); srand(time(NULL)); // On randomize un peu tout a... // Initialisation des boutons Init_buttons(); // Initialisation des oprations Init_operations(); // Initialize the brush container Init_brush_container(); Windows_open=0; // Paintbrush if (!(Paintbrush_sprite=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE))) Error(ERROR_MEMORY); // Load preset paintbrushes (uses Paintbrush_ variables) Init_paintbrushes(); // Set a valid paintbrush afterwards *Paintbrush_sprite=1; Paintbrush_width=1; Paintbrush_height=1; Paintbrush_offset_X=0; Paintbrush_offset_Y=0; Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND; #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // Prefer cycling active by default Cycling_mode=1; #endif // Charger la configuration des touches Set_config_defaults(); switch(Load_CFG(1)) { case ERROR_CFG_MISSING: // Pas un problme, on a les valeurs par dfaut. break; case ERROR_CFG_CORRUPTED: DEBUG("Corrupted CFG file.",0); break; case ERROR_CFG_OLD: DEBUG("Unknown CFG file version, not loaded.",0); break; } // Charger la configuration du .INI temp=Load_INI(&Config); if (temp) Error(temp); if(!Config.Allow_multi_shortcuts) { Remove_duplicate_shortcuts(); } Compute_menu_offsets(); file_in_command_line=Analyze_command_line(argc, argv, main_filename, main_directory, spare_filename, spare_directory); Current_help_section=0; Help_position=0; // Load sprites, palette etc. gfx = Load_graphics(Config.Skin_file, &initial_gradients); if (gfx == NULL) { gfx = Load_graphics(DEFAULT_SKIN_FILENAME, &initial_gradients); if (gfx == NULL) { printf("%s", Gui_loading_error_message); Error(ERROR_GUI_MISSING); } } Set_current_skin(Config.Skin_file, gfx); // Override colors // Gfx->Default_palette[MC_Black]=Config.Fav_menu_colors[0]; // Gfx->Default_palette[MC_Dark] =Config.Fav_menu_colors[1]; // Gfx->Default_palette[MC_Light]=Config.Fav_menu_colors[2]; // Gfx->Default_palette[MC_White]=Config.Fav_menu_colors[3]; // Even when using the skin's palette, if RGB range is small // the colors will be unusable. Compute_optimal_menu_colors(Gfx->Default_palette); // Infos sur les trames (Sieve) Sieve_mode=0; Copy_preset_sieve(0); // Font if (!(Menu_font=Load_font(Config.Font_file))) if (!(Menu_font=Load_font(DEFAULT_FONT_FILENAME))) { printf("Unable to open the default font file: %s\n", DEFAULT_FONT_FILENAME); Error(ERROR_GUI_MISSING); } memcpy(Main_palette, Gfx->Default_palette, sizeof(T_Palette)); Fore_color=Best_color_range(255,255,255,Config.Palette_cells_X*Config.Palette_cells_Y); Back_color=Best_color_range(0,0,0,Config.Palette_cells_X*Config.Palette_cells_Y); // Allocation de mmoire pour la brosse if (!(Brush =(byte *)malloc( 1* 1))) Error(ERROR_MEMORY); if (!(Smear_brush =(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE))) Error(ERROR_MEMORY); starting_videomode=Current_resolution; Horizontal_line_buffer=NULL; Screen_width=Screen_height=Current_resolution=0; Init_mode_video( Video_mode[starting_videomode].Width, Video_mode[starting_videomode].Height, Video_mode[starting_videomode].Fullscreen, Pixel_ratio); // Windows only: move back the window to its original position. #if defined(__WIN32__) if (!Video_mode[starting_videomode].Fullscreen) { if (Config.Window_pos_x != 9999 && Config.Window_pos_y != 9999) { //RECT r; static SDL_SysWMinfo pInfo; SDL_VERSION(&pInfo.version); SDL_GetWMInfo(&pInfo); //GetWindowRect(pInfo.window, &r); SetWindowPos(pInfo.window, 0, Config.Window_pos_x, Config.Window_pos_y, 0, 0, SWP_NOSIZE); } } // Open a console for debugging... //ActivateConsole(); #endif Main_image_width=Screen_width/Pixel_width; Main_image_height=Screen_height/Pixel_height; Spare_image_width=Screen_width/Pixel_width; Spare_image_height=Screen_height/Pixel_height; starting_image_mode = Config.Default_mode_layers ? IMAGE_MODE_LAYERED : IMAGE_MODE_ANIMATION; // Allocation de mmoire pour les diffrents crans virtuels (et brosse) if (Init_all_backup_lists(starting_image_mode , Screen_width, Screen_height)==0) Error(ERROR_MEMORY); // Update toolbars' visibility, now that the current image has a mode Check_menu_mode(); // Nettoyage de l'cran virtuel (les autres recevront celui-ci par copie) memset(Main_screen,0,Main_image_width*Main_image_height); // Now that the backup system is there, we can store the gradients. memcpy(Main_backups->Pages->Gradients->Range, initial_gradients.Range, sizeof(initial_gradients.Range)); memcpy(Spare_backups->Pages->Gradients->Range, initial_gradients.Range, sizeof(initial_gradients.Range)); Gradient_function=Gradient_basic; Gradient_lower_bound=0; Gradient_upper_bound=0; Gradient_random_factor=1; Gradient_bounds_range=1; Current_gradient=0; // Initialisation de diverses variables par calcul: Compute_magnifier_data(); Compute_limits(); Compute_paintbrush_coordinates(); // On affiche le menu: Display_paintbrush_in_menu(); Display_sprite_in_menu(BUTTON_PAL_LEFT,Config.Palette_vertical?MENU_SPRITE_VERTICAL_PALETTE_SCROLL:-1); Display_menu(); Draw_menu_button(BUTTON_PAL_LEFT,BUTTON_RELEASED); Draw_menu_button(BUTTON_PAL_RIGHT,BUTTON_RELEASED); // On affiche le curseur pour dbuter correctement l'tat du programme: Display_cursor(); Spare_image_is_modified=0; Main_image_is_modified=0; // Gestionnaire de signaux, quand il ne reste plus aucun espoir Init_sighandler(); // Le programme dbute en mode de dessin la main Select_button(BUTTON_DRAW,LEFT_SIDE); // On initialise la brosse initiale 1 pixel blanc: Brush_width=1; Brush_height=1; for (temp=0;temp<256;temp++) Brush_colormap[temp]=temp; Capture_brush(0,0,0,0,0); *Brush=MC_White; *Brush_original_pixels=MC_White; // Make sure the load dialog points to the right place when first shown. // Done after loading everything else, but before checking for emergency // backups if (file_in_command_line > 0) { strcpy(Main_selector.Directory, main_directory); } // Test de recuperation de fichiers sauvs switch (Check_recovery()) { T_IO_Context context; default: // Some files were loaded from last crash-exit. // Do not load files from command-line, nor show splash screen. Compute_optimal_menu_colors(Main_palette); Check_menu_mode(); Display_all_screen(); Display_menu(); Display_cursor(); Verbose_message("Images recovered", "Grafx2 has recovered images from\n" "last session, before a crash or\n" "shutdown. Browse the history using\n" "the Undo/Redo button, and when\n" "you find a state that you want to\n" "save, use the 'Save as' button to\n" "save the image.\n" "Some backups can be present in\n" "the spare page too.\n"); break; case -1: // Unable to write lock file Verbose_message("Warning", "Safety backups (every minute) are\n" "disabled because Grafx2 is running\n" "from a read-only device, or other\n" "instances are running."); break; case 0: switch (file_in_command_line) { case 0: if (Config.Opening_message) Button_Message_initial(); break; case 2: // Load this file Init_context_layered_image(&context, spare_filename, spare_directory); Load_image(&context); Destroy_context(&context); Redraw_layered_image(); End_of_modification(); Button_Page(); // no break ! proceed with the other file now case 1: Init_context_layered_image(&context, main_filename, main_directory); Load_image(&context); Destroy_context(&context); Redraw_layered_image(); End_of_modification(); // If only one image was loaded, assume the spare has same image type if (file_in_command_line==1) Spare_backups->Pages->Image_mode = Main_backups->Pages->Image_mode; Hide_cursor(); Compute_optimal_menu_colors(Main_palette); Back_color=Main_backups->Pages->Background_transparent ? Main_backups->Pages->Transparent_color : Best_color_range(0,0,0,Config.Palette_cells_X*Config.Palette_cells_Y); Fore_color=Main_palette[Back_color].R+Main_palette[Back_color].G+Main_palette[Back_color].B < 3*127 ? Best_color_range(255,255,255,Config.Palette_cells_X*Config.Palette_cells_Y) : Best_color_range(0,0,0,Config.Palette_cells_X*Config.Palette_cells_Y); Check_menu_mode(); Display_all_screen(); Display_menu(); Display_cursor(); Resolution_in_command_line = 0; break; default: break; } } Allow_drag_and_drop(1); return(1); } // ------------------------- Fermeture du programme -------------------------- void Program_shutdown(void) { int return_code; // Windows only: Recover the window position. #if defined(__WIN32__) { RECT r; static SDL_SysWMinfo pInfo; SDL_GetWMInfo(&pInfo); GetWindowRect(pInfo.window, &r); Config.Window_pos_x = r.left; Config.Window_pos_y = r.top; } #else // All other targets: irrelevant dimensions. // Do not attempt to force them back on next program run. Config.Window_pos_x = 9999; Config.Window_pos_y = 9999; #endif // Remove the safety backups, this is normal exit Delete_safety_backups(); // On libre le buffer de gestion de lignes free(Horizontal_line_buffer); Horizontal_line_buffer = NULL; // On libre le pinceau spcial free(Paintbrush_sprite); Paintbrush_sprite = NULL; // On libre les diffrents crans virtuels et brosse: free(Brush); Brush = NULL; Set_number_of_backups(0); // Free the skin (Gui graphics) data free(Gfx); Gfx=NULL; // On prend bien soin de passer dans le rpertoire initial: if (chdir(Initial_directory)!=-1) { // On sauvegarde les donnes dans le .CFG et dans le .INI if (Config.Auto_save) { return_code=Save_CFG(); if (return_code) Error(return_code); return_code=Save_INI(&Config); if (return_code) Error(return_code); } } else Error(ERROR_MISSING_DIRECTORY); SDL_Quit(); #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) chdir("/usr/gp2x"); execl("/usr/gp2x/gp2xmenu", "/usr/gp2x/gp2xmenu", NULL); #endif } // -------------------------- Procdure principale --------------------------- int main(int argc,char * argv[]) { if(!Init_program(argc,argv)) { Program_shutdown(); return 0; } Main_handler(); Program_shutdown(); return 0; } grafx2_2.4+git20180105/src/global.h0000664000000000000000000011702713223665306015150 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2014 Sergii Pylypenko Copyright 2009 Franck Charlet Copyright 2009 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file global.h /// This file contains all global variables. /// They are prefixed by ::GFX2_GLOBAL so they are extern when needed. ////////////////////////////////////////////////////////////////////////////// #ifndef _GLOBAL_H_ #define _GLOBAL_H_ #include #include "struct.h" // MAIN declares the variables, // other files only have an extern definition. #ifdef GLOBAL_VARIABLES /// Magic prefix to make all declarations extern, except when included by main.c. #define GFX2_GLOBAL #else #define GFX2_GLOBAL extern #endif // -- CONFIGURATION variables /// Current configuration. GFX2_GLOBAL T_Config Config; /// Array of special keys. GFX2_GLOBAL word Config_Key[NB_SPECIAL_SHORTCUTS][2]; /// A video mode (resolution) usable by Grafx2. typedef struct { short Width; ///< Screen width short Height; ///< Screen height byte Mode; ///< Unused (used to be Mode-X, SVGA, etc) word Fullscreen; ///< 0 for window, 1 for fullscreen byte State; ///< How good is the mode supported. 0:Good (white) 1:OK (light) 2:So-so (dark) 4:User-disabled (black); +128 => System doesn't support it at all. } T_Video_mode; /// Array of all video modes supported by your platform. Actually filled up to ::Nb_video_modes, excluded. GFX2_GLOBAL T_Video_mode Video_mode[MAX_VIDEO_MODES]; /// Actual number of video modes in ::Video_mode. GFX2_GLOBAL int Nb_video_modes; // -- Menu colors GFX2_GLOBAL byte MC_Black; ///< Index of color to use as "black" in the GUI menus. GFX2_GLOBAL byte MC_Dark; ///< Index of color to use as "dark grey" in the GUI menus. GFX2_GLOBAL byte MC_Light; ///< Index of color to use as "light grey" in the GUI menus. GFX2_GLOBAL byte MC_White; ///< Index of color to use as "white" in the GUI menus. GFX2_GLOBAL byte MC_Trans; ///< Index of color to use as "transparent" while loading the GUI file. GFX2_GLOBAL byte MC_OnBlack; ///< Index of color immediately lighter than "black" in the GUI menus. GFX2_GLOBAL byte MC_Window; ///< Index of color to use as window background in the GUI menus. GFX2_GLOBAL byte MC_Lighter; ///< Index of color lighter than window in the GUI menus. GFX2_GLOBAL byte MC_Darker; ///< Index of color darker than window in the GUI menus. // Input state GFX2_GLOBAL word Mouse_X; ///< Current mouse cursor position. GFX2_GLOBAL word Mouse_Y; ///< Current mouse cursor position. GFX2_GLOBAL byte Mouse_K; ///< Current mouse buttons state. Bitfield: 1 for RMB, 2 for LMB. GFX2_GLOBAL byte Keyboard_click_allowed; ///< Set to 0 when you edit a textfield so you can use space without exiting it /// Helper macro to take only one button when both are pressed (LMB has priority) #define Mouse_K_unique (Mouse_K==0?0:(Mouse_K&1?1:(Mouse_K&2?2:0))) /// Last key pressed, 0 if none. Set by the latest call to ::Get_input() GFX2_GLOBAL dword Key; /// /// Last character typed, converted to ANSI character set (Windows-1252). /// This is mostly used when the user enters text (filename, etc). GFX2_GLOBAL dword Key_ANSI; // Keyboard modifiers // (Name conflict with windows.h) #ifdef MOD_SHIFT #undef MOD_SHIFT #endif #ifdef MOD_CTRL #undef MOD_CTRL #endif #ifdef MOD_ALT #undef MOD_ALT #endif /// Key modifier for SHIFT key. Used as mask in ::Key, for example. #define MOD_SHIFT 0x1000 /// Key modifier for CONTROL key. Used as mask in ::Key, for example. #define MOD_CTRL 0x2000 /// Key modifier for ALT key. Used as mask in ::Key, for example. #define MOD_ALT 0x4000 /// Key modifier for META key. Used as mask in ::Key, for example. #define MOD_META 0x8000 /// Boolean set to true when the OS/window manager requests the application to close. ie: [X] button GFX2_GLOBAL byte Quit_is_required; /// /// This boolean is true when the current operation allows changing the /// foreground or background color. GFX2_GLOBAL byte Allow_color_change_during_operation; // -- Mouse cursor data /// Current mouse cursor. Value is in enum ::CURSOR_SHAPES GFX2_GLOBAL byte Cursor_shape; /// Backup of ::Cursor_shape, used while a window is open (and needs a different cursor) GFX2_GLOBAL byte Cursor_shape_before_window; /// Boolean, means the cursor should not be drawn. It's togglable by the user. GFX2_GLOBAL byte Cursor_hidden; /// Boolean, means the cursor is currently hovering over a menu GUI element. GFX2_GLOBAL byte Cursor_in_menu; /// Boolean, means the cursor was hovering over a menu GUI element. GFX2_GLOBAL byte Cursor_in_menu_previous; /// Storage for the graphics under the mouse cursor. Used by ::Hide_cursor and ::Display_cursor GFX2_GLOBAL byte Cursor_background[CURSOR_SPRITE_HEIGHT][CURSOR_SPRITE_WIDTH]; // -- Paintbrush data /// Active paintbrush. It's an index in enum ::PAINTBRUSH_SHAPES GFX2_GLOBAL byte Paintbrush_shape; /// Backup of ::Paintbrush_shape, before fill operation GFX2_GLOBAL byte Paintbrush_shape_before_fill; /// Backup of ::Paintbrush_shape, before color picker operation GFX2_GLOBAL byte Paintbrush_shape_before_colorpicker; /// Backup of ::Paintbrush_shape, before lasso operation GFX2_GLOBAL byte Paintbrush_shape_before_lasso; /// Boolean, true when the preview paintbrush shouldn't be drawn. GFX2_GLOBAL byte Paintbrush_hidden; /// Cordinate of the preview paintbrush in image space. GFX2_GLOBAL short Paintbrush_X; /// Cordinate of the preview paintbrush in image space. GFX2_GLOBAL short Paintbrush_Y; /// Pixel data of the current brush GFX2_GLOBAL byte * Paintbrush_sprite; /// Current paintbrush's width GFX2_GLOBAL short Paintbrush_width; /// Current paintbrush's height GFX2_GLOBAL short Paintbrush_height; /// Position of current paintbrush's handle GFX2_GLOBAL short Paintbrush_offset_X; /// Position of current paintbrush's handle GFX2_GLOBAL short Paintbrush_offset_Y; // -- Graphic commands /// On the screen, draw a point. GFX2_GLOBAL Func_pixel Pixel; /// Test a pixel color from screen. GFX2_GLOBAL Func_read Read_pixel; /// Redraw all screen, without overwriting the menu. GFX2_GLOBAL Func_display Display_screen; /// Draw a rectangle on screen. GFX2_GLOBAL Func_block Block; /// Draw a point from the image to screen (no zoom). GFX2_GLOBAL Func_pixel Pixel_preview_normal; /// Draw a point from the image to screen (magnified part). GFX2_GLOBAL Func_pixel Pixel_preview_magnifier; /// Draw a point from the image to screen (zoomed if needed). GFX2_GLOBAL Func_pixel Pixel_preview; /// Draw a horizontal XOR line on screen. GFX2_GLOBAL Func_line_XOR Horizontal_XOR_line; /// Draw a vertical XOR line on screen. GFX2_GLOBAL Func_line_XOR Vertical_XOR_line; /// Display part of the brush on screen, color mode. GFX2_GLOBAL Func_display_brush_color Display_brush_color; /// Display part of the brush on screen, monochrome mode. GFX2_GLOBAL Func_display_brush_mono Display_brush_mono; /// Clear the brush currently displayed on screen, redrawing the image instead. GFX2_GLOBAL Func_display_brush_color Clear_brush; /// Remap part of the screen after the menu colors have changed. GFX2_GLOBAL Func_remap Remap_screen; /// Draw a line on screen. GFX2_GLOBAL Func_procsline Display_line; /// Draw a line on screen, without doubling it if using wide pixels. (to be used when the line is already doubled in the input buffer) GFX2_GLOBAL Func_procsline Display_line_fast; /// Read a line of pixels from screen. GFX2_GLOBAL Func_procsline Read_line; /// Redraw all magnified part on screen, without overwriting the menu. GFX2_GLOBAL Func_display_zoom Display_zoomed_screen; /// Display part of the brush on the magnified part of screen, color mode. GFX2_GLOBAL Func_display_brush_color_zoom Display_brush_color_zoom; /// Display part of the brush on the magnified part of screen, monochrome mode. GFX2_GLOBAL Func_display_brush_mono_zoom Display_brush_mono_zoom; /// Clear the brush currently displayed on the magnified part of screen, redrawing the image instead. GFX2_GLOBAL Func_display_brush_color_zoom Clear_brush_scaled; /// Draw an arbitrary brush on screen (not the current brush) GFX2_GLOBAL Func_draw_brush Display_brush; // -- Screen data /// Requested window width. This is set when the user resizes the window. GFX2_GLOBAL int Resize_width; /// Requested window height. This is set when the user resizes the window. GFX2_GLOBAL int Resize_height; /// Current video mode. Index in ::Video_mode GFX2_GLOBAL int Current_resolution; /// After loading an image, this holds the "original screen width", if the file format supported it. GFX2_GLOBAL short Original_screen_X; /// After loading an image, this holds the "original screen height", if the file format supported it. GFX2_GLOBAL short Original_screen_Y; /// /// Current screen (or window) width, in pixels. /// Note that this takes ::Pixel_ratio into account. GFX2_GLOBAL short Screen_width; /// /// Current screen (or window) height, in pixels. /// Note that this takes ::Pixel_ratio into account. GFX2_GLOBAL short Screen_height; /// Coordinate (in image space) of the topmost visible pixel. GFX2_GLOBAL short Limit_top; /// /// Coordinate (in image space) of the lowest visible pixel. /// This can be larger than the image height, if the screen is bigger than image. GFX2_GLOBAL short Limit_bottom; /// Coordinate (in image space) of the leftmost visible pixel. GFX2_GLOBAL short Limit_left; /// /// Coordinate (in image space) of the rightmost visible pixel. /// This can be larger than the image width, if the screen is bigger than image. GFX2_GLOBAL short Limit_right; /// /// Coordinate (in image space) of the lowest visible pixel, limited by the /// image height. Compare with ::Limit_bottom, which is not clipped. GFX2_GLOBAL short Limit_visible_bottom; /// /// Coordinate (in image space) of the rightmost visible pixel, limited by the /// image width. Compare with ::Limit_right, which is not clipped. GFX2_GLOBAL short Limit_visible_right; /// Coordinate (in image space) of the pixel at the top of the magnified view. GFX2_GLOBAL short Limit_top_zoom; /// /// Coordinate (in image space) of the pixel at the bottom of the magnified view. /// This can be larger than the image height, if the screen is bigger than image. GFX2_GLOBAL short Limit_bottom_zoom; /// Coordinate (in image space) of the pixel at the left of the magnified view. GFX2_GLOBAL short Limit_left_zoom; /// /// Coordinate (in image space) of the pixel at the right of the magnified view. /// This can be larger than the image width, if the screen is bigger than image. GFX2_GLOBAL short Limit_right_zoom; /// /// Coordinate (in image space) of the lowest visible pixel, limited by the /// image height. Compare with ::Limit_bottom, which is not clipped. GFX2_GLOBAL short Limit_visible_bottom_zoom; /// Coordinate (in image space) of the rightmost visible pixel. /// This can be larger than the image width, if the screen is bigger than image. GFX2_GLOBAL short Limit_visible_right_zoom; /// Buffer of pixels, used when drawing something to screen. GFX2_GLOBAL byte * Horizontal_line_buffer; /// Current pixel ratio. Index in enum ::PIXEL_RATIO GFX2_GLOBAL int Pixel_ratio; /// Current width of pixels, according to ::Pixel_ratio GFX2_GLOBAL int Pixel_width; /// Current height of pixels, according to ::Pixel_ratio GFX2_GLOBAL int Pixel_height; // -- Current image data /// Pointer to the pixel data of the main image GFX2_GLOBAL byte * Main_screen; /// Palette of the main image GFX2_GLOBAL T_Palette Main_palette; /// Boolean, means the image has been modified since last save. GFX2_GLOBAL byte Main_image_is_modified; /// Width in pixels of the main image. GFX2_GLOBAL short Main_image_width; /// Height in pixels of the main image. GFX2_GLOBAL short Main_image_height; /// X position (in image space) of the pixel to display in the top left corner of screen. GFX2_GLOBAL short Main_offset_X; /// Y position (in image space) of the pixel to display in the top left corner of screen. GFX2_GLOBAL short Main_offset_Y; /// File format of the image currently edited. It's a value of enum ::FILE_FORMATS GFX2_GLOBAL byte Main_fileformat; /// File selector settings T_Selector_settings Main_selector; /// X position (in screen coordinates) of the separator between normal and magnified views. GFX2_GLOBAL short Main_separator_position; /// X position (in screen coordinates) of the first pixel of the magnified view. GFX2_GLOBAL short Main_X_zoom; /// Proportion of the non-magnified part of the screen. GFX2_GLOBAL float Main_separator_proportion; /// Boolean, true if the main image has the magnifier active. GFX2_GLOBAL byte Main_magnifier_mode; /// Zoom factor used in the magnifier (main image). GFX2_GLOBAL word Main_magnifier_factor; /// Height of the magnified view for the main image. GFX2_GLOBAL word Main_magnifier_height; /// Width of the magnified view for the main image. GFX2_GLOBAL word Main_magnifier_width; /// X position (in image space) of the pixel to display in the top left corner of the magnified view. GFX2_GLOBAL short Main_magnifier_offset_X; /// Y position (in image space) of the pixel to display in the top left corner of the magnified view. GFX2_GLOBAL short Main_magnifier_offset_Y; /// Index of layer currently being edited GFX2_GLOBAL int Main_current_layer; /// Bitfield that records which layers are visible. 2^0 for 0, 2^1 for 1, 2^2 for 2, etc. GFX2_GLOBAL dword Main_layers_visible; /// Index to use next time, when creating incremental backups, to make unique filename. GFX2_GLOBAL long Main_safety_number; /// Number of edit actions since the last safety backup GFX2_GLOBAL long Main_edits_since_safety_backup; /// SDL Time of the previous safety backup GFX2_GLOBAL Uint32 Main_time_of_safety_backup; /// Letter prefix for the filenames of safety backups. a or b GFX2_GLOBAL byte Main_safety_backup_prefix; /// Lookup table for XOR effects, pointing each color to the most different one GFX2_GLOBAL byte xor_lut[256]; // -- Spare page data /// Palette of the spare page GFX2_GLOBAL T_Palette Spare_palette; /// Boolean, means the spare page has been modified since last save. GFX2_GLOBAL byte Spare_image_is_modified; /// Width in pixels of the spare image. GFX2_GLOBAL short Spare_image_width; /// Height in pixels of the spare image. GFX2_GLOBAL short Spare_image_height; /// X position (in image space) of the pixel to display in the top left corner of screen. GFX2_GLOBAL short Spare_offset_X; /// Y position (in image space) of the pixel to display in the top left corner of screen. GFX2_GLOBAL short Spare_offset_Y; /// Name of the directory that holds the image currently edited as spare page. GFX2_GLOBAL char Spare_file_directory[MAX_PATH_CHARACTERS]; /// Filename (without directory) of the image currently edited as spare page. GFX2_GLOBAL char Spare_filename[MAX_PATH_CHARACTERS]; /// File format of the image currently edited as spare page. It's a value of enum ::FILE_FORMATS GFX2_GLOBAL byte Spare_fileformat; /// File selector settings T_Selector_settings Spare_selector; /// X position (in screen coordinates) of the separator between normal and magnified views. GFX2_GLOBAL short Spare_separator_position; /// X position (in screen coordinates) of the first pixel of the magnified view. GFX2_GLOBAL short Spare_X_zoom; /// Proportion of the non-magnified part of the screen. GFX2_GLOBAL float Spare_separator_proportion; /// Boolean, true if the main image has the magnifier active. GFX2_GLOBAL byte Spare_magnifier_mode; /// Zoom factor used in the magnifier (spare page). GFX2_GLOBAL word Spare_magnifier_factor; /// Width of the magnified view for the spare page. GFX2_GLOBAL word Spare_magnifier_height; /// Height of the magnified view for the spare page. GFX2_GLOBAL word Spare_magnifier_width; /// X position (in image space) of the pixel to display in the top left corner of the magnified view. GFX2_GLOBAL short Spare_magnifier_offset_X; /// Y position (in image space) of the pixel to display in the top left corner of the magnified view. GFX2_GLOBAL short Spare_magnifier_offset_Y; /// Index of layer currently being edited GFX2_GLOBAL int Spare_current_layer; /// Bitfield that records which layers are visible. 2^0 for 0, 2^1 for 1, 2^2 for 2, etc. GFX2_GLOBAL dword Spare_layers_visible; /// Index to use next time, when creating incremental backups, to make unique filename. GFX2_GLOBAL long Spare_safety_number; /// Number of edit actions since the last safety backup GFX2_GLOBAL long Spare_edits_since_safety_backup; /// SDL Time of the previous safety backup GFX2_GLOBAL Uint32 Spare_time_of_safety_backup; /// Letter prefix for the filenames of safety backups. a or b GFX2_GLOBAL byte Spare_safety_backup_prefix; // -- Image backups /// Backup of the current screen, used during drawing when FX feedback is OFF. GFX2_GLOBAL byte * Screen_backup; /// List of backup pages for the main image. GFX2_GLOBAL T_List_of_pages * Main_backups; /// List of backup pages for the spare page. GFX2_GLOBAL T_List_of_pages * Spare_backups; // -- Brush data /// Pixel data of the current brush (remapped). GFX2_GLOBAL byte * Brush; /// Pixel data of the current brush (before remap). GFX2_GLOBAL byte * Brush_original_pixels; /// Palette of the brush, from when it was grabbed. GFX2_GLOBAL T_Palette Brush_original_palette; /// Back_color used when the brush was grabbed GFX2_GLOBAL byte Brush_original_back_color; /// Color mapping from ::Brush_original_pixels to ::Brush GFX2_GLOBAL byte Brush_colormap[256]; /// X coordinate of the brush's "hot spot". It is < ::Brush_width GFX2_GLOBAL word Brush_offset_X; /// Y coordinate of the brush's "hot spot". It is < ::Brush_height GFX2_GLOBAL word Brush_offset_Y; /// Width of the current brush. GFX2_GLOBAL word Brush_width; /// Height of the current brush. GFX2_GLOBAL word Brush_height; /// Name of the directory that holds the brush fil (after loading or saving it). GFX2_GLOBAL char Brush_file_directory[MAX_PATH_CHARACTERS]; /// Filename (without directory) of the brush (after loading or saving it). GFX2_GLOBAL char Brush_filename[MAX_PATH_CHARACTERS]; /// File format of the brush. It's a value of enum ::FILE_FORMATS GFX2_GLOBAL byte Brush_fileformat; /// Fileselector settings T_Selector_settings Brush_selector; /// Indicator used for the "Rotate brush" operation. GFX2_GLOBAL byte Brush_rotation_center_is_defined; /// Position of the brush's rotation center, in screen coordinates. GFX2_GLOBAL short Brush_rotation_center_X; /// Position of the brush's rotation center, in screen coordinates. GFX2_GLOBAL short Brush_rotation_center_Y; // -- Menu data (toolbox) /// Boolean, true if the menu has to be displayed. GFX2_GLOBAL byte Menu_is_visible; /// Height of the menu, when it's displayed GFX2_GLOBAL word Menu_height; /// /// Y position (in screen coordinates) where the menu begins. /// This is always either ::Screen_height (when menu is hidden) or (::Screen_height - ::Menu_height) /// As a result, the drawing algoritm always draws the image from 0 to ::Menu_Y-1 GFX2_GLOBAL word Menu_Y; /// Y position of the status bar (in screen coordinates) GFX2_GLOBAL word Menu_status_Y; /// Scaling factor for the menu and all GUI elements GFX2_GLOBAL byte Menu_factor_X; /// Scaling factor for the menu and all GUI elements GFX2_GLOBAL byte Menu_factor_Y; /// Size of a color cell in the menu's palette. GFX2_GLOBAL word Menu_palette_cell_width; // -- Window data /// Number of stacked windows currently displayed. 0 when no window is present. GFX2_GLOBAL byte Windows_open; /// Backup of ::Menu_is_visible, used to store it while a window is open. GFX2_GLOBAL byte Menu_is_visible_before_window; /// Backup of ::Menu_Y, used to store it while a window is open. GFX2_GLOBAL word Menu_Y_before_window; /// Backup of ::Paintbrush_hidden, used to store it while a window is open. GFX2_GLOBAL byte Paintbrush_hidden_before_window; /// The global stack of editor screens. GFX2_GLOBAL T_Window Window_stack[8]; /// Position of the left border of the topmost window (in screen coordinates) #define Window_pos_X Window_stack[Windows_open-1].Pos_X /// Position of the top border of the topmost window (in screen coordinates) #define Window_pos_Y Window_stack[Windows_open-1].Pos_Y /// /// Width of the topmost window, in "window pixels" /// (multiply by ::Menu_factor_X to get screen pixels) #define Window_width Window_stack[Windows_open-1].Width /// /// Height of the topmost window, in "window pixels" /// (multiply by ::Menu_factor_Y to get screen pixels) #define Window_height Window_stack[Windows_open-1].Height /// Total number of buttons/controls in the topmost window. #define Window_nb_buttons Window_stack[Windows_open-1].Nb_buttons /// List of normal buttons in the topmost window. #define Window_normal_button_list Window_stack[Windows_open-1].Normal_button_list /// List of "palette" buttons in the topmost window. #define Window_palette_button_list Window_stack[Windows_open-1].Palette_button_list /// List of sliders (scrollers) in the topmost window. #define Window_scroller_button_list Window_stack[Windows_open-1].Scroller_button_list /// List of special buttons in the topmost window. #define Window_special_button_list Window_stack[Windows_open-1].Special_button_list /// List of dropdown buttons in the topmost window. #define Window_dropdown_button_list Window_stack[Windows_open-1].Dropdown_button_list /// List of list buttons in the topmost window. #define Window_list_button_list Window_stack[Windows_open-1].List_button_list /// /// The function ::Window_clicked_button() set this to ::LEFT_SIDE or ::RIGHT_SIDE /// after a button is activated through left or right mouse click. #define Window_attribute1 Window_stack[Windows_open-1].Attribute1 /// /// The function ::Window_clicked_button() set this to return extra information: /// - When a scroller was clicked: the scroller position (0-n) /// - When a palette was clicked: the color index (0-255) /// - When a dropdown was used: the selected item's number T_Dropdown_choice::Number #define Window_attribute2 Window_stack[Windows_open-1].Attribute2 #define Window_draggable Window_stack[Windows_open-1].Draggable // -- Information about the different drawing modes (effects) /// Current effecting function. When no effect is selected this is ::No_effect() GFX2_GLOBAL Func_effect Effect_function; /// /// Array of booleans, indicates which colors should never be picked by /// ::Best_color() GFX2_GLOBAL byte Exclude_color[256]; // -- Smear mode /// Smear mode is activated GFX2_GLOBAL byte Smear_mode; /// Boolean, indicates that a smear is in progress. GFX2_GLOBAL byte Smear_start; /// Pointer to the sprite to use for smear; it contains pixels from the image. GFX2_GLOBAL byte * Smear_brush; /// Width of the ::Smear_brush GFX2_GLOBAL word Smear_brush_width; /// Height of the ::Smear_brush GFX2_GLOBAL word Smear_brush_height; /// Limits of the smear. GFX2_GLOBAL short Smear_min_X; /// Limits of the smear. GFX2_GLOBAL short Smear_max_X; /// Limits of the smear. GFX2_GLOBAL short Smear_min_Y; /// Limits of the smear. GFX2_GLOBAL short Smear_max_Y; // -- Shade mode /// List of the shade tables GFX2_GLOBAL T_Shade Shade_list[8]; /// Shade currently selected (index in ::Shade_list) GFX2_GLOBAL byte Shade_current; /// Conversion table in use GFX2_GLOBAL byte * Shade_table; /// Conversion table for a left click GFX2_GLOBAL byte Shade_table_left[256]; /// Conversion table for a right click GFX2_GLOBAL byte Shade_table_right[256]; /// Boolean, true when the shade mode is active. GFX2_GLOBAL byte Shade_mode; /// Boolean, true when the quick-shade mode is active. GFX2_GLOBAL byte Quick_shade_mode; /// Size of the step, in Quick-shade mode. It's the number of colors to "jump". GFX2_GLOBAL byte Quick_shade_step; /// Determines how colors should loop in Quick-shade more. Value in enum ::SHADE_MODES GFX2_GLOBAL byte Quick_shade_loop; // -- Stencil mode /// Boolean, true when stencil mode is active. GFX2_GLOBAL byte Stencil_mode; /// Array of the protected colors by Stencil mode. GFX2_GLOBAL byte Stencil[256]; // -- Grid mode /// Boolean, true when the Grid mode is active. GFX2_GLOBAL byte Snap_mode; /// Boolean, true when the Grid is displayed in zoomed view. GFX2_GLOBAL byte Show_grid; /// Width of the grid in Grid mode. GFX2_GLOBAL word Snap_width; /// Height of the grid in Grid mode. GFX2_GLOBAL word Snap_height; /// Position of the starting pixel, in Grid mode. GFX2_GLOBAL word Snap_offset_X; /// Position of the starting pixel, in Grid mode. GFX2_GLOBAL word Snap_offset_Y; // -- Sieve mode /// Boolean, true when the Sieve mode is active GFX2_GLOBAL byte Sieve_mode; /// Sprite of the sieve pattern. It's actually an array of booleans. GFX2_GLOBAL byte Sieve[16][16]; /// Width of the sieve pattern, in Sieve mode. GFX2_GLOBAL short Sieve_width; /// Height of the sieve pattern, in Sieve mode. GFX2_GLOBAL short Sieve_height; // -- Colorize mode /// Boolean, true when the Colorize mode is active. GFX2_GLOBAL byte Colorize_mode; /// % of opacity of Colorize mode (for translucency) GFX2_GLOBAL byte Colorize_opacity; /// Sets the colorization mode: 0 transparency, 1 additive, 2 substractive GFX2_GLOBAL byte Colorize_current_mode; /// /// Table of precomputed factors used by Colorize mode. It hold 0 to 255 when /// opacity is 100%, 0 to 128 when opacity is 50%, etc. // FIXME: This only caches a multiplication and a division. Maybe we should scrap it GFX2_GLOBAL word Factors_table[256]; /// /// Table of precomputed factors used by Colorize mode. It hold 255 to 0 when /// opacity is 100%, 128 to 0 when opacity is 50%, etc. // FIXME: This only caches a multiplication, a division, a substraction. Maybe we should scrap it GFX2_GLOBAL word Factors_inv_table[256]; // -- Smooth mode /// Boolean, true when the Smooth mode is active GFX2_GLOBAL byte Smooth_mode; /// Matrix of "weights" used by the Smooth mode. GFX2_GLOBAL byte Smooth_matrix[3][3]; // -- Tiling mode /// Boolean, true when the Tiling mode is active GFX2_GLOBAL byte Tiling_mode; /// Position of the starting pixel in Tiling mode. GFX2_GLOBAL short Tiling_offset_X; /// Position of the starting pixel in Tiling mode. GFX2_GLOBAL short Tiling_offset_Y; // -- Mask mode /// Boolean, true when the Tiling mode is active GFX2_GLOBAL byte Mask_mode; /// Array of booleans. True if the indexed color is protected by the mask. GFX2_GLOBAL byte Mask_table[256]; // -- Tilemap mode /// Tilemap mode for main page GFX2_GLOBAL byte Main_tilemap_mode; /// Tilemap mode for spare page GFX2_GLOBAL byte Spare_tilemap_mode; // -- Magnifier data #ifdef GLOBAL_VARIABLES word ZOOM_FACTOR[NB_ZOOM_FACTORS]={2,3,4,5,6,8,10,12,14,16,18,20, 24, 28, 32}; #else /// Successive zoom factors, used by the Magnifier. extern word ZOOM_FACTOR[NB_ZOOM_FACTORS]; #endif // -- Data for ellipses and circles // FIXME: move most of these to graph.c GFX2_GLOBAL long Ellipse_cursor_X; GFX2_GLOBAL long Ellipse_cursor_Y; GFX2_GLOBAL long Ellipse_vertical_radius_squared; GFX2_GLOBAL long Ellipse_horizontal_radius_squared; GFX2_GLOBAL qword Ellipse_limit; GFX2_GLOBAL long Circle_cursor_X; GFX2_GLOBAL long Circle_cursor_Y; GFX2_GLOBAL long Circle_limit; // -- Data for gradients /// First color of the gradient. GFX2_GLOBAL short Gradient_lower_bound; /// Last color of the gradient GFX2_GLOBAL short Gradient_upper_bound; /// Boolean, true if the gradient should use colors in descending order GFX2_GLOBAL int Gradient_is_inverted; /// Number of colors in the range ::Gradient_lower_bound to ::Gradient_upper_bound (included) GFX2_GLOBAL long Gradient_bounds_range; /// Maximum value passed to the gradient function. The pixels assigned this value should use last gradient color. GFX2_GLOBAL long Gradient_total_range; /// Amount of randomness to use in gradient (1-256+) GFX2_GLOBAL long Gradient_random_factor; /// Gradient speed of cycling (0-64) GFX2_GLOBAL byte Gradient_speed; /// Pointer to a gradient function, depending on the selected method. GFX2_GLOBAL Func_gradient Gradient_function; /// /// Pointer to the pixel-drawing function that gradients should use: /// either ::Pixel (if the gradient must be drawn on menus only) /// or ::Display_pixel (if the gradient must be drawn on the image) GFX2_GLOBAL Func_pixel Gradient_pixel; /// Index in ::T_Page::Gradients of the currently selected gradient. GFX2_GLOBAL byte Current_gradient; /// Boolean, true when the color cycling is active. GFX2_GLOBAL byte Cycling_mode; // -- Airbrush data /// Mode to use in airbrush: 0 for multicolor, 1 for mono. GFX2_GLOBAL byte Airbrush_mode; /// Diameter of the airbrush, in pixels. GFX2_GLOBAL short Airbrush_size; /// Delay between two airbrush "shots", in 1/100s GFX2_GLOBAL byte Airbrush_delay; /// Number of pixels that are emitted by the airbrush, in mono mode. GFX2_GLOBAL byte Airbrush_mono_flow; /// Number of pixels that are emitted by the airbrush for each color (multi mode) GFX2_GLOBAL byte Airbrush_multi_flow[256]; /// -- Misc data about the program /// Boolean, set to true to exit the program. GFX2_GLOBAL byte Quitting; /// Name of the directory that was current when the program was run. GFX2_GLOBAL char Initial_directory[MAX_PATH_CHARACTERS]; /// Name of the directory that holds the program's (read-only) data: skins, icon, etc. GFX2_GLOBAL char Data_directory[MAX_PATH_CHARACTERS]; /// Name of the directory where grafx2 reads and writes configuration (gfx2.ini, gfx2.cfg) GFX2_GLOBAL char Config_directory[MAX_PATH_CHARACTERS]; /// Current foreground color for drawing. GFX2_GLOBAL byte Fore_color; /// Current background color for drawing. GFX2_GLOBAL byte Back_color; /// For the "Freehand draw" tool, this determines which variant is selected, from ::OPERATION_CONTINUOUS_DRAW to ::OPERATION_FILLED_CONTOUR GFX2_GLOBAL byte Selected_freehand_mode; /// For the Curve tool, this determines which variant is selected, either ::OPERATION_3_POINTS_CURVE or ::OPERATION_4_POINTS_CURVE GFX2_GLOBAL byte Selected_curve_mode; /// For the Line tool, this determines which variant is selected, either ::OPERATION_LINE, ::OPERATION_K_LINE or ::OPERATION_CENTERED_LINES GFX2_GLOBAL byte Selected_line_mode; /// Determines which color appears in the first cell of the menu palette. Change this value to "scroll" the palette. GFX2_GLOBAL byte First_color_in_palette; /// Boolean, true if Grafx2 was run with a command-line argument to set a resolution on startup (overrides config) GFX2_GLOBAL byte Resolution_in_command_line; // - Graphic /// Pointer to the font selected for menus. GFX2_GLOBAL byte * Menu_font; /// Pointer to the current active skin. GFX2_GLOBAL T_Gui_skin * Gfx; /// Pointer to the current active skin. GFX2_GLOBAL T_Paintbrush Paintbrush[NB_PAINTBRUSH_SPRITES]; // -- Help data /// Index of the ::Help_section shown by the Help screen. GFX2_GLOBAL byte Current_help_section; /// Line number of the help viewer, in current ::Help_section. 0 for top, increase value to scroll down. GFX2_GLOBAL word Help_position; // -- Operation data /// Index of the operation which was selected (ex: drawing rectangle) before the current interruption (ex: colorpicking). GFX2_GLOBAL word Operation_before_interrupt; /// Index of the current operation. This is the active "tool". GFX2_GLOBAL word Current_operation; /// /// This stack is used to memorize all parameters needed during the course of /// an operation. For example when drawing a rectangle: color, starting /// coordinates, ending coordinates. GFX2_GLOBAL word Operation_stack[OPERATION_STACK_SIZE]; /// Number of parameters stored in ::Operation_stack (0=empty) GFX2_GLOBAL byte Operation_stack_size; /// Boolean, true if the operation (drawing) started in the magnified area. GFX2_GLOBAL byte Operation_in_magnifier; /// Last color hovered by the colorpicker. -1 if it wasn't over the image. GFX2_GLOBAL short Colorpicker_color; /// Position of the colorpicker tool, in image coordinates. GFX2_GLOBAL short Colorpicker_X; /// Position of the colorpicker tool, in image coordinates. GFX2_GLOBAL short Colorpicker_Y; GFX2_GLOBAL short * Polyfill_table_of_points; GFX2_GLOBAL int Polyfill_number_of_points; /// Brush container GFX2_GLOBAL T_Brush_template Brush_container[BRUSH_CONTAINER_COLUMNS*BRUSH_CONTAINER_ROWS]; #ifdef GLOBAL_VARIABLES byte CURSOR_FOR_OPERATION[NB_OPERATIONS]= { CURSOR_SHAPE_TARGET , // Freehand continuous draw CURSOR_SHAPE_TARGET , // Freehand discontinuous draw CURSOR_SHAPE_TARGET , // Freehand point-by-point draw CURSOR_SHAPE_TARGET , // Filled contour CURSOR_SHAPE_TARGET , // Lines CURSOR_SHAPE_TARGET , // Linked lines CURSOR_SHAPE_TARGET , // Centered lines CURSOR_SHAPE_XOR_TARGET , // Empty rectangle CURSOR_SHAPE_XOR_TARGET , // Filled rectangle CURSOR_SHAPE_XOR_TARGET , // Empty circle CURSOR_SHAPE_XOR_TARGET , // Filled circle CURSOR_SHAPE_XOR_TARGET , // Empty ellipse CURSOR_SHAPE_XOR_TARGET , // Filled ellipse CURSOR_SHAPE_BUCKET , // Fill CURSOR_SHAPE_BUCKET , // Color replacer CURSOR_SHAPE_XOR_TARGET , // Rectangular brush grabbing CURSOR_SHAPE_TARGET , // Polygonal brush grabbing CURSOR_SHAPE_COLORPICKER , // Colorpicker CURSOR_SHAPE_XOR_RECTANGLE , // Position the magnify window CURSOR_SHAPE_TARGET , // Curve with 3 control points CURSOR_SHAPE_TARGET , // Curve with 4 control points CURSOR_SHAPE_TARGET , // Airbrush CURSOR_SHAPE_TARGET , // Polygon CURSOR_SHAPE_TARGET , // Polyform CURSOR_SHAPE_TARGET , // Filled polygon CURSOR_SHAPE_TARGET , // Filled polyform CURSOR_SHAPE_MULTIDIRECTIONAL , // Scroll image CURSOR_SHAPE_XOR_TARGET , // Gradient-filled circle CURSOR_SHAPE_XOR_TARGET , // Gradient-filled ellipse CURSOR_SHAPE_XOR_ROTATION , // Rotate brush CURSOR_SHAPE_XOR_TARGET , // Stretch brush CURSOR_SHAPE_TARGET , // Distort brush CURSOR_SHAPE_XOR_TARGET , // Gradient-filled rectangle CURSOR_SHAPE_COLORPICKER , // Colorpick on right mouse button CURSOR_SHAPE_MULTIDIRECTIONAL , // Pan view }; #else /// ::Cursor_shape to use for each operation. extern byte CURSOR_FOR_OPERATION[NB_OPERATIONS]; #endif /// /// Procedures to call for each state (determined by ::Operation_stack_size) of /// each operation, and for each mouse state (no button,left button,right button) GFX2_GLOBAL struct { Func_action Action; ///< Function to call byte Hide_cursor; ///< Boolean: Need to hide/unhide cursor during this step byte Fast_mouse; ///< Operation should take shortcuts with mouse movements } Operation[NB_OPERATIONS][3][OPERATION_STACK_SIZE]; // -- misc /// /// Indicator of error in previous file operations. /// - 0: OK /// - 1: Error when beginning operation. Existing data should be ok. /// - 2: Error while operation was in progress. Data is modified. /// - -1: Interruption of a preview. GFX2_GLOBAL signed char File_error; /// Current line number when reading/writing gfx2.ini GFX2_GLOBAL int Line_number_in_INI_file; // -- For iconv #ifdef ENABLE_FILENAMES_ICONV #include #define TOCODE "CP1252" #define FROMCODE "UTF-8" GFX2_GLOBAL iconv_t cd; GFX2_GLOBAL iconv_t cd_inv; #endif /* ENABLE_FILENAMES_ICONV */ // -- Specific to SDL /// Pointer to the program's screen. GFX2_GLOBAL SDL_Surface * Screen_SDL; /// Pointer to the current joystick controller. GFX2_GLOBAL SDL_Joystick* Joystick; /// Indicates "no keyboard shortcut". #define KEY_NONE 0 /// /// This is the "key identifier" for the mouse 3rd button. /// It was chosen to not conflict with any SDL key number. #define KEY_MOUSEMIDDLE (SDLK_LAST+1) /// /// This is the "key identifier" for the mouse wheelup. /// It was chosen to not conflict with any SDL key number. #define KEY_MOUSEWHEELUP (SDLK_LAST+2) /// /// This is the "key identifier" for the mouse wheeldown. /// It was chosen to not conflict with any SDL key number. #define KEY_MOUSEWHEELDOWN (SDLK_LAST+3) /// /// This is the "key identifier" for joystick button number 0. /// All numbers starting with this one are reserved for joystick buttons /// (since their is an unknown number of them, and for example 18 on GP2X) /// It was chosen to not conflict with any SDL key number. #define KEY_JOYBUTTON (SDLK_LAST+4) /// The joystick axis are {X,Y} - on all platforms so far. /// If there is ever a platform where they are reversed, put /// these lines in each platform "case" below. #define JOYSTICK_AXIS_X (0) #define JOYSTICK_AXIS_Y (1) #ifdef __GP2X__ #define JOYSTICK_THRESHOLD (4096) /// Button definitions for the gp2x #define JOY_BUTTON_UP (0) #define JOY_BUTTON_DOWN (4) #define JOY_BUTTON_LEFT (2) #define JOY_BUTTON_RIGHT (6) #define JOY_BUTTON_UPLEFT (1) #define JOY_BUTTON_UPRIGHT (7) #define JOY_BUTTON_DOWNLEFT (3) #define JOY_BUTTON_DOWNRIGHT (5) #define JOY_BUTTON_CLICK (18) #define JOY_BUTTON_A (12) #define JOY_BUTTON_B (13) #define JOY_BUTTON_Y (14) #define JOY_BUTTON_X (15) #define JOY_BUTTON_L (10) #define JOY_BUTTON_R (11) #define JOY_BUTTON_START (8) #define JOY_BUTTON_SELECT (9) #define JOY_BUTTON_VOLUP (16) #define JOY_BUTTON_VOLDOWN (17) #define KEY_ESC (KEY_JOYBUTTON+JOY_BUTTON_X) #elif defined(__WIZ__) /// Button definitions for the Wiz #define JOY_BUTTON_UP (0) #define JOY_BUTTON_DOWN (4) #define JOY_BUTTON_LEFT (2) #define JOY_BUTTON_RIGHT (6) #define JOY_BUTTON_UPLEFT (1) #define JOY_BUTTON_UPRIGHT (7) #define JOY_BUTTON_DOWNLEFT (3) #define JOY_BUTTON_DOWNRIGHT (5) #define JOY_BUTTON_L (10) #define JOY_BUTTON_R (11) #define JOY_BUTTON_A (12) #define JOY_BUTTON_B (13) #define JOY_BUTTON_X (14) #define JOY_BUTTON_Y (15) #define JOY_BUTTON_MENU (8) #define JOY_BUTTON_SELECT (9) #define JOY_BUTTON_VOLUP (16) #define JOY_BUTTON_VOLDOWN (17) #define KEY_ESC (KEY_JOYBUTTON+JOY_BUTTON_X) #elif defined (__CAANOO__) #define JOYSTICK_THRESHOLD (4096) /// Button definitions for the Caanoo #define JOY_BUTTON_A (0) #define JOY_BUTTON_X (1) #define JOY_BUTTON_B (2) #define JOY_BUTTON_Y (3) #define JOY_BUTTON_L (4) #define JOY_BUTTON_R (5) #define JOY_BUTTON_HOME (6) #define JOY_BUTTON_HOLD (7) #define JOY_BUTTON_I (8) #define JOY_BUTTON_II (9) #define JOY_BUTTON_JOY (10) #define KEY_ESC (KEY_JOYBUTTON+JOY_BUTTON_HOME) #else /// /// This is the key identifier for ESC. When hard-coding keyboard shortcuts /// for buttons, etc. we use this instead of SDLK_ESCAPE, /// so the console ports can get a joybutton equivalent of it. #define KEY_ESC SDLK_ESCAPE #endif #endif grafx2_2.4+git20180105/src/fileformats.c0000664000000000000000000045312513223665306016220 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ///@file fileformats.c /// Saving and loading different picture formats. #ifndef __no_pnglib__ #include #if !defined(PNG_HAVE_PLTE) #define PNG_HAVE_PLTE 0x02 #endif #if (PNG_LIBPNG_VER_MAJOR <= 1) && (PNG_LIBPNG_VER_MINOR < 4) // Compatibility layer to allow us to use libng 1.4 or any older one. // This function is renamed in 1.4 #define png_set_expand_gray_1_2_4_to_8(x) png_set_gray_1_2_4_to_8(x) // Wrappers that are mandatory in 1.4. Older version allowed direct access. #define png_get_rowbytes(png_ptr,info_ptr) ((info_ptr)->rowbytes) #define png_get_image_width(png_ptr,info_ptr) ((info_ptr)->width) #define png_get_image_height(png_ptr,info_ptr) ((info_ptr)->height) #define png_get_bit_depth(png_ptr,info_ptr) ((info_ptr)->bit_depth) #define png_get_color_type(png_ptr,info_ptr) ((info_ptr)->color_type) #endif #endif #ifndef png_jmpbuf # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) #endif #include #include "errors.h" #include "global.h" #include "loadsave.h" #include "misc.h" #include "struct.h" #include "io.h" #include "pages.h" #include "windows.h" // Best_color() //////////////////////////////////// IMG //////////////////////////////////// // -- Tester si un fichier est au format IMG -------------------------------- void Test_IMG(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier T_IMG_Header IMG_header; byte signature[6]={0x01,0x00,0x47,0x12,0x6D,0xB0}; Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Lecture et vrification de la signature if (Read_bytes(file,IMG_header.Filler1,6) && Read_word_le(file,&(IMG_header.Width)) && Read_word_le(file,&(IMG_header.Height)) && Read_bytes(file,IMG_header.Filler2,118) && Read_bytes(file,IMG_header.Palette,sizeof(T_Palette)) ) { if ( (!memcmp(IMG_header.Filler1,signature,6)) && IMG_header.Width && IMG_header.Height) File_error=0; } // Fermeture du fichier fclose(file); } } // -- Lire un fichier au format IMG ----------------------------------------- void Load_IMG(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier byte * buffer; FILE *file; word x_pos,y_pos; long file_size; T_IMG_Header IMG_header; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (Read_bytes(file,IMG_header.Filler1,6) && Read_word_le(file,&(IMG_header.Width)) && Read_word_le(file,&(IMG_header.Height)) && Read_bytes(file,IMG_header.Filler2,118) && Read_bytes(file,IMG_header.Palette,sizeof(T_Palette)) ) { buffer=(byte *)malloc(IMG_header.Width); Pre_load(context, IMG_header.Width,IMG_header.Height,file_size,FORMAT_IMG,PIXEL_SIMPLE,0); if (File_error==0) { memcpy(context->Palette,IMG_header.Palette,sizeof(T_Palette)); context->Width=IMG_header.Width; context->Height=IMG_header.Height; for (y_pos=0;(y_posHeight) && (!File_error);y_pos++) { if (Read_bytes(file,buffer,context->Width)) { for (x_pos=0; x_posWidth;x_pos++) Set_pixel(context, x_pos,y_pos,buffer[x_pos]); } else File_error=2; } } free(buffer); buffer = NULL; } else File_error=1; fclose(file); } else File_error=1; } // -- Sauver un fichier au format IMG --------------------------------------- void Save_IMG(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; short x_pos,y_pos; T_IMG_Header IMG_header; byte signature[6]={0x01,0x00,0x47,0x12,0x6D,0xB0}; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { setvbuf(file, NULL, _IOFBF, 64*1024); memcpy(IMG_header.Filler1,signature,6); IMG_header.Width=context->Width; IMG_header.Height=context->Height; memset(IMG_header.Filler2,0,118); IMG_header.Filler2[4]=0xFF; IMG_header.Filler2[22]=64; // Lo(Longueur de la signature) IMG_header.Filler2[23]=0; // Hi(Longueur de la signature) memcpy(IMG_header.Filler2+23,"GRAFX2 by SunsetDesign (IMG format taken from PV (c)W.Wiedmann)",64); memcpy(IMG_header.Palette,context->Palette,sizeof(T_Palette)); if (Write_bytes(file,IMG_header.Filler1,6) && Write_word_le(file,IMG_header.Width) && Write_word_le(file,IMG_header.Height) && Write_bytes(file,IMG_header.Filler2,118) && Write_bytes(file,IMG_header.Palette,sizeof(T_Palette)) ) { for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) for (x_pos=0; x_posWidth; x_pos++) Write_one_byte(file,Get_pixel(context, x_pos,y_pos)); fclose(file); if (File_error) remove(filename); } else // Error d'criture (disque plein ou protg) { fclose(file); remove(filename); File_error=1; } } else { fclose(file); remove(filename); File_error=1; } } //////////////////////////////////// IFF //////////////////////////////////// typedef struct { word Width; word Height; word X_org; // Inutile word Y_org; // Inutile byte BitPlanes; byte Mask; // 0=none, 1=mask, 2=transp color, 3=Lasso byte Compression; // 0=none, 1=packbits, 2=vertical RLE byte Pad1; // Inutile word Transp_col; // transparent color for masking mode 2 byte X_aspect; // Inutile byte Y_aspect; // Inutile word X_screen; word Y_screen; } T_IFF_Header; byte * IFF_buffer; FILE *IFF_file; // -- Tester si un fichier est au format IFF -------------------------------- void Test_IFF(T_IO_Context * context, const char *sub_type) { char filename[MAX_PATH_CHARACTERS]; char format[4]; char section[4]; dword dummy; Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; if ((IFF_file=fopen(filename, "rb"))) { do // Dummy loop, so that all breaks jump to end. { if (! Read_bytes(IFF_file,section,4)) break; if (memcmp(section,"FORM",4)) break; if (! Read_dword_be(IFF_file, &dummy)) break; // On aurait pu vrifier que ce long est gal la taille // du fichier - 8, mais a aurait interdit de charger des // fichiers tronqus (et dj que c'est chiant de perdre // une partie du fichier il faut quand mme pouvoir en // garder un peu... Sinon, moi je pleure :'( !!! ) if (! Read_bytes(IFF_file,format,4)) break; if (!memcmp(format,"ANIM",4)) { // An ANIM header: need to check that it encloses an image if (! Read_bytes(IFF_file,section,4)) break; if (memcmp(section,"FORM",4)) break; if (! Read_dword_be(IFF_file, &dummy)) break; if (! Read_bytes(IFF_file,format,4)) break; } if ( memcmp(format,sub_type,4)) break; // If we reach this part, file is indeed ILBM/PBM or ANIM File_error=0; } while (0); fclose(IFF_file); } } void Test_PBM(T_IO_Context * context) { Test_IFF(context, "PBM "); } void Test_LBM(T_IO_Context * context) { Test_IFF(context, "ILBM"); } // -- Lire un fichier au format IFF ----------------------------------------- byte Image_HAM; // ---------------- Adapter la palette pour les images HAM ---------------- void Adapt_palette_HAM(T_IO_Context * context) { short i,j,temp; byte color; if (Image_HAM==6) { for (i=1; i<=14; i++) { // On recopie a palette de base memcpy(context->Palette+(i<<4),context->Palette,48); // On modifie les teintes de cette palette for (j=0; j<16; j++) { color=(i<<4)+j; if (i<=7) { if (i&1) { temp=context->Palette[j].R+16; context->Palette[color].R=(temp<63)?temp:63; } if (i&2) { temp=context->Palette[j].G+16; context->Palette[color].G=(temp<63)?temp:63; } if (i&4) { temp=context->Palette[j].B+16; context->Palette[color].B=(temp<63)?temp:63; } } else { if ((i-7)&1) { temp=context->Palette[j].R-16; context->Palette[color].R=(temp>=0)?temp:0; } if ((i-7)&2) { temp=context->Palette[j].G-16; context->Palette[color].G=(temp>=0)?temp:0; } if ((i-7)&4) { temp=context->Palette[j].B-16; context->Palette[color].B=(temp>=0)?temp:0; } } } } // Ici, il reste les 16 dernires couleurs modifier for (i=240,j=0; j<16; i++,j++) { temp=context->Palette[j].R+8; context->Palette[i].R=(temp<63)?temp:63; temp=context->Palette[j].G+8; context->Palette[i].G=(temp<63)?temp:63; temp=context->Palette[j].B+8; context->Palette[i].B=(temp<63)?temp:63; } } else if (Image_HAM==8) { for (i=1; i<=3; i++) { // On recopie la palette de base memcpy(context->Palette+(i<<6),context->Palette,192); // On modifie les teintes de cette palette for (j=0; j<64; j++) { color=(i<<6)+j; switch (i) { case 1 : temp=context->Palette[j].R+16; context->Palette[color].R=(temp<63)?temp:63; break; case 2 : temp=context->Palette[j].G+16; context->Palette[color].G=(temp<63)?temp:63; break; default: temp=context->Palette[j].B+16; context->Palette[color].B=(temp<63)?temp:63; } } } } else // Image 64 couleurs sauve en 32. { for (i=0; i<32; i++) { j=i+32; context->Palette[j].R=context->Palette[i].R>>1; context->Palette[j].G=context->Palette[i].G>>1; context->Palette[j].B=context->Palette[i].B>>1; } } } // Inspired by Allegro: storing a 4-character identifier as a 32bit litteral #define ID4(a,b,c,d) ((((a)&255)<<24) | (((b)&255)<<16) | (((c)&255)<<8) | (((d)&255))) /// Skips the current section in an IFF file. /// This function should be called while the file pointer is right /// after the 4-character code that identifies the section. int IFF_Skip_section(void) { dword size; if (!Read_dword_be(IFF_file,&size)) return 0; if (size&1) size++; if (fseek(IFF_file,size,SEEK_CUR)) return 0; return 1; } // ------------------------- Attendre une section ------------------------- byte IFF_Wait_for(const char * expected_section) { // Valeur retourne: 1=Section trouve, 0=Section non trouve (erreur) byte section_read[4]; if (! Read_bytes(IFF_file,section_read,4)) return 0; while (memcmp(section_read,expected_section,4)) // Sect. pas encore trouve { if (!IFF_Skip_section()) return 0; if (! Read_bytes(IFF_file,section_read,4)) return 0; } return 1; } // Les images ILBM sont stocks en bitplanes donc on doit trifouiller les bits pour // en faire du chunky /// /// Decodes the color of one pixel from the ILBM line buffer. /// @param x_pos Position of the pixel in graphic line /// @param real_line_size Width of one bitplane in memory, in bytes /// @param bitplanes Number of bitplanes byte Get_IFF_color(word x_pos, word real_line_size, byte bitplanes) { byte shift = 7 - (x_pos & 7); int address,masked_bit,plane; byte color=0; for(plane=bitplanes-1;plane>=0;plane--) { address = (real_line_size * plane + x_pos) >> 3; masked_bit = (IFF_buffer[address] >> shift) & 1; color = (color << 1) + masked_bit; } return color; } void Set_IFF_color(word x_pos, byte color, word real_line_size, byte bitplanes) { byte shift = 7 - (x_pos & 7); int address, plane; for(plane=0;plane> 3; IFF_buffer[address] |= (color&1) << shift; color = color >> 1; } } // ----------------------- Afficher une ligne ILBM ------------------------ void Draw_IFF_line(T_IO_Context *context, short y_pos, short real_line_size, byte bitplanes) { byte color; byte red,green,blue; byte temp; short x_pos; if (Image_HAM<=1) // ILBM { for (x_pos=0; x_posWidth; x_pos++) { Set_pixel(context, x_pos,y_pos,Get_IFF_color(x_pos,real_line_size, bitplanes)); } } else { color=0; red=context->Palette[0].R; green =context->Palette[0].G; blue =context->Palette[0].B; if (Image_HAM==6) for (x_pos=0; x_posWidth; x_pos++) // HAM6 { temp=Get_IFF_color(x_pos,real_line_size, bitplanes); switch (temp & 0xF0) { case 0x10: // blue blue=(temp&0x0F)<<2; color=Best_color(red,green,blue); break; case 0x20: // red red=(temp&0x0F)<<2; color=Best_color(red,green,blue); break; case 0x30: // green green=(temp&0x0F)<<2; color=Best_color(red,green,blue); break; default: // Nouvelle couleur color=temp; red=context->Palette[color].R; green =context->Palette[color].G; blue =context->Palette[color].B; } Set_pixel(context, x_pos,y_pos,color); } else for (x_pos=0; x_posWidth; x_pos++) // HAM8 { temp=Get_IFF_color(x_pos,real_line_size, bitplanes); switch (temp & 0x03) { case 0x01: // blue blue=temp>>2; color=Best_color(red,green,blue); break; case 0x02: // red red=temp>>2; color=Best_color(red,green,blue); break; case 0x03: // green green=temp>>2; color=Best_color(red,green,blue); break; default: // Nouvelle couleur color=temp; red=context->Palette[color].R; green =context->Palette[color].G; blue =context->Palette[color].B; } Set_pixel(context, x_pos,y_pos,color); } } } void Load_IFF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; T_IFF_Header header; char format[4]; char section[4]; byte temp_byte; short b256; dword nb_colors; dword section_size; short x_pos; short y_pos; short counter; short line_size; // Taille d'une ligne en octets short plane_line_size; // Size of line in bytes for 1 plane short real_line_size; // Taille d'une ligne en pixels byte color; long file_size; dword dummy; int iff_format; int plane; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((IFF_file=fopen(filename, "rb"))) { file_size=File_length_file(IFF_file); // FORM + size(4) Read_bytes(IFF_file,section,4); Read_dword_be(IFF_file,&dummy); Read_bytes(IFF_file,format,4); if (!memcmp(format,"ANIM",4)) { // Skip a bit, brother Read_bytes(IFF_file,section,4); Read_dword_be(IFF_file,&dummy); Read_bytes(IFF_file,format,4); } if (!memcmp(format,"ILBM",4)) iff_format = FORMAT_LBM; else iff_format = FORMAT_PBM; if (!IFF_Wait_for("BMHD")) File_error=1; Read_dword_be(IFF_file,&dummy); // Maintenant on lit le header pour pouvoir commencer le chargement de l'image if ( (Read_word_be(IFF_file,&header.Width)) && (Read_word_be(IFF_file,&header.Height)) && (Read_word_be(IFF_file,&header.X_org)) && (Read_word_be(IFF_file,&header.Y_org)) && (Read_byte(IFF_file,&header.BitPlanes)) && (Read_byte(IFF_file,&header.Mask)) && (Read_byte(IFF_file,&header.Compression)) && (Read_byte(IFF_file,&header.Pad1)) && (Read_word_be(IFF_file,&header.Transp_col)) && (Read_byte(IFF_file,&header.X_aspect)) && (Read_byte(IFF_file,&header.Y_aspect)) && (Read_word_be(IFF_file,&header.X_screen)) && (Read_word_be(IFF_file,&header.Y_screen)) && header.Width && header.Height) { if ( (header.BitPlanes) && (IFF_Wait_for("CMAP")) ) { Read_dword_be(IFF_file,&nb_colors); nb_colors/=3; if (((dword)1< il faut copier les 32 coul. } // sur les 32 suivantes et assombrir ces dernires. else { if ((header.BitPlanes==6) || (header.BitPlanes==8)) Image_HAM=header.BitPlanes; else /* File_error=1;*/ /* C'est cens tre incorrect mais j'ai */ Image_HAM=0; /* trouv un fichier comme a, alors... */ } } else Image_HAM=0; if ( (!File_error) && (nb_colors>=2) && (nb_colors<=256) ) { byte real_bit_planes = header.BitPlanes; if (header.Mask==1) header.BitPlanes++; // Deluxe paint le fait... alors on le fait... Back_color=header.Transp_col; if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); // On peut maintenant charger la nouvelle palette if (Read_bytes(IFF_file,context->Palette,3*nb_colors)) { if (Image_HAM) { Palette_256_to_64(context->Palette); Adapt_palette_HAM(context); Palette_64_to_256(context->Palette); } // On lit l'octet de padding du CMAP si la taille est impaire if (nb_colors&1) if (Read_byte(IFF_file,&temp_byte)) File_error=20; // Keep reading sections until we find the body while (1) { if (! Read_bytes(IFF_file,section,4)) { File_error=46; break; } // Found body : stop searching if (!memcmp(section,"BODY",4)) break; else if (!memcmp(section,"CRNG",4)) { // Handle CRNG // The content of a CRNG is as follows: word padding; word rate; word flags; byte min_col; byte max_col; // if ( (Read_dword_be(IFF_file,§ion_size)) && (Read_word_be(IFF_file,&padding)) && (Read_word_be(IFF_file,&rate)) && (Read_word_be(IFF_file,&flags)) && (Read_byte(IFF_file,&min_col)) && (Read_byte(IFF_file,&max_col))) { if (section_size == 8 && min_col != max_col) { // Valid cycling range if (max_colCycle_range[context->Color_cycles].Start=min_col; context->Cycle_range[context->Color_cycles].End=max_col; context->Cycle_range[context->Color_cycles].Inverse=(flags&2)?1:0; context->Cycle_range[context->Color_cycles].Speed=(flags&1) ? rate/78 : 0; context->Color_cycles++; } } else { File_error=47; break; } } else { // ignore any number of unknown sections if (!IFF_Skip_section()) { File_error=48; break; } } } if ( !File_error ) { Read_dword_be(IFF_file,§ion_size); context->Width = header.Width; context->Height = header.Height; Original_screen_X = header.X_screen; Original_screen_Y = header.Y_screen; Pre_load(context, context->Width,context->Height,file_size,iff_format,PIXEL_SIMPLE,0); context->Background_transparent = header.Mask == 2; context->Transparent_color = context->Background_transparent ? header.Transp_col : 0; if (context->Type == CONTEXT_MAIN_IMAGE) { Main_backups->Pages->Image_mode = IMAGE_MODE_ANIMATION; Update_screen_targets(); } if (File_error==0) { if (!memcmp(format,"ILBM",4)) // "ILBM": InterLeaved BitMap { // Calcul de la taille d'une ligne ILBM (pour les images ayant des dimensions exotiques) real_line_size = (context->Width+15) & ~15; plane_line_size = real_line_size >> 3; // 8bits per byte line_size = plane_line_size * header.BitPlanes; switch(header.Compression) { case 0: // non compress IFF_buffer=(byte *)malloc(line_size); for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) { if (Read_bytes(IFF_file,IFF_buffer,line_size)) Draw_IFF_line(context, y_pos,real_line_size, header.BitPlanes); else File_error=21; } free(IFF_buffer); IFF_buffer = NULL; break; case 1: // compress packbits (Amiga) /*Init_lecture();*/ IFF_buffer=(byte *)malloc(line_size); for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) { for (x_pos=0; ((x_pos 127 alors il faut rpter 256-'temp_byte' fois la couleur de l'octet suivant // Si temp_byte <= 127 alors il faut afficher directement les 'temp_byte' octets suivants if (temp_byte>127) { if(Read_byte(IFF_file, &color)!=1) { File_error=23; break; } b256=(short)(256-temp_byte); for (counter=0; counter<=b256; counter++) if (x_pos=line_size || Read_byte(IFF_file, &(IFF_buffer[x_pos++]))!=1) File_error=25; } if (!File_error) Draw_IFF_line(context, y_pos,real_line_size,header.BitPlanes); } free(IFF_buffer); IFF_buffer = NULL; /*Close_lecture();*/ break; case 2: // compress vertical RLE (Atari ST) IFF_buffer=(byte *)malloc(line_size*context->Height); plane_line_size = real_line_size >> 3; for (plane = 0; plane < header.BitPlanes && !File_error; plane++) { word cmd_count; word cmd; signed char * commands; word count; y_pos = 0; x_pos = 0; if (!IFF_Wait_for("VDAT")) { File_error = 30; break; } Read_dword_be(IFF_file,§ion_size); Read_word_be(IFF_file,&cmd_count); cmd_count -= 2; commands = (signed char *)malloc(cmd_count); if (!Read_bytes(IFF_file,commands,cmd_count)) { File_error = 31; break; } for (cmd = 0; cmd < cmd_count && x_pos < plane_line_size; cmd++) { if (commands[cmd] <= 0) { // cmd=0 : load count from data, COPY // cmd < 0 : count = -cmd, COPY if (commands[cmd] == 0) Read_word_be(IFF_file,&count); else count = -commands[cmd]; while (count-- > 0 && x_pos < plane_line_size) { Read_bytes(IFF_file,IFF_buffer+x_pos+y_pos*line_size+plane*plane_line_size,2); if(++y_pos >= context->Height) { y_pos = 0; x_pos += 2; } } } else if (commands[cmd] >= 1) { // cmd=1 : load count from data, RLE // cmd >1 : count = cmd, RLE byte data[2]; if (commands[cmd] == 1) Read_word_be(IFF_file,&count); else count = (word)commands[cmd]; Read_bytes(IFF_file,data,2); while (count-- > 0 && x_pos < plane_line_size) { memcpy(IFF_buffer+x_pos+y_pos*line_size+plane*plane_line_size,data,2); if (++y_pos >= context->Height) { y_pos = 0; x_pos += 2; } } } } free(commands); } if (!File_error) { byte * save_IFF_buffer = IFF_buffer; for (y_pos = 0; y_pos < context->Height; y_pos++) { Draw_IFF_line(context,y_pos,real_line_size,real_bit_planes); IFF_buffer += line_size; } IFF_buffer = save_IFF_buffer; } free(IFF_buffer); IFF_buffer = NULL; break; default: // compression non reconnue File_error = 32; } } else // "PBM ": Planar(?) BitMap { real_line_size=context->Width+(context->Width&1); if (!header.Compression) { // non compress IFF_buffer=(byte *)malloc(real_line_size); for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) { if (Read_bytes(IFF_file,IFF_buffer,real_line_size)) for (x_pos=0; x_posWidth; x_pos++) Set_pixel(context, x_pos,y_pos,IFF_buffer[x_pos]); else File_error=26; } free(IFF_buffer); IFF_buffer = NULL; } else { // compress /*Init_lecture();*/ for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) { for (x_pos=0; ((x_pos127) { if(Read_byte(IFF_file, &color)!=1) { File_error=28; break; } b256=256-temp_byte; for (counter=0; counter<=b256; counter++) Set_pixel(context, x_pos++,y_pos,color); } else for (counter=0; counter<=temp_byte; counter++) { byte byte_read=0; if(Read_byte(IFF_file, &byte_read)!=1) { File_error=29; break; } Set_pixel(context, x_pos++,y_pos,byte_read); } } } /*Close_lecture();*/ } } /* while (!File_error && is_anim) { dword delta_size; // Just loaded the first image successfully : now keep reading // FORM + size(4) if (!Read_bytes(IFF_file,section,4)) break; Read_dword_be(IFF_file,&dummy); // ILBM, hopefully Read_bytes(IFF_file,format,4); if (!IFF_Wait_for("DLTA")) { File_error=1; break; } Set_loading_layer(context, context->Current_layer+1); Read_dword_be(IFF_file,&delta_size); fseek(IFF_file, delta_size + (delta_size & 1), SEEK_CUR); } */ } } else Set_file_error(2); } else { File_error=1; } } else Set_file_error(1); } else File_error=1; } else File_error=1; fclose(IFF_file); } else File_error=1; } // -- Sauver un fichier au format IFF --------------------------------------- byte IFF_color_list[129]; word IFF_list_size; byte IFF_repetition_mode; // ------------- Ecrire les couleurs que l'on vient de traiter ------------ void Transfer_colors(void) { byte index; if (IFF_list_size>0) { if (IFF_repetition_mode) { Write_one_byte(IFF_file,257-IFF_list_size); Write_one_byte(IFF_file,IFF_color_list[0]); } else { Write_one_byte(IFF_file,IFF_list_size-1); for (index=0; index et on a 3 couleurs qui se suivent { IFF_list_size-=2; Transfer_colors(); IFF_color_list[0]=color; IFF_color_list[1]=color; IFF_color_list[2]=color; IFF_list_size=3; IFF_repetition_mode=1; } } else // La couleur n'est pas la mme que la prcdente { if (!IFF_repetition_mode) // On conserve le mode... { IFF_color_list[IFF_list_size++]=color; if (IFF_list_size==128) Transfer_colors(); } else // On change de mode... { Transfer_colors(); IFF_color_list[IFF_list_size]=color; IFF_list_size++; } } } } void Save_IFF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; T_IFF_Header header; word x_pos; word y_pos; byte temp_byte; int file_size; int i; int palette_entries; byte bit_depth; if (context->Format == FORMAT_LBM) { // Check how many bits are used by pixel colors for (y_pos=0; y_posHeight; y_pos++) for (x_pos=0; x_posWidth; x_pos++) temp_byte |= Get_pixel(context, x_pos,y_pos); bit_depth=0; do { bit_depth++; temp_byte>>=1; } while (temp_byte); } else // FORMAT_PBM { bit_depth=8; } palette_entries = 1<File_name, context->File_directory); // Ouverture du fichier if ((IFF_file=fopen(filename,"wb"))) { setvbuf(IFF_file, NULL, _IOFBF, 64*1024); Write_bytes(IFF_file,"FORM",4); Write_dword_be(IFF_file,0); // On mettra la taille jour la fin if (context->Format == FORMAT_LBM) Write_bytes(IFF_file,"ILBM",4); else Write_bytes(IFF_file,"PBM ",4); Write_bytes(IFF_file,"BMHD",4); Write_dword_be(IFF_file,20); header.Width=context->Width; header.Height=context->Height; header.X_org=0; header.Y_org=0; header.BitPlanes=bit_depth; header.Mask=context->Background_transparent ? 2 : 0; header.Compression=1; header.Pad1=0; header.Transp_col=context->Background_transparent ? context->Transparent_color : 0; header.X_aspect=context->Ratio == PIXEL_WIDE ? 2 : 1; header.Y_aspect=context->Ratio == PIXEL_TALL ? 2 : 1; header.X_screen = context->Width;// Screen_width?; header.Y_screen = context->Height;// Screen_height?; Write_word_be(IFF_file,header.Width); Write_word_be(IFF_file,header.Height); Write_word_be(IFF_file,header.X_org); Write_word_be(IFF_file,header.Y_org); Write_bytes(IFF_file,&header.BitPlanes,1); Write_bytes(IFF_file,&header.Mask,1); Write_bytes(IFF_file,&header.Compression,1); Write_bytes(IFF_file,&header.Pad1,1); Write_word_be(IFF_file,header.Transp_col); Write_bytes(IFF_file,&header.X_aspect,1); Write_bytes(IFF_file,&header.Y_aspect,1); Write_word_be(IFF_file,header.X_screen); Write_word_be(IFF_file,header.Y_screen); Write_bytes(IFF_file,"CMAP",4); Write_dword_be(IFF_file,palette_entries*3); Write_bytes(IFF_file,context->Palette,palette_entries*3); for (i=0; iColor_cycles; i++) { word flags=0; flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not flags|= context->Cycle_range[i].Inverse?2:0; // Inverted Write_bytes(IFF_file,"CRNG",4); Write_dword_be(IFF_file,8); // Section size Write_word_be(IFF_file,0); // Padding Write_word_be(IFF_file,context->Cycle_range[i].Speed*78); // Rate Write_word_be(IFF_file,flags); // Flags Write_byte(IFF_file,context->Cycle_range[i].Start); // Min color Write_byte(IFF_file,context->Cycle_range[i].End); // Max color // No padding, size is multiple of 2 } Write_bytes(IFF_file,"BODY",4); Write_dword_be(IFF_file,0); // On mettra la taille jour la fin if (context->Format == FORMAT_LBM) { short line_size; // Size of line in bytes short plane_line_size; // Size of line in bytes for 1 plane short real_line_size; // Size of line in pixels // Calcul de la taille d'une ligne ILBM (pour les images ayant des dimensions exotiques) real_line_size = (context->Width+15) & ~15; plane_line_size = real_line_size >> 3; // 8bits per byte line_size = plane_line_size * header.BitPlanes; IFF_buffer=(byte *)malloc(line_size); // Start encoding IFF_list_size=0; for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) { // Dispatch the pixel into planes memset(IFF_buffer,0,line_size); for (x_pos=0; x_posWidth; x_pos++) Set_IFF_color(x_pos, Get_pixel(context, x_pos,y_pos), real_line_size, header.BitPlanes); if (context->Width&1) // odd width fix Set_IFF_color(x_pos, 0, real_line_size, header.BitPlanes); // encode the resulting sequence of bytes if (header.Compression) { int plane_width=line_size/header.BitPlanes; int plane; for (plane=0; planeHeight) && (!File_error)); y_pos++) { for (x_pos=0; ((x_posWidth) && (!File_error)); x_pos++) New_color(Get_pixel(context, x_pos,y_pos)); if (context->Width&1) // odd width fix New_color(0); if (!File_error) Transfer_colors(); } } fclose(IFF_file); if (!File_error) { file_size=File_length(filename); IFF_file=fopen(filename,"rb+"); fseek(IFF_file,52+palette_entries*3+context->Color_cycles*16,SEEK_SET); Write_dword_be(IFF_file,file_size-56-palette_entries*3-context->Color_cycles*16); if (!File_error) { fseek(IFF_file,4,SEEK_SET); // Si la taille de la section de l'image (taille fichier-8) est // impaire, on rajoute un 0 (Padding) la fin. if ((file_size) & 1) { Write_dword_be(IFF_file,file_size-7); fseek(IFF_file,0,SEEK_END); temp_byte=0; if (! Write_bytes(IFF_file,&temp_byte,1)) File_error=1; } else Write_dword_be(IFF_file,file_size-8); fclose(IFF_file); if (File_error) remove(filename); } else { File_error=1; fclose(IFF_file); remove(filename); } } else // Il y a eu une erreur lors du compactage => on efface le fichier remove(filename); } else File_error=1; } //////////////////////////////////// BMP //////////////////////////////////// typedef struct { byte Signature[2]; // ='BM' = 0x4D42 dword Size_1; // file size word Reserved_1; // 0 word Reserved_2; // 0 dword Offset; // Offset of bitmap data start dword Size_2; // 40 dword Width; int32_t Height; // signed: negative means a top-down bitmap (rare) word Planes; // 1 word Nb_bits; // 1,4,8 ou 24 dword Compression; dword Size_3; dword XPM; dword YPM; dword Nb_Clr; dword Clr_Imprt; } T_BMP_Header; // -- Tester si un fichier est au format BMP -------------------------------- void Test_BMP(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_BMP_Header header; File_error=1; Get_full_filename(filename, context->File_name, context->File_directory); if ((file=fopen(filename, "rb"))) { if (Read_bytes(file,&(header.Signature),2) // "BM" && Read_dword_le(file,&(header.Size_1)) && Read_word_le(file,&(header.Reserved_1)) && Read_word_le(file,&(header.Reserved_2)) && Read_dword_le(file,&(header.Offset)) && Read_dword_le(file,&(header.Size_2)) && Read_dword_le(file,&(header.Width)) && Read_dword_le(file,(dword *)&(header.Height)) && Read_word_le(file,&(header.Planes)) && Read_word_le(file,&(header.Nb_bits)) && Read_dword_le(file,&(header.Compression)) && Read_dword_le(file,&(header.Size_3)) && Read_dword_le(file,&(header.XPM)) && Read_dword_le(file,&(header.YPM)) && Read_dword_le(file,&(header.Nb_Clr)) && Read_dword_le(file,&(header.Clr_Imprt)) ) { if ( header.Signature[0]=='B' && header.Signature[1]=='M' && header.Size_2==40 && header.Width && header.Height ) File_error=0; } fclose(file); } } // Find the 8 important bits in a dword byte Bitmap_mask(dword pixel, dword mask) { byte result; int i; int bits_found; switch(mask) { // Shortcuts to quickly handle the common 24/32bit cases case 0x000000FF: return (pixel & 0x000000FF); case 0x0000FF00: return (pixel & 0x0000FF00)>>8; case 0x00FF0000: return (pixel & 0x00FF0000)>>16; case 0xFF000000: return (pixel & 0xFF000000)>>24; } // Uncommon : do it bit by bit. bits_found=0; result=0; // Process the mask from low to high bit for (i=0;i<32;i++) { // Found a bit in the mask if (mask & (1<=8) return result; } } // Less than 8 bits in the mask: scale the result to 8 bits return result << (8-bits_found); } // -- Charger un fichier au format BMP -------------------------------------- void Load_BMP(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_BMP_Header header; byte * buffer; word index; byte local_palette[256][4]; // R,G,B,0 word nb_colors = 0; short x_pos; short y_pos; word line_size; byte a,b,c=0; long file_size; byte negative_height; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (Read_bytes(file,header.Signature,2) && Read_dword_le(file,&(header.Size_1)) && Read_word_le(file,&(header.Reserved_1)) && Read_word_le(file,&(header.Reserved_2)) && Read_dword_le(file,&(header.Offset)) && Read_dword_le(file,&(header.Size_2)) && Read_dword_le(file,&(header.Width)) && Read_dword_le(file,(dword *)&(header.Height)) && Read_word_le(file,&(header.Planes)) && Read_word_le(file,&(header.Nb_bits)) && Read_dword_le(file,&(header.Compression)) && Read_dword_le(file,&(header.Size_3)) && Read_dword_le(file,&(header.XPM)) && Read_dword_le(file,&(header.YPM)) && Read_dword_le(file,&(header.Nb_Clr)) && Read_dword_le(file,&(header.Clr_Imprt)) ) { switch (header.Nb_bits) { case 1 : case 4 : case 8 : if (header.Nb_Clr) nb_colors=header.Nb_Clr; else nb_colors=1<Palette,0,sizeof(T_Palette)); // On peut maintenant transfrer la nouvelle palette for (index=0; indexPalette[index].R=local_palette[index][2]; context->Palette[index].G=local_palette[index][1]; context->Palette[index].B=local_palette[index][0]; } context->Width=header.Width; context->Height=header.Height; if (fseek(file, header.Offset, SEEK_SET)) File_error=2; switch (header.Compression) { case 0 : // Pas de compression line_size=context->Width; x_pos=(32/header.Nb_bits); // x_pos sert de variable temporaire // On arrondit line_size au premier multiple de x_pos suprieur if (line_size % x_pos) line_size=((line_size/x_pos)*x_pos)+x_pos; // On convertit cette taille en octets line_size=(line_size*header.Nb_bits)>>3; buffer=(byte *)malloc(line_size); for (y_pos=0; (y_pos < context->Height && !File_error); y_pos++) { short target_y; target_y = negative_height ? y_pos : context->Height-1-y_pos; if (Read_bytes(file,buffer,line_size)) for (x_pos=0; x_posWidth; x_pos++) switch (header.Nb_bits) { case 8 : Set_pixel(context, x_pos,target_y,buffer[x_pos]); break; case 4 : if (x_pos & 1) Set_pixel(context, x_pos,target_y,buffer[x_pos>>1] & 0xF); else Set_pixel(context, x_pos,target_y,buffer[x_pos>>1] >> 4 ); break; case 1 : if ( buffer[x_pos>>3] & (0x80>>(x_pos&7)) ) Set_pixel(context, x_pos,target_y,1); else Set_pixel(context, x_pos,target_y,0); } else File_error=2; } free(buffer); buffer = NULL; break; case 1 : // Compression RLE 8 bits x_pos=0; y_pos=context->Height-1; /*Init_lecture();*/ if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) File_error=2; while (!File_error) { if (a) // Encoded mode for (index=1; index<=a; index++) Set_pixel(context, x_pos++,y_pos,b); else // Absolute mode switch (b) { case 0 : // End of line x_pos=0; y_pos--; break; case 1 : // End of bitmap break; case 2 : // Delta if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) File_error=2; x_pos+=a; y_pos-=b; break; default: // Nouvelle srie while (b) { if(Read_byte(file, &a)!=1) File_error=2; //Read_one_byte(file, &c); Set_pixel(context, x_pos++,y_pos,a); //if (--c) //{ // Set_pixel(context, x_pos++,y_pos,c); // b--; //} b--; } if (ftell(file) & 1) fseek(file, 1, SEEK_CUR); } if (a==0 && b==1) break; if(Read_byte(file, &a) !=1 || Read_byte(file, &b)!=1) { File_error=2; } } /*Close_lecture();*/ break; case 2 : // Compression RLE 4 bits x_pos=0; y_pos=context->Height-1; /*Init_lecture();*/ if(Read_byte(file, &a)!=1 || Read_byte(file, &b) != 1) File_error =2; while ( (!File_error) && ((a)||(b!=1)) ) { if (a) // Encoded mode (A fois les 1/2 pixels de B) for (index=1; index<=a; index++) { if (index & 1) Set_pixel(context, x_pos,y_pos,b>>4); else Set_pixel(context, x_pos,y_pos,b&0xF); x_pos++; } else // Absolute mode switch (b) { case 0 : //End of line x_pos=0; y_pos--; break; case 1 : // End of bitmap break; case 2 : // Delta if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) File_error=2; x_pos+=a; y_pos-=b; break; default: // Nouvelle srie (B 1/2 pixels bruts) for (index=1; ((index<=b) && (!File_error)); index++,x_pos++) { if (index&1) { if(Read_byte(file, &c)!=1) File_error=2; Set_pixel(context, x_pos,y_pos,c>>4); } else Set_pixel(context, x_pos,y_pos,c&0xF); } // On lit l'octet rendant le nombre d'octets pair, si // ncessaire. Encore un truc de crtin "made in MS". if ( ((b&3)==1) || ((b&3)==2) ) { byte dummy; if(Read_byte(file, &dummy)!=1) File_error=2; } } if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) File_error=2; } /*Close_lecture();*/ } fclose(file); } else { fclose(file); File_error=1; } } } else { // Image 16/24/32 bits dword red_mask; dword green_mask; dword blue_mask; if (header.Nb_bits == 16) { red_mask = 0x00007C00; green_mask = 0x000003E0; blue_mask = 0x0000001F; } else { red_mask = 0x00FF0000; green_mask = 0x0000FF00; blue_mask = 0x000000FF; } File_error=0; context->Width=header.Width; context->Height=header.Height; Pre_load(context,header.Width,header.Height,file_size,FORMAT_BMP,PIXEL_SIMPLE,1); if (File_error==0) { switch (header.Compression) { case 3: // BI_BITFIELDS if (!Read_dword_le(file,&red_mask) || !Read_dword_le(file,&green_mask) || !Read_dword_le(file,&blue_mask)) File_error=2; break; default: break; } if (fseek(file, header.Offset, SEEK_SET)) File_error=2; } if (File_error==0) { switch (header.Nb_bits) { // 24bit bitmap default: case 24: line_size=context->Width*3; x_pos=(line_size % 4); // x_pos sert de variable temporaire if (x_pos>0) line_size+=(4-x_pos); buffer=(byte *)malloc(line_size); for (y_pos=0; (y_pos < context->Height && !File_error); y_pos++) { short target_y; target_y = negative_height ? y_pos : context->Height-1-y_pos; if (Read_bytes(file,buffer,line_size)) for (x_pos=0,index=0; x_posWidth; x_pos++,index+=3) Set_pixel_24b(context, x_pos,target_y,buffer[index+2],buffer[index+1],buffer[index+0]); else File_error=2; } break; // 32bit bitmap case 32: line_size=context->Width*4; buffer=(byte *)malloc(line_size); for (y_pos=0; (y_pos < context->Height && !File_error); y_pos++) { short target_y; target_y = negative_height ? y_pos : context->Height-1-y_pos; if (Read_bytes(file,buffer,line_size)) for (x_pos=0; x_posWidth; x_pos++) { dword pixel=*(((dword *)buffer)+x_pos); Set_pixel_24b(context, x_pos,target_y,Bitmap_mask(pixel,red_mask),Bitmap_mask(pixel,green_mask),Bitmap_mask(pixel,blue_mask)); } else File_error=2; } break; // 16bit bitmap case 16: line_size=(context->Width*2) + (context->Width&1)*2; buffer=(byte *)malloc(line_size); for (y_pos=0; (y_pos < context->Height && !File_error); y_pos++) { short target_y; target_y = negative_height ? y_pos : context->Height-1-y_pos; if (Read_bytes(file,buffer,line_size)) for (x_pos=0; x_posWidth; x_pos++) { word pixel=*(((word *)buffer)+x_pos); Set_pixel_24b(context, x_pos,target_y,Bitmap_mask(pixel,red_mask),Bitmap_mask(pixel,green_mask),Bitmap_mask(pixel,blue_mask)); } else File_error=2; } break; } free(buffer); buffer = NULL; fclose(file); } } } else { fclose(file); File_error=1; } } else File_error=1; } // -- Sauvegarder un fichier au format BMP ---------------------------------- void Save_BMP(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_BMP_Header header; short x_pos; short y_pos; long line_size; word index; byte local_palette[256][4]; // R,G,B,0 File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); // Ouverture du fichier if ((file=fopen(filename,"wb"))) { setvbuf(file, NULL, _IOFBF, 64*1024); // Image width must be a multiple of 4 bytes line_size = context->Width; if (line_size & 3) line_size += (4 - (line_size & 3)); header.Signature[0] = 'B'; header.Signature[1] = 'M'; header.Size_1 =(line_size*context->Height)+1078; header.Reserved_1 =0; header.Reserved_2 =0; header.Offset =1078; // Size of header data (including palette) header.Size_2 =40; // Size of header header.Width =context->Width; header.Height =context->Height; header.Planes =1; header.Nb_bits =8; header.Compression=0; header.Size_3 =0; header.XPM =0; header.YPM =0; header.Nb_Clr =0; header.Clr_Imprt =0; if (Write_bytes(file,header.Signature,2) && Write_dword_le(file,header.Size_1) && Write_word_le(file,header.Reserved_1) && Write_word_le(file,header.Reserved_2) && Write_dword_le(file,header.Offset) && Write_dword_le(file,header.Size_2) && Write_dword_le(file,header.Width) && Write_dword_le(file,header.Height) && Write_word_le(file,header.Planes) && Write_word_le(file,header.Nb_bits) && Write_dword_le(file,header.Compression) && Write_dword_le(file,header.Size_3) && Write_dword_le(file,header.XPM) && Write_dword_le(file,header.YPM) && Write_dword_le(file,header.Nb_Clr) && Write_dword_le(file,header.Clr_Imprt)) { // Chez Bill, ils ont dit: "On va mettre les couleur dans l'ordre // inverse, et pour faire chier, on va les mettre sur une chelle de // 0 255 parce que le standard VGA c'est de 0 63 (logique!). Et // puis comme c'est pas assez dbile, on va aussi y rajouter un octet // toujours 0 pour forcer les gens s'acheter des gros disques // durs... Comme a, a fera passer la pillule lorsqu'on sortira // Windows 95." ... for (index=0; index<256; index++) { local_palette[index][0]=context->Palette[index].B; local_palette[index][1]=context->Palette[index].G; local_palette[index][2]=context->Palette[index].R; local_palette[index][3]=0; } if (Write_bytes(file,local_palette,1024)) { // ... Et Bill, il a dit: "OK les gars! Mais seulement si vous rangez // les pixels dans l'ordre inverse, mais que sur les Y quand-mme // parce que faut pas pousser." for (y_pos=context->Height-1; ((y_pos>=0) && (!File_error)); y_pos--) for (x_pos=0; x_posFile_name, context->File_directory); if ((file=fopen(filename, "rb"))) { if ( (Read_bytes(file,signature,6)) && ((!memcmp(signature,"GIF87a",6))||(!memcmp(signature,"GIF89a",6))) ) File_error=0; fclose(file); } } // -- Lire un fichier au format GIF ----------------------------------------- // -- Lire un fichier au format GIF ----------------------------------------- // Dfinition de quelques variables globales au chargement du GIF87a word GIF_nb_bits; // Nb de bits composants un code complet word GIF_remainder_bits; // Nb de bits encore dispos dans GIF_last_byte byte GIF_remainder_byte; // Nb d'octets avant le prochain bloc de Raster Data word GIF_current_code; // Code trait (qui vient d'tre lu en gnral) byte GIF_last_byte; // Octet de lecture des bits word GIF_pos_X; // Coordonnes d'affichage de l'image word GIF_pos_Y; word GIF_interlaced; // L'image est entrelace word GIF_finished_interlaced_image; // L'image entrelace est finie de charger word GIF_pass; // index de passe de l'image entrelace FILE *GIF_file; // L'handle du fichier // -- Lit le code GIF_nb_bits suivant -- word GIF_get_next_code(void) { word nb_bits_to_process=GIF_nb_bits; word nb_bits_processed =0; word current_nb_bits; GIF_current_code=0; while (nb_bits_to_process) { if (GIF_remainder_bits==0) // Il ne reste plus de bits... { // Lire l'octet suivant: // Si on a atteint la fin du bloc de Raster Data if (GIF_remainder_byte==0) // Lire l'octet nous donnant la taille du bloc de Raster Data suivant if(Read_byte(GIF_file, &GIF_remainder_byte)!=1) File_error=2; if(Read_byte(GIF_file,&GIF_last_byte)!=1) File_error = 2; GIF_remainder_byte--; GIF_remainder_bits=8; } current_nb_bits=(nb_bits_to_process<=GIF_remainder_bits)?nb_bits_to_process:GIF_remainder_bits; GIF_current_code|=(GIF_last_byte & ((1<>=current_nb_bits; nb_bits_processed +=current_nb_bits; nb_bits_to_process-=current_nb_bits; GIF_remainder_bits -=current_nb_bits; } return GIF_current_code; } // -- Affiche un nouveau pixel -- void GIF_new_pixel(T_IO_Context * context, T_GIF_IDB *idb, int is_transparent, byte color) { if (!is_transparent || color!=context->Transparent_color) Set_pixel(context, idb->Pos_X+GIF_pos_X, idb->Pos_Y+GIF_pos_Y,color); GIF_pos_X++; if (GIF_pos_X>=idb->Image_width) { GIF_pos_X=0; if (!GIF_interlaced) GIF_pos_Y++; else { switch (GIF_pass) { case 0 : GIF_pos_Y+=8; break; case 1 : GIF_pos_Y+=8; break; case 2 : GIF_pos_Y+=4; break; default: GIF_pos_Y+=2; } if (GIF_pos_Y>=idb->Image_height) { switch(++GIF_pass) { case 1 : GIF_pos_Y=4; break; case 2 : GIF_pos_Y=2; break; case 3 : GIF_pos_Y=1; break; case 4 : GIF_finished_interlaced_image=1; } } } } } void Load_GIF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; char signature[6]; word * alphabet_stack; // Pile de dcodage d'une chane word * alphabet_prefix; // Table des prfixes des codes word * alphabet_suffix; // Table des suffixes des codes word alphabet_free; // Position libre dans l'alphabet word alphabet_max; // Nombre d'entres possibles dans l'alphabet word alphabet_stack_pos; // Position dans la pile de dcodage d'un chane T_GIF_LSDB LSDB; T_GIF_IDB IDB; T_GIF_GCE GCE; word nb_colors; // Nombre de couleurs dans l'image word color_index; // index de traitement d'une couleur byte size_to_read; // Nombre de donnes lire (divers) byte block_identifier; // Code indicateur du type de bloc en cours byte initial_nb_bits; // Nb de bits au dbut du traitement LZW word special_case=0; // Mmoire pour le cas spcial word old_code=0; // Code prcdent word byte_read; // Sauvegarde du code en cours de lecture word value_clr; // Valeur <=> Clear tables word value_eof; // Valeur <=> End d'image long file_size; int number_LID; // Nombre d'images trouves dans le fichier int current_layer = 0; int last_delay = 0; byte is_transparent = 0; byte is_looping=0; enum PIXEL_RATIO ratio; byte disposal_method = DISPOSAL_METHOD_RESTORE_BGCOLOR; byte previous_disposal_method = DISPOSAL_METHOD_RESTORE_BGCOLOR; word previous_width=0; word previous_height=0; word previous_pos_x=0; word previous_pos_y=0; /////////////////////////////////////////////////// FIN DES DECLARATIONS // number_LID=0; Get_full_filename(filename, context->File_name, context->File_directory); if ((GIF_file=fopen(filename, "rb"))) { file_size=File_length_file(GIF_file); if ( (Read_bytes(GIF_file,signature,6)) && ( (memcmp(signature,"GIF87a",6)==0) || (memcmp(signature,"GIF89a",6)==0) ) ) { // Allocation de mmoire pour les tables & piles de traitement: alphabet_stack =(word *)malloc(4096*sizeof(word)); alphabet_prefix=(word *)malloc(4096*sizeof(word)); alphabet_suffix=(word *)malloc(4096*sizeof(word)); if (Read_word_le(GIF_file,&(LSDB.Width)) && Read_word_le(GIF_file,&(LSDB.Height)) && Read_byte(GIF_file,&(LSDB.Resol)) && Read_byte(GIF_file,&(LSDB.Backcol)) && Read_byte(GIF_file,&(LSDB.Aspect)) ) { // Lecture du Logical Screen Descriptor Block russie: Original_screen_X=LSDB.Width; Original_screen_Y=LSDB.Height; if (LSDB.Aspect==17) ratio=PIXEL_TALL; else if (LSDB.Aspect==113) ratio=PIXEL_WIDE; else ratio=PIXEL_SIMPLE; Pre_load(context, LSDB.Width,LSDB.Height,file_size,FORMAT_GIF,ratio,0); context->Width=LSDB.Width; context->Height=LSDB.Height; // Palette globale dispo = (LSDB.Resol and $80) // Profondeur de couleur =((LSDB.Resol and $70) shr 4)+1 // Nombre de bits/pixel = (LSDB.Resol and $07)+1 // Ordre de Classement = (LSDB.Aspect and $80) nb_colors=(1 << ((LSDB.Resol & 0x07)+1)); if (LSDB.Resol & 0x80) { // Palette globale dispo: if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); // Load the palette for(color_index=0;color_indexPalette[color_index].R)); Read_byte(GIF_file,&(context->Palette[color_index].G)); Read_byte(GIF_file,&(context->Palette[color_index].B)); } } // On lit un indicateur de block Read_byte(GIF_file,&block_identifier); while (block_identifier!=0x3B && !File_error) { switch (block_identifier) { case 0x21: // Bloc d'extension { byte function_code; // Lecture du code de fonction: Read_byte(GIF_file,&function_code); // Lecture de la taille du bloc: Read_byte(GIF_file,&size_to_read); while (size_to_read!=0 && !File_error) { switch(function_code) { case 0xFE: // Comment Block Extension // On rcupre le premier commentaire non-vide, // on jette les autres. if (context->Comment[0]=='\0') { int nb_char_to_keep=Min(size_to_read,COMMENT_SIZE); Read_bytes(GIF_file,context->Comment,nb_char_to_keep); context->Comment[nb_char_to_keep+1]='\0'; // Si le commentaire etait trop long, on fait avance-rapide // sur la suite. if (size_to_read>nb_char_to_keep) fseek(GIF_file,size_to_read-nb_char_to_keep,SEEK_CUR); } // Lecture de la taille du bloc suivant: Read_byte(GIF_file,&size_to_read); break; case 0xF9: // Graphics Control Extension // Prvu pour la transparence if ( Read_byte(GIF_file,&(GCE.Packed_fields)) && Read_word_le(GIF_file,&(GCE.Delay_time)) && Read_byte(GIF_file,&(GCE.Transparent_color))) { previous_disposal_method = disposal_method; disposal_method = (GCE.Packed_fields >> 2) & 7; last_delay = GCE.Delay_time; context->Transparent_color= GCE.Transparent_color; is_transparent = GCE.Packed_fields & 1; if (number_LID == 0) context->Background_transparent = is_transparent; is_transparent &= is_looping; } else File_error=2; // Lecture de la taille du bloc suivant: Read_byte(GIF_file,&size_to_read); break; case 0xFF: // Application Extension // Normally, always a 11-byte block if (size_to_read == 0x0B) { char aeb[0x0B]; Read_bytes(GIF_file,aeb, 0x0B); if (File_error) ; else if (!memcmp(aeb,"NETSCAPE2.0",0x0B)) { is_looping=1; // The well-known Netscape extension. // Load as an animation if (context->Type == CONTEXT_MAIN_IMAGE) { Main_backups->Pages->Image_mode = IMAGE_MODE_ANIMATION; Update_screen_targets(); } // Skip sub-block do { if (! Read_byte(GIF_file,&size_to_read)) File_error=1; fseek(GIF_file,size_to_read,SEEK_CUR); } while (!File_error && size_to_read!=0); } else if (!memcmp(aeb,"GFX2PATH\x00\x00\x00",0x0B)) { // Original file path if (context->Original_file_name && context->Original_file_directory) { Read_byte(GIF_file,&size_to_read); if (!File_error && size_to_read) { Read_bytes(GIF_file,context->Original_file_directory, size_to_read); Read_byte(GIF_file,&size_to_read); if (!File_error && size_to_read) { Read_bytes(GIF_file,context->Original_file_name, size_to_read); Read_byte(GIF_file,&size_to_read); // Normally 0 } } } else { // Nothing to do, just skip sub-block Read_byte(GIF_file,&size_to_read); while (size_to_read!=0 && !File_error) { fseek(GIF_file,size_to_read,SEEK_CUR); Read_byte(GIF_file,&size_to_read); } } } else if (!memcmp(aeb,"CRNG\0\0\0\0" "1.0",0x0B)) { // Color animation. Similar to a CRNG chunk in IFF file format. word rate; word flags; byte min_col; byte max_col; // Read_byte(GIF_file,&size_to_read); for(;size_to_read>0 && !File_error;size_to_read-=6) { if ( (Read_word_be(GIF_file,&rate)) && (Read_word_be(GIF_file,&flags)) && (Read_byte(GIF_file,&min_col)) && (Read_byte(GIF_file,&max_col))) { if (min_col != max_col) { // Valid cycling range if (max_colCycle_range[context->Color_cycles].Start=min_col; context->Cycle_range[context->Color_cycles].End=max_col; context->Cycle_range[context->Color_cycles].Inverse=(flags&2)?1:0; context->Cycle_range[context->Color_cycles].Speed=(flags&1)?rate/78:0; context->Color_cycles++; } } else { File_error=1; } } // Read end-of-block delimiter if (!File_error) Read_byte(GIF_file,&size_to_read); if (size_to_read!=0) File_error=1; } else { // Unknown extension, skip. Read_byte(GIF_file,&size_to_read); while (size_to_read!=0 && !File_error) { fseek(GIF_file,size_to_read,SEEK_CUR); Read_byte(GIF_file,&size_to_read); } } } else { fseek(GIF_file,size_to_read,SEEK_CUR); // Lecture de la taille du bloc suivant: Read_byte(GIF_file,&size_to_read); } break; default: // On saute le bloc: fseek(GIF_file,size_to_read,SEEK_CUR); // Lecture de la taille du bloc suivant: Read_byte(GIF_file,&size_to_read); break; } } } break; case 0x2C: // Local Image Descriptor { if (number_LID!=0) { // This a second layer/frame, or more. // Attempt to add a layer to current image current_layer++; Set_loading_layer(context, current_layer); if (context->Type == CONTEXT_MAIN_IMAGE && Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION) { // Copy the content of previous layer. memcpy( Main_backups->Pages->Image[Main_current_layer].Pixels, Main_backups->Pages->Image[Main_current_layer-1].Pixels, Main_backups->Pages->Width*Main_backups->Pages->Height); } else { Fill_canvas(context, is_transparent ? context->Transparent_color : LSDB.Backcol); } } else { // First frame/layer, fill canvas with backcolor Fill_canvas(context, is_transparent ? context->Transparent_color : LSDB.Backcol); } // Duration was set in the previously loaded GCE Set_frame_duration(context, last_delay*10); number_LID++; // lecture de 10 derniers octets if ( Read_word_le(GIF_file,&(IDB.Pos_X)) && Read_word_le(GIF_file,&(IDB.Pos_Y)) && Read_word_le(GIF_file,&(IDB.Image_width)) && Read_word_le(GIF_file,&(IDB.Image_height)) && Read_byte(GIF_file,&(IDB.Indicator)) && IDB.Image_width && IDB.Image_height) { // Palette locale dispo = (IDB.Indicator and $80) // Image entrelace = (IDB.Indicator and $40) // Ordre de classement = (IDB.Indicator and $20) // Nombre de bits/pixel = (IDB.Indicator and $07)+1 (si palette locale dispo) if (IDB.Indicator & 0x80) { // Palette locale dispo if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); nb_colors=(1 << ((IDB.Indicator & 0x07)+1)); // Load the palette for(color_index=0;color_indexPalette[color_index].R)); Read_byte(GIF_file,&(context->Palette[color_index].G)); Read_byte(GIF_file,&(context->Palette[color_index].B)); } } if (number_LID!=1) { // This a second layer/frame, or more. if (context->Type == CONTEXT_MAIN_IMAGE && Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION) { // Need to clear previous image to back-color. if (previous_disposal_method==DISPOSAL_METHOD_RESTORE_BGCOLOR) { int y; for (y=0; yPages->Image[Main_current_layer].Pixels + (previous_pos_y+y)* Main_backups->Pages->Width+previous_pos_x, is_transparent ? context->Transparent_color : LSDB.Backcol, previous_width); } } } previous_height=IDB.Image_height; previous_width=IDB.Image_width; previous_pos_x=IDB.Pos_X; previous_pos_y=IDB.Pos_Y; File_error=0; if (!Read_byte(GIF_file,&(initial_nb_bits))) File_error=1; value_clr =(1<value_clr) { alphabet_stack[alphabet_stack_pos++]=alphabet_suffix[GIF_current_code]; GIF_current_code=alphabet_prefix[GIF_current_code]; } special_case=alphabet_stack[alphabet_stack_pos++]=GIF_current_code; do GIF_new_pixel(context, &IDB, is_transparent, alphabet_stack[--alphabet_stack_pos]); while (alphabet_stack_pos!=0); alphabet_prefix[alphabet_free ]=old_code; alphabet_suffix[alphabet_free++]=GIF_current_code; old_code=byte_read; if (alphabet_free>alphabet_max) { if (GIF_nb_bits<12) alphabet_max =((1 << (++GIF_nb_bits))-1); } } else // Code Clear rencontr { GIF_nb_bits =initial_nb_bits + 1; alphabet_max =((1 << GIF_nb_bits)-1); alphabet_free =(1<=0) if ( /* (GIF_pos_X!=0) || */ ( ( (!GIF_interlaced) && (GIF_pos_Y!=IDB.Image_height) && (GIF_pos_X!=0)) || ( (GIF_interlaced) && (!GIF_finished_interlaced_image) ) ) ) File_error=2; // No need to read more than one frame in animation preview mode if (context->Type == CONTEXT_PREVIEW && is_looping) { goto early_exit; } // Same with brush if (context->Type == CONTEXT_BRUSH && is_looping) { goto early_exit; } } // Le fichier contenait un IDB else File_error=2; } default: break; } // Lecture du code de fonction suivant: if (!Read_byte(GIF_file,&block_identifier)) File_error=2; } } // Le fichier contenait un LSDB else File_error=1; early_exit: // Libration de la mmoire utilise par les tables & piles de traitement: free(alphabet_suffix); free(alphabet_prefix); free(alphabet_stack); alphabet_suffix = alphabet_prefix = alphabet_stack = NULL; } // Le fichier contenait au moins la signature GIF87a ou GIF89a else File_error=1; fclose(GIF_file); } // Le fichier tait ouvrable else File_error=1; } // -- Sauver un fichier au format GIF --------------------------------------- int GIF_stop; // "On peut arrter la sauvegarde du fichier" byte GIF_buffer[256]; // buffer d'criture de bloc de donnes compiles // -- Vider le buffer GIF dans le buffer KM -- void GIF_empty_buffer(void) { word index; if (GIF_remainder_byte) { GIF_buffer[0]=GIF_remainder_byte; for (index=0;index<=GIF_remainder_byte;index++) Write_one_byte(GIF_file,GIF_buffer[index]); GIF_remainder_byte=0; } } // -- Ecrit un code GIF_nb_bits -- void GIF_set_code(word Code) { word nb_bits_to_process=GIF_nb_bits; word nb_bits_processed =0; word current_nb_bits; while (nb_bits_to_process) { current_nb_bits=(nb_bits_to_process<=(8-GIF_remainder_bits))?nb_bits_to_process:(8-GIF_remainder_bits); GIF_last_byte|=(Code & ((1<>=current_nb_bits; GIF_remainder_bits +=current_nb_bits; nb_bits_processed +=current_nb_bits; nb_bits_to_process-=current_nb_bits; if (GIF_remainder_bits==8) // Il ne reste plus de bits coder sur l'octet courant { // Ecrire l'octet balancer: GIF_buffer[++GIF_remainder_byte]=GIF_last_byte; // Si on a atteint la fin du bloc de Raster Data if (GIF_remainder_byte==255) // On doit vider le buffer qui est maintenant plein GIF_empty_buffer(); GIF_last_byte=0; GIF_remainder_bits=0; } } } // -- Lire le pixel suivant -- byte GIF_next_pixel(T_IO_Context *context, T_GIF_IDB *idb) { byte temp; temp=Get_pixel(context, GIF_pos_X,GIF_pos_Y); if (++GIF_pos_X>=idb->Image_width) { GIF_pos_X=0; if (++GIF_pos_Y>=idb->Image_height) GIF_stop=1; } return temp; } void Save_GIF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; word * alphabet_prefix; // Table des prfixes des codes word * alphabet_suffix; // Table des suffixes des codes word * alphabet_daughter; // Table des chanes filles (plus longues) word * alphabet_sister; // Table des chanes soeurs (mme longueur) word alphabet_free; // Position libre dans l'alphabet word alphabet_max; // Nombre d'entres possibles dans l'alphabet word start; // Code prcdent (sert au linkage des chanes) int descend; // Boolen "On vient de descendre" T_GIF_LSDB LSDB; T_GIF_IDB IDB; byte block_identifier; // Code indicateur du type de bloc en cours word current_string; // Code de la chane en cours de traitement byte current_char; // Caractre coder word index; // index de recherche de chane int current_layer; word clear; // LZW clear code word eof; // End of image code /////////////////////////////////////////////////// FIN DES DECLARATIONS // File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); if ((GIF_file=fopen(filename,"wb"))) { setvbuf(GIF_file, NULL, _IOFBF, 64*1024); // On crit la signature du fichier if (Write_bytes(GIF_file,"GIF89a",6)) { // La signature du fichier a t correctement crite. // Allocation de mmoire pour les tables alphabet_prefix=(word *)malloc(4096*sizeof(word)); alphabet_suffix=(word *)malloc(4096*sizeof(word)); alphabet_daughter =(word *)malloc(4096*sizeof(word)); alphabet_sister =(word *)malloc(4096*sizeof(word)); // On initialise le LSDB du fichier if (Config.Screen_size_in_GIF) { LSDB.Width=Screen_width; LSDB.Height=Screen_height; } else { LSDB.Width=context->Width; LSDB.Height=context->Height; } LSDB.Resol =0x97; // Image en 256 couleurs, avec une palette // 0x97 = 1001 0111 // = Global Color Table Flag 1 Bit // Color Resolution 3 Bits // Sort Flag 1 Bit // Size of Global Color Table 3 Bits // TODO XXX Color resolution should be set to 7 = 8bit per RGB component // it is set to 1 => 2bit per RGB component... // I guess most decoders are ignoring it anyway LSDB.Backcol=context->Transparent_color; switch(context->Ratio) { case PIXEL_TALL: LSDB.Aspect = 17; // 1:2 break; case PIXEL_WIDE: LSDB.Aspect = 113; // 2:1 break; default: LSDB.Aspect = 0; // undefined, which is most frequent. // 49 would be 1:1 ratio } // On sauve le LSDB dans le fichier if (Write_word_le(GIF_file,LSDB.Width) && Write_word_le(GIF_file,LSDB.Height) && Write_byte(GIF_file,LSDB.Resol) && Write_byte(GIF_file,LSDB.Backcol) && Write_byte(GIF_file,LSDB.Aspect) ) { // Le LSDB a t correctement crit. int i; // On sauve la palette for(i=0;i<256 && !File_error;i++) { if (!Write_byte(GIF_file,context->Palette[i].R) ||!Write_byte(GIF_file,context->Palette[i].G) ||!Write_byte(GIF_file,context->Palette[i].B)) File_error=1; } if (!File_error) { // La palette a t correctement crite. // Ecriture de la transparence //Write_bytes(GIF_file,"\x21\xF9\x04\x01\x00\x00\xNN\x00",8); // "Netscape" animation extension // Write_bytes(GIF_file,"\x21\xFF\x0BNETSCAPE2.0\x03\xLL\xSS\xSS\x00",19); // LL : 01 to loop // SSSS : number of loops if (context->Type == CONTEXT_MAIN_IMAGE && Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION) if (context->Nb_layers>1) Write_bytes(GIF_file,"\x21\xFF\x0BNETSCAPE2.0\x03\x01\x00\x00\x00",19); // Ecriture du commentaire if (context->Comment[0]) { Write_bytes(GIF_file,"\x21\xFE",2); Write_byte(GIF_file,strlen(context->Comment)); Write_bytes(GIF_file,context->Comment,strlen(context->Comment)+1); } // Write cycling colors if (context->Color_cycles) { int i; Write_bytes(GIF_file,"\x21\xff\x0B" "CRNG\0\0\0\0" "1.0",14); Write_byte(GIF_file,context->Color_cycles*6); for (i=0; iColor_cycles; i++) { word flags=0; flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not flags|= context->Cycle_range[i].Inverse?2:0; // Inverted Write_word_be(GIF_file,context->Cycle_range[i].Speed*78); // Rate Write_word_be(GIF_file,flags); // Flags Write_byte(GIF_file,context->Cycle_range[i].Start); // Min color Write_byte(GIF_file,context->Cycle_range[i].End); // Max color } Write_byte(GIF_file,0); } // Loop on all layers for (current_layer=0; current_layer < context->Nb_layers && !File_error; current_layer++) { // Write a Graphic Control Extension T_GIF_GCE GCE; Set_saving_layer(context, current_layer); GCE.Block_identifier = 0x21; GCE.Function = 0xF9; GCE.Block_size=4; if (context->Type == CONTEXT_MAIN_IMAGE && Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION) { // Animation frame int duration; GCE.Packed_fields=(2<<2)|(context->Background_transparent); duration=Get_frame_duration(context)/10; GCE.Delay_time=duration<0xFFFF?duration:0xFFFF; } else { // Layered image if (current_layer==0) GCE.Packed_fields=(1<<2)|(context->Background_transparent); else GCE.Packed_fields=(1<<2)|(1); GCE.Delay_time=5; // Duration 5/100s (minimum viable value for current web browsers) if (current_layer == context->Nb_layers -1) GCE.Delay_time=0xFFFF; // Infinity (10 minutes) } GCE.Transparent_color=context->Transparent_color; GCE.Block_terminator=0x00; if (Write_byte(GIF_file,GCE.Block_identifier) && Write_byte(GIF_file,GCE.Function) && Write_byte(GIF_file,GCE.Block_size) && Write_byte(GIF_file,GCE.Packed_fields) && Write_word_le(GIF_file,GCE.Delay_time) && Write_byte(GIF_file,GCE.Transparent_color) && Write_byte(GIF_file,GCE.Block_terminator) ) { // first look for the maximum pixel value // to decide how many bit per pixel are needed. byte temp, max = 0; for(GIF_pos_Y = 0; GIF_pos_Y < context->Height; GIF_pos_Y++) { for(GIF_pos_X = 0; GIF_pos_X < context->Width; GIF_pos_X++) { temp=Get_pixel(context, GIF_pos_X, GIF_pos_Y); if(temp > max) max = temp; } } IDB.Nb_bits_pixel=2; // Find the minimum bpp value to fit all pixels while((int)max >= (1 << IDB.Nb_bits_pixel)) { IDB.Nb_bits_pixel++; } // On va crire un block indicateur d'IDB et l'IDB du fichier block_identifier=0x2C; IDB.Pos_X=0; IDB.Pos_Y=0; IDB.Image_width=context->Width; IDB.Image_height=context->Height; IDB.Indicator=0x07; // Image non entrelace, pas de palette locale. clear = 1 << IDB.Nb_bits_pixel; // Clear Code eof = clear + 1; // End of Picture Code if ( Write_byte(GIF_file,block_identifier) && Write_word_le(GIF_file,IDB.Pos_X) && Write_word_le(GIF_file,IDB.Pos_Y) && Write_word_le(GIF_file,IDB.Image_width) && Write_word_le(GIF_file,IDB.Image_height) && Write_byte(GIF_file,IDB.Indicator) && Write_byte(GIF_file,IDB.Nb_bits_pixel)) { // Le block indicateur d'IDB et l'IDB ont ts correctements // crits. GIF_pos_X=0; GIF_pos_Y=0; GIF_last_byte=0; GIF_remainder_bits=0; GIF_remainder_byte=0; index=4096; File_error=0; GIF_stop=0; // Rintialisation de la table: alphabet_free=clear + 2; // 258 for 8bpp GIF_nb_bits =IDB.Nb_bits_pixel + 1; // 9 for 8 bpp alphabet_max =clear+clear-1; // 511 for 8bpp GIF_set_code(clear); //256 for 8bpp for (start=0;start<4096;start++) { alphabet_daughter[start]=4096; alphabet_sister[start]=4096; } ////////////////////////////////////////////// COMPRESSION LZW // start=current_string=GIF_next_pixel(context, &IDB); descend=1; do { current_char=GIF_next_pixel(context, &IDB); // On regarde si dans la table on aurait pas une chane // quivalente current_string+Caractere while ( (index0xFFF) { // Rintialisation de la table: GIF_set_code(clear); // 256 for 8bpp alphabet_free=clear+2; // 258 for 8bpp GIF_nb_bits =IDB.Nb_bits_pixel + 1; // 9 for 8bpp alphabet_max =clear+clear-1; // 511 for 8bpp for (start=0;start<4096;start++) { alphabet_daughter[start]=4096; alphabet_sister[start]=4096; } } else if (alphabet_free>alphabet_max+1) { // On augmente le nb de bits GIF_nb_bits++; alphabet_max=(1< // // 00 if (context->Original_file_name != NULL && context->Original_file_directory != NULL) { long name_size = 1+strlen(context->Original_file_name); long dir_size = 1+strlen(context->Original_file_directory); if (name_size<256 && dir_size<256) { if (! Write_bytes(GIF_file,"\x21\xFF\x0BGFX2PATH\x00\x00\x00", 14) || ! Write_byte(GIF_file,dir_size) || ! Write_bytes(GIF_file, context->Original_file_directory, dir_size) || ! Write_byte(GIF_file,name_size) || ! Write_bytes(GIF_file, context->Original_file_name, name_size) || ! Write_byte(GIF_file,0)) File_error=1; } } // On crit un GIF TERMINATOR, exig par SVGA et SEA. if (! Write_byte(GIF_file,'\x3B')) File_error=1; } } // On a pu crire la palette else File_error=1; } // On a pu crire le LSDB else File_error=1; // Libration de la mmoire utilise par les tables free(alphabet_sister); free(alphabet_daughter); free(alphabet_suffix); free(alphabet_prefix); } // On a pu crire la signature du fichier else File_error=1; fclose(GIF_file); if (File_error) remove(filename); } // On a pu ouvrir le fichier en criture else File_error=1; } //////////////////////////////////// PCX //////////////////////////////////// typedef struct { byte Manufacturer; // |_ Il font chier ces cons! Ils auraient pu byte Version; // | mettre une vraie signature! byte Compression; // L'image est-elle compresse? byte Depth; // Nombre de bits pour coder un pixel (inutile puisqu'on se sert de Plane) word X_min; // |_ Coin haut-gauche | word Y_min; // | de l'image |_ (Crtin!) word X_max; // |_ Coin bas-droit | word Y_max; // | de l'image | word X_dpi; // |_ Densit de |_ (Presque inutile parce que word Y_dpi; // | l'image | aucun moniteur n'est pareil!) byte Palette_16c[48]; // Palette 16 coul (inutile pour 256c) (dbile!) byte Reserved; // Ca me plait a aussi! byte Plane; // 4 => 16c , 1 => 256c , ... word Bytes_per_plane_line;// Doit toujours tre pair word Palette_info; // 1 => color , 2 => Gris (ignor partir de la version 4) word Screen_X; // |_ Dimensions de word Screen_Y; // | l'cran d'origine byte Filler[54]; // Ca... J'adore! } T_PCX_Header; T_PCX_Header PCX_header; // -- Tester si un fichier est au format PCX -------------------------------- void Test_PCX(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); if ((file=fopen(filename, "rb"))) { if (Read_byte(file,&(PCX_header.Manufacturer)) && Read_byte(file,&(PCX_header.Version)) && Read_byte(file,&(PCX_header.Compression)) && Read_byte(file,&(PCX_header.Depth)) && Read_word_le(file,&(PCX_header.X_min)) && Read_word_le(file,&(PCX_header.Y_min)) && Read_word_le(file,&(PCX_header.X_max)) && Read_word_le(file,&(PCX_header.Y_max)) && Read_word_le(file,&(PCX_header.X_dpi)) && Read_word_le(file,&(PCX_header.Y_dpi)) && Read_bytes(file,&(PCX_header.Palette_16c),48) && Read_byte(file,&(PCX_header.Reserved)) && Read_byte(file,&(PCX_header.Plane)) && Read_word_le(file,&(PCX_header.Bytes_per_plane_line)) && Read_word_le(file,&(PCX_header.Palette_info)) && Read_word_le(file,&(PCX_header.Screen_X)) && Read_word_le(file,&(PCX_header.Screen_Y)) && Read_bytes(file,&(PCX_header.Filler),54) ) { // Vu que ce header a une signature de merde et peu significative, il // va falloir que je teste diffrentes petites valeurs dont je connais // l'intervalle. Grrr! if ( (PCX_header.Manufacturer!=10) || (PCX_header.Compression>1) || ( (PCX_header.Depth!=1) && (PCX_header.Depth!=2) && (PCX_header.Depth!=4) && (PCX_header.Depth!=8) ) || ( (PCX_header.Plane!=1) && (PCX_header.Plane!=2) && (PCX_header.Plane!=4) && (PCX_header.Plane!=8) && (PCX_header.Plane!=3) ) || (PCX_header.X_maxWidth; x_pos++) { color=(IFF_buffer[x_pos/reduction]>>((reduction_minus_one-(x_pos%reduction))*depth)) & byte_mask; Set_pixel(context, x_pos,y_pos,color); } } void Load_PCX(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; short line_size; short real_line_size; // width de l'image corrige short width_read; short x_pos; short y_pos; byte byte1; byte byte2; byte index; dword nb_colors; long file_size; byte palette_CGA[9]={ 84,252,252, 252, 84,252, 252,252,252}; long position; long image_size; byte * buffer; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (Read_byte(file,&(PCX_header.Manufacturer)) && Read_byte(file,&(PCX_header.Version)) && Read_byte(file,&(PCX_header.Compression)) && Read_byte(file,&(PCX_header.Depth)) && Read_word_le(file,&(PCX_header.X_min)) && Read_word_le(file,&(PCX_header.Y_min)) && Read_word_le(file,&(PCX_header.X_max)) && Read_word_le(file,&(PCX_header.Y_max)) && Read_word_le(file,&(PCX_header.X_dpi)) && Read_word_le(file,&(PCX_header.Y_dpi)) && Read_bytes(file,&(PCX_header.Palette_16c),48) && Read_byte(file,&(PCX_header.Reserved)) && Read_byte(file,&(PCX_header.Plane)) && Read_word_le(file,&(PCX_header.Bytes_per_plane_line)) && Read_word_le(file,&(PCX_header.Palette_info)) && Read_word_le(file,&(PCX_header.Screen_X)) && Read_word_le(file,&(PCX_header.Screen_Y)) && Read_bytes(file,&(PCX_header.Filler),54) ) { context->Width=PCX_header.X_max-PCX_header.X_min+1; context->Height=PCX_header.Y_max-PCX_header.Y_min+1; Original_screen_X=PCX_header.Screen_X; Original_screen_Y=PCX_header.Screen_Y; if (PCX_header.Plane!=3) { Pre_load(context, context->Width,context->Height,file_size,FORMAT_PCX,PIXEL_SIMPLE,0); if (File_error==0) { // On prpare la palette accueillir les valeurs du fichier PCX if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); nb_colors=(dword)(1<4) memcpy(context->Palette,PCX_header.Palette_16c,48); else { context->Palette[1].R=0; context->Palette[1].G=0; context->Palette[1].B=0; byte1=PCX_header.Palette_16c[3]>>5; if (nb_colors==4) { // Pal. CGA "alakon" (du Turc Allahkoum qui signifie " la con" :)) memcpy(context->Palette+1,palette_CGA,9); if (!(byte1&2)) { context->Palette[1].B=84; context->Palette[2].B=84; context->Palette[3].B=84; } } // Palette monochrome (on va dire que c'est du N&B) else { context->Palette[1].R=252; context->Palette[1].G=252; context->Palette[1].B=252; } } // On se positionne la fin du fichier - 769 octets pour voir s'il y // a une palette. if ( (PCX_header.Depth==8) && (PCX_header.Version>=5) && (file_size>(256*3)) ) { fseek(file,file_size-((256*3)+1),SEEK_SET); // On regarde s'il y a une palette aprs les donnes de l'image if (Read_byte(file,&byte1)) if (byte1==12) // Lire la palette si c'est une image en 256 couleurs { int index; // On lit la palette 256c que ces crtins ont foutue la fin du fichier for(index=0;index<256;index++) if ( ! Read_byte(file,&(context->Palette[index].R)) || ! Read_byte(file,&(context->Palette[index].G)) || ! Read_byte(file,&(context->Palette[index].B)) ) { File_error=2; DEBUG("ERROR READING PCX PALETTE !",index); break; } } } // Maintenant qu'on a lu la palette que ces crtins sont alls foutre // la fin, on retourne juste aprs le header pour lire l'image. fseek(file,128,SEEK_SET); if (!File_error) { line_size=PCX_header.Bytes_per_plane_line*PCX_header.Plane; real_line_size=(short)PCX_header.Bytes_per_plane_line<<3; // On se sert de donnes ILBM car le dessin de ligne en moins de 256 // couleurs se fait comme avec la structure ILBM. Image_HAM=0; IFF_buffer=(byte *)malloc(line_size); // Chargement de l'image if (PCX_header.Compression) // Image compresse { /*Init_lecture();*/ image_size=(long)PCX_header.Bytes_per_plane_line*context->Height; if (PCX_header.Depth==8) // 256 couleurs (1 plan) { for (position=0; ((positionHeight) && (!File_error)); y_pos++) { for (x_pos=0; ((x_posHeight) && (!File_error);y_pos++) { if ((width_read=Read_bytes(file,IFF_buffer,line_size))) { if (PCX_header.Plane==1) for (x_pos=0; x_posWidth;x_pos++) Set_pixel(context, x_pos,y_pos,IFF_buffer[x_pos]); else { if (PCX_header.Depth==1) Draw_IFF_line(context, y_pos,real_line_size,PCX_header.Plane); else Draw_PCX_line(context, y_pos,PCX_header.Depth); } } else File_error=2; } } free(IFF_buffer); IFF_buffer = NULL; } } } else { // Image 24 bits!!! Pre_load(context,context->Width,context->Height,file_size,FORMAT_PCX,PIXEL_SIMPLE,1); if (File_error==0) { line_size=PCX_header.Bytes_per_plane_line*3; buffer=(byte *)malloc(line_size); if (!PCX_header.Compression) { for (y_pos=0;(y_posHeight) && (!File_error);y_pos++) { if (Read_bytes(file,buffer,line_size)) { for (x_pos=0; x_posWidth; x_pos++) Set_pixel_24b(context, x_pos,y_pos,buffer[x_pos+(PCX_header.Bytes_per_plane_line*0)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*1)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*2)]); } else File_error=2; } } else { /*Init_lecture();*/ for (y_pos=0,position=0;(y_posHeight) && (!File_error);) { // Lecture et dcompression de la ligne if(Read_byte(file,&byte1)!=1) File_error=2; if (!File_error) { if ((byte1 & 0xC0)==0xC0) { byte1-=0xC0; // facteur de rptition if(Read_byte(file,&byte2)!=1) File_error=2; // octet rpter if (!File_error) { for (index=0; (index=line_size) { for (x_pos=0; x_posWidth; x_pos++) Set_pixel_24b(context, x_pos,y_pos,buffer[x_pos+(PCX_header.Bytes_per_plane_line*0)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*1)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*2)]); y_pos++; position=0; } } } } else { buffer[position++]=byte1; if (position>=line_size) { for (x_pos=0; x_posWidth; x_pos++) Set_pixel_24b(context, x_pos,y_pos,buffer[x_pos+(PCX_header.Bytes_per_plane_line*0)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*1)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*2)]); y_pos++; position=0; } } } } if (position!=0) File_error=2; /*Close_lecture();*/ } free(buffer); buffer = NULL; } } } else { File_error=1; } fclose(file); } else File_error=1; } // -- Ecrire un fichier au format PCX --------------------------------------- void Save_PCX(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; short line_size; short x_pos; short y_pos; byte counter; byte last_pixel; byte pixel_read; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename,"wb"))) { setvbuf(file, NULL, _IOFBF, 64*1024); PCX_header.Manufacturer=10; PCX_header.Version=5; PCX_header.Compression=1; PCX_header.Depth=8; PCX_header.X_min=0; PCX_header.Y_min=0; PCX_header.X_max=context->Width-1; PCX_header.Y_max=context->Height-1; PCX_header.X_dpi=0; PCX_header.Y_dpi=0; memcpy(PCX_header.Palette_16c,context->Palette,48); PCX_header.Reserved=0; PCX_header.Plane=1; PCX_header.Bytes_per_plane_line=(context->Width&1)?context->Width+1:context->Width; PCX_header.Palette_info=1; PCX_header.Screen_X=Screen_width; PCX_header.Screen_Y=Screen_height; memset(PCX_header.Filler,0,54); if (Write_bytes(file,&(PCX_header.Manufacturer),1) && Write_bytes(file,&(PCX_header.Version),1) && Write_bytes(file,&(PCX_header.Compression),1) && Write_bytes(file,&(PCX_header.Depth),1) && Write_word_le(file,PCX_header.X_min) && Write_word_le(file,PCX_header.Y_min) && Write_word_le(file,PCX_header.X_max) && Write_word_le(file,PCX_header.Y_max) && Write_word_le(file,PCX_header.X_dpi) && Write_word_le(file,PCX_header.Y_dpi) && Write_bytes(file,&(PCX_header.Palette_16c),48) && Write_bytes(file,&(PCX_header.Reserved),1) && Write_bytes(file,&(PCX_header.Plane),1) && Write_word_le(file,PCX_header.Bytes_per_plane_line) && Write_word_le(file,PCX_header.Palette_info) && Write_word_le(file,PCX_header.Screen_X) && Write_word_le(file,PCX_header.Screen_Y) && Write_bytes(file,&(PCX_header.Filler),54) ) { line_size=PCX_header.Bytes_per_plane_line*PCX_header.Plane; for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) { pixel_read=Get_pixel(context, 0,y_pos); // Compression et criture de la ligne for (x_pos=0; ((x_pos1) || (last_pixel>=0xC0) ) Write_one_byte(file,counter|0xC0); Write_one_byte(file,last_pixel); } } // Ecriture de l'octet (12) indiquant que la palette arrive if (!File_error) Write_one_byte(file,12); // Ecriture de la palette if (!File_error) { if (! Write_bytes(file,context->Palette,sizeof(T_Palette))) File_error=1; } } else File_error=1; fclose(file); if (File_error) remove(filename); } else File_error=1; } //////////////////////////////////// SCx //////////////////////////////////// typedef struct { byte Filler1[4]; word Width; word Height; byte Filler2; byte Planes; } T_SCx_Header; // -- Tester si un fichier est au format SCx -------------------------------- void Test_SCx(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier //byte Signature[3]; T_SCx_Header SCx_header; Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Lecture et vrification de la signature if (Read_bytes(file,SCx_header.Filler1,4) && Read_word_le(file, &(SCx_header.Width)) && Read_word_le(file, &(SCx_header.Height)) && Read_byte(file, &(SCx_header.Filler2)) && Read_byte(file, &(SCx_header.Planes)) ) { if ( (!memcmp(SCx_header.Filler1,"RIX",3)) && SCx_header.Width && SCx_header.Height) File_error=0; } // Fermeture du fichier fclose(file); } } // -- Lire un fichier au format SCx ----------------------------------------- void Load_SCx(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; word x_pos,y_pos; long size,real_size; long file_size; T_SCx_Header SCx_header; T_Palette SCx_Palette; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (Read_bytes(file,SCx_header.Filler1,4) && Read_word_le(file, &(SCx_header.Width)) && Read_word_le(file, &(SCx_header.Height)) && Read_byte(file, &(SCx_header.Filler2)) && Read_byte(file, &(SCx_header.Planes)) ) { Pre_load(context, SCx_header.Width,SCx_header.Height,file_size,FORMAT_SCx,PIXEL_SIMPLE,0); if (File_error==0) { if (!SCx_header.Planes) size=sizeof(T_Palette); else size=sizeof(T_Components)*(1<Palette,0,sizeof(T_Palette)); Palette_64_to_256(SCx_Palette); memcpy(context->Palette,SCx_Palette,size); context->Width=SCx_header.Width; context->Height=SCx_header.Height; if (!SCx_header.Planes) { // 256 couleurs (raw) IFF_buffer=(byte *)malloc(context->Width); for (y_pos=0;(y_posHeight) && (!File_error);y_pos++) { if (Read_bytes(file,IFF_buffer,context->Width)) for (x_pos=0; x_posWidth;x_pos++) Set_pixel(context, x_pos,y_pos,IFF_buffer[x_pos]); else File_error=2; } } else { // moins de 256 couleurs (planar) size=((context->Width+7)>>3)*SCx_header.Planes; real_size=(size/SCx_header.Planes)<<3; IFF_buffer=(byte *)malloc(size); Image_HAM=0; for (y_pos=0;(y_posHeight) && (!File_error);y_pos++) { if (Read_bytes(file,IFF_buffer,size)) Draw_IFF_line(context, y_pos,real_size,SCx_header.Planes); else File_error=2; } } free(IFF_buffer); IFF_buffer = NULL; } else File_error=1; } } else File_error=1; fclose(file); } else File_error=1; } // -- Sauver un fichier au format SCx --------------------------------------- void Save_SCx(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; short x_pos,y_pos; T_SCx_Header SCx_header; byte last_char; last_char=strlen(context->File_name)-1; if (context->File_name[last_char]=='?') { if (context->Width<=320) context->File_name[last_char]='I'; else { if (context->Width<=360) context->File_name[last_char]='Q'; else { if (context->Width<=640) context->File_name[last_char]='F'; else { if (context->Width<=800) context->File_name[last_char]='N'; else context->File_name[last_char]='O'; } } } } Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { T_Palette palette_64; setvbuf(file, NULL, _IOFBF, 64*1024); memcpy(palette_64,context->Palette,sizeof(T_Palette)); Palette_256_to_64(palette_64); memcpy(SCx_header.Filler1,"RIX3",4); SCx_header.Width=context->Width; SCx_header.Height=context->Height; SCx_header.Filler2=0xAF; SCx_header.Planes=0x00; if (Write_bytes(file,SCx_header.Filler1,4) && Write_word_le(file, SCx_header.Width) && Write_word_le(file, SCx_header.Height) && Write_byte(file, SCx_header.Filler2) && Write_byte(file, SCx_header.Planes) && Write_bytes(file,&palette_64,sizeof(T_Palette)) ) { for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) for (x_pos=0; x_posWidth; x_pos++) Write_one_byte(file,Get_pixel(context, x_pos,y_pos)); fclose(file); if (File_error) remove(filename); } else // Error d'criture (disque plein ou protg) { fclose(file); remove(filename); File_error=1; } } else { fclose(file); remove(filename); File_error=1; } } //////////////////////////////////// XPM //////////////////////////////////// void Save_XPM(T_IO_Context* context) { FILE* file; char filename[MAX_PATH_CHARACTERS]; int i,j; Get_full_filename(filename, context->File_name, context->File_directory); File_error = 0; file = fopen(filename, "w"); if (file == NULL) { File_error = 1; return; } setvbuf(file, NULL, _IOFBF, 64*1024); fprintf(file, "/* XPM */\nstatic char* pixmap[] = {\n"); fprintf(file, "\"%d %d 256 2\",\n", context->Width, context->Height); for (i = 0; i < 256; i++) { fprintf(file,"\"%2.2X c #%2.2x%2.2x%2.2x\",\n", i, context->Palette[i].R, context->Palette[i].G, context->Palette[i].B); } for (j = 0; j < context->Height; j++) { fprintf(file, "\""); for (i = 0; i < context->Width; i++) { fprintf(file, "%2.2X", Get_pixel(context, i, j)); } fprintf(file,"\"\n"); } fclose(file); } //////////////////////////////////// PNG //////////////////////////////////// #ifndef __no_pnglib__ // -- Tester si un fichier est au format PNG -------------------------------- void Test_PNG(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier byte png_header[8]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Lecture du header du fichier if (Read_bytes(file,png_header,8)) { if ( !png_sig_cmp(png_header, 0, 8)) File_error=0; } fclose(file); } } /// Used by a callback in Load_PNG T_IO_Context * PNG_current_context; int PNG_read_unknown_chunk(png_structp ptr, png_unknown_chunkp chunk) { (void)ptr; // unused // png_unknown_chunkp members: // png_byte name[5]; // png_byte *data; // png_size_t size; if (!strcmp((const char *)chunk->name, "crNg")) { // Color animation. Similar to a CRNG chunk in an IFF file. unsigned int i; byte *chunk_ptr = chunk->data; // Should be a multiple of 6 if (chunk->size % 6) return (-1); for(i=0;isize/6 && i<16; i++) { word rate; word flags; byte min_col; byte max_col; // Rate (big-endian word) rate = *(chunk_ptr++) << 8; rate |= *(chunk_ptr++); // Flags (big-endian) flags = *(chunk_ptr++) << 8; flags |= *(chunk_ptr++); // Min color min_col = *(chunk_ptr++); // Max color max_col = *(chunk_ptr++); // Check validity if (min_col != max_col) { // Valid cycling range if (max_colCycle_range[i].Start=min_col; PNG_current_context->Cycle_range[i].End=max_col; PNG_current_context->Cycle_range[i].Inverse=(flags&2)?1:0; PNG_current_context->Cycle_range[i].Speed=(flags&1) ? rate/78 : 0; PNG_current_context->Color_cycles=i+1; } } return (1); // >0 = success } return (0); /* did not recognize */ } png_bytep * Row_pointers; // -- Lire un fichier au format PNG ----------------------------------------- void Load_PNG(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier byte png_header[8]; byte row_pointers_allocated; png_bytep trans; int num_trans; png_color_16p trans_values; png_structp png_ptr; png_infop info_ptr; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { // Load header (8 first bytes) if (Read_bytes(file,png_header,8)) { // Do we recognize a png file signature ? if ( !png_sig_cmp(png_header, 0, 8)) { // Prepare internal PNG loader png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr) { // Prepare internal PNG loader info_ptr = png_create_info_struct(png_ptr); if (info_ptr) { png_byte color_type; png_byte bit_depth; png_voidp user_chunk_ptr; // Setup a return point. If a pnglib loading error occurs // in this if(), the else will be executed. if (!setjmp(png_jmpbuf(png_ptr))) { png_init_io(png_ptr, file); // Inform pnglib we already loaded the header. png_set_sig_bytes(png_ptr, 8); // Hook the handler for unknown chunks user_chunk_ptr = png_get_user_chunk_ptr(png_ptr); png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, &PNG_read_unknown_chunk); // This is a horrid way to pass parameters, but we don't get // much choice. PNG loader can't be reintrant. PNG_current_context=context; // Load file information png_read_info(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr,info_ptr); bit_depth = png_get_bit_depth(png_ptr,info_ptr); // If it's any supported file // (Note: As of writing this, this test covers every possible // image format of libpng) if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA ) { int num_text; png_text *text_ptr; int unit_type; png_uint_32 res_x; png_uint_32 res_y; // Comment (tEXt) context->Comment[0]='\0'; // Clear the previous comment if ((num_text=png_get_text(png_ptr, info_ptr, &text_ptr, NULL))) { while (num_text--) { if (!strcmp(text_ptr[num_text].key,"Title")) { int size; size = Min(text_ptr[num_text].text_length, COMMENT_SIZE); strncpy(context->Comment, text_ptr[num_text].text, size); context->Comment[size]='\0'; break; // Skip all others tEXt chunks } } } // Pixel Ratio (pHYs) if (png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type)) { // Ignore unit, and use the X/Y ratio as a hint for // WIDE or TALL pixels if (res_x>0 && res_y>0) { if (res_y/res_x>1) { context->Ratio=PIXEL_WIDE; } else if (res_x/res_y>1) { context->Ratio=PIXEL_TALL; } } } if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) Pre_load(context,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),File_length_file(file),FORMAT_PNG,PIXEL_SIMPLE,1); else Pre_load(context,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),File_length_file(file),FORMAT_PNG,context->Ratio,0); if (File_error==0) { int x,y; png_colorp palette; int num_palette; // 16-bit images if (bit_depth == 16) { // Reduce to 8-bit png_set_strip_16(png_ptr); } else if (bit_depth < 8) { // Inform libpng we want one byte per pixel, // even though the file was less than 8bpp png_set_packing(png_ptr); } // Images with alpha channel if (color_type & PNG_COLOR_MASK_ALPHA) { // Tell libpng to ignore it png_set_strip_alpha(png_ptr); } // Greyscale images : if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { // Map low bpp greyscales to full 8bit (0-255 range) if (bit_depth < 8) { #if (PNG_LIBPNG_VER_MAJOR <= 1) && (PNG_LIBPNG_VER_MINOR < 4) // Works well with png 1.2.8, but deprecated in 1.4 ... png_set_gray_1_2_4_to_8(png_ptr); #else // ...where this seems to replace it: png_set_expand_gray_1_2_4_to_8(png_ptr); #endif } // Create greyscale palette for (x=0;x<256;x++) { context->Palette[x].R=x; context->Palette[x].G=x; context->Palette[x].B=x; } } else if (color_type == PNG_COLOR_TYPE_PALETTE) // Palette images { if (bit_depth < 8) { // Clear unused colors if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); } // Get a pointer to the PNG palette png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); // Copy all colors to the context for (x=0;xPalette[x].R=palette[x].red; context->Palette[x].G=palette[x].green; context->Palette[x].B=palette[x].blue; } // The palette must not be freed: it is owned by libpng. palette = NULL; } // Transparency (tRNS) if (png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)) { if (color_type == PNG_COLOR_TYPE_PALETTE && trans!=NULL) { int i; for (i=0; iTransparent_color = i; context->Background_transparent = 1; break; } } } else if ((color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_RGB) && trans_values!=NULL) { // In this case, num_trans is supposed to be "1", // and trans_values[0] contains the reference color // (RGB triplet) that counts as transparent. // Ideally, we should reserve this color in the palette, // (so it's not merged and averaged with a neighbor one) // and after creating the optimized palette, find its // index and mark it transparent. // Current implementation: ignore. } } context->Width=png_get_image_width(png_ptr,info_ptr); context->Height=png_get_image_height(png_ptr,info_ptr); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); // Allocate row pointers Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * context->Height); row_pointers_allocated = 0; /* read file */ if (!setjmp(png_jmpbuf(png_ptr))) { if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_PALETTE ) { // 8bpp for (y=0; yHeight; y++) Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr)); row_pointers_allocated = 1; png_read_image(png_ptr, Row_pointers); for (y=0; yHeight; y++) for (x=0; xWidth; x++) Set_pixel(context, x, y, Row_pointers[y][x]); } else { switch (context->Type) { case CONTEXT_PREVIEW: // 24bpp // It's a preview // Unfortunately we need to allocate loads of memory for (y=0; yHeight; y++) Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr)); row_pointers_allocated = 1; png_read_image(png_ptr, Row_pointers); for (y=0; yHeight; y++) for (x=0; xWidth; x++) Set_pixel_24b(context, x, y, Row_pointers[y][x*3],Row_pointers[y][x*3+1],Row_pointers[y][x*3+2]); break; case CONTEXT_MAIN_IMAGE: case CONTEXT_BRUSH: case CONTEXT_SURFACE: // It's loading an actual image // We'll save memory and time by writing directly into // our pre-allocated 24bit buffer for (y=0; yHeight; y++) Row_pointers[y] = (png_byte*) (&(context->Buffer_image_24b[y * context->Width])); png_read_image(png_ptr, Row_pointers); break; case CONTEXT_PALETTE: // No pixels to draw in a palette! break; } } } else File_error=2; /* cleanup heap allocation */ if (row_pointers_allocated) { for (y=0; yHeight; y++) { free(Row_pointers[y]); Row_pointers[y] = NULL; } } free(Row_pointers); Row_pointers = NULL; } else File_error=2; } else // Unsupported image type File_error=1; } else File_error=1; } else File_error=1; } } /*Close_lecture();*/ } else // Lecture header impossible: Error ne modifiant pas l'image File_error=1; fclose(file); } else // Ouv. fichier impossible: Error ne modifiant pas l'image File_error=1; } void Save_PNG(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; int y; byte * pixel_ptr; png_structp png_ptr; png_infop info_ptr; png_unknown_chunk crng_chunk; byte cycle_data[16*6]; // Storage for color-cycling data, referenced by crng_chunk Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; Row_pointers = NULL; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { setvbuf(file, NULL, _IOFBF, 64*1024); /* initialisation */ if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) && (info_ptr = png_create_info_struct(png_ptr))) { if (!setjmp(png_jmpbuf(png_ptr))) { png_init_io(png_ptr, file); /* en-tete */ if (!setjmp(png_jmpbuf(png_ptr))) { png_set_IHDR(png_ptr, info_ptr, context->Width, context->Height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_PLTE(png_ptr, info_ptr, (png_colorp)context->Palette, 256); { // Commentaires texte PNG // Cette partie est optionnelle #ifdef PNG_iTXt_SUPPORTED png_text text_ptr[2] = { {-1, "Software", "Grafx2", 6, 0, NULL, NULL}, {-1, "Title", NULL, 0, 0, NULL, NULL} #else png_text text_ptr[2] = { {-1, "Software", "Grafx2", 6}, {-1, "Title", NULL, 0} #endif }; int nb_text_chunks=1; if (context->Comment[0]) { text_ptr[1].text=context->Comment; text_ptr[1].text_length=strlen(context->Comment); nb_text_chunks=2; } png_set_text(png_ptr, info_ptr, text_ptr, nb_text_chunks); } if (context->Background_transparent) { // Transparency byte opacity[256]; // Need to fill a segment with '255', up to the transparent color // which will have a 0. This piece of data (1 to 256 bytes) // will be stored in the file. memset(opacity, 255,context->Transparent_color); opacity[context->Transparent_color]=0; png_set_tRNS(png_ptr, info_ptr, opacity, (int)1 + context->Transparent_color,0); } switch(Pixel_ratio) { case PIXEL_WIDE: case PIXEL_WIDE2: png_set_pHYs(png_ptr, info_ptr, 3000, 6000, PNG_RESOLUTION_METER); break; case PIXEL_TALL: case PIXEL_TALL2: case PIXEL_TALL3: png_set_pHYs(png_ptr, info_ptr, 6000, 3000, PNG_RESOLUTION_METER); break; default: break; } // Write cycling colors if (context->Color_cycles) { // Save a chunk called 'crNg' // The case is selected by the following rules from PNG standard: // char 1: non-mandatory = lowercase // char 2: private (not standard) = lowercase // char 3: reserved = always uppercase // char 4: can be copied by editors = lowercase // First, turn our nice structure into byte array // (just to avoid padding in structures) byte *chunk_ptr = cycle_data; int i; for (i=0; iColor_cycles; i++) { word flags=0; flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not flags|= context->Cycle_range[i].Inverse?2:0; // Inverted // Big end of Rate *(chunk_ptr++) = (context->Cycle_range[i].Speed*78) >> 8; // Low end of Rate *(chunk_ptr++) = (context->Cycle_range[i].Speed*78) & 0xFF; // Big end of Flags *(chunk_ptr++) = (flags) >> 8; // Low end of Flags *(chunk_ptr++) = (flags) & 0xFF; // Min color *(chunk_ptr++) = context->Cycle_range[i].Start; // Max color *(chunk_ptr++) = context->Cycle_range[i].End; } // Build one unknown_chuck structure memcpy(crng_chunk.name, "crNg",5); crng_chunk.data=cycle_data; crng_chunk.size=context->Color_cycles*6; crng_chunk.location=PNG_HAVE_PLTE; // Give it to libpng png_set_unknown_chunks(png_ptr, info_ptr, &crng_chunk, 1); // libpng seems to ignore the location I provided earlier. png_set_unknown_chunk_location(png_ptr, info_ptr, 0, PNG_HAVE_PLTE); } png_write_info(png_ptr, info_ptr); /* ecriture des pixels de l'image */ Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * context->Height); pixel_ptr = context->Target_address; for (y=0; yHeight; y++) Row_pointers[y] = (png_byte*)(pixel_ptr+y*context->Pitch); if (!setjmp(png_jmpbuf(png_ptr))) { png_write_image(png_ptr, Row_pointers); /* cloture png */ if (!setjmp(png_jmpbuf(png_ptr))) { png_write_end(png_ptr, NULL); } else File_error=1; } else File_error=1; } else File_error=1; } else { File_error=1; } png_destroy_write_struct(&png_ptr, &info_ptr); } else File_error=1; // fermeture du fichier fclose(file); } // S'il y a eu une erreur de sauvegarde, on ne va tout de mme pas laisser // ce fichier pourri trainait... Ca fait pas propre. if (File_error) remove(filename); if (Row_pointers) { free(Row_pointers); Row_pointers=NULL; } } #endif // __no_pnglib__ grafx2_2.4+git20180105/src/io.c0000664000000000000000000003360313223665306014307 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ // Fonctions de lecture/ecriture file, grent les systmes big-endian et // little-endian. #include #include #include #include #include #include #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include #include #include #elif defined(__WIN32__) #include #include //#include #elif defined(__MINT__) #include #include #include #else #include #endif #include "struct.h" #include "io.h" #include "realpath.h" // Lit un octet // Renvoie -1 si OK, 0 en cas d'erreur int Read_byte(FILE *file, byte *dest) { return fread(dest, 1, 1, file) == 1; } // Ecrit un octet // Renvoie -1 si OK, 0 en cas d'erreur int Write_byte(FILE *file, byte b) { return fwrite(&b, 1, 1, file) == 1; } // Lit des octets // Renvoie -1 si OK, 0 en cas d'erreur int Read_bytes(FILE *file, void *dest, size_t size) { return fread(dest, 1, size, file) == size; } // Ecrit des octets // Renvoie -1 si OK, 0 en cas d'erreur int Write_bytes(FILE *file, void *src, size_t size) { return fwrite(src, 1, size, file) == size; } // Lit un word (little-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Read_word_le(FILE *file, word *dest) { if (fread(dest, 1, sizeof(word), file) != sizeof(word)) return 0; #if SDL_BYTEORDER != SDL_LIL_ENDIAN *dest = SDL_Swap16(*dest); #endif return -1; } // Ecrit un word (little-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Write_word_le(FILE *file, word w) { #if SDL_BYTEORDER != SDL_LIL_ENDIAN w = SDL_Swap16(w); #endif return fwrite(&w, 1, sizeof(word), file) == sizeof(word); } // Lit un word (big-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Read_word_be(FILE *file, word *dest) { if (fread(dest, 1, sizeof(word), file) != sizeof(word)) return 0; #if SDL_BYTEORDER != SDL_BIG_ENDIAN *dest = SDL_Swap16(*dest); #endif return -1; } // Ecrit un word (big-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Write_word_be(FILE *file, word w) { #if SDL_BYTEORDER != SDL_BIG_ENDIAN w = SDL_Swap16(w); #endif return fwrite(&w, 1, sizeof(word), file) == sizeof(word); } // Lit un dword (little-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Read_dword_le(FILE *file, dword *dest) { if (fread(dest, 1, sizeof(dword), file) != sizeof(dword)) return 0; #if SDL_BYTEORDER != SDL_LIL_ENDIAN *dest = SDL_Swap32(*dest); #endif return -1; } // Ecrit un dword (little-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Write_dword_le(FILE *file, dword dw) { #if SDL_BYTEORDER != SDL_LIL_ENDIAN dw = SDL_Swap32(dw); #endif return fwrite(&dw, 1, sizeof(dword), file) == sizeof(dword); } // Lit un dword (big-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Read_dword_be(FILE *file, dword *dest) { if (fread(dest, 1, sizeof(dword), file) != sizeof(dword)) return 0; #if SDL_BYTEORDER != SDL_BIG_ENDIAN *dest = SDL_Swap32(*dest); #endif return -1; } // Ecrit un dword (big-endian) // Renvoie -1 si OK, 0 en cas d'erreur int Write_dword_be(FILE *file, dword dw) { #if SDL_BYTEORDER != SDL_BIG_ENDIAN dw = SDL_Swap32(dw); #endif return fwrite(&dw, 1, sizeof(dword), file) == sizeof(dword); } // Dtermine la position du dernier '/' ou '\\' dans une chaine, // typiquement pour sparer le nom de file d'un chemin. // Attention, sous Windows, il faut s'attendre aux deux car // par exemple un programme lanc sous GDB aura comme argv[0]: // d:\Data\C\GFX2\grafx2/grafx2.exe char * Find_last_separator(const char * str) { const char * position = NULL; for (; *str != '\0'; str++) if (*str == PATH_SEPARATOR[0] #ifdef __WIN32__ || *str == '/' #elif __AROS__ || *str == ':' #endif ) position = str; return (char *)position; } // Rcupre la partie "nom de file seul" d'un chemin void Extract_filename(char *dest, const char *source) { const char * position = Find_last_separator(source); if (position) strcpy(dest,position+1); else strcpy(dest,source); } // Rcupre la partie "rpertoire+/" d'un chemin. void Extract_path(char *dest, const char *source) { char * position=NULL; Realpath(source,dest); position = Find_last_separator(dest); if (position) *(position+1) = '\0'; else strcat(dest, PATH_SEPARATOR); } /// /// Appends a file or directory name to an existing directory name. /// As a special case, when the new item is equal to PARENT_DIR, this /// will remove the rightmost directory name. /// reverse_path is optional, if it's non-null, the function will /// write there : /// - if filename is ".." : The name of eliminated directory/file /// - else: ".." void Append_path(char *path, const char *filename, char *reverse_path) { // Parent if (!strcmp(filename, PARENT_DIR)) { // Going up one directory long len; char * separator_pos; // Remove trailing slash len=strlen(path); if (len && (!strcmp(path+len-1,PATH_SEPARATOR) #ifdef __WIN32__ || path[len-1]=='/' #endif )) path[len-1]='\0'; separator_pos=Find_last_separator(path); if (separator_pos) { if (reverse_path) strcpy(reverse_path, separator_pos+1); #if defined(__AROS__) // Don't strip away the colon if (*separator_pos == ':') *(separator_pos+1)='\0'; else *separator_pos='\0'; #else *separator_pos='\0'; #endif } else { if (reverse_path) strcpy(reverse_path, path); path[0]='\0'; } #if defined(__WIN32__) // Roots of drives need a pending antislash if (path[0]!='\0' && path[1]==':' && path[2]=='\0') { strcat(path, PATH_SEPARATOR); } #endif } else // Sub-directory { long len; // Add trailing slash if needed len=strlen(path); if (len && (strcmp(path+len-1,PATH_SEPARATOR) #ifdef __WIN32__ && path[len-1]!='/' #elif __AROS__ && path[len-1]!=':' // To avoid paths like volume:/dir #endif )) { strcpy(path+len, PATH_SEPARATOR); len+=strlen(PATH_SEPARATOR); } strcat(path, filename); if (reverse_path) strcpy(reverse_path, PARENT_DIR); } } int File_exists(char * fname) // Dtermine si un file pass en paramtre existe ou non dans le // rpertoire courant. { struct stat buf; int result; result=stat(fname,&buf); if (result!=0) return(errno!=ENOENT); else return 1; } int Directory_exists(char * directory) // Dtermine si un rpertoire pass en paramtre existe ou non dans le // rpertoire courant. { DIR* entry; // Structure de lecture des lments if (strcmp(directory,PARENT_DIR)==0) return 1; else { // On va chercher si le rpertoire existe l'aide d'un Opendir. S'il // renvoie NULL c'est que le rpertoire n'est pas accessible... entry=opendir(directory); if (entry==NULL) return 0; else { closedir(entry); return 1; } } } /// Check if a file or directory is hidden. int File_is_hidden(const char *fname, const char *full_name) { #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) || defined(__MINT__) // False (unable to determine, or irrelevent for platform) (void)fname;//unused (void)full_name;//unused return 0; #elif defined(__WIN32__) unsigned long att; if (full_name!=NULL) att = GetFileAttributesA(full_name); else att = GetFileAttributesA(fname); if (att==INVALID_FILE_ATTRIBUTES) return 0; return (att&FILE_ATTRIBUTE_HIDDEN)?1:0; #else (void)full_name;//unused // On linux/unix (default), files are considered hidden if their name // begins with a . // As a special case, we'll consider 'parent directory' (..) never hidden. return fname[0]=='.' && strcmp(fname, PARENT_DIR); #endif } // Taille de fichier, en octets int File_length(const char * fname) { struct stat infos_fichier; if (stat(fname,&infos_fichier)) return 0; return infos_fichier.st_size; } int File_length_file(FILE * file) { struct stat infos_fichier; if (fstat(fileno(file),&infos_fichier)) return 0; return infos_fichier.st_size; } void For_each_file(const char * directory_name, void Callback(const char *)) { // Pour scan de rpertoire DIR* current_directory; //Rpertoire courant struct dirent* entry; // Structure de lecture des lments char full_filename[MAX_PATH_CHARACTERS]; int filename_position; strcpy(full_filename, directory_name); current_directory=opendir(directory_name); if(current_directory == NULL) return; // Rpertoire invalide ... filename_position = strlen(full_filename); #if defined(__AROS__) if (filename_position==0 || (strcmp(full_filename+filename_position-1,PATH_SEPARATOR) && strcmp(full_filename+filename_position-1,":"))) #else if (filename_position==0 || strcmp(full_filename+filename_position-1,PATH_SEPARATOR)) #endif { strcat(full_filename, PATH_SEPARATOR); filename_position = strlen(full_filename); } while ((entry=readdir(current_directory))) { struct stat Infos_enreg; strcpy(&full_filename[filename_position], entry->d_name); stat(full_filename,&Infos_enreg); if (S_ISREG(Infos_enreg.st_mode)) { Callback(full_filename); } } closedir(current_directory); } /// Scans a directory, calls Callback for each file or directory in it, void For_each_directory_entry(const char * directory_name, void Callback(const char *, byte is_file, byte is_directory, byte is_hidden)) { // Pour scan de rpertoire DIR* current_directory; //Rpertoire courant struct dirent* entry; // Structure de lecture des lments char full_filename[MAX_PATH_CHARACTERS]; int filename_position; strcpy(full_filename, directory_name); current_directory=opendir(full_filename); if(current_directory == NULL) return; // Rpertoire invalide ... filename_position = strlen(full_filename); #if defined(__AROS__) if (filename_position==0 || (strcmp(full_filename+filename_position-1,PATH_SEPARATOR) && strcmp(full_filename+filename_position-1,":"))) #else if (filename_position==0 || strcmp(full_filename+filename_position-1,PATH_SEPARATOR)) #endif { strcat(full_filename, PATH_SEPARATOR); filename_position = strlen(full_filename); } while ((entry=readdir(current_directory))) { struct stat Infos_enreg; strcpy(&full_filename[filename_position], entry->d_name); stat(full_filename,&Infos_enreg); Callback( full_filename, S_ISREG(Infos_enreg.st_mode), S_ISDIR(Infos_enreg.st_mode), File_is_hidden(entry->d_name, full_filename)); } closedir(current_directory); } void Get_full_filename(char * output_name, char * file_name, char * directory_name) { strcpy(output_name,directory_name); if (output_name[0] != '\0') { // Append a separator at the end of path, if there isn't one already. // This handles the case of directory variables which contain one, // as well as directories like "/" on Unix. #if defined(__AROS__) // additional check for ':' to avoid paths like PROGDIR:/unnamed.gif if ((output_name[strlen(output_name)-1]!=PATH_SEPARATOR[0]) && (output_name[strlen(output_name)-1]!=':')) #else if (output_name[strlen(output_name)-1]!=PATH_SEPARATOR[0]) #endif strcat(output_name,PATH_SEPARATOR); } strcat(output_name,file_name); } /// Lock file used to prevent several instances of grafx2 from harming each others' backups #ifdef __WIN32__ HANDLE Lock_file_handle = INVALID_HANDLE_VALUE; #else int Lock_file_handle = -1; #endif byte Create_lock_file(const char *file_directory) { #if defined (__amigaos__)||(__AROS__)||(__ANDROID__) #warning "Missing code for your platform, please check and correct!" #else char lock_filename[MAX_PATH_CHARACTERS]; #ifdef GCWZERO strcpy(lock_filename,"/media/home/.grafx2/"); #else strcpy(lock_filename,file_directory); #endif strcat(lock_filename,"gfx2.lck"); #ifdef __WIN32__ // Windowzy method for creating a lock file Lock_file_handle = CreateFile( lock_filename, GENERIC_WRITE, 0, // No sharing NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (Lock_file_handle == INVALID_HANDLE_VALUE) { return -1; } #else // Unixy method for lock file Lock_file_handle = open(lock_filename,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR); if (Lock_file_handle == -1) { // Usually write-protected media return -1; } if (lockf(Lock_file_handle, F_TLOCK, 0)==-1) { close(Lock_file_handle); // Usually write-protected media return -1; } #endif #endif // __amigaos__ or __AROS__ return 0; } void Release_lock_file(const char *file_directory) { char lock_filename[MAX_PATH_CHARACTERS]; #ifdef __WIN32__ if (Lock_file_handle != INVALID_HANDLE_VALUE) { CloseHandle(Lock_file_handle); } #else if (Lock_file_handle != -1) { close(Lock_file_handle); Lock_file_handle = -1; } #endif // Actual deletion strcpy(lock_filename,file_directory); strcat(lock_filename,"gfx2.lck"); remove(lock_filename); } grafx2_2.4+git20180105/src/setup.c0000664000000000000000000002142613223665307015041 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2014 Sergii Pylypenko Copyright 2011 Pawel Gralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include #include #if defined(__WIN32__) #include #include // Mingw's _mkdir() #elif defined(__macosx__) #import #import #elif defined(__FreeBSD__) #include #elif defined(__MINT__) #include #include #elif defined(__linux__) #include #include #elif defined(__HAIKU__) #include #endif #include "struct.h" #include "io.h" #include "setup.h" #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // This is a random default value ... #define PATH_MAX 32768 #endif int Create_ConfigDirectory(char * config_dir) { #ifdef __WIN32__ // Mingw's mkdir has a weird name and only one argument return _mkdir(config_dir); #else return mkdir(config_dir,S_IRUSR|S_IWUSR|S_IXUSR); #endif } // Determine which directory contains the executable. // IN: Main's argv[0], some platforms need it, some don't. // OUT: Write into program_dir. Trailing / or \ is kept. // Note : in fact this is only used to check for the datafiles and fonts in // this same directory. void Set_program_directory(const char * argv0, char * program_dir) { // MacOSX #if defined(__macosx__) CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); (void)argv0; // unused CFURLGetFileSystemRepresentation(url,true,(UInt8*)program_dir,MAXPATHLEN); CFRelease(url); // Append trailing slash strcat(program_dir ,"/"); // AmigaOS and alike: hard-coded volume name. #elif defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) (void)argv0; // unused strcpy(program_dir,"PROGDIR:"); #elif defined(__MINT__) static char path[1024]={0}; char currentDrive='A'; (void)argv0; // unused currentDrive=currentDrive+Dgetdrv(); Dgetpath(path,0); sprintf(program_dir,"%c:\%s",currentDrive,path); // Append trailing slash strcat(program_dir,PATH_SEPARATOR); #elif defined(__ANDROID__) (void)argv0; // unused getcwd(program_dir, MAX_PATH_CHARACTERS); strcat(program_dir, "/"); // Linux: argv[0] unreliable #elif defined(__linux__) if (argv0[0]!='/') { char path[PATH_MAX]; readlink("/proc/self/exe", path, sizeof(path)); Extract_path(program_dir, path); return; } Extract_path(program_dir, argv0); // Others: The part of argv[0] before the executable name. // Keep the last \ or /. // On Windows, Mingw32 already provides the full path in all cases. #else Extract_path(program_dir, argv0); #endif } // Determine which directory contains the read-only data. // IN: The directory containing the executable // OUT: Write into data_dir. Trailing / or \ is kept. void Set_data_directory(const char * program_dir, char * data_dir) { // On all platforms, data is relative to the executable's directory strcpy(data_dir,program_dir); // On MacOSX, it is stored in a special folder: #if defined(__macosx__) strcat(data_dir,"Contents/Resources/"); // On GP2X, AROS and Android, executable is not in bin/ #elif defined (__GP2X__) || defined (__gp2x__) || defined (__WIZ__) || defined (__CAANOO__) || defined(GCWZERO) || defined(__AROS__) || defined(__ANDROID__) strcat(data_dir,"share/grafx2/"); //on tos, the same directory is used for everything #elif defined (__MINT__) strcpy(data_dir, program_dir); // Haiku provides us with an API to find it. #elif defined(__HAIKU__) if (find_path(Set_data_directory, B_FIND_PATH_DATA_DIRECTORY, "grafx2/", data_dir, PATH_MAX) != B_OK) { // If the program is not installed, find_path will fail. Try from local dir then. strcat(data_dir,"../share/grafx2/"); } // All other targets, program is in a "bin" subdirectory #else strcat(data_dir,"../share/grafx2/"); #endif } // Determine which directory should store the user's configuration. // // For most Unix and Windows platforms: // If a config file already exists in program_dir, it will return it in priority // (Useful for development, and possibly for upgrading from DOS version) // If the standard directory doesn't exist yet, this function will attempt // to create it ($(HOME)/.grafx2, or %APPDATA%\GrafX2) // If it cannot be created, this function will return the executable's // own directory. // IN: The directory containing the executable // OUT: Write into config_dir. Trailing / or \ is kept. void Set_config_directory(const char * program_dir, char * config_dir) { // AmigaOS4 provides the PROGIR: alias to the directory where the executable is. #if defined(__amigaos4__) || defined(__AROS__) strcpy(config_dir,"PROGDIR:"); // GP2X #elif defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // On the GP2X, the program is installed to the sdcard, and we don't want to mess with the system tree which is // on an internal flash chip. So, keep these settings locals. strcpy(config_dir,program_dir); // For TOS we store everything in the program dir #elif defined(__MINT__) strcpy(config_dir,program_dir); // For all other platforms, there is some kind of settigns dir to store this. #else char filename[MAX_PATH_CHARACTERS]; #ifdef GCWZERO strcpy(config_dir, "/media/home/.grafx2/"); #else // In priority: check root directory strcpy(config_dir, program_dir); #endif // On all the remaining targets except OSX, the executable is in ./bin #if !defined(__macosx__) strcat(config_dir, "../"); #endif strcpy(filename, config_dir); strcat(filename, CONFIG_FILENAME); if (!File_exists(filename)) { char *config_parent_dir; #if defined(__WIN32__) // "%APPDATA%\GrafX2" const char* Config_SubDir = "GrafX2"; config_parent_dir = getenv("APPDATA"); #elif defined(__BEOS__) || defined(__HAIKU__) // "`finddir B_USER_SETTINGS_DIRECTORY`/grafx2" const char* Config_SubDir = "grafx2"; { static char parent[MAX_PATH_CHARACTERS]; find_directory(B_USER_SETTINGS_DIRECTORY, 0, false, parent, MAX_PATH_CHARACTERS); config_parent_dir = parent; } #elif defined(__macosx__) // "~/Library/Preferences/com.googlecode.grafx2" const char* Config_SubDir = "Library/Preferences/com.googlecode.grafx2"; config_parent_dir = getenv("HOME"); #elif defined(__MINT__) const char* Config_SubDir = ""; printf("GFX2.CFG not found in %s\n",filename); strcpy(config_parent_dir, config_dir); #else // ~/.config/grafx2 const char* Config_SubDir; config_parent_dir = getenv("XDG_CONFIG_HOME"); if (config_parent_dir) Config_SubDir = "grafx2"; else { Config_SubDir = ".config/grafx2"; config_parent_dir = getenv("HOME"); } #endif if (config_parent_dir && config_parent_dir[0]!='\0') { int size = strlen(config_parent_dir); strcpy(config_dir, config_parent_dir); if (config_parent_dir[size-1] != '\\' && config_parent_dir[size-1] != '/') { strcat(config_dir,PATH_SEPARATOR); } strcat(config_dir,Config_SubDir); if (Directory_exists(config_dir)) { // Rpertoire trouv, ok strcat(config_dir,PATH_SEPARATOR); } else { // Tentative de cration if (!Create_ConfigDirectory(config_dir)) { // Russi strcat(config_dir,PATH_SEPARATOR); } else { // Echec: on se rabat sur le repertoire de l'executable. strcpy(config_dir,program_dir); #if defined(__macosx__) strcat(config_dir, "../"); #endif } } } } #endif } grafx2_2.4+git20180105/src/pxsimple.h0000664000000000000000000000663513223665306015553 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file pxsimple.h /// Renderer for simple pixels (1x1). This is the normal one. ////////////////////////////////////////////////////////////////////////////// #include "struct.h" void Pixel_simple (word x,word y,byte color); byte Read_pixel_simple (word x,word y); void Block_simple (word start_x,word start_y,word width,word height,byte color); void Pixel_preview_normal_simple (word x,word y,byte color); void Pixel_preview_magnifier_simple (word x,word y,byte color); void Horizontal_XOR_line_simple (word x_pos,word y_pos,word width); void Vertical_XOR_line_simple (word x_pos,word y_pos,word height); void Display_brush_color_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_brush_mono_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); void Clear_brush_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); void Remap_screen_simple (word x_pos,word y_pos,word width,word height,byte * conversion_table); void Display_part_of_screen_simple (word width,word height,word image_width); void Display_line_on_screen_simple (word x_pos,word y_pos,word width,byte * line); void Read_line_screen_simple (word x_pos,word y_pos,word width,byte * line); void Display_part_of_screen_scaled_simple(word width,word height,word image_width,byte * buffer); void Display_brush_color_zoom_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); void Display_brush_mono_zoom_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); void Clear_brush_scaled_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); void Display_brush_simple (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_transparent_mono_line_on_screen_simple( word x_pos, word y_pos, word width, byte* line, byte transp_color, byte color); void Display_transparent_line_on_screen_simple(word x_pos,word y_pos,word width,byte* line,byte transp_color); grafx2_2.4+git20180105/src/tiles.c0000664000000000000000000003066013223665307015021 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Yves Rizoud Copyright 2010-2011 Adrien Destugues Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include "struct.h" #include "global.h" #include "graph.h" #include "sdlscreen.h" #include "engine.h" #include "windows.h" #include "input.h" #include "misc.h" #include "tiles.h" // These helpers are only needed internally at the moment #define TILE_FOR_COORDS(x,y) (((y)-Snap_offset_Y)/Snap_height*Main_tilemap_width+((x)-Snap_offset_X)/Snap_width) #define TILE_AT(x,y) (y)*Main_tilemap_width+(x) #define TILE_X(t) (((t)%Main_tilemap_width)*Snap_width+Snap_offset_X) #define TILE_Y(t) (((t)/Main_tilemap_width)*Snap_height+Snap_offset_Y) enum TILE_FLIPPED { TILE_FLIPPED_NONE = 0, TILE_FLIPPED_X = 1, TILE_FLIPPED_Y = 2, TILE_FLIPPED_XY = 3, // needs be TILE_FLIPPED_X|TILE_FLIPPED_Y }; // globals /// Tilemap for the main screen T_Tile * Main_tilemap; /// Number of tiles (horizontally) for the main page's tilemap short Main_tilemap_width; /// Number of tiles (vertically) for the main page's tilemap short Main_tilemap_height; /// Tilemap for the spare T_Tile * Spare_tilemap; /// Number of tiles (horizontally) for the spare page's tilemap short Spare_tilemap_width; /// Number of tiles (vertically) for the spare page's tilemap short Spare_tilemap_height; /// /// Draw a pixel while Tilemap mode is active : This will paint on all /// similar tiles of the layer, visible on the screen or not. void Tilemap_draw(word x, word y, byte color) { int tile, first_tile; int rel_x, rel_y; if (x < Snap_offset_X || y < Snap_offset_Y || x >= Snap_offset_X + Main_tilemap_width*Snap_width || y >= Snap_offset_Y + Main_tilemap_height*Snap_height) return; tile = first_tile = TILE_FOR_COORDS(x,y); rel_x = (x - Snap_offset_X + Snap_width) % Snap_width; rel_y = (y - Snap_offset_Y + Snap_height) % Snap_height; do { int xx,yy; switch(Main_tilemap[tile].Flipped ^ Main_tilemap[first_tile].Flipped) { case 0: // no default: xx = (tile % Main_tilemap_width)*Snap_width+Snap_offset_X + rel_x; yy = (tile / Main_tilemap_width)*Snap_height+Snap_offset_Y + rel_y; break; case 1: // horizontal xx = (tile % Main_tilemap_width)*Snap_width+Snap_offset_X + Snap_width-rel_x-1; yy = (tile / Main_tilemap_width)*Snap_height+Snap_offset_Y + rel_y; break; case 2: // vertical xx = (tile % Main_tilemap_width)*Snap_width+Snap_offset_X + rel_x; yy = (tile / Main_tilemap_width)*Snap_height+Snap_offset_Y + Snap_height - rel_y - 1; break; case 3: // both xx = (tile % Main_tilemap_width)*Snap_width+Snap_offset_X + Snap_width-rel_x-1; yy = (tile / Main_tilemap_width)*Snap_height+Snap_offset_Y + Snap_height - rel_y - 1; break; } if (yy>=Limit_top&&yy<=Limit_bottom&&xx>=Limit_left&&xx<=Limit_right) Pixel_in_current_screen_with_preview(xx,yy,color); else Pixel_in_current_screen(xx,yy,color); tile = Main_tilemap[tile].Next; } while (tile != first_tile); Update_rect(0,0,0,0); } /// int Tile_is_same(int t1, int t2) { byte *bmp1,*bmp2; int y; bmp1 = Main_backups->Pages->Image[Main_current_layer].Pixels+(TILE_Y(t1))*Main_image_width+(TILE_X(t1)); bmp2 = Main_backups->Pages->Image[Main_current_layer].Pixels+(TILE_Y(t2))*Main_image_width+(TILE_X(t2)); for (y=0; y < Snap_height; y++) { if (memcmp(bmp1+y*Main_image_width, bmp2+y*Main_image_width, Snap_width)) return 0; } return 1; } /// int Tile_is_same_flipped_x(int t1, int t2) { byte *bmp1,*bmp2; int y, x; bmp1 = Main_backups->Pages->Image[Main_current_layer].Pixels+(TILE_Y(t1))*Main_image_width+(TILE_X(t1)); bmp2 = Main_backups->Pages->Image[Main_current_layer].Pixels+(TILE_Y(t2))*Main_image_width+(TILE_X(t2)+Snap_width-1); for (y=0; y < Snap_height; y++) { for (x=0; x < Snap_width; x++) if (*(bmp1+y*Main_image_width+x) != *(bmp2+y*Main_image_width-x)) return 0; } return 1; } /// int Tile_is_same_flipped_y(int t1, int t2) { byte *bmp1,*bmp2; int y; bmp1 = Main_backups->Pages->Image[Main_current_layer].Pixels+(TILE_Y(t1))*Main_image_width+(TILE_X(t1)); bmp2 = Main_backups->Pages->Image[Main_current_layer].Pixels+(TILE_Y(t2)+Snap_height-1)*Main_image_width+(TILE_X(t2)); for (y=0; y < Snap_height; y++) { if (memcmp(bmp1+y*Main_image_width, bmp2-y*Main_image_width, Snap_width)) return 0; } return 1; } /// int Tile_is_same_flipped_xy(int t1, int t2) { byte *bmp1,*bmp2; int y, x; bmp1 = Main_backups->Pages->Image[Main_current_layer].Pixels+(TILE_Y(t1))*Main_image_width+(TILE_X(t1)); bmp2 = Main_backups->Pages->Image[Main_current_layer].Pixels+(TILE_Y(t2)+Snap_height-1)*Main_image_width+(TILE_X(t2)+Snap_width-1); for (y=0; y < Snap_height; y++) { for (x=0; x < Snap_width; x++) if (*(bmp1+y*Main_image_width+x) != *(bmp2-y*Main_image_width-x)) return 0; } return 1; } /// Create or update a tilemap based on current screen (layer)'s pixels. void Tilemap_update(void) { int width; int height; int tile; int count=1; T_Tile * tile_ptr; int wait_window=0; byte old_cursor=0; if (!Main_tilemap_mode) return; width=(Main_image_width-Snap_offset_X)/Snap_width; height=(Main_image_height-Snap_offset_Y)/Snap_height; if (width<1 || height<1 || width*height>1000000l || (tile_ptr=(T_Tile *)malloc(width*height*sizeof(T_Tile))) == NULL) { // Cannot enable tilemap because either the image is too small // for the grid settings (and I don't want to implement partial tiles) // Or the number of tiles seems unreasonable (one million) : This can // happen if you set grid 1x1 for example. Disable_main_tilemap(); return; } if (Main_tilemap) { // Recycle existing tilemap free(Main_tilemap); Main_tilemap=NULL; } Main_tilemap=tile_ptr; Main_tilemap_width=width; Main_tilemap_height=height; if (width*height > 1000 || Config.Tilemap_show_count) { wait_window=1; old_cursor=Cursor_shape; Open_window(180,36,"Creating tileset"); Print_in_window(26, 20, "Please wait...",MC_Black,MC_Light); Cursor_shape=CURSOR_SHAPE_HOURGLASS; Update_window_area(0,0,Window_width, Window_height); Display_cursor(); Get_input(0); } // Initialize array with all tiles unique by default for (tile=0; tile */ #include #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "engine.h" #include "readline.h" #include "buttons.h" #include "pages.h" #include "help.h" #include "sdlscreen.h" #include "errors.h" #include "op_c.h" #include "windows.h" #include "input.h" #include "palette.h" #include "shade.h" byte Palette_view_is_RGB = 1; // Indique si on est en HSL ou en RGB float Gamma = 1.0; // Coordinates of the color count (on histogram button) static const int COUNT_X = 138; static const int COUNT_Y = 64; // Nombre de graduations pour une composante RGB int RGB_scale = 256; // 24bit //int RGB_scale = 64; // VGA //int RGB_scale = 16; // Amiga //int RGB_scale = 4; // MSX2 //int RGB_scale = 3; // Amstrad CPC // Nombre de graduations pour une composante dans le mode actuel int Color_count=256; // Les composantes vont de 0 (Color_count-1) int Color_max=255; // Le demi-pas est une quantit que l'on ajoute une composante // avant de faire un arrondi par division. int Color_halfstep=0; void Set_palette_RGB_scale(int scale) { if (scale>= 2 && scale <= 256) RGB_scale = scale; } int Get_palette_RGB_scale(void) { return RGB_scale; } void Set_palette_Gamma(int gamma) { Gamma = gamma / 10.0; } /// /// Round a 0-255 RGB component according to the RGB_scale and gamm correction. // The result is a color as similar as possible, but that can be encoded in the // picture colorspace. /// The result is also in the 0-255 range. byte Round_palette_component(byte comp) { // Apply Gamma correction float fc = pow(comp/255.0,Gamma)*255; // Convert to encodable value comp = ceil(fc); comp = (comp*RGB_scale/256+(RGB_scale-(256-1)*RGB_scale/256)/2) * (255/(RGB_scale-1)); // Apply reverse Gamma correction fc = pow(comp/255.0,1/Gamma)*255; return fc; } /// /// Turns a RGB component from 0-(RGB_scale-1) scale to 0-255 and apply reverse // gamma correction. /// The passed value should come from Round_palette_component(), /// otherwise the rounding will be "down". static int Decode_component(int comp) { float res = pow((float)comp/Color_max,1/Gamma)*255; return (int)res; } /// Turns a RGB component from 0-255 to 0-(RGB_scale-1) and apply Gamma correction. static int Encode_component(int comp) { float res = pow(comp/255.0,Gamma)*Color_max; return ceil(res); } /// Compute the component at a given distance from the current one. /// Used by the add/remove and lighten/darken operations. static int Add_encoded(int comp, int offset) { int new = Decode_component(Encode_component(comp)+offset); if (new < 0) new = 0; if (new > 255) new = 255; return new; } // Dfinir les units pour les graduations R G B ou H S V void Component_unit(int count) { Color_count = count; Color_max = count-1; Color_halfstep = 256/count/2; } void Set_HSL(T_Palette start_palette, T_Palette end_palette, byte color, short diff_h, short diff_s, short diff_l) { byte h, s, l; RGB_to_HSL(start_palette[color].R,start_palette[color].G,start_palette[color].B,&h,&s,&l); // La teinte (Hue) est cyclique h=(diff_h+256+h); // Pour les autres (Saturation, Lightness), au lieu d'additionner, // on va faire un ratio, cela utilise mieux la plage de valeurs 0-255 if (diff_s<0) s=(255+diff_s)*s/255; else if (diff_s>0) s=255-(255-diff_s)*(255-s)/255; if (diff_l<0) l=(255+diff_l)*l/255; else if (diff_l>0) l=255-(255-diff_l)*(255-l)/255; HSL_to_RGB(h,s,l,&end_palette[color].R,&end_palette[color].G,&end_palette[color].B); } void Set_red(byte color, short new_color, T_Palette palette) { if (new_color< 0) new_color= 0; if (new_color>255) new_color=255; // Arrondi new_color=Round_palette_component(new_color); palette[color].R=new_color; } void Set_green(byte color, short new_color, T_Palette palette) { if (new_color< 0) new_color= 0; if (new_color>255) new_color=255; // Arrondi new_color=Round_palette_component(new_color); palette[color].G=new_color; } void Set_blue(byte color, short new_color, T_Palette palette) { if (new_color< 0) new_color= 0; if (new_color>255) new_color=255; // Arrondi new_color=Round_palette_component(new_color); palette[color].B=new_color; } void Format_component(byte value, char *str) // Formate une chaine de 4 caractres+\0 : "nnn " { Num2str(value,str,3); str[3]=' '; str[4]='\0'; } void Spread_colors(short start,short end,T_Palette palette) // Modifie la palette pour obtenir un dgrad de couleur entre les deux bornes // passes en paramtre { short start_red; short start_green; short start_blue; short end_red; short end_green; short end_blue; short index; // On vrifie qu'il y ait assez de couleurs entre le dbut et la fin pour // pouvoir faire un dgrad: if ( (start!=end) && (start+1!=end) ) { start_red = Encode_component(palette[start].R); start_green = Encode_component(palette[start].G); start_blue = Encode_component(palette[start].B); end_red = Encode_component(palette[end ].R); end_green = Encode_component(palette[end ].G); end_blue = Encode_component(palette[end ].B); for (index=start+1;index=Window_pos_Y) && (y_pos=Window_pos_X) && (x_posPages->Image_mode != IMAGE_MODE_ANIMATION && Main_backups->Pages->Image_mode != IMAGE_MODE_MODE5) { Remap_general_lowlevel(conversion_table,Main_visible_image.Image,Main_visible_image.Image, Main_image_width,Main_image_height,Main_image_width); } // Remap all layers for (layer=0; layerPages->Nb_layers; layer++) Remap_general_lowlevel(conversion_table,Main_backups->Pages->Image[layer].Pixels,Main_backups->Pages->Image[layer].Pixels,Main_image_width,Main_image_height,Main_image_width); // Remap transparent color Main_backups->Pages->Transparent_color = conversion_table[Main_backups->Pages->Transparent_color]; // On calcule les limites l'cran de l'image if (Main_image_height>=Menu_Y_before_window) end_y=Menu_Y_before_window; else end_y=Main_image_height; if (!Main_magnifier_mode) { if (Main_image_width>=Screen_width) end_x=Screen_width; else end_x=Main_image_width; } else { if (Main_image_width>=Main_separator_position) end_x=Main_separator_position; else end_x=Main_image_width; if ((Main_X_zoom+(Main_image_width*Main_magnifier_factor))>=Screen_width) end_x_mag=Screen_width; else end_x_mag=(Main_X_zoom+(Main_image_width*Main_magnifier_factor)); if (Main_image_height*Main_magnifier_factor>=Menu_Y_before_window) end_y_mag=Menu_Y_before_window; else end_y_mag=Main_image_height*Main_magnifier_factor; } // On doit maintenant faire la traduction l'cran Remap_zone_highlevel(0,0,end_x,end_y,conversion_table); if (Main_magnifier_mode) { Remap_zone_highlevel(Main_separator_position,0,end_x_mag,end_y_mag,conversion_table); // Il peut encore rester le bas de la barre de split remapper si la // partie zoome ne descend pas jusqu'en bas... Remap_zone_highlevel(Main_separator_position,end_y_mag, (Main_separator_position+(SEPARATOR_WIDTH*Menu_factor_X)), Menu_Y_before_window,conversion_table); } // Remappe tous les fonds de fenetre (qui doivent contenir un bout d'cran) Remap_window_backgrounds(conversion_table, 0, Menu_Y_before_window); } void Swap(int with_remap,short block_1_start,short block_2_start,short block_size,T_Palette palette, dword * color_usage) { short pos_1; short pos_2; short end_1; short end_2; byte conversion_table[256]; T_Components temp_palette[256]; dword temp_usage[256]; // On fait une copie de la palette memcpy(temp_palette, palette, sizeof(T_Palette)); // On fait une copie de la table d'used des couleurs memcpy(temp_usage, color_usage, sizeof(dword) * 256); // On commence initialiser la table de conversion un tat o elle ne // fera aucune conversion. for (pos_1=0;pos_1<=255;pos_1++) conversion_table[pos_1]=pos_1; // On calcul les dernires couleurs de chaque bloc. end_1=block_1_start+block_size-1; end_2=block_2_start+block_size-1; if ((block_2_start>=block_1_start) && (block_2_start<=end_1)) { // Le bloc destination commence dans le bloc source. for (pos_1=block_1_start,pos_2=end_1+1;pos_1<=end_2;pos_1++) { // Il faut transformer la couleur pos_1 en pos_2: conversion_table[pos_2]=pos_1; color_usage[pos_1]=temp_usage[pos_2]; palette[pos_1].R=temp_palette[pos_2].R; palette[pos_1].G=temp_palette[pos_2].G; palette[pos_1].B=temp_palette[pos_2].B; // On gre la mise jour de pos_2 if (pos_2==end_2) pos_2=block_1_start; else pos_2++; } } else if ((block_2_start=block_1_start)) { // Le bloc destination dborde dans le bloc source. for (pos_1=block_2_start,pos_2=block_1_start;pos_1<=end_1;pos_1++) { // Il faut transformer la couleur pos_1 en pos_2: conversion_table[pos_2]=pos_1; color_usage[pos_1]=temp_usage[pos_2]; palette[pos_1].R=temp_palette[pos_2].R; palette[pos_1].G=temp_palette[pos_2].G; palette[pos_1].B=temp_palette[pos_2].B; // On gre la mise jour de pos_2 if (pos_2==end_1) pos_2=block_2_start; else pos_2++; } } else { // Le bloc source et le bloc destination sont distincts. for (pos_1=block_1_start,pos_2=block_2_start;pos_1<=end_1;pos_1++,pos_2++) { // Il va falloir permutter la couleur pos_1 avec la couleur pos_2 conversion_table[pos_1]=pos_2; conversion_table[pos_2]=pos_1; // On intervertit le nombre d'used des couleurs pour garder une // cohrence lors d'un ventuel "Zap unused". SWAP_DWORDS(color_usage[pos_1], color_usage[pos_2]) // On fait un changement de teinte: SWAP_BYTES(palette[pos_1].R, palette[pos_2].R) SWAP_BYTES(palette[pos_1].G, palette[pos_2].G) SWAP_BYTES(palette[pos_1].B, palette[pos_2].B) } } if (with_remap) { Remap_image_highlevel(conversion_table); } else { // Restore color usage. Shouldn't have reordered it in the first place. memcpy(color_usage, temp_usage, sizeof(dword) * 256); } } void Set_nice_menu_colors(dword * color_usage,int not_picture) { short index,index2; byte color; byte replace_table[256]; T_Components rgb[4]; short new_colors[4]={255,254,253,252}; // On initialise la table de remplacement for (index=0; index<256; index++) replace_table[index]=index; // On recherche les 4 couleurs les moins utilises dans l'image pour pouvoir // les remplacer par les nouvelles couleurs. for (index2=0; index2<4; index2++) for (index=255; index>=0; index--) { if ((index!=new_colors[0]) && (index!=new_colors[1]) && (index!=new_colors[2]) && (index!=new_colors[3]) && (color_usage[index]new_colors[index+1]) { index2 =new_colors[index]; new_colors[index] =new_colors[index+1]; new_colors[index+1]=index2; color=1; } } } while (color); // On sauvegarde dans rgb les teintes qu'on va remplacer et on met les // couleurs du menu par dfaut for (index=0; index<4; index++) { const T_Components * target_rgb; target_rgb=Favorite_GUI_color(index); color=new_colors[index]; rgb[index].R=Main_palette[color].R; rgb[index].G=Main_palette[color].G; rgb[index].B=Main_palette[color].B; Main_palette[color].R=Round_palette_component(target_rgb->R); Main_palette[color].G=Round_palette_component(target_rgb->G); Main_palette[color].B=Round_palette_component(target_rgb->B); } // Maintenant qu'on a plac notre nouvelle palette, on va chercher quelles // sont les couleurs qui peuvent remplacer les anciennes Hide_cursor(); for (index=0; index<4; index++) replace_table[new_colors[index]]=Best_color_nonexcluded (rgb[index].R,rgb[index].G,rgb[index].B); if (not_picture) { // Remap caused by preview. Only remap screen Remap_zone_highlevel(0,0,Screen_width,Screen_height,replace_table); } else { // On fait un changement des couleurs visibles l'cran et dans l'image Remap_image_highlevel(replace_table); } Display_cursor(); } void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dword * color_usage) { char str[5]; // buffer d'affichage du compteur byte conversion_table[256]; // Table de conversion int color_1; // |_ Variables de balayages int color_2; // | de la palette int best_color_1=0; int best_color_2=0; long difference; long best_difference; dword used; dword best_used; // On commence par initialiser la table de conversion dans un tat o // aucune conversion ne sera effectue. for (color_1=0; color_1<=255; color_1++) conversion_table[color_1]=color_1; // Si on ne connait pas encore le nombre de couleurs utilises, on le // calcule! (!!! La fonction appele Efface puis Affiche le curseur !!!) if ((*used_colors)<0) Update_color_count(used_colors,color_usage); Hide_cursor(); // On tasse la palette vers le dbut parce qu'elle doit ressembler // du Gruyre (et comme Papouille il aime pas le fromage...) // Pour cela, on va scruter la couleur color_1 et se servir de l'indice // color_2 comme position de destination. for (color_1=color_2=0;color_1<=255;color_1++) { if (color_usage[color_1]) { // On commence par s'occuper des teintes de la palette palette[color_2].R=palette[color_1].R; palette[color_2].G=palette[color_1].G; palette[color_2].B=palette[color_1].B; // Ensuite, on met jour le tableau d'occupation des couleurs. color_usage[color_2]=color_usage[color_1]; // On va maintenant s'occuper de la table de conversion: conversion_table[color_1]=color_2; // Maintenant, la place dsigne par color_2 est occupe, alors on // doit passer un indice de destination suivant. color_2++; } } // On met toutes les couleurs inutilises en noir for (;color_2<256;color_2++) { palette[color_2].R=0; palette[color_2].G=0; palette[color_2].B=0; color_usage[color_2]=0; } // Maintenant qu'on a une palette clean, on va boucler en rduisant // le nombre de couleurs jusqu' ce qu'on atteigne le nombre dsir. // (The stop condition is further down) while (1) { // Il s'agit de trouver les 2 couleurs qui se ressemblent le plus // parmis celles qui sont utilises (bien sr) et de les remplacer par // une seule couleur qui est la moyenne pondre de ces 2 couleurs // en fonction de leur utilisation dans l'image. best_difference =26*255*26*255+55*255*255+19*255*19*255; best_used=0x7FFFFFFF; for (color_1=0;color_1<(*used_colors);color_1++) for (color_2=color_1+1;color_2<(*used_colors);color_2++) if (color_1!=color_2) { difference =26*abs((long)palette[color_1].R-palette[color_2].R)* 26*abs((long)palette[color_1].R-palette[color_2].R)+ 55*abs((long)palette[color_1].G-palette[color_2].G)* 55*abs((long)palette[color_1].G-palette[color_2].G)+ 19*abs((long)palette[color_1].B-palette[color_2].B)* 19*abs((long)palette[color_1].B-palette[color_2].B); if (difference<=best_difference) { used=color_usage[color_1]+color_usage[color_2]; if ((differencebest_color_2) { // La color_1 va scroller en arrire. // Donc on transfre son utilisation dans l'utilisation de la // couleur qui la prcde. color_usage[color_1-1]=color_usage[color_1]; // Et on transfre ses teintes dans les teintes de la couleur qui // la prcde. palette[color_1-1].R=palette[color_1].R; palette[color_1-1].G=palette[color_1].G; palette[color_1-1].B=palette[color_1].B; } // Une fois la palette et la table d'utilisation gres, on peut // s'occuper de notre table de conversion. if (conversion_table[color_1]>best_color_2) // La color_1 avait l'intention de se faire remplacer par une // couleur que l'on va (ou que l'on a dj) bouger en arrire. conversion_table[color_1]--; } // On vient d'jecter une couleur, donc on peut mettre jour le nombre // de couleurs utilises. (*used_colors)--; // A la fin, on doit passer (dans la palette) les teintes du dernier // lment de notre ensemble en noir. palette[*used_colors].R=0; palette[*used_colors].G=0; palette[*used_colors].B=0; // Au passage, on va s'assurer que l'on a pas oubli de la mettre une // utilisation nulle. color_usage[*used_colors]=0; // Aprs avoir ject une couleur, on le fait savoir l'utilisateur par // l'intermdiaire du compteur de nombre utilises. Num2str(*used_colors,str,3); Print_in_window(COUNT_X,COUNT_Y,str,MC_Black,MC_Light); } // Maintenant, tous ces calculs doivent tres pris en compte dans la // palette, l'image et l'cran. Remap_image_highlevel(conversion_table); // Et voila pour l'image et l'cran Display_cursor(); } // Position of the numeric values of the R G B sliders static const int NUMERIC_R_X = 216; static const int NUMERIC_G_X = 243; static const int NUMERIC_B_X = 270; static const int NUMERIC_Y = 183; // Position of the whole button static const int NUMERIC_BOX_X = 215; static const int NUMERIC_BOX_Y = 181; static const int NUMERIC_BOX_W = 81; static const int NUMERIC_BOX_H = 12; void Set_palette_slider(T_Scroller_button * slider, word nb_elements, word position, char * value, short x_pos) { slider->Nb_elements=nb_elements; slider->Position=position; Compute_slider_cursor_length(slider); Window_draw_slider(slider); Print_counter(x_pos,NUMERIC_Y,value,MC_Black,MC_Light); } void Display_sliders(T_Scroller_button * red_slider, T_Scroller_button * green_slider, T_Scroller_button * blue_slider, byte block_is_selected, T_Components * palette) { char str[5]; if (block_is_selected) { Set_palette_slider(red_slider,Color_max*2+1,Color_max," 0",NUMERIC_R_X); Set_palette_slider(green_slider,Color_max*2+1,Color_max," 0",NUMERIC_G_X); Set_palette_slider(blue_slider,Color_max*2+1,Color_max," 0",NUMERIC_B_X); } else { byte j1, j2, j3; j1= palette[Fore_color].R; j2= palette[Fore_color].G; j3= palette[Fore_color].B; if (!Palette_view_is_RGB) { RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); } Format_component(Encode_component(j1), str); Set_palette_slider(red_slider,Color_count,Color_max-Encode_component(j1),str,NUMERIC_R_X); Format_component(Encode_component(j2),str); Set_palette_slider(green_slider,Color_count,Color_max-Encode_component(j2),str,NUMERIC_G_X); Format_component(Encode_component(j3),str); Set_palette_slider(blue_slider,Color_count,Color_max-Encode_component(j3),str,NUMERIC_B_X); } } void Draw_all_palette_sliders(T_Scroller_button * red_slider, T_Scroller_button * green_slider, T_Scroller_button * blue_slider, T_Palette palette,byte start,byte end) { char str[5]; Hide_cursor(); // Raffichage des jauges: if (start!=end) { // Dans le cas d'un bloc, tout 0. red_slider->Position =Color_max; Window_draw_slider(red_slider); Print_counter(NUMERIC_R_X,NUMERIC_Y," 0",MC_Black,MC_Light); green_slider->Position =Color_max; Window_draw_slider(green_slider); Print_counter(NUMERIC_G_X,NUMERIC_Y," 0",MC_Black,MC_Light); blue_slider->Position =Color_max; Window_draw_slider(blue_slider); Print_counter(NUMERIC_B_X,NUMERIC_Y," 0",MC_Black,MC_Light); } else { // Dans le cas d'une seule couleur, composantes. byte j1, j2, j3; j1= palette[start].R; j2= palette[start].G; j3= palette[start].B; if (!Palette_view_is_RGB) { RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); } Format_component(Encode_component(j1),str); red_slider->Position=Color_max-Encode_component(j1); Window_draw_slider(red_slider); Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); Format_component(Encode_component(j2),str); green_slider->Position=Color_max-Encode_component(j2); Window_draw_slider(green_slider); Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); Format_component(Encode_component(j3),str); blue_slider->Position=Color_max-Encode_component(j3); Window_draw_slider(blue_slider); Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } Display_cursor(); } int Window_Histogram(unsigned char block_start, unsigned char block_end, dword* color_usage) { int i, j; unsigned int max_count = 0; int old_height=0; int hovered_color=-1; int new_hovered_color; int bar_width; T_Special_button *histo; int clicked_button; /* Draws an histogram of the selected range in a separate window */ if (block_start == block_end) { // only one color selected: auto-detect the range for (block_start=0; block_start!=255; block_start++) if (color_usage[block_start]) break; for (block_end=255; block_end!=0; block_end--) if (color_usage[block_end]) break; } // Normalize the histogram towards the most used color // Step 1 : find the most used color in the range for(i=block_start; i<= block_end; i++) { if(color_usage[i] > max_count) max_count = color_usage[i]; } if (max_count == 0) { Warning_message("All these colors are unused!"); Hide_cursor(); return -1; } Open_window(263, 150, "Histogram"); Window_set_normal_button(120, 130, 42, 14, "Close",-1,1,SDLK_RETURN); Print_in_window(6, 17, "Color:", MC_Dark, MC_Light); Print_in_window(110+12*8, 17, "Pixels", MC_Dark, MC_Light); // Step 2 : draw bars bar_width=256/(block_end-block_start+1); j = 0; for(i=block_start; i<= block_end; i++) { int height = 100*color_usage[i]/max_count; // Don't draw anything if the color is unused if (color_usage[i]!=0) { // Draw at least one pixel if the color is used if (height==0) height=1; Window_rectangle( 3+j*bar_width, 127-height, bar_width, height, i); //if (i == MC_Light) { Window_rectangle( 3+j*bar_width, 126-height, bar_width, 1,MC_Black); //} } // vertical outline if (height>old_height) Window_rectangle( 2+j*bar_width, 126-height, 1, height-old_height+1,MC_Black); else if (old_height>height) Window_rectangle( 3+j*bar_width, 126-old_height, 1, old_height-height+1,MC_Black); old_height=height; j++; } // Last vertical outline if (old_height!=0) Window_rectangle( 3+j*(256/(block_end-block_start+1)), 126-old_height, 1, old_height+1,MC_Black); histo = Window_set_special_button(3, 27, j*bar_width, 100); // 2 Update_window_area(0,0,263,150); Display_cursor(); do { // Find hovered area if (Window_click_in_rectangle(histo->Pos_X,histo->Pos_Y,histo->Pos_X+histo->Width-1,histo->Pos_Y+histo->Height-1)) { short x_pos; x_pos=((short)Mouse_X-Window_pos_X)/Menu_factor_X; new_hovered_color=block_start+(x_pos-histo->Pos_X)/bar_width; } else new_hovered_color=-1; // When changing hovered color, update the info area if (new_hovered_color!=hovered_color) { char str[12]; hovered_color=new_hovered_color; Hide_cursor(); if (hovered_color==-1) { Window_rectangle(6+6*8,17,3*8,7,MC_Light); Update_window_area(6+6*8,17,3*8,7); Window_rectangle(86,17,2*8,8,MC_Light); Update_window_area(86,17,2*8,8); Window_rectangle(110,17,11*8,7,MC_Light); Update_window_area(110,17,11*8,7); } else { Num2str(hovered_color,str ,3); Print_in_window(6+6*8,17,str,MC_Black,MC_Light); Window_rectangle(86,17,2*8,8,hovered_color); Update_window_area(86,17,2*8,8); Num2str(color_usage[hovered_color],str ,11); Print_in_window(110,17,str,MC_Black,MC_Light); } Display_cursor(); } clicked_button=Window_clicked_button(); if (Key == KEY_ESC) clicked_button=1; } while( clicked_button < 1); Close_window(); if (clicked_button==2) { // This is a counter-hack. Close_window() sets Mouse_K to zero // on exit, I don't know why (It will become 1 again if you move // the mouse slightly) // Here I force it back to 1, so that the Wait_end_of_click() // will really wait for a release of mouse button. Mouse_K=1; return hovered_color; } return -1; } void Print_RGB_or_HSL(byte mode) { Print_in_window(224,16,mode?"H":"R",MC_Dark,MC_Light); Print_in_window(251,16,mode?"S":"G",MC_Dark,MC_Light); Print_in_window(278,16,mode?"L":"B",MC_Dark,MC_Light); } void Tag_used_colors(byte color, dword color_usage[]) { word index; for (index=0;index<=255;index++) { short x_pos=Window_palette_button_list->Pos_X+6+((index>>4)*10); short y_pos=Window_palette_button_list->Pos_Y+3+((index&15)* 5); byte col; col=(color&&color_usage[index])?MC_White:MC_Light; Window_rectangle(x_pos+5,y_pos+0,1,5,col); } Update_window_area(Window_palette_button_list->Pos_X+3,Window_palette_button_list->Pos_Y+3,12*16,5*16); } void Button_Palette(void) { static const int BUTTON_PLUS_X = 182; static const int BUTTON_PLUS_Y = 163; static const int BUTTON_MINUS_X = 198; static const int BUTTON_MINUS_Y = 163; // Coordinates of the block that displays Backcolor static const int BGCOLOR_DISPLAY_X = 176; static const int BGCOLOR_DISPLAY_Y = 65; static const int BGCOLOR_DISPLAY_W = 40; static const int BGCOLOR_DISPLAY_H = 96; // Coordinates of the block that displays Forecolor static const int FGCOLOR_DISPLAY_X = 180; static const int FGCOLOR_DISPLAY_Y = 69; static const int FGCOLOR_DISPLAY_W = 32; static const int FGCOLOR_DISPLAY_H = 88; // Coordinates of the Color# static const int COLOR_X = 111; static const int COLOR_Y = 79; static short reduce_colors_number = 256; short temp_color; // Variable pouvant reservir pour diffrents calculs intermdiaires dword temp; byte color,click; // Variables pouvant reservir pour diffrents calculs intermdiaires short clicked_button; word old_mouse_x; word old_mouse_y; byte old_mouse_k; byte block_start; byte block_end; byte first_color; byte last_color; char str[10]; word i; T_Scroller_button * red_slider; T_Scroller_button * green_slider; T_Scroller_button * blue_slider; T_Dropdown_button * reduce_dropdown; T_Dropdown_button * sort_dropdown; byte image_is_backed_up = 0; byte need_to_remap = 0; dword color_usage[256]; short used_colors = -1; // -1 <=> Inconnu byte conversion_table[256]; //T_Components * backup_palette; //T_Components * temp_palette; //T_Components * working_palette; static byte show_used_colors=0; static const int C1_X = 5; static const int C1_W = 45; static const int C2_X = 51; static const int C2_W = 53; static const int C3_X = 105; static const int C3_W = 53; static const int C4_X = 159; static const int C4_W = 53; static const int L1 = 16; static const int L2 = 31; static const int L3 = 46; static const int L4 = 61; backup_palette =(T_Components *)malloc(sizeof(T_Palette)); temp_palette=(T_Components *)malloc(sizeof(T_Palette)); working_palette=(T_Components *)malloc(sizeof(T_Palette)); Component_unit(RGB_scale); Open_window(299, 196,"Palette"); memcpy(working_palette, Main_palette, sizeof(T_Palette)); Palette_edit_step(); Window_set_palette_button(5, 89); // 1 // Frame around the palette sliders //Window_display_frame (172, 63, 122, 129); // Graduation des jauges de couleur Window_rectangle(220,39+32,17,1,MC_Dark); Window_rectangle(247,39+32,17,1,MC_Dark); Window_rectangle(274,39+32,17,1,MC_Dark); Window_rectangle(220,39+64,17,1,MC_Dark); Window_rectangle(247,39+64,17,1,MC_Dark); Window_rectangle(274,39+64,17,1,MC_Dark); Window_rectangle(220,39+96,17,1,MC_Dark); Window_rectangle(247,39+96,17,1,MC_Dark); Window_rectangle(274,39+96,17,1,MC_Dark); // Jauges de couleur red_slider = Window_set_scroller_button(223, 27, 128+24,Color_count,1,Color_max-Decode_component(working_palette[Fore_color].R));// 2 green_slider = Window_set_scroller_button(250, 27, 128+24,Color_count,1,Color_max-Decode_component(working_palette[Fore_color].G));// 3 blue_slider = Window_set_scroller_button(277, 27, 128+24,Color_count,1,Color_max-Decode_component(working_palette[Fore_color].B));// 4 if(Palette_view_is_RGB==1) { Print_RGB_or_HSL(0); Component_unit(RGB_scale); } else { Print_RGB_or_HSL(1); Component_unit(256); } first_color=last_color=block_start=block_end=Fore_color; Tag_color_range(block_start,block_end); // Affichage dans le block de visu de la couleur en cours Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); // Affichage des valeurs de la couleur courante (pour 1 couleur) Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette); Print_in_window(7, COLOR_Y, "Color number:", MC_Dark, MC_Light); Num2str(Fore_color, str, 3); Print_in_window(COLOR_X, COLOR_Y, str, MC_Black, MC_Light); Window_set_normal_button(C4_X,L3,C4_W,14,"Merge" ,0,1,SDLK_m); // 5 Window_set_normal_button(C2_X,L3,C2_W,14,"Gray" ,1,1,SDLK_g); // 6 Window_set_normal_button(C1_X,L1,C1_W,14,"Swap" ,0,1,KEY_NONE); // 7 Window_set_normal_button(C2_X,L1,C2_W,14,"X-Swap" ,1,1,SDLK_x); // 8 Window_set_normal_button(C3_X,L1,C3_W,14,"Copy" ,1,1,SDLK_c); // 9 Window_set_normal_button(C3_X,L3,C3_W,14,"Spread" ,4,1,SDLK_e); // 10 reduce_dropdown = Window_set_dropdown_button(89, L4, 83, 14, 84, "Reduce", 0, 0, 1, RIGHT_SIDE|LEFT_SIDE, 0); // 11 Window_dropdown_add_item(reduce_dropdown, 256, "to uniques"); Window_dropdown_add_item(reduce_dropdown, 128, "to 128"); Window_dropdown_add_item(reduce_dropdown, 64, "to 64"); Window_dropdown_add_item(reduce_dropdown, 32, "to 32"); Window_dropdown_add_item(reduce_dropdown, 16, "to 16"); Window_dropdown_add_item(reduce_dropdown, 8, "to 8"); Window_dropdown_add_item(reduce_dropdown, 4, "to 4"); Window_dropdown_add_item(reduce_dropdown, 2, "to 2"); Window_dropdown_add_item(reduce_dropdown, 0, "Other"); Window_set_normal_button( 5,178,35,14,"Undo" ,1,1,SDLK_u); // 12 Window_set_normal_button(122,178,51,14,"Cancel",0,1,KEY_ESC); // 13 Window_set_normal_button(177,178,35,14,"OK" ,0,1,SDLK_RETURN); // 14 Window_set_normal_button(C4_X,L2,C4_W,14,"Used",0,1,SDLK_d); // 15 Window_set_normal_button(C1_X,L4,83,14,"Zap unused",0,1,SDLK_DELETE);//16 Window_set_repeatable_button(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,1,SDLK_KP_PLUS); // 17 Window_set_repeatable_button(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,1,SDLK_KP_MINUS); // 18 Window_set_normal_button(C1_X,L3,C1_W,14,"Neg" ,1,1,SDLK_n); // 19 Window_set_normal_button(C1_X,L2,C1_W,14,"Flip" ,1,1,SDLK_i); // 20 Window_set_normal_button(C2_X,L2,C2_W,14,"X-Flip" ,5,1,SDLK_v); // 21 // Button without outline (RGB/HSL switch) Window_set_normal_button(NUMERIC_BOX_X,14,81,11,"" ,0,1,SDLK_h); // 22 Window_display_frame_mono(NUMERIC_BOX_X-1,14-1,81+2,11+2,MC_Light); sort_dropdown = Window_set_dropdown_button(C3_X, L2, C3_W, 14, 80, " Sort", 0, 1, 1, RIGHT_SIDE|LEFT_SIDE, 0); // 23 Window_dropdown_add_item(sort_dropdown, 0, "Hue/Light"); Window_dropdown_add_item(sort_dropdown, 1, "Lightness"); Window_dropdown_add_item(sort_dropdown, 2, "Histogram"); Window_set_normal_button(NUMERIC_BOX_X,NUMERIC_BOX_Y,NUMERIC_BOX_W,NUMERIC_BOX_H,"" ,0,1,KEY_NONE); // 24 // Button without outline Window_display_frame_mono(NUMERIC_BOX_X-1,NUMERIC_BOX_Y-1,NUMERIC_BOX_W+2,NUMERIC_BOX_H+2,MC_Light); Window_set_normal_button(C4_X,L1,C4_W,14,"Histo",0,1,KEY_NONE);// 25 Window_set_normal_button( 44,178,35,14,"Load" ,1,1,SDLK_l); // 26 Window_set_normal_button( 83,178,35,14,"Save" ,1,1,SDLK_s); // 27 // Dessin des petits effets spciaux pour les boutons [+] et [-] Draw_thingumajig(BUTTON_PLUS_X-5, BUTTON_PLUS_Y,MC_White,-1); Draw_thingumajig(BUTTON_MINUS_X+16,BUTTON_MINUS_Y,MC_Dark,+1); Display_cursor(); Update_color_count(&used_colors,color_usage); if (show_used_colors) Tag_used_colors(1, color_usage); Update_window_area(0,0,299,196); do { old_mouse_x=Mouse_X; old_mouse_y=Mouse_Y; old_mouse_k=Mouse_K; clicked_button=Window_clicked_button(); switch (clicked_button) { case 0 : // Nulle part break; case -1 : // Hors de la fentre case 1 : // palette if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) { Hide_cursor(); temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); // Right click outside the window if (Mouse_K==RIGHT_SIDE && clicked_button==-1) { if (Back_color!=temp_color) { Back_color=temp_color; // 4 blocks de back_color entourant la fore_color Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); } Display_cursor(); } // Right-click inside the palette else if (Mouse_K==RIGHT_SIDE) { // Contextual menu T_Dropdown_button dropdown; T_Dropdown_choice *item; dropdown.Pos_X =0; dropdown.Pos_Y =0; dropdown.Height =0; dropdown.Dropdown_width=48; dropdown.First_item =NULL; dropdown.Bottom_up =1; Window_dropdown_add_item(&dropdown, 1, "Copy"); Window_dropdown_add_item(&dropdown, 2, "Paste"); item=Dropdown_activate(&dropdown,Mouse_X,Mouse_Y); if (item && item->Number == 1) { // Copy Set_clipboard_colors(block_end+1-block_start,working_palette + block_start); Display_cursor(); } else if (item && item->Number == 2) { // Paste int nb_colors; // Backup Palette_edit_step(); nb_colors = Get_clipboard_colors(working_palette, block_start); if (nb_colors>0) { memcpy(temp_palette,working_palette,sizeof(T_Palette)); Set_palette(working_palette); need_to_remap=1; Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); } else { Display_cursor(); } } else if (Back_color!=temp_color) { // Just select back color Back_color=temp_color; // 4 blocks de back_color entourant la fore_color Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_cursor(); } else { Display_cursor(); } Window_dropdown_clear_items(&dropdown); } else { if (!old_mouse_k) { // On vient de clicker sur une couleur (et une seule) if ( (Fore_color!=temp_color) || (block_start!=block_end) ) { // La couleur en question est nouvelle ou elle annule un // ancien bloc. Il faut donc slectionner cette couleur comme // unique couleur choisie. Fore_color=first_color=last_color=block_start=block_end=temp_color; Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); Update_window_area(COLOR_X,COLOR_Y,56,7); // Affichage des jauges Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Palette_edit_select_range(); } } else { // On maintient le click, on va donc tester si le curseur bouge if (temp_color!=last_color) { // On commence par ordonner la 1re et dernire couleur du bloc if (first_colortemp_color) { block_start=temp_color; block_end=first_color; // Affichage du n de la couleur slectionne Num2str(block_start,str ,3); Num2str(block_end ,str+4,3); str[3]=26; // Flche vers la droite Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,1,NULL); // Affichage dans le block de visu du bloc (dgrad) en cours Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,block_start,block_end); } else { block_start=block_end=first_color; Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); // Affichage du n de la couleur slectionne Window_rectangle(COLOR_X+24,COLOR_Y,32,7,MC_Light); Update_window_area(COLOR_X+24,COLOR_Y,32,7); Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); } // On tagge le bloc (ou la couleur) Tag_color_range(block_start,block_end); } last_color=temp_color; } Display_cursor(); } } break; case 2 : // Jauge rouge Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if(Palette_view_is_RGB) { Set_red(Fore_color,Decode_component(Color_max-red_slider->Position),working_palette); Format_component(Color_max-red_slider->Position,str); } else { HSL_to_RGB( 255-red_slider->Position, 255-green_slider->Position, 255-blue_slider->Position, &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); Format_component((int)255-red_slider->Position,str); } Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) Set_red(i,Add_encoded(temp_palette[i].R, Color_max-red_slider->Position),working_palette); } else { byte greys=0; byte non_greys=0; // Check if the range contains both greys and non-greys for (i=block_start; i<=block_end; i++) if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) non_greys=1; else greys=1; for (i=block_start; i<=block_end; i++) { byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); } } if (red_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-red_slider->Position),str,4); str[0]='-'; } else if (red_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 3 : // Jauge verte Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if(Palette_view_is_RGB) { Set_green (Fore_color,Decode_component(Color_max-green_slider->Position),working_palette); Format_component(Color_max-green_slider->Position,str); } else { HSL_to_RGB( 255-red_slider->Position, 255-green_slider->Position, 255-blue_slider->Position, &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); Format_component((int)255-green_slider->Position,str); } Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) Set_green (i,Add_encoded(temp_palette[i].G, Color_max-green_slider->Position),working_palette); } else { byte greys=0; byte non_greys=0; // Check if the range contains both greys and non-greys for (i=block_start; i<=block_end; i++) if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) non_greys=1; else greys=1; for (i=block_start; i<=block_end; i++) { byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); } } if (green_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-green_slider->Position),str,4); str[0]='-'; } else if (green_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 4 : // Jauge bleue Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if(Palette_view_is_RGB) { Set_blue (Fore_color,Decode_component(Color_max-blue_slider->Position),working_palette); Format_component(Color_max-blue_slider->Position,str); } else { HSL_to_RGB( 255-red_slider->Position, 255-green_slider->Position, 255-blue_slider->Position, &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); Format_component((int)255-blue_slider->Position,str); } Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) Set_blue(i,Add_encoded(temp_palette[i].B, Color_max-blue_slider->Position),working_palette); } else { byte greys=0; byte non_greys=0; // Check if the range contains both greys and non-greys for (i=block_start; i<=block_end; i++) if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) non_greys=1; else greys=1; for (i=block_start; i<=block_end; i++) { byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); } } if (blue_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-blue_slider->Position),str,4); str[0]='-'; } else if (blue_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 5 : // Merge if (block_start!=block_end) { dword sum_r=0, sum_g=0, sum_b=0, used=0; Palette_edit_step(); // Compute weighted average for (i=block_start; i<=block_end; i++) { used+=color_usage[i]; sum_r+=working_palette[i].R * color_usage[i]; sum_g+=working_palette[i].G * color_usage[i]; sum_b+=working_palette[i].B * color_usage[i]; } // Do normal average if no pixels used if (used==0) { sum_r=sum_g=sum_b=used=0; for (i=block_start; i<=block_end; i++) { used+=1; sum_r+=working_palette[i].R; sum_g+=working_palette[i].G; sum_b+=working_palette[i].B; } } for (i=block_start; i<=block_end; i++) { Set_red (i,sum_r/used,working_palette); Set_green(i,sum_g/used,working_palette); Set_blue (i,sum_b/used,working_palette); } } else { temp_color=Wait_click_in_palette(Window_palette_button_list); if (temp_color>=0) { dword sum_r=0, sum_g=0, sum_b=0, used; Palette_edit_step(); // Compute weighted average used=color_usage[temp_color]+color_usage[Fore_color]; if (used) { sum_r=(working_palette[temp_color].R * color_usage[temp_color] + working_palette[Fore_color].R * color_usage[Fore_color]) / used; sum_g=(working_palette[temp_color].G * color_usage[temp_color] + working_palette[Fore_color].G * color_usage[Fore_color]) / used; sum_b=(working_palette[temp_color].B * color_usage[temp_color] + working_palette[Fore_color].B * color_usage[Fore_color]) / used; } else // Normal average { sum_r=(working_palette[temp_color].R+working_palette[Fore_color].R)/2; sum_g=(working_palette[temp_color].G+working_palette[Fore_color].G)/2; sum_b=(working_palette[temp_color].B+working_palette[Fore_color].B)/2; } Set_red (temp_color,sum_r,working_palette); Set_green(temp_color,sum_g,working_palette); Set_blue (temp_color,sum_b,working_palette); Set_red (Fore_color,sum_r,working_palette); Set_green(Fore_color,sum_g,working_palette); Set_blue (Fore_color,sum_b,working_palette); Wait_end_of_click(); } } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // On prpare la "modifiabilit" des nouvelles couleurs Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; break; case 6 : // Grey scale // Backup Palette_edit_step(); // Grey Scale for (i=block_start;i<=block_end;i++) { temp_color=(dword)( ((dword)working_palette[i].R*30) + ((dword)working_palette[i].G*59) + ((dword)working_palette[i].B*11) )/100; Set_red(i,temp_color,working_palette); Set_green (i,temp_color,working_palette); Set_blue (i,temp_color,working_palette); } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // On prpare la "modifiabilit" des nouvelles couleurs Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; break; case 7 : // Swap case 8 : // X-Swap temp_color=Wait_click_in_palette(Window_palette_button_list); if ((temp_color>=0) && (temp_color!=block_start)) { Hide_cursor(); Palette_edit_step(); // On calcule le nombre de couleurs a swapper sans risquer de sortir // de la palette (La var. first_color est utilise pour conomiser 1 var; c'est tout) first_color=(temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color; if (clicked_button==8) // On ne fait de backup de l'image que si on // est en mode X-SWAP. if (!image_is_backed_up) { Backup_layers(LAYER_ALL); image_is_backed_up=1; } Swap(clicked_button==8,block_start,temp_color,first_color,working_palette,color_usage); memcpy(temp_palette,working_palette,sizeof(T_Palette)); // On dplace le bloc vers les modifs: last_color=block_end=temp_color+first_color-1; Fore_color=first_color=block_start=temp_color; // On raffiche le n des bornes du bloc: if (block_start!=block_end) { // Cas d'un bloc multi-couleur Num2str(block_start,str ,3); Num2str(block_end ,str+4,3); str[3]=26; // Flche vers la droite // Affichage dans le block de visu du bloc (dgrad) en cours Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,block_start,block_end); } else { // Cas d'une seule couleur Num2str(Fore_color,str,3); Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); } Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // On tag le bloc (ou la couleur) Tag_color_range(block_start,block_end); if (show_used_colors) Tag_used_colors(1, color_usage); need_to_remap=1; Set_palette(working_palette); Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // En cas de X-Swap, tout l'ecran a pu changer de couleur. if (clicked_button==8) { Palette_edit_step(); // Disable Undo Update_rect(0, 0, Screen_width, Menu_Y_before_window); End_of_modification(); } Wait_end_of_click(); } break; case 9 : // Copy (to other slot) temp_color=Wait_click_in_palette(Window_palette_button_list); if ((temp_color>=0) && (temp_color!=block_start)) { Hide_cursor(); Palette_edit_step(); memcpy(working_palette+temp_color,backup_palette+block_start, ((temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color)*3); memcpy(temp_palette,working_palette,sizeof(T_Palette)); Set_palette(working_palette); // On dplace le bloc vers les modifs: last_color=block_end=((temp_color+block_end-block_start<=255)?(temp_color+block_end-block_start):255); Fore_color=first_color=block_start=temp_color; // On raffiche le n des bornes du bloc: if (block_start!=block_end) { // Cas d'un bloc multi-couleur Num2str(block_start,str ,3); Num2str(block_end ,str+4,3); str[3]=26; // Flche vers la droite // Affichage dans le block de visu du bloc (dgrad) en cours Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,block_start,block_end); } else { // Cas d'une seule couleur Num2str(Fore_color,str,3); Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); } Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // On tag le bloc (ou la couleur) Tag_color_range(block_start,block_end); need_to_remap=1; Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Wait_end_of_click(); } break; case 10 : // Spread if (block_start!=block_end) { Palette_edit_step(); Spread_colors(block_start,block_end,working_palette); } else { temp_color=Wait_click_in_palette(Window_palette_button_list); if (temp_color>=0) { Palette_edit_step(); if (temp_color 256) break; // Cancel reduce_colors_number = choice; } else // Each other dropdown item has a number of colors as id. reduce_colors_number = Window_attribute2; if (reduce_colors_number >= 2) { if (!image_is_backed_up) { Backup_layers(LAYER_ALL); image_is_backed_up = 1; } Reduce_palette(&used_colors, reduce_colors_number, working_palette, color_usage); if ((Config.Safety_colors) && (used_colors<4)) { memcpy(temp_palette, Main_palette, sizeof(T_Palette)); memcpy(Main_palette, working_palette, sizeof(T_Palette)); Set_nice_menu_colors(color_usage, 0); memcpy(working_palette, Main_palette, sizeof(T_Palette)); memcpy(Main_palette, temp_palette, sizeof(T_Palette)); } Set_palette(working_palette); // On dfinit la nouvelle palette Draw_all_palette_sliders(red_slider, green_slider, blue_slider, working_palette, block_start, block_end); memcpy(temp_palette, working_palette, sizeof(T_Palette)); Palette_edit_step(); // Disable Undo End_of_modification(); need_to_remap = 1; } break; case 12: // Undo Palette_edit_undo_redo(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Set_palette(working_palette); need_to_remap=1; break; case 15 : // Used : show usage tags show_used_colors = !show_used_colors; Tag_used_colors(show_used_colors, color_usage); break; case 16 : // Zap unused Palette_edit_step(); if (used_colors==-1) Update_color_count(&used_colors,color_usage); for (i=0; i<256; i++) { if (!color_usage[i]) { temp_color=block_start+(i % (block_end+1-block_start)); working_palette[i].R=backup_palette[temp_color].R; working_palette[i].G=backup_palette[temp_color].G; working_palette[i].B=backup_palette[temp_color].B; } } if ((Config.Safety_colors) && (used_colors<4) && (block_end==block_start)) { memcpy(temp_palette,Main_palette,sizeof(T_Palette)); memcpy(Main_palette,working_palette,sizeof(T_Palette)); Set_nice_menu_colors(color_usage,0); memcpy(working_palette,Main_palette,sizeof(T_Palette)); memcpy(Main_palette,temp_palette,sizeof(T_Palette)); } Set_palette(working_palette); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); need_to_remap=1; break; case 17 : // [+] if (!Palette_view_is_RGB) break; Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if (red_slider->Position) { (red_slider->Position)--; Window_draw_slider(red_slider); Set_red(Fore_color,Decode_component(Color_max-red_slider->Position),working_palette); Format_component(Color_max-red_slider->Position,str); Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (green_slider->Position) { (green_slider->Position)--; Window_draw_slider(green_slider); Set_green (Fore_color,Decode_component(Color_max-green_slider->Position),working_palette); Format_component(Color_max-green_slider->Position,str); Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (blue_slider->Position) { (blue_slider->Position)--; Window_draw_slider(blue_slider); Set_blue (Fore_color,Decode_component(Color_max-blue_slider->Position),working_palette); Format_component(Color_max-blue_slider->Position,str); Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } } else { if (red_slider->Position) { (red_slider->Position)--; Window_draw_slider(red_slider); } if (green_slider->Position) { (green_slider->Position)--; Window_draw_slider(green_slider); } if (blue_slider->Position) { (blue_slider->Position)--; Window_draw_slider(blue_slider); } for (i=block_start; i<=block_end; i++) { Set_red(i,Add_encoded(temp_palette[i].R, Color_max-red_slider->Position),working_palette); Set_green (i,Add_encoded(temp_palette[i].G, Color_max-green_slider->Position),working_palette); Set_blue (i,Add_encoded(temp_palette[i].B, Color_max-blue_slider->Position),working_palette); } // -- red -- if (red_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-red_slider->Position),str,4); str[0]='-'; } else if (red_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- green -- if (green_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-green_slider->Position),str,4); str[0]='-'; } else if (green_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- blue -- if (blue_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-blue_slider->Position),str,4); str[0]='-'; } else if (blue_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 18 : // [-] if (!Palette_view_is_RGB) break; Hide_cursor(); Palette_edit_alter_channel(); if (block_start==block_end) { if (red_slider->PositionPosition)++; Window_draw_slider(red_slider); Set_red(Fore_color,Decode_component(Color_max-red_slider->Position),working_palette); Format_component(Color_max-red_slider->Position,str); Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (green_slider->PositionPosition)++; Window_draw_slider(green_slider); Set_green (Fore_color,Decode_component(Color_max-green_slider->Position),working_palette); Format_component(Color_max-green_slider->Position,str); Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (blue_slider->PositionPosition)++; Window_draw_slider(blue_slider); Set_blue (Fore_color,Decode_component(Color_max-blue_slider->Position),working_palette); Format_component(Color_max-blue_slider->Position,str); Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } } else { if (red_slider->Position<(Color_max*2)) { (red_slider->Position)++; Window_draw_slider(red_slider); } if (green_slider->Position<(Color_max*2)) { (green_slider->Position)++; Window_draw_slider(green_slider); } if (blue_slider->Position<(Color_max*2)) { (blue_slider->Position)++; Window_draw_slider(blue_slider); } for (i=block_start; i<=block_end; i++) { Set_red(i,temp_palette[i].R+Decode_component(Color_max-red_slider->Position),working_palette); Set_green (i,temp_palette[i].G+Decode_component(Color_max-green_slider->Position),working_palette); Set_blue (i,temp_palette[i].B+Decode_component(Color_max-blue_slider->Position),working_palette); } // -- red -- if (red_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-red_slider->Position),str,4); str[0]='-'; } else if (red_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- green -- if (green_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-green_slider->Position),str,4); str[0]='-'; } else if (green_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- blue -- if (blue_slider->Position>Color_max) { // Jauge dans les ngatifs: Num2str(-(Color_max-blue_slider->Position),str,4); str[0]='-'; } else if (blue_slider->PositionPosition ,str,4); str[0]='+'; } else { // Jauge nulle: strcpy(str," 0"); } Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; Display_cursor(); Set_palette(working_palette); break; case 19 : // Negative // Backup Palette_edit_step(); // Negative for (i=block_start;i<=block_end;i++) { Set_red(i,255-working_palette[i].R,working_palette); Set_green (i,255-working_palette[i].G,working_palette); Set_blue (i,255-working_palette[i].B,working_palette); } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Set_palette(working_palette); // On prpare la "modifiabilit" des nouvelles couleurs memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; break; case 20 : // Inversion case 21 : // X-Inversion // Backup Palette_edit_step(); // Not undoable if X-Invert // On initialise la table de conversion for (i=0; i<=255; i++) conversion_table[i]=i; // Inversion for (i=block_start; i < block_start + (block_end-block_start+1)/2;i++) { temp_color=block_end-(i-block_start); Set_red (i,backup_palette[temp_color].R,working_palette); Set_green (i,backup_palette[temp_color].G,working_palette); Set_blue (i,backup_palette[temp_color].B,working_palette); Set_red (temp_color,backup_palette[i].R,working_palette); Set_green (temp_color,backup_palette[i].G,working_palette); Set_blue (temp_color,backup_palette[i].B,working_palette); if (clicked_button==21) { conversion_table[i]=temp_color; conversion_table[temp_color]=i; temp=color_usage[i]; color_usage[i]=color_usage[temp_color]; color_usage[temp_color]=temp; } } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // Si on est en X-Invert, on remap l'image (=> on fait aussi 1 backup) if (clicked_button==21) { if (!image_is_backed_up) { Backup_layers(LAYER_ALL); image_is_backed_up=1; } Hide_cursor(); Remap_image_highlevel(conversion_table); Display_cursor(); End_of_modification(); Palette_edit_step(); // Disable Undo } // On prpare la "modifiabilit" des nouvelles couleurs Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; break; case 22 : // HSL <> RGB // Acte les changements en cours sur une ou plusieurs couleurs Palette_edit_select_range(); Hide_cursor(); Palette_view_is_RGB = !Palette_view_is_RGB; if(! Palette_view_is_RGB) { // On passe en HSL Print_RGB_or_HSL(1); Component_unit(256); // Display the + and - button as disabled Window_draw_normal_bouton(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,0); Window_draw_normal_bouton(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,0); } else { // On passe en RGB Print_RGB_or_HSL(0); Component_unit(RGB_scale); // Display the + and - button as enabled Window_draw_normal_bouton(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,1); Window_draw_normal_bouton(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,1); } Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette); Display_cursor(); Update_window_area(BUTTON_PLUS_X-1,BUTTON_PLUS_Y-1,14,14); Update_window_area(BUTTON_MINUS_X-1,BUTTON_MINUS_Y-1,14,14); break; case 23 : // Sort palette { byte h = 0, l = 0, s=0; byte oh=0,ol=0,os=0; // Valeur pour la couleur prcdente int swap=1; byte remap_table[256]; byte inverted_table[256]; byte begin, end; long lightness; long old_lightness; if(block_start==block_end) { begin = 0; end = 255; } else { begin = block_start; end = block_end; } // Init remap table for (i=0;i<256;i++) remap_table[i]=i; // Make a backup because remapping is an undoable modification if (!image_is_backed_up) { Backup_layers(LAYER_ALL); image_is_backed_up=1; } if(Window_attribute2==0) // Sort by Hue (H) and Lightness (L) while(swap==1) { swap=0; h=0;l=255;s=0; for(temp_color=begin;temp_color<=end;temp_color++) { oh=h; ol=l; os=s; RGB_to_HSL(working_palette[temp_color].R, working_palette[temp_color].G, working_palette[temp_color].B,&h,&s,&l); if( ((s==0) && (os>0)) // A grey is before a saturated color || ((s>0 && os > 0) && (hol))) // 2 saturated colors: sort by H, then by L || ((os==0 && s==0) && l>ol)) // Two greys: sort by L only { // Swap color with the previous one SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R) SWAP_BYTES(working_palette[temp_color].G, working_palette[temp_color-1].G) SWAP_BYTES(working_palette[temp_color].B, working_palette[temp_color-1].B) SWAP_DWORDS(color_usage[temp_color], color_usage[temp_color-1]) SWAP_BYTES(remap_table[temp_color], remap_table[temp_color-1]) swap=1; } } } else if(Window_attribute2==1) // Sort only on perceived lightness while(swap==1) { swap=0; lightness=Perceptual_lightness(working_palette+begin); for(temp_color=begin+1;temp_color<=end;temp_color++) { old_lightness=lightness; lightness=Perceptual_lightness(working_palette+temp_color); if(lightness>old_lightness) { // Swap color with the previous one SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R) SWAP_BYTES(working_palette[temp_color].G, working_palette[temp_color-1].G) SWAP_BYTES(working_palette[temp_color].B, working_palette[temp_color-1].B) SWAP_DWORDS(color_usage[temp_color], color_usage[temp_color-1]) SWAP_BYTES(remap_table[temp_color], remap_table[temp_color-1]) swap=1; } } } else // Sort by color usage in histogram while(swap==1) { swap=0; lightness=color_usage[begin]; for(temp_color=begin+1;temp_color<=end;temp_color++) { old_lightness=lightness; lightness=color_usage[temp_color]; if(lightness>old_lightness) { // Swap color with the previous one SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R) SWAP_BYTES(working_palette[temp_color].G, working_palette[temp_color-1].G) SWAP_BYTES(working_palette[temp_color].B, working_palette[temp_color-1].B) SWAP_DWORDS(color_usage[temp_color], color_usage[temp_color-1]) SWAP_BYTES(remap_table[temp_color], remap_table[temp_color-1]) swap=1; } } } for (i=0;i<256;i++) inverted_table[remap_table[i]]=i; Remap_image_highlevel(inverted_table); // Maintenant, tous ces calculs doivent tres pris en compte dans la // palette, l'image et l'cran. Set_palette(working_palette); Palette_edit_step(); // Disable Undo End_of_modification(); need_to_remap=1; } break; case 24: // R G B value: Hex entry { char str[7]; unsigned int new_color; Hide_cursor(); Print_in_window(NUMERIC_BOX_X+2,NUMERIC_BOX_Y+2,"Hex",MC_Black,MC_Light); // Clear out remaining area Window_rectangle(NUMERIC_BOX_X+1+3*8,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-3-3*8, NUMERIC_BOX_H-3,MC_Light); Update_window_area(NUMERIC_BOX_X+1+3*8,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-3-3*8, NUMERIC_BOX_H-3); str[0]='\0'; Display_cursor(); if (Readline(NUMERIC_BOX_X+NUMERIC_BOX_W-2-6*8, NUMERIC_BOX_Y+2, str, 6, INPUT_TYPE_HEXA)) { int length = strlen(str); short new_red, new_blue, new_green; if (length==3 || length==6) { sscanf(str, "%x", &new_color); if (length==3) { new_color = ((new_color&0xF00)*0x1100) | ((new_color&0x0F0)*0x110) | ((new_color&0x00F)*0x11); } new_red=(new_color&0xFF0000) >> 16; new_green=(new_color&0x00FF00) >> 8; new_blue=(new_color&0x0000FF); // Backup Palette_edit_step(); // Assign color for (i=block_start;i<=block_end;i++) { Set_red(i,new_red,working_palette); Set_green (i,new_green,working_palette); Set_blue (i,new_blue,working_palette); } // On prpare la "modifiabilit" des nouvelles couleurs Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); need_to_remap=1; } } // Clear out numeric area Window_rectangle(NUMERIC_BOX_X+1,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-2, NUMERIC_BOX_H-2,MC_Light); Update_window_area(NUMERIC_BOX_X+1,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-2, NUMERIC_BOX_H-2); Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); } break; case 25: // Number of colors used: Open histogram { int selected_col; selected_col=Window_Histogram(block_start, block_end, color_usage); if (selected_col!=-1) { // Tag selected color Fore_color=first_color=last_color=block_start=block_end=selected_col; Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); Update_window_area(COLOR_X,COLOR_Y,56,7); // Affichage des jauges Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Palette_edit_select_range(); } Display_cursor(); Input_sticky_control=0; Wait_end_of_click(); break; } case 26: // Load palette (TODO) break; case 27: // Save palette Save_picture(CONTEXT_PALETTE); break; } if (!Mouse_K) { if (Key) { if (Is_shortcut(Key,SPECIAL_PREVIOUS_FORECOLOR)) // Dcaler Forecolor vers la gauche { if (block_start==block_end) { Fore_color--; first_color--; last_color--; block_start--; block_end--; Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Hide_cursor(); Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Display_cursor(); } Key=0; } else if (Is_shortcut(Key,SPECIAL_NEXT_FORECOLOR)) // Dcaler Forecolor vers la droite { if (block_start==block_end) { Fore_color++; first_color++; last_color++; block_start++; block_end++; Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Hide_cursor(); Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Display_cursor(); } Key=0; } else if (Is_shortcut(Key,SPECIAL_PREVIOUS_BACKCOLOR)) { Back_color--; Hide_cursor(); Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_cursor(); Key=0; } else if (Is_shortcut(Key,SPECIAL_NEXT_BACKCOLOR)) { Back_color++; Hide_cursor(); Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_cursor(); Key=0; } else if (Key == SDLK_BACKSPACE) // Remise des couleurs du menu l'tat normal en essayant // de ne pas trop modifier l'image. { if (!image_is_backed_up) { Backup_layers(LAYER_ALL); image_is_backed_up=1; } if (used_colors==-1) Update_color_count(&used_colors, color_usage); Palette_edit_step(); memcpy(temp_palette,Main_palette,sizeof(T_Palette)); memcpy(Main_palette,working_palette,sizeof(T_Palette)); Set_nice_menu_colors(color_usage,0); memcpy(working_palette,Main_palette,sizeof(T_Palette)); memcpy(Main_palette,temp_palette,sizeof(T_Palette)); Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Update_color_count(&used_colors,color_usage); // End_of_modification(); // Not really needed, the change was in palette entries need_to_remap=1; Key=0; } else if (Is_shortcut(Key,0x100+BUTTON_COLORPICKER)) { // Rcupration d'une couleur derrire le menu Get_color_behind_window(&color,&click); if (click) { Hide_cursor(); if (click==RIGHT_SIDE) { if (Back_color!=color) { Back_color=color; // 4 blocks de back_color entourant la fore_color Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); } } else { Fore_color=first_color=last_color=block_start=block_end=color; Tag_color_range(block_start,block_end); // Affichage du n de la couleur slectionne Window_rectangle(COLOR_X+24,COLOR_Y,32,7,MC_Light); Update_window_area(COLOR_X+24,COLOR_Y,32,7); Num2str(Fore_color,str,3); Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Palette_edit_select_range(); } Display_cursor(); Wait_end_of_click(); } Key=0; } else if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Key=0; Window_help(BUTTON_PALETTE, NULL); } else if (Is_shortcut(Key,0x100+BUTTON_PALETTE)) { // Close (confirm) clicked_button=14; } else if (Key == SHORTCUT_COPY) { Set_clipboard_colors(block_end+1-block_start,working_palette + block_start); } else if (Key == SHORTCUT_PASTE) { int nb_colors; Hide_cursor(); // Backup Palette_edit_step(); nb_colors = Get_clipboard_colors(working_palette, block_start); if (nb_colors>0) { memcpy(temp_palette,working_palette,sizeof(T_Palette)); Set_palette(working_palette); need_to_remap=1; Display_cursor(); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); } } } if (need_to_remap) { Hide_cursor(); Compute_optimal_menu_colors(working_palette); // On remappe brutalement Remap_screen_after_menu_colors_change(); // Puis on remet les trucs qui ne devaient pas changer Window_draw_palette_bouton(5,89); if (show_used_colors) Tag_used_colors(1, color_usage); Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H,Back_color); Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,block_start,block_end); Update_window_area(8,82,16*10,5*16); Display_cursor(); need_to_remap=0; } } } while ((clicked_button!=13) && (clicked_button!=14)); if (clicked_button==14) // Sortie par OK { if ( (!image_is_backed_up) && memcmp(Main_palette,working_palette,sizeof(T_Palette)) ) Backup_layers(LAYER_NONE); memcpy(Main_palette,working_palette,sizeof(T_Palette)); End_of_modification(); // Not really needed, the change was in palette entries } Compute_optimal_menu_colors(Main_palette); // La variable employe ici n'a pas vraiment de rapport avec son nom... need_to_remap=(Window_pos_Y+(Window_height*Menu_factor_Y)Position = (rgb_scale_slider->Position < 128) ? rgb_scale_slider->Position * 2 : 256; Num2str(rgb_scale_slider->Position,str,3); Print_in_window(RGBScale_X,RGBScale_Y,str,MC_Black,MC_Light); Window_draw_slider(rgb_scale_slider); break; case 10: // /2 RGB scale rgb_scale_slider->Position = (rgb_scale_slider->Position <= 2) ? 1 : (rgb_scale_slider->Position)/2; Num2str(rgb_scale_slider->Position,str,3); Print_in_window(RGBScale_X,RGBScale_Y,str,MC_Black,MC_Light); Window_draw_slider(rgb_scale_slider); break; case 11: // Gamma slider Num2str(Window_attribute2,str,2); Hide_cursor(); Print_in_window(178,99,str,MC_Black,MC_Light); Display_cursor(); break; } } while (clicked_button!=1 && clicked_button!=2 && clicked_button!=3 && clicked_button!=4); // We need to get the sliders positions before closing the window, because they will be freed. palette_cols=256-columns_slider->Position; palette_lines=16-lines_slider->Position; rgb_scale=rgb_scale_slider->Position; gamma=gamma_slider->Position/10.f; Close_window(); Unselect_button(BUTTON_PALETTE); Display_cursor(); if (clicked_button==4) // Cancel return; if (palette_vertical != Config.Palette_vertical) { Config.Palette_vertical=palette_vertical; palette_needs_redraw=1; } if (palette_cols!=Config.Palette_cells_X || palette_lines!=Config.Palette_cells_Y) { Config.Palette_cells_X = palette_cols; Config.Palette_cells_Y = palette_lines; palette_needs_redraw=1; } if (rgb_scale!=RGB_scale || gamma != Gamma) { Gamma = gamma; Set_palette_RGB_scale(rgb_scale); Set_palette(Main_palette); Compute_optimal_menu_colors(Main_palette); } if (clicked_button==1) { Menu_tag_colors("Tag colors to exclude",Exclude_color,&dummy,1, NULL, SPECIAL_EXCLUDE_COLORS_MENU); } else if (clicked_button==2) { // Open the menu with Shade settings. Same as the shortcut, except // that this will not activate shade mode on exit. Shade_settings_menu(); } if (palette_needs_redraw) { Change_palette_cells(); Display_menu(); Display_sprite_in_menu(BUTTON_PAL_LEFT,Config.Palette_vertical?MENU_SPRITE_VERTICAL_PALETTE_SCROLL:-1); Draw_menu_button(BUTTON_PAL_LEFT,BUTTON_RELEASED); Draw_menu_button(BUTTON_PAL_RIGHT,BUTTON_RELEASED); } } // ========= Clipboard management ============== int Palette_clipboard_count=0; T_Palette Palette_clipboard; /// Put some colors in the clipboard. /// @param nb_colors Number of colors to push /// @param colors First color of the input array void Set_clipboard_colors(int nb_colors, T_Components *colors) { Palette_clipboard_count=nb_colors; if (nb_colors) { memcpy(Palette_clipboard, colors, nb_colors*sizeof(T_Components)); } } /// Get some RGB colors from clipboard. /// @param palette Target palette /// @param start_color Index of first color to replace /// @return Number of colors retrieved (0-256) int Get_clipboard_colors(T_Palette palette, byte start_color) { int nb_colors = Palette_clipboard_count; if (nb_colors==0) return 0; if (start_color+nb_colors > 256) { nb_colors=256-start_color; } memcpy(palette+start_color, Palette_clipboard, nb_colors*sizeof(T_Components)); return nb_colors; } /// Get the favorite color to use for GUI's black,dark,light or white. const T_Components * Favorite_GUI_color(byte color_index) { static const T_Components cpc_colors[4] = { { 0, 0, 0}, { 0, 0,128}, // Dark blue {128,128,128}, // Grey {255,255,255} }; if (RGB_scale==3) { // Check if ALL GUI colors are compatible with /rgb 3 int i; for (i=0; i<4; i++) { T_Components col; col=Gfx->Default_palette[Gfx->Color[i]]; if ((col.R!=255 && col.R!=128 && col.R!=0) ||(col.G!=255 && col.G!=128 && col.G!=0) ||(col.B!=255 && col.B!=128 && col.B!=0)) // Specialized colors for CPC palette return &cpc_colors[color_index]; } // Skin has suitable colors return &(Gfx->Default_palette[Gfx->Color[color_index]]); } else // Should be Config.Fav_menu_colors[index] if using user colors return &(Gfx->Default_palette[Gfx->Color[color_index]]); } grafx2_2.4+git20180105/src/misc.c0000664000000000000000000005471213223665306014637 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include #include #include "struct.h" #include "sdlscreen.h" #include "global.h" #include "errors.h" #include "buttons.h" #include "engine.h" #include "misc.h" #include "keyboard.h" #include "sdlscreen.h" #include "windows.h" #include "palette.h" #include "input.h" #include "graph.h" #include "pages.h" ///Count used palette indexes in the whole picture ///Return the total number of different colors ///Fill in "usage" with the count for each color word Count_used_colors(dword* usage) { int nb_pixels = 0; Uint8* current_pixel; Uint8 color; word nb_colors = 0; int i; int layer; for (i = 0; i < 256; i++) usage[i]=0; // Compute total number of pixels in the picture nb_pixels = Main_image_height * Main_image_width; // For each layer for (layer = 0; layer < Main_backups->Pages->Nb_layers; layer++) { current_pixel = Main_backups->Pages->Image[layer].Pixels; // For each pixel in picture for (i = 0; i < nb_pixels; i++) { color=*current_pixel; // get color in picture for this pixel usage[color]++; // add it to the counter // go to next pixel current_pixel++; } } // count the total number of unique used colors for (i = 0; i < 256; i++) { if (usage[i]!=0) nb_colors++; } return nb_colors; } /// Same as ::Count_used_colors, but use a block screen memory instead of /// picture data. Used to count colors in the loading screen. word Count_used_colors_screen_area(dword* usage, word start_x, word start_y, word width, word height) { Uint8 color; word x, y; word nb_colors = 0; int i; // Init usage table for (i = 0; i < 256; i++) usage[i]=0; // For each pixel in screen area for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { // Get color in screen memory color=*(Screen_pixels+((start_x + x)+(start_y + y) * Screen_width * Pixel_height) * Pixel_width); usage[color]++; //Un point de plus pour cette couleur } } //On va maintenant compter dans la table les couleurs utilises: for (i = 0; i < 256; i++) { if (usage[i]!=0) nb_colors++; } return nb_colors; } /// Same as ::Count_used_colors, but for a given rectangle in the picture only. /// Used bu the C64 block constraint checker. word Count_used_colors_area(dword* usage, word start_x, word start_y, word width, word height) { Uint8 color; word x, y; word nb_colors = 0; int i; // Init usage table for (i = 0; i < 256; i++) usage[i]=0; // On parcourt l'cran courant pour compter les utilisations des couleurs for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { // Get color from picture color=*(Main_screen+((start_x + x)+(start_y + y)*Main_image_width)); usage[color]++; //Un point de plus pour cette couleur } } //On va maintenant compter dans la table les couleurs utilises: for (i = 0; i < 256; i++) { if (usage[i]!=0) nb_colors++; } return nb_colors; } void Set_palette(T_Palette palette) { register int i; SDL_Color PaletteSDL[256]; for(i=0;i<256;i++) { PaletteSDL[i].r=(palette[i].R=Round_palette_component(palette[i].R)); PaletteSDL[i].g=(palette[i].G=Round_palette_component(palette[i].G)); PaletteSDL[i].b=(palette[i].B=Round_palette_component(palette[i].B)); } SDL_SetPalette(Screen_SDL, SDL_PHYSPAL | SDL_LOGPAL, PaletteSDL,0,256); } void Set_color(byte color, byte red, byte green, byte blue) { SDL_Color comp; comp.r=red; comp.g=green; comp.b=blue; SDL_SetPalette(Screen_SDL, SDL_PHYSPAL | SDL_LOGPAL, &comp, color, 1); } void Wait_end_of_click(void) { // On dsactive tous les raccourcis clavier while(Mouse_K) Get_input(20); } void Clear_current_image_with_stencil(byte color, byte * stencil) //Effacer l'image courante avec une certaine couleur en mode Stencil { int nb_pixels=0; //ECX //al=color //edi=Screen_pixels byte* pixel=Main_backups->Pages->Image[Main_current_layer].Pixels; int i; nb_pixels=Main_image_height*Main_image_width; for(i=0;iPages->Image[Main_current_layer].Pixels, color , Main_image_width * Main_image_height ); } void Init_chrono(dword delay) // Dmarrer le chrono { Timer_delay = delay; Timer_start = SDL_GetTicks()/55; return; } void Pixel_in_brush (word x, word y, byte color) { *(Brush + y * Brush_width + x)=color; } byte Read_pixel_from_brush (word x, word y) { return *(Brush + y * Brush_width + x); } void Ellipse_compute_limites(short horizontal_radius,short vertical_radius) { Ellipse_horizontal_radius_squared = (long)horizontal_radius * horizontal_radius; Ellipse_vertical_radius_squared = (long)vertical_radius * vertical_radius; Ellipse_limit = (qword)Ellipse_horizontal_radius_squared * Ellipse_vertical_radius_squared; } // FIXME: move to graph.c, it's the only caller byte Pixel_in_ellipse(void) { qword ediesi = (qword)Ellipse_cursor_X * Ellipse_cursor_X * Ellipse_vertical_radius_squared + (qword)Ellipse_cursor_Y * Ellipse_cursor_Y * Ellipse_horizontal_radius_squared; if((ediesi) <= Ellipse_limit) return 255; return 0; } // FIXME: move to graph.c, it's the only caller byte Pixel_in_circle(void) { if(Circle_cursor_X * Circle_cursor_X + Circle_cursor_Y * Circle_cursor_Y <= Circle_limit) return 255; return 0; } void Copy_part_of_image_to_another(byte * source,word source_x,word source_y,word width,word height,word source_width,byte * dest,word dest_x,word dest_y,word destination_width) { // ESI = adresse de la source en (S_Pox_X,source_y) byte* esi = source + source_y * source_width + source_x; // EDI = adresse de la destination (dest_x,dest_y) byte* edi = dest + dest_y * destination_width + dest_x; int line; // Pour chaque ligne for (line=0;line < height; line++) { memcpy(edi,esi,width); // Passe la ligne suivante esi+=source_width; edi+=destination_width; } } byte Read_pixel_from_spare_screen(word x,word y) { // return *(Spare_screen+y*Spare_image_width+x); // Clipping is required as this can be called with coordinates from main image // (can be a bigger or smaller image) if (x>=Spare_image_width || y>=Spare_image_height) return Spare_backups->Pages->Transparent_color; if (Spare_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION) { return *(Spare_backups->Pages->Image[Spare_current_layer].Pixels + y*Spare_image_width + x); } else { return *(Spare_visible_image.Image + y*Spare_image_width + x); } } void Rotate_90_deg_lowlevel(byte * source, byte * dest, short width, short height) { word x,y; for(y=0;y0;dx--) { // Pour chaque pixel for(cx=width;cx>0;cx--) { *out_buffer = conversion_table[*in_buffer]; in_buffer++; out_buffer++; } in_buffer += buffer_width-width; out_buffer += buffer_width-width; } } void Copy_image_to_brush(short start_x,short start_y,short Brush_width,short Brush_height,word image_width) { byte* src=start_y*image_width+start_x+Main_backups->Pages->Image[Main_current_layer].Pixels; //Adr dpart image (ESI) byte* dest=Brush_original_pixels; //Adr dest brosse (EDI) int dx; for (dx=Brush_height;dx!=0;dx--) //Pour chaque ligne { // On fait une copie de la ligne memcpy(dest,src,Brush_width); // On passe la ligne suivante src+=image_width; dest+=Brush_width; } } byte Read_pixel_from_feedback_screen (word x,word y) { return *(FX_feedback_screen+y*Main_image_width+x); } dword Round_div(dword numerator,dword divisor) { return numerator/divisor; } byte Effect_sieve(word x,word y) { return Sieve[x % Sieve_width][y % Sieve_height]; } void Replace_colors_within_limits(byte * replace_table) { int y; int x; byte* pixel; // Pour chaque ligne : for(y = Limit_top;y <= Limit_bottom; y++) { // Pour chaque pixel sur la ligne : for (x = Limit_left;x <= Limit_right;x ++) { pixel = Main_backups->Pages->Image[Main_current_layer].Pixels+y*Main_image_width+x; *pixel = replace_table[*pixel]; } } } byte Read_pixel_from_backup_screen (word x,word y) { return *(Screen_backup + x + Main_image_width * y); } void Palette_256_to_64(T_Palette palette) { int i; for(i=0;i<256;i++) { palette[i].R = palette[i].R >> 2; palette[i].G = palette[i].G >> 2; palette[i].B = palette[i].B >> 2; } } void Palette_64_to_256(T_Palette palette) { int i; for(i=0;i<256;i++) { palette[i].R = (palette[i].R << 2)|(palette[i].R >> 4); palette[i].G = (palette[i].G << 2)|(palette[i].G >> 4); palette[i].B = (palette[i].B << 2)|(palette[i].B >> 4); } } byte Effect_interpolated_colorize (word x,word y,byte color) { // factor_a = 256*(100-Colorize_opacity)/100 // factor_b = 256*( Colorize_opacity)/100 // // (Couleur_dessous*factor_a+color*facteur_B)/256 // // On place dans ESI 3*Couleur_dessous ( = position de cette couleur dans la // palette des teintes) et dans EDI, 3*color. byte color_under = Read_pixel_from_feedback_screen(x,y); byte blue_under=Main_palette[color_under].B; byte blue=Main_palette[color].B; byte green_under=Main_palette[color_under].G; byte green=Main_palette[color].G; byte red_under=Main_palette[color_under].R; byte red=Main_palette[color].R; // On rcupre les 3 composantes RVB // blue blue = (Factors_inv_table[blue] + Factors_table[blue_under]) / 256; green = (Factors_inv_table[green] + Factors_table[green_under]) / 256; red = (Factors_inv_table[red] + Factors_table[red_under]) / 256; return Best_color(red,green,blue); } byte Effect_additive_colorize (word x,word y,byte color) { byte color_under = Read_pixel_from_feedback_screen(x,y); byte blue_under=Main_palette[color_under].B; byte green_under=Main_palette[color_under].G; byte red_under=Main_palette[color_under].R; byte blue=Main_palette[color].B; byte green=Main_palette[color].G; byte red=Main_palette[color].R; return Best_color( red>red_under?red:red_under, green>green_under?green:green_under, blue>blue_under?blue:blue_under); } byte Effect_substractive_colorize(word x,word y,byte color) { byte color_under = Read_pixel_from_feedback_screen(x,y); byte blue_under=Main_palette[color_under].B; byte green_under=Main_palette[color_under].G; byte red_under=Main_palette[color_under].R; byte blue=Main_palette[color].B; byte green=Main_palette[color].G; byte red=Main_palette[color].R; return Best_color( redTimer_start) Timer_state=1; } void Flip_Y_lowlevel(byte *src, short width, short height) { // ESI pointe sur la partie haute de la brosse // EDI sur la partie basse byte* ESI = src ; byte* EDI = src + (height - 1) *width; byte tmp; word cx; while(ESI < EDI) { // Il faut inverser les lignes pointes par ESI et // EDI ("Brush_width" octets en tout) for(cx = width;cx>0;cx--) { tmp = *ESI; *ESI = *EDI; *EDI = tmp; ESI++; EDI++; } // On change de ligne : // ESI pointe dj sur le dbut de la ligne suivante // EDI pointe sur la fin de la ligne en cours, il // doit pointer sur le dbut de la prcdente... EDI -= 2 * width; // On recule de 2 lignes } } void Flip_X_lowlevel(byte *src, short width, short height) { // ESI pointe sur la partie gauche et EDI sur la partie // droite byte* ESI = src; byte* EDI = src + width - 1; byte* line_start; byte* line_end; byte tmp; word cx; while(ESI0;cx--) { tmp=*ESI; *ESI=*EDI; *EDI=tmp; EDI+=width; ESI+=width; } // On change de colonne // ESI > colonne suivante // EDI > colonne prcdente ESI = line_start + 1; EDI = line_end - 1; } } // Rotate a pixel buffer 180 on itself. void Rotate_180_deg_lowlevel(byte *src, short width, short height) { // ESI pointe sur la partie suprieure de la brosse // EDI pointe sur la partie basse byte* ESI = src; byte* EDI = src + height*width - 1; // EDI pointe sur le dernier pixel de la derniere ligne byte tmp; word cx; // In case of odd height, the algorithm in this function would // miss the middle line, so we do it this way: if (height & 1) { Flip_X_lowlevel(src, width, height); Flip_Y_lowlevel(src, width, height); return; } while(ESI < EDI) { // On change les deux lignes pointes par EDI et // ESI (Brush_width octets) // En mme temps, on change les pixels, donc EDI // pointe sur la FIN de sa ligne for(cx=width;cx>0;cx--) { tmp = *ESI; *ESI = *EDI; *EDI = tmp; EDI--; // Attention ici on recule ! ESI++; } } } void Rescale(byte *src_buffer, short src_width, short src_height, byte *dst_buffer, short dst_width, short dst_height, short x_flipped, short y_flipped) { int offset,line,column; int x_pos_in_brush; // Position courante dans l'ancienne brosse int y_pos_in_brush; int initial_x_pos; // Position X de dbut de parcours de ligne int initial_y_pos; // Position Y de dbut de parcours de ligne int delta_x, delta_y; offset=0; // Calcul de la valeur initiale de y_pos: if (y_flipped) { initial_y_pos=(src_height)-1; // Inversion en Y de la brosse delta_y = -1 * src_height; } else { initial_y_pos=0; // Pas d'inversion en Y de la brosse delta_y = src_height; } // Calcul de la valeur initiale de x_pos pour chaque ligne: if (x_flipped) { initial_x_pos = (src_width)-1; // Inversion en X de la brosse delta_x = -1 * src_width; } else { initial_x_pos = 0; // Pas d'inversion en X de la brosse delta_x = src_width; } // Pour chaque ligne for (line=0;line0;y--) { // Pour chaque ligne memcpy(dest,src,length); memcpy(dest - x_offset,src+length,x_offset); // On passe la ligne suivante dest += Main_image_width; src += Main_image_width; } // On vient de faire le traitement pour otutes les lignes au-dessous de y_offset // Maintenant on traite celles au dessus dest = x_offset + main_dest; for(y = y_offset;y>0;y--) { memcpy(dest,src,length); memcpy(dest - x_offset,src+length,x_offset); dest += Main_image_width; src += Main_image_width; } Update_rect(0,0,0,0); } void Zoom_a_line(byte* original_line, byte* zoomed_line, word factor, word width ) { byte color; word x; // Pour chaque pixel for(x=0;x #elif defined(__macosx__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #if defined(__OpenBSD__) #include #endif #include #include #elif defined(__BEOS__) || defined(__HAIKU__) #include #elif defined(__AROS__) || defined(__amigaos4__) || defined(__MORPHOS__) || defined(__amigaos__) #include #elif defined(__MINT__) #include #include #elif defined(__SKYOS__) #include #else #include // sysinfo() for free RAM #endif #if defined (__MINT__) // atari have two kinds of memory // standard and fast ram void Atari_Memory_free(unsigned long *stRam,unsigned long *ttRam){ *stRam=Mxalloc(-1L,0); *ttRam = Mxalloc(-1L,1); } #else // Indique quelle est la mmoire disponible unsigned long Memory_free(void) { // Memory is no longer relevant. If there is ANY problem or doubt here, // you can simply return 10*1024*1024 (10Mb), to make the "Pages"something // memory allocation functions happy. // However, it is still a good idea to make a proper function if you can... // If Grafx2 thinks the memory is full, weird things may happen. And if memory // ever becomes full and you're still saying there are 10MB free here, the // program will crash without saving any picture backup ! You've been warned... #if defined(__WIN32__) MEMORYSTATUS mstt; mstt.dwLength = sizeof(MEMORYSTATUS); GlobalMemoryStatus(&mstt); return mstt.dwAvailPhys; #elif defined(__macosx__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) int mib[2]; int maxmem; size_t len; mib[0] = CTL_HW; mib[1] = HW_USERMEM; len = sizeof(maxmem); sysctl(mib,2,&maxmem,&len,NULL,0); return maxmem; #elif defined(__HAIKU__) || defined(__BEOS__) int pages; system_info systemInfo; get_system_info(&systemInfo); pages = systemInfo.max_pages - systemInfo.used_pages; return pages * B_PAGE_SIZE; #elif defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) return AvailMem(MEMF_ANY); #elif defined(__linux__) struct sysinfo info; sysinfo(&info); return info.freeram*info.mem_unit; #else // AvailMem is misleading on os4 (os4 caches stuff in memory that you can still allocate) #warning "There is missing code there for your platform ! please check and correct :)" return 10*1024*1024; #endif } #endif // Arrondir un nombre rel la valeur entire la plus proche // TODO : this should probably be replaced with round() from C99... short Round(float value) { short temp=value; if (value>=0) { if ((value-temp)>= 0.5) temp++; } else { if ((value-temp)<=-0.5) temp--; } return temp; } // Arrondir le rsultat d'une division la valeur entire suprieure short Round_div_max(short numerator,short divisor) { if (!(numerator % divisor)) return (numerator/divisor); else return (numerator/divisor)+1; } // Retourne le minimum entre deux nombres int Min(int a,int b) { return (ab)?a:b; } /* Round number n to d decimal points */ double Fround(double n, unsigned d) { double exp; exp = pow(10.0, d); return floor(n * exp + 0.5) / exp; } /// Count number of bits in a word (16bit). /// Based on Wikipedia article for Hamming_weight, it's optimized /// for cases when zeroes are more frequent. int Popcount_word(word x) { word count; for (count=0; x; count++) x &= x-1; return count; } /// Count number of bits in a dword (32bit). /// Based on Wikipedia article for Hamming_weight, it's optimized /// for cases when zeroes are more frequent. int Popcount_dword(dword x) { dword count; for (count=0; x; count++) x &= x-1; return count; } // Fonction retournant le libell d'une mode (ex: " 320x200") char * Mode_label(int mode) { static char str[24]; if (! Video_mode[mode].Fullscreen) return "window"; sprintf(str, "%dx%d", Video_mode[mode].Width, Video_mode[mode].Height); return str; } // Trouve un mode video partir d'une chaine: soit "window", // soit de la forme "320x200" // Renvoie -1 si la chaine n'est pas convertible int Convert_videomode_arg(const char *argument) { // Je suis paresseux alors je vais juste tester les libells int mode_index; for (mode_index=0; mode_index */ #include "struct.h" #include "global.h" #include "hotkeys.h" #ifdef __VBCC__ #define false 0 #define true 1 #endif T_Key_config ConfigKey[NB_SHORTCUTS] = { {0, "Scroll up", "Scrolls the picture up, both in", "magnify and normal mode.", "", false, SDLK_UP, // HAUT 0}, {1, "Scroll down", "Scrolls the picture down, both in", "magnify and normal mode.", "", false, SDLK_DOWN, // BAS 0}, {2, "Scroll left", "Scrolls the picture to the left,", "both in magnify and normal mode.", "", false, SDLK_LEFT, // GAUCHE 0}, {3, "Scroll right", "Scrolls the picture to the right,", "both in magnify and normal mode.", "", false, SDLK_RIGHT, // DROITE 0}, #ifdef GCWZERO #define FAST_MOD MOD_CTRL #else #define FAST_MOD MOD_SHIFT #endif {4, "Faster scroll up", "Used to scroll upwards in the", "picture fast, either in magnify and", "normal mode.", true, SDLK_UP|FAST_MOD, // Shift + Up 0}, {5, "Faster scroll down", "Used to scroll downwards in the", "picture fast, either in magnify and", "normal mode.", true, SDLK_DOWN|FAST_MOD, // Shift + Down 0}, {6, "Faster scroll left", "Used to scroll to the left in the", "picture fast, either in magnify and", "normal mode.", true, SDLK_LEFT|FAST_MOD, // Shift + Left 0}, {7, "Faster scroll right", "Used to scroll to the right in the", "picture fast, either in magnify and", "normal mode.", true, SDLK_RIGHT|FAST_MOD, // Shift + Right 0}, #undef FAST_MOD {8, "Slower scroll up", "Used to scroll upwards in the", "picture pixel by pixel, either in", "magnify and normal mode.", true, SDLK_UP|MOD_ALT, // Alt + Haut 0}, {9, "Slower scroll down", "Used to scroll downwards in the", "picture pixel by pixel, either in", "magnify and normal mode.", true, SDLK_DOWN|MOD_ALT, // Alt + Bas 0}, {10, "Slower scroll left", "Used to scroll to the left in the", "picture pixel by pixel, either in", "magnify and normal mode.", true, SDLK_LEFT|MOD_ALT, // Alt + Gauche 0}, {11, "Slower scroll right", "Used to scroll to the right in the", "picture pixel by pixel, either in", "magnify and normal mode.", true, SDLK_RIGHT|MOD_ALT, // Alt + Droite 0}, {12, "Move mouse cursor 1 pixel up", "Used to simulate a very small mouse", "deplacement up.It's very useful", "when you want ultra-high precision.", true, #ifdef GCWZERO SDLK_UNKNOWN, #else SDLK_UP|MOD_CTRL, // Ctrl + Haut #endif 0}, {13, "Move mouse cursor 1 pixel down", "Used to simulate a very small mouse", "deplacement down.It's very useful", "when you want ultra-high precision.", true, #ifdef GCWZERO SDLK_UNKNOWN, #else SDLK_DOWN|MOD_CTRL, // Ctrl + Bas #endif 0}, {14, "Move mouse cursor 1 pixel left", "Used to simulate a very small mouse", "deplacement left.It's very useful", "when you want ultra-high precision.", true, #ifdef GCWZERO SDLK_UNKNOWN, #else SDLK_LEFT|MOD_CTRL, // Ctrl + Gauche #endif 0}, {15, "Move mouse cursor 1 pixel right", "Used to simulate a very small mouse", "deplacement right.It's very useful", "when you want ultra-high precision.", true, #ifdef GCWZERO SDLK_UNKNOWN, #else SDLK_RIGHT|MOD_CTRL, // Ctrl + Droite #endif 0}, {16, "Simulate left mouse click", "Used to simulate a click with the", "left mouse button. It's useful", "when you want ultra-high precision.", true, #ifdef GCWZERO SDLK_SPACE, // Space #else SDLK_SPACE|MOD_CTRL, // Ctrl + Space #endif 0}, {17, "Simulate right mouse click", "Used to simulate a click with the", "right mouse button.. It's useful", "when you want ultra-high precision.", true, #ifdef GCWZERO SDLK_BACKSPACE, // R-shoulderpad #else SDLK_SPACE|MOD_SHIFT, // Shift + Space #endif 0}, {18, "Show/hide menu toolbars", "Hides all toolbar menus, or shows", "them back.", "", false, SDLK_F10, // F10 0}, {19, "Show/hide cursor", "Switch the cursor display on/off.", "This only works on the \"small cross\"", "and \"hand\" cursors.", true, SDLK_F9, // F9 0}, {20, "Set paintbrush to 1 pixel", "Useful when you want to use a", "\"single-pixel-brush\".", "", true, SDLK_DELETE, // Del 0}, {21, "Paintbrush choice", "Opens a menu where you can choose a", "paintbrush out of 24 predefined", "ones.", true, SDLK_F4, // F4 0}, {22, "Monochrome brush", "Turn your current user-defined brush", "into a single colored one. All non-", "transparent colors are set to FG.", true, SDLK_F4|MOD_SHIFT, // Shift + F4 0}, {23, "Freehand drawing", "Set the drawing mode to the", "classical freehand one.", "", true, SDLK_d, // D 0}, {24, "Switch freehand drawing mode", "Alternates between: continuous,", "discontinuous, point by point,", "and contour fill", true, SDLK_d|MOD_SHIFT, // Shift + D 0}, {25, "Continuous freehand drawing", "Switch directly to continuous", "freehand drawing mode.", "", true, SDLK_d|MOD_CTRL, // Ctrl + D 0}, {26, "Line", "Allows you to draw lines.", "", "", true, SDLK_l, // L 0}, {27, "Knotted lines", "Allows you to draw linked lines.", "This mode can also be called", "\"Polyline\".", true, SDLK_l|MOD_SHIFT, // Shift + L 0}, {28, "Spray", "Allows you to spray brushes", "randomly in the picture.", "", true, SDLK_a, // A (Q en AZERTY) 0}, {29, "Spray menu", "Opens a menu in which you can", "configure the spray flow and size.", "", true, SDLK_a|MOD_SHIFT, // Shift + A 0}, {30, "Flood-fill", "Allows you to fill an area of the", "picture made of pixels of the same", "color.", true, SDLK_f, // F 0}, {124, "Replace color", "This tool replaces all the pixels of", "the clicked color to the fore-color", "or the back-color.", true, SDLK_f|MOD_SHIFT, // Shift + F 0}, {31, "Bezier's curves", "Allows you to draw Bezier's curves.", "", "", true, SDLK_i, // I 0}, {32, "Bezier's curve with 3 or 4 points", "Allows you to choose whether you", "want to draw Bezier's curves with", "3 or 4 points.", true, SDLK_i|MOD_SHIFT, // Shift + I 0}, {33, "Empty rectangle", "Allows you to draw a rectangle using", "the brush.", "", true, SDLK_r, // R 0}, {34, "Filled rectangle", "Allows you to draw a filled", "rectangle.", "", true, SDLK_r|MOD_SHIFT, // Shift + R 0}, {35, "Empty circle", "Allows you to draw a circle using", "the brush.", "", true, SDLK_c, // C 0}, {36, "Empty ellipse", "Allows you to draw an ellipse using", "the brush.", "", true, SDLK_c|MOD_CTRL, // Ctrl + C 0}, {37, "Filled circle", "Allows you to draw a filled circle.", "", "", true, SDLK_c|MOD_SHIFT, // Shift + C 0}, {38, "Filled ellipse", "Allows you to draw a filled ellipse.", "", "", true, SDLK_c|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + C 0}, {39, "Empty polygon", "Allows you to draw a polygon using", "the brush.", "", true, SDLK_n, // N 0}, {40, "Empty \"polyform\"", "Allows you to draw a freehand", "polygon using the brush.", "", true, SDLK_n|MOD_CTRL, // Ctrl + N 0}, {41, "Filled polygon", "Allows you to draw a filled polygon.", "", "", true, SDLK_n|MOD_SHIFT, // Shift + N 0}, {42, "Filled \"polyform\"", "Allows you to draw a filled freehand", "polygon.", "", true, SDLK_n|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + N 0}, {43, "Rectangle with gradation", "Allows you to draw a rectangle with", "a color gradation.", "", true, SDLK_r|MOD_ALT, // Alt + R 0}, {44, "Gradation menu", "Allows you to configure the way", "color gradations are calculated.", "", true, SDLK_g|MOD_ALT, // Alt + G 0}, {45, "Sphere with gradation", "Allows you to draw a rectangle with", "a color gradation.", "", true, SDLK_c|MOD_ALT, // Alt + C 0}, {46, "Ellipse with gradation", "Allows you to draw an ellipse filled", "with a color gradation.", "", true, SDLK_c|MOD_SHIFT|MOD_ALT, // Shift + Alt + C 0}, {47, "Adjust picture", "Allows you to move the whole picture", "Around. What gets out from a side", "reappears on the other.", true, SDLK_KP5, // Kpad5 0}, {48, "Picture effects", "Opens the 'Picture effects' window.", "", "", true, SDLK_KP5|MOD_SHIFT, // Shift + Kpad5 0}, {49, "Drawing effects", "Opens a menu where you can enable/", "disable and configure the drawing", "effects.", true, SDLK_e, // E 0}, {50, "Shade mode", "Enables or disables Shade mode", "", "", true, SDLK_F5, // F5 0}, {51, "Shade menu", "Opens a the menu for Shade settings.", "", "", true, SDLK_F5|MOD_SHIFT, // Shift + F5 0}, {131, "Quick-shade mode", "Enables or disables Quick-shade", "mode.", "", true, SDLK_F5|MOD_CTRL, // Ctrl + F5 0}, {132, "Quick-shade menu", "Opens a the menu for Quick-shade", "settings.", "", true, SDLK_F5|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + F5 0}, {52, "Stencil mode", "Enables or disables Stencil mode.", "", "", true, SDLK_F6, // F6 0}, {53, "Stencil menu", "Opens a the menu for Stencil", "settings.", "", true, SDLK_F6|MOD_SHIFT, // Shift + F6 0}, {54, "Mask mode", "Enables or disables Mask mode.", "", "", true, SDLK_F6|MOD_ALT, // Alt + F6 0}, {55, "Mask menu", "Opens a the menu for Mask settings.", "", "", true, SDLK_F6|MOD_SHIFT|MOD_ALT, // Shift + Alt + F6 0}, {56, "Grid mode", "Enables or disables the Grid mode.", "", "", true, SDLK_g, // G 0}, {57, "Grid menu", "Open a menu where you can configure", "the grid used by Grid mode.", "", true, SDLK_g|MOD_SHIFT, // Shift + G 0}, {58, "Sieve mode", "Enables or disables the Sieve mode.", "", "", true, SDLK_g|MOD_CTRL, // Ctrl + G 0}, {59, "Sieve menu", "Opens a menu where you can configure", "the sieve.", "", true, SDLK_g|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + G 0}, {60, "Invert sieve", "Inverts the pattern defined in the", "Sieve menu.", "", true, SDLK_g|MOD_CTRL|MOD_ALT, // Ctrl + Alt + G 0}, {61, "Colorize mode", "Enables or disables the Colorize", "mode.", "", true, SDLK_F7, // F7 0}, {62, "Colorize menu", "Opens a menu where you can give the", "opacity percentage for Colorize", "mode.", true, SDLK_F7|MOD_SHIFT, // Shift + F7 0}, {63, "Smooth mode", "Enables or disables the Smooth", "mode.", "", true, SDLK_F8, // F8 0}, {123, "Smooth menu", "Opens a menu where you can define", "the Smooth matrix.", "", true, SDLK_F8|MOD_SHIFT, // Shift + F8 0}, {64, "Smear mode", "Enables or disables the Smear mode.", "", "", true, SDLK_F8|MOD_ALT, // Alt + F8 0}, {65, "Tiling mode", "Enables or disables the Tiling", "mode.", "", true, SDLK_b|MOD_ALT, // Alt + B 0}, {66, "Tiling menu", "Opens a menu where you can configure", "the origin of the tiling.", "", true, SDLK_b|MOD_SHIFT|MOD_ALT, // Shift + Alt + B 0}, {206, "Tilemap mode", "Enables or disables the Tilemap", "mode.", "", true, 0, // No key 0}, {207, "Tilemap menu", "Opens a menu where you can configure", "the tilemap settings.", "", true, 0, // No key 0}, {67, "Classical brush grabbing", "Allows you to pick a brush defined", "within a rectangle.", "", true, SDLK_b, // B #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) SDLK_C|MOD_META // Right-Amiga + C #else 0 #endif }, {68, "\"Lasso\" brush grabbing", "Allows you to pick a brush defined", "within a freehand polygon.", "", true, SDLK_b|MOD_CTRL, // Ctrl + B 0}, {69, "Get previous brush back", "Restore the last user-defined brush.", "", "", true, SDLK_b|MOD_SHIFT, // Shift + B 0}, {70, "Horizontal brush flipping", "Reverse brush horizontally.", "", "", true, SDLK_x, // X 0}, {71, "Vertical brush flipping", "Reverse brush vertically.", "", "", true, SDLK_y, // Y 0}, {72, "90 brush rotation", "Rotate the user-defined brush by 90", "(counter-clockwise).", "", true, SDLK_z, // Z (W en AZERTY) 0}, {73, "180 brush rotation", "Rotate the user-defined brush by", "180.", "", true, SDLK_z|MOD_SHIFT, // Shift + Z 0}, {74, "Strech brush", "Allows you to resize the", "user-defined brush.", "", true, SDLK_s, // S 0}, {75, "Distort brush", "Allows you to distort the", "user-defined brush.", "", true, SDLK_s|MOD_SHIFT, // Shift + S 0}, {76, "Outline brush", "Outlines the user-defined brush", "with the fore color.", "", true, SDLK_o, // O 0}, {77, "Nibble brush", "Deletes the borders of the", "user-defined brush.This does the", "opposite of the Outline option.", true, SDLK_o|MOD_SHIFT, // Shift + O 0}, {78, "Get colors from brush", "Copy colors of the spare page that", "are used in the brush.", "", true, SDLK_F11, // F11 0}, {79, "Recolorize brush", "Recolorize the user-defined brush in", "order to get a brush which looks as", "if it was grabbed in the spare page.", true, SDLK_F12, // F12 0}, {80, "Rotate by any angle", "Rotate the brush by an angle that", "you can define.", "", true, SDLK_w, // W (Z en AZERTY) 0}, {81, "Pipette", "Allows you to copy the color of a", "pixel in the picture into the", "foreground or background color.", true, SDLK_BACKQUOTE, // `~ (Key sous le Esc - en AZERTY) 0}, {82, "Swap foreground/background colors", "Invert foreground and background", "colors.", "", true, SDLK_BACKQUOTE|MOD_SHIFT, // Shift + `~ 0}, {83, "Magnifier mode", "Allows you to zoom into the picture.", "", "", true, SDLK_m, // M (, ? sur AZERTY) KEY_MOUSEMIDDLE}, {84, "Zoom factor menu", "Opens a menu where you can choose a", "magnifying factor.", "", true, SDLK_m|MOD_SHIFT, // Shift + M 0}, {85, "Zoom in", "Increase magnifying factor.", "", "", true, SDLK_KP_PLUS, // Grey + KEY_MOUSEWHEELUP}, {86, "Zoom out", "Decrease magnifying factor.", "", "", true, SDLK_KP_MINUS, // Grey - KEY_MOUSEWHEELDOWN}, {87, "Brush effects menu", "Opens a menu which proposes", "different effects on the", "user-defined brush.", true, SDLK_b|MOD_CTRL|MOD_ALT, // Ctrl + Alt + B 0}, {88, "Text", "Opens a menu which permits you to", "type in a character string and", "render it as a brush.", true, SDLK_t, // T 0}, {89, "Screen resolution menu", "Opens a menu where you can choose", "the screen resolution and image", "dimensions.", true, SDLK_RETURN, // Enter 0}, {90, "\"Safety\" resolution", "Resets the resolution to a 'safe'", "mode that should work everywhere:", "usually a 640x400 window.", false, SDLK_RETURN|MOD_SHIFT, // Shift + Enter 0}, {91, "Help and credits", "Opens a window where you can get", "information about the program,", "or contextual help.", true, #ifdef GCWZERO SDLK_TAB, // L-Shoulderpad #else SDLK_F1, // F1 #endif 0}, {92, "Statistics", "Displays miscellaneous more or less", "useful information.", "", true, SDLK_F1|MOD_SHIFT, // Shift + F1 0}, {93, "Jump to spare page", "Swap current page and spare page.", "", "", true, #ifdef GCWZERO SDLK_UNKNOWN, #else SDLK_TAB, // Tab #endif 0}, {94, "Copy current page to spare page", "Copy current page to spare page.", "", "", true, SDLK_TAB|MOD_SHIFT, // Shift + Tab 0}, {95, "Save picture as...", "Opens a file-selector that allows", "you to save your picture with a new", "path-name.", true, SDLK_F2, // F2 #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) SDLK_A|MOD_META // Right-Amiga + A #else 0 #endif }, {96, "Save picture", "Saves your picture with the last", "name you gave it.", "", true, SDLK_F2|MOD_SHIFT, // Shift + F2 #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) SDLK_S|MOD_META // Right-Amiga + S #else 0 #endif }, {97, "Load picture", "Opens a file-selector that allows", "you to load a new picture.", "", true, SDLK_F3, // F3 #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) SDLK_O|MOD_META // Right-Amiga + O #else 0 #endif }, {98, "Re-load picture", "Re-load the current picture. This", "allows you to cancel modifications", "made since last saving.", true, SDLK_F3|MOD_SHIFT, // Shift + F3 0}, {99, "Save brush", "Opens a file-selector that allows", "you to save your current", "user-defined brush.", true, SDLK_F2|MOD_CTRL, // Ctrl + F2 0}, {100, "Load brush", "Opens a file-selector that allows", "you to load a brush.", "", true, SDLK_F3|MOD_CTRL, // Ctrl + F3 0}, {101, "Settings", "Opens a menu which permits you to", "modify some parameters of the", "program.", true, SDLK_F10|MOD_SHIFT, // Shift + F10 0}, {102, "Undo (Oops!)", "Cancel the last action which", "modified the picture.", "", true, SDLK_u, // U // Secondary shortcut is button I on the Caanoo, L on the Wiz, unset on others #if defined (__CAANOO__) (KEY_JOYBUTTON+JOY_BUTTON_I) #elif defined (__WIZ__) (KEY_JOYBUTTON+JOY_BUTTON_L) #elif defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) SDLK_Z|MOD_META // Right-Amiga + Z #else 0 #endif // -- }, {103, "Redo", "Redo the last undone action.", "", "", true, SDLK_u|MOD_SHIFT, // Shift + U // Secondary shortcut is button II on the Caanoo, R on the Wiz, unset on others #if defined (__CAANOO__) (KEY_JOYBUTTON+JOY_BUTTON_II) #elif defined (__WIZ__) (KEY_JOYBUTTON+JOY_BUTTON_R) #else 0 #endif // -- }, {133, "Kill", "Kills the current page. It actually", "removes the current page from the", "list of \"Undo\" pages.", true, SDLK_DELETE|MOD_SHIFT, // Shift + Suppr 0}, {104, "Clear page", "Clears the picture with color 0,", "or the transparent color if it's", "a layered image.", true, #ifdef GCWZERO SDLK_UNKNOWN, // BackSpace #else SDLK_BACKSPACE, // BackSpace #endif 0}, {105, "Clear page with backcolor", "Clears the picture with the", "current backcolor.", "", true, SDLK_BACKSPACE|MOD_SHIFT, // Shift + BackSpace 0}, {106, "Quit program", "Allows you to leave the program.", "If modifications were not saved,", "confirmation is asked.", false, SDLK_q, // Q (A en AZERTY) // Secondary shortcut is button Home on the Caanoo, Menu on the Wiz, unset on others #if defined (__CAANOO__) (KEY_JOYBUTTON+JOY_BUTTON_HOME) #elif defined (__WIZ__) (KEY_JOYBUTTON+JOY_BUTTON_MENU) #eif defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) SDLK_Q|MOD_META // Right-Amiga + Q #else 0 #endif // -- }, {107, "Palette menu", "Opens a menu which allows you to", "modify the current palette.", "", true, SDLK_p, // P 0}, {125, "Secondary palette menu", "Opens a menu which allows you to", "define color series and some tagged", "colors.", true, SDLK_p|MOD_SHIFT, // Shift + P 0}, {130, "Exclude colors menu", "Opens a menu which allows you to", "define the colors you don't want to", "use in Smooth and Transparency", true, SDLK_p|MOD_CTRL, // Ctrl + P 0}, {108, "Scroll palette to the left", "Scroll palette in the tool bar to", "the left, column by column.", "", true, SDLK_PAGEUP, // PgUp 0}, {109, "Scroll palette to the right", "Scroll palette in the tool bar to", "the right, column by column.", "", true, SDLK_PAGEDOWN, // PgDn 0}, {110, "Scroll palette to the left faster", "Scroll palette in the tool bar to", "the left, 8 columns by 8 columns.", "", true, SDLK_PAGEUP|MOD_SHIFT, // Shift + PgUp 0}, {111, "Scroll palette to the right faster", "Scroll palette in the tool bar to", "the right, 8 columns by 8 columns.", "", true, SDLK_PAGEDOWN|MOD_SHIFT, // Shift + PgDn 0}, {112, "Center brush attachment point", "Set the attachement of the", "user-defined brush to its center.", "", true, SDLK_KP5|MOD_CTRL, // Ctrl + 5 (pav numrique) 0}, {113, "Top-left brush attachment point", "Set the attachement of the", "user-defined brush to its top-left", "corner.", true, SDLK_HOME|MOD_CTRL, // Ctrl + 7 0}, {114, "Top-right brush attachment point", "Set the attachement of the", "user-defined brush to its top-right", "corner.", true, SDLK_PAGEUP|MOD_CTRL, // Ctrl + 9 0}, {115, "Bottom-left brush attachment point", "Set the attachement of the", "user-defined brush to its", "bottom-left corner.", true, SDLK_END|MOD_CTRL, // Ctrl + 1 0}, {116, "Bottom-right brush attachment point", "Set the attachement of the", "user-defined brush to its", "bottom-right corner.", true, SDLK_PAGEDOWN|MOD_CTRL, // Ctrl + 3 0}, {117, "Next foreground color", "Set the foreground color to the next", "in the palette.", "", true, #ifdef GCWZERO SDLK_RIGHT|MOD_SHIFT, #else SDLK_RIGHTBRACKET, // ] (0x en AZERTY) #endif 0}, {118, "Previous foreground color", "Set the foreground color to the", "previous in the palette.", "", true, #ifdef GCWZERO SDLK_LEFT|MOD_SHIFT, #else SDLK_LEFTBRACKET, // [ (^ en AZERTY) #endif 0}, {119, "Next background color", "Set the background color to the next", "in the palette.", "", true, #ifdef GCWZERO SDLK_DOWN|MOD_SHIFT, #else SDLK_RIGHTBRACKET|MOD_SHIFT, // Shift + ] #endif 0}, {120, "Previous background color", "Set the background color to the", "previous in the palette.", "", true, #ifdef GCWZERO SDLK_UP|MOD_SHIFT, #else SDLK_LEFTBRACKET|MOD_SHIFT, // Shift + [ #endif 0}, {126, "Next user-defined forecolor", "Set the foreground color to the next", "in the user-defined color series.", "", true, SDLK_EQUALS, // "=+" 0}, {127, "Previous user-defined forecolor", "Set the foreground color to the", "previous in the user-defined color", "series.", true, SDLK_MINUS, // "-_" (")" en AZERTY 0}, {128, "Next user-defined backcolor", "Set the background color to the next", "in the user-defined color series.", "", true, SDLK_EQUALS|MOD_SHIFT, // Shift + "=+" 0}, {129, "Previous user-defined backcolor", "Set the background color to the", "previous in the user-defined color", "series.", true, SDLK_MINUS|MOD_SHIFT, // Shift + "-_" (")" en AZERTY 0}, {121, "Shrink paintbrush", "Decrease the width of the paintbrush", "if it is special circle or square.", "", true, SDLK_COMMA, // , < (;. en AZERTY) 0}, {122, "Enlarge paintbrush", "Increase the width of the paintbrush", "if it is special circle or square.", "", true, SDLK_PERIOD, // .> (:/ en AZERTY) 0}, {134, "Effects off", "Turns off all drawing effects. This", "is the same as the 'All off' button", "in the Effects screen", true, SDLK_e|MOD_SHIFT, // Shift-E 0}, {135, "Transparency 10%", "Turns transparency on and sets its", "opacity at 10%.", "", true, SDLK_1, // 1 0}, {136, "Transparency 20%", "Turns transparency on and sets its", "opacity at 20%.", "", true, SDLK_2, // 2 0}, {137, "Transparency 30%", "Turns transparency on and sets its", "opacity at 30%.", "", true, SDLK_3, // 3 0}, {138, "Transparency 40%", "Turns transparency on and sets its", "opacity at 40%.", "", true, SDLK_4, // 4 0}, {139, "Transparency 50%", "Turns transparency on and sets its", "opacity at 50%.", "", true, SDLK_5, // 5 0}, {140, "Transparency 60%", "Turns transparency on and sets its", "opacity at 60%.", "", true, SDLK_6, // 6 0}, {141, "Transparency 70%", "Turns transparency on and sets its", "opacity at 70%.", "", true, SDLK_7, // 7 0}, {142, "Transparency 80%", "Turns transparency on and sets its", "opacity at 80%.", "", true, SDLK_8, // 8 0}, {143, "Transparency 90%", "Turns transparency on and sets its", "opacity at 90%.", "", true, SDLK_9, // 9 0}, {144, "Transparency 0%", "Turns transparency on and sets its", "opacity at 0%.", "", true, SDLK_0, // 0 0}, {145, "Zoom 1:1", "Turns magnifier mode off.", "", "", true, SDLK_1|MOD_CTRL, /* Ctrl + 1 */ 0}, {146, "Zoom 2:1", "Turns magnifier mode on and set its", "factor to 2:1", "", true, SDLK_2|MOD_CTRL, /* Ctrl + 2 */ 0}, {147, "Zoom 3:1", "Turns magnifier mode on and set its", "factor to 3:1", "", true, SDLK_3|MOD_CTRL, /* Ctrl + 3 */ 0}, {148, "Zoom 4:1", "Turns magnifier mode on and set its", "factor to 4:1", "", true, SDLK_4|MOD_CTRL, /* Ctrl + 4 */ 0}, {149, "Zoom 5:1", "Turns magnifier mode on and set its", "factor to 5:1", "", true, SDLK_5|MOD_CTRL, /* Ctrl + 5 */ 0}, {150, "Zoom 6:1", "Turns magnifier mode on and set its", "factor to 6:1", "", true, SDLK_6|MOD_CTRL, /* Ctrl + 6 */ 0}, {151, "Zoom 8:1", "Turns magnifier mode on and set its", "factor to 8:1", "", true, SDLK_7|MOD_CTRL, /* Ctrl + 7 */ 0}, {152, "Zoom 10:1", "Turns magnifier mode on and set its", "factor to 10:1", "", true, SDLK_8|MOD_CTRL, /* Ctrl + 8 */ 0}, {153, "Zoom 12:1", "Turns magnifier mode on and set its", "factor to 12:1", "", true, 0, 0}, {154, "Zoom 14:1", "Turns magnifier mode on and set its", "factor to 14:1", "", true, 0, 0}, {155, "Zoom 16:1", "Turns magnifier mode on and set its", "factor to 16:1", "", true, 0, 0}, {156, "Zoom 18:1", "Turns magnifier mode on and set its", "factor to 18:1", "", true, 0, 0}, {157, "Zoom 20:1", "Turns magnifier mode on and set its", "factor to 20:1", "", true, 0, 0}, {158, "Show/Hide Grid", "Turns on or off the visible grid in ", "the magnified view. Grid cells match", "the size ", true, SDLK_g|MOD_SHIFT|MOD_ALT, // Shift + Alt + G, 0}, {159, "Select layer 1", "Makes the layer 1 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {160, "Toggle layer 1", "Makes layer 1 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {161, "Select layer 2", "Makes the layer 2 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {162, "Toggle layer 2", "Makes layer 2 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {163, "Select layer 3", "Makes the layer 3 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {164, "Toggle layer 3", "Makes layer 3 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {165, "Select layer 4", "Makes the layer 4 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {166, "Toggle layer 4", "Makes layer 4 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {167, "Select layer 5", "Makes the layer 5 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {168, "Toggle layer 5", "Makes layer 5 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {169, "Select layer 6", "Makes the layer 6 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {170, "Toggle layer 6", "Makes layer 6 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {171, "Select layer 7", "Makes the layer 7 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {172, "Toggle layer 7", "Makes layer 7 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {173, "Select layer 8", "Makes the layer 8 visible and", "set it as the active one, where", "you can draw.", true, 0, 0}, {174, "Toggle layer 8", "Makes layer 8 visible or invisible.", "If it's the current active layer,", "toggle all other layers instead.", true, 0, 0}, {175, "Add a layer", "Adds a new layer on top of the", "active one. The new layer is filled", "with transparent color.", true, SDLK_INSERT|MOD_ALT, // Alt + Insert 0}, {209, "Duplicate layer", "Adds a new layer on top of the", "active one. The new layer is a copy", "of the current one.", true, 0, // No shortcut 0}, {176, "Delete a layer", "Delete the current layer.", "You can't delete the last", "layer.", true, SDLK_DELETE|MOD_ALT, // Alt + Delete 0}, {177, "Merge a layer", "Merges the current layer with", "the one directly below it.", "", true, SDLK_END|MOD_ALT, // Alt + End 0}, {178, "Swap layer (up)", "Moves the current layer one position", "up the stack. No effect if already", "on top.", true, SDLK_PAGEUP|MOD_ALT, // Alt + PageUp 0}, {179, "Swap layer (down)", "Moves the current layer one position", "down the stack. No effect if already", "on bottom.", true, SDLK_PAGEDOWN|MOD_ALT, // Alt + PageDown 0}, {180, "Layers menu", "Opens a window with options related", "to layers and image transparency.", "", true, SDLK_HOME|MOD_ALT, // Alt + Home 0}, {181, "Brush factory", "Opens a window where you can run a", "Lua script.", "", true, 0, // No shortcut 0}, {182, "Repeat script", "Re-run the last script selected", "in the Brush factory window.", "", true, 0, // No shortcut 0}, {183, "Double brush size", "Resizes the current user brush", "by doubling width and height.", "", true, SDLK_h|MOD_SHIFT, // Shift+H 0}, {184, "Double brush width", "Resizes the current user brush", "by doubling its width.", "", true, SDLK_x|MOD_SHIFT, // Shift+X 0}, {185, "Double brush height", "Resizes the current user brush", "by doubling its height.", "", true, SDLK_y|MOD_SHIFT, // Shift+Y 0}, {186, "Halve brush size", "Resizes the current user brush", "by halving its width and height", "", true, SDLK_h, // H 0}, {187, "Run script #1", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {188, "Run script #2", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {189, "Run script #3", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {190, "Run script #4", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {191, "Run script #5", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {192, "Run script #6", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {193, "Run script #7", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {194, "Run script #8", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {195, "Run script #9", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {196, "Run script #10", "Runs a recorded Lua script.", "", "", true, 0, // No shortcut 0}, {197, "Toggle color cycling", "Activates or desactivates color", "cycling, if the current image has", "cycling colors. (See gradient menu)", true, SDLK_BACKQUOTE|MOD_CTRL, // Ctrl + `~ 0}, {198, "Format checker", "Performs a format check on the", "current image.", "", true, 0, 0}, {199, "Format checker menu", "Allows you to setup the checks", "performed by the format checker.", "", true, 0, 0}, {200, "Set frame time", "Opens a window where you", "can set the current animation", "frame duration.", true, 0, // No shortcut 0}, {201, "Go to first frame", "Edits the first frame of", "an animation", "", true, 0, // No shortcut 0}, {202, "Go to last frame", "Edits the last frame of", "an animation", "", true, 0, // No shortcut 0}, {203, "Go to previous frame", "Edits the previous frame of", "an animation", "", true, 0, // No shortcut 0}, {204, "Go to next frame", "Edits the next frame of", "an animation", "", true, 0, // No shortcut 0}, {205, "Preview animation", "Runs the current animation.", "", "", true, 0, // No shortcut 0}, {208, "Pan view", "While this key is being held,", "click and drag the mouse to", "pan the view.", true, #ifdef GCWZERO SDLK_F1, // Space #else SDLK_SPACE, // Space #endif 0}, }; word Ordering[NB_SHORTCUTS]= { SPECIAL_SCROLL_UP, // Scroll up SPECIAL_SCROLL_DOWN, // Scroll down SPECIAL_SCROLL_LEFT, // Scroll left SPECIAL_SCROLL_RIGHT, // Scroll right SPECIAL_SCROLL_UP_FAST, // Scroll up faster SPECIAL_SCROLL_DOWN_FAST, // Scroll down faster SPECIAL_SCROLL_LEFT_FAST, // Scroll left faster SPECIAL_SCROLL_RIGHT_FAST, // Scroll right faster SPECIAL_SCROLL_UP_SLOW, // Scroll up slower SPECIAL_SCROLL_DOWN_SLOW, // Scroll down slower SPECIAL_SCROLL_LEFT_SLOW, // Scroll left slower SPECIAL_SCROLL_RIGHT_SLOW, // Scroll right slower SPECIAL_MOUSE_UP, // Emulate mouse up SPECIAL_MOUSE_DOWN, // Emulate mouse down SPECIAL_MOUSE_LEFT, // Emulate mouse left SPECIAL_MOUSE_RIGHT, // Emulate mouse right SPECIAL_CLICK_LEFT, // Emulate mouse click left SPECIAL_CLICK_RIGHT, // Emulate mouse click right 0x100+BUTTON_HIDE, // Show / Hide menus SPECIAL_SHOW_HIDE_CURSOR, // Show / Hide cursor SPECIAL_DOT_PAINTBRUSH, // Paintbrush = "." 0x100+BUTTON_PAINTBRUSHES, // Paintbrush choice 0x200+BUTTON_PAINTBRUSHES, // Monochrome brush 0x100+BUTTON_DRAW, // Freehand drawing 0x200+BUTTON_DRAW, // Switch freehand drawing mode SPECIAL_CONTINUOUS_DRAW, // Continuous freehand drawing 0x100+BUTTON_LINES, // Line 0x200+BUTTON_LINES, // Knotted lines 0x100+BUTTON_AIRBRUSH, // Spray 0x200+BUTTON_AIRBRUSH, // Spray menu 0x100+BUTTON_FLOODFILL, // Floodfill 0x200+BUTTON_FLOODFILL, // Replace color 0x100+BUTTON_CURVES, // Bzier's curves 0x200+BUTTON_CURVES, // Bzier's curve with 3 or 4 points 0x100+BUTTON_RECTANGLES, // Empty rectangle 0x100+BUTTON_FILLRECT, // Filled rectangle 0x100+BUTTON_CIRCLES, // Empty circle 0x200+BUTTON_CIRCLES, // Empty ellipse 0x100+BUTTON_FILLCIRC, // Filled circle 0x200+BUTTON_FILLCIRC, // Filled ellipse 0x100+BUTTON_POLYGONS, // Empty polygon 0x200+BUTTON_POLYGONS, // Empty polyform 0x100+BUTTON_POLYFILL, // Polyfill 0x200+BUTTON_POLYFILL, // Filled polyform 0x100+BUTTON_GRADRECT, // Gradient rectangle 0x200+BUTTON_GRADRECT, // Gradation menu 0x100+BUTTON_SPHERES, // Spheres 0x200+BUTTON_SPHERES, // Gradient ellipses 0x100+BUTTON_ADJUST, // Adjust picture 0x200+BUTTON_ADJUST, // Flip picture menu 0x100+BUTTON_EFFECTS, // Menu des effets SPECIAL_SHADE_MODE, // Shade mode SPECIAL_SHADE_MENU, // Shade menu SPECIAL_QUICK_SHADE_MODE, // Quick-shade mode SPECIAL_QUICK_SHADE_MENU, // Quick-shade menu SPECIAL_STENCIL_MODE, // Stencil mode SPECIAL_STENCIL_MENU, // Stencil menu SPECIAL_MASK_MODE, // Mask mode SPECIAL_MASK_MENU, // Mask menu SPECIAL_GRID_MODE, // Grid mode SPECIAL_GRID_MENU, // Grid menu SPECIAL_SIEVE_MODE, // Sieve mode SPECIAL_SIEVE_MENU, // Sieve menu SPECIAL_INVERT_SIEVE, // Inverser la trame du mode Sieve SPECIAL_COLORIZE_MODE, // Colorize mode SPECIAL_COLORIZE_MENU, // Colorize menu SPECIAL_SMOOTH_MODE, // Smooth mode SPECIAL_SMOOTH_MENU, // Smooth menu SPECIAL_SMEAR_MODE, // Smear mode SPECIAL_TILING_MODE, // Tiling mode SPECIAL_TILING_MENU, // Tiling menu SPECIAL_TILEMAP_MODE, // Tilemap mode SPECIAL_TILEMAP_MENU, // Tilemap menu 0x100+BUTTON_BRUSH, // Pick brush 0x100+BUTTON_POLYBRUSH, // Pick polyform brush 0x200+BUTTON_BRUSH, // Restore brush SPECIAL_FLIP_X, // Flip X SPECIAL_FLIP_Y, // Flip Y SPECIAL_ROTATE_90, // 90 brush rotation SPECIAL_ROTATE_180, // 180 brush rotation SPECIAL_STRETCH, // Stretch brush SPECIAL_DISTORT, // Distort brush SPECIAL_OUTLINE, // Outline brush SPECIAL_NIBBLE, // Nibble brush SPECIAL_GET_BRUSH_COLORS, // Get colors from brush SPECIAL_RECOLORIZE_BRUSH, // Recolorize brush SPECIAL_ROTATE_ANY_ANGLE, // Rotate brush by any angle 0x100+BUTTON_COLORPICKER, // Pipette 0x200+BUTTON_COLORPICKER, // Swap fore/back color 0x100+BUTTON_MAGNIFIER, // Magnifier mode 0x200+BUTTON_MAGNIFIER, // Zoom factor menu SPECIAL_ZOOM_IN, // Zoom in SPECIAL_ZOOM_OUT, // Zoom out 0x100+BUTTON_BRUSH_EFFECTS, // Brush effects menu 0x100+BUTTON_TEXT, // Text 0x100+BUTTON_RESOL, // Resolution menu 0x200+BUTTON_RESOL, // Safety resolution 0x100+BUTTON_HELP, // Help & credits 0x200+BUTTON_HELP, // Statistics 0x100+BUTTON_PAGE, // Go to spare page 0x200+BUTTON_PAGE, // Copy to spare page 0x100+BUTTON_SAVE, // Save as 0x200+BUTTON_SAVE, // Save 0x100+BUTTON_LOAD, // Load 0x200+BUTTON_LOAD, // Re-load SPECIAL_SAVE_BRUSH, // Save brush SPECIAL_LOAD_BRUSH, // Load brush 0x100+BUTTON_SETTINGS, // Settings 0x100+BUTTON_UNDO, // Undo 0x200+BUTTON_UNDO, // Redo 0x100+BUTTON_KILL, // Kill 0x100+BUTTON_CLEAR, // Clear 0x200+BUTTON_CLEAR, // Clear with backcolor 0x100+BUTTON_QUIT, // Quit 0x100+BUTTON_PALETTE, // Palette menu 0x200+BUTTON_PALETTE, // Palette menu secondaire SPECIAL_EXCLUDE_COLORS_MENU, // Exclude colors menu 0x100+BUTTON_PAL_LEFT, // Scroll palette left 0x100+BUTTON_PAL_RIGHT, // Scroll palette right 0x200+BUTTON_PAL_LEFT, // Scroll palette left faster 0x200+BUTTON_PAL_RIGHT, // Scroll palette right faster SPECIAL_CENTER_ATTACHMENT, // Center brush attachement SPECIAL_TOP_LEFT_ATTACHMENT, // Top-left brush attachement SPECIAL_TOP_RIGHT_ATTACHMENT, // Top-right brush attachement SPECIAL_BOTTOM_LEFT_ATTACHMENT, // Bottom-left brush attachement SPECIAL_BOTTOM_RIGHT_ATTACHMENT, // Bottom right brush attachement SPECIAL_NEXT_FORECOLOR, // Next foreground color SPECIAL_PREVIOUS_FORECOLOR, // Previous foreground color SPECIAL_NEXT_BACKCOLOR, // Next background color SPECIAL_PREVIOUS_BACKCOLOR, // Previous background color SPECIAL_NEXT_USER_FORECOLOR, // Next user-defined foreground color SPECIAL_PREVIOUS_USER_FORECOLOR, // Previous user-defined foreground color SPECIAL_NEXT_USER_BACKCOLOR, // Next user-defined background color SPECIAL_PREVIOUS_USER_BACKCOLOR, // Previous user-defined background color SPECIAL_SMALLER_PAINTBRUSH, // Sets paintbrush size: smaller SPECIAL_BIGGER_PAINTBRUSH, // Sets paintbrush size: bigger SPECIAL_EFFECTS_OFF, // Turns off all effects SPECIAL_TRANSPARENCY_1, // Sets transparency level 10% SPECIAL_TRANSPARENCY_2, // Sets transparency level 20% SPECIAL_TRANSPARENCY_3, // Sets transparency level 30% SPECIAL_TRANSPARENCY_4, // Sets transparency level 40% SPECIAL_TRANSPARENCY_5, // Sets transparency level 50% SPECIAL_TRANSPARENCY_6, // Sets transparency level 60% SPECIAL_TRANSPARENCY_7, // Sets transparency level 70% SPECIAL_TRANSPARENCY_8, // Sets transparency level 80% SPECIAL_TRANSPARENCY_9, // Sets transparency level 90% SPECIAL_TRANSPARENCY_0, // Sets transparency level 00% SPECIAL_ZOOM_1, /**< Sets zoom factor to 1:1 (no magnification) */ SPECIAL_ZOOM_2, /**< Sets zoom factor to 2:1 */ SPECIAL_ZOOM_3, /**< Sets zoom factor to 3:1 */ SPECIAL_ZOOM_4, /**< Sets zoom factor to 4:1 */ SPECIAL_ZOOM_5, /**< Sets zoom factor to 5:1 */ SPECIAL_ZOOM_6, /**< Sets zoom factor to 6:1 */ SPECIAL_ZOOM_8, /**< Sets zoom factor to 8:1 */ SPECIAL_ZOOM_10, /**< Sets zoom factor to 10:1 */ SPECIAL_ZOOM_12, /**< Sets zoom factor to 12:1 */ SPECIAL_ZOOM_14, /**< Sets zoom factor to 14:1 */ SPECIAL_ZOOM_16, /**< Sets zoom factor to 16:1 */ SPECIAL_ZOOM_18, /**< Sets zoom factor to 18:1 */ SPECIAL_ZOOM_20, /**< Sets zoom factor to 20:1 */ SPECIAL_SHOW_GRID, SPECIAL_LAYER1_SELECT, SPECIAL_LAYER1_TOGGLE, SPECIAL_LAYER2_SELECT, SPECIAL_LAYER2_TOGGLE, SPECIAL_LAYER3_SELECT, SPECIAL_LAYER3_TOGGLE, SPECIAL_LAYER4_SELECT, SPECIAL_LAYER4_TOGGLE, SPECIAL_LAYER5_SELECT, SPECIAL_LAYER5_TOGGLE, SPECIAL_LAYER6_SELECT, SPECIAL_LAYER6_TOGGLE, SPECIAL_LAYER7_SELECT, SPECIAL_LAYER7_TOGGLE, SPECIAL_LAYER8_SELECT, SPECIAL_LAYER8_TOGGLE, 0x100+BUTTON_LAYER_ADD, 0x200+BUTTON_LAYER_ADD, 0x100+BUTTON_LAYER_REMOVE, 0x100+BUTTON_LAYER_MERGE, 0x100+BUTTON_LAYER_UP, 0x100+BUTTON_LAYER_DOWN, 0x100+BUTTON_LAYER_MENU, 0x200+BUTTON_BRUSH_EFFECTS, SPECIAL_REPEAT_SCRIPT, SPECIAL_BRUSH_DOUBLE, SPECIAL_BRUSH_DOUBLE_WIDTH, SPECIAL_BRUSH_DOUBLE_HEIGHT, SPECIAL_BRUSH_HALVE, SPECIAL_RUN_SCRIPT_1, SPECIAL_RUN_SCRIPT_2, SPECIAL_RUN_SCRIPT_3, SPECIAL_RUN_SCRIPT_4, SPECIAL_RUN_SCRIPT_5, SPECIAL_RUN_SCRIPT_6, SPECIAL_RUN_SCRIPT_7, SPECIAL_RUN_SCRIPT_8, SPECIAL_RUN_SCRIPT_9, SPECIAL_RUN_SCRIPT_10, SPECIAL_CYCLE_MODE, SPECIAL_FORMAT_CHECKER, SPECIAL_FORMAT_CHECKER_MENU, 0x100+BUTTON_ANIM_TIME, 0x100+BUTTON_ANIM_FIRST_FRAME, 0x100+BUTTON_ANIM_LAST_FRAME, 0x100+BUTTON_ANIM_PREV_FRAME, 0x100+BUTTON_ANIM_NEXT_FRAME, 0x100+BUTTON_ANIM_PLAY, // Unused at this time SPECIAL_HOLD_PAN, }; grafx2_2.4+git20180105/src/pversion.c0000664000000000000000000000004213223665306015534 0ustar rootrootchar Program_version[]="2.5wip"; grafx2_2.4+git20180105/src/factory.c0000664000000000000000000022473713223665306015361 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2009-2011 Adrien Destugues Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ /*! \file factory.c * \brief Brush factory - generates brush from lua scripts * * The brush factory allows you to generate brushes with Lua code. */ #include #include "brush.h" #include "buttons.h" #include "engine.h" #include "errors.h" #include "filesel.h" // Get_item_by_index #include "global.h" #include "graph.h" #include "io.h" // find_last_separator #include "misc.h" #include "pages.h" // Backup() #include "readline.h" #include "sdlscreen.h" #include "windows.h" #include "palette.h" #include "input.h" // Is_shortcut() #include "help.h" // Window_help() #include "graph.h" #include "filesel.h" // Read_list_of_drives() #include "realpath.h" #include "setup.h" #include "tiles.h" /// Lua scripts bound to shortcut keys. char * Bound_script[10]; #ifdef __ENABLE_LUA__ #include #include #include #include // for DBL_MAX #include // chdir() #include //for INT_MIN #include // strncpy() /// /// Number of characters for name in fileselector. /// Window is adjusted according to it. #define NAME_WIDTH 34 /// Number of characters for the description block #define DESC_WIDTH ((NAME_WIDTH+2)*8/6) /// Position of fileselector top, in window space #define FILESEL_Y 30 // Work data that can be used during a script static byte * Brush_backup = NULL; static word Brush_backup_width; static word Brush_backup_height; static byte Palette_has_changed; static byte Brush_was_altered; static byte Original_fore_color; static byte Original_back_color; static byte Is_backed_up; static T_Page * Main_backup_page; static byte * Main_backup_screen; static byte Cursor_is_visible; static byte Window_needs_update; /// Helper function to clamp a double to 0-255 range static inline byte clamp_byte(double value) { if (value<0.0) return 0; else if (value>255.0) return 255; else return (byte)value; } /// /// This macro reads a Lua argument into a double or integral lvalue. /// If argument is invalid, it will break the caller and raise a verbose message. /// This macro uses 2 existing symbols: L for the context, and nb_args=lua_gettop(L) /// @param index Index of the argument to check, starting at 1. /// @param func_name The name of the lua callback, to display a message in case of error. /// @param dest Destination lvalue. Can be a double, or any integral type. Conversion will "floor". /// @param min_value Check for minimum value. Pass a double, or if you don't care, -DBL_MAX. /// @param max_value Check for maximum value. Pass a double, or if you don't care, DBL_MAX. #define LUA_ARG_NUMBER(index, func_name, dest, min_value, max_value) \ do { \ double value; \ if (nb_args < (index)) return luaL_error(L, "%s: Argument %d is missing.", func_name, (index)); \ if (!lua_isnumber(L, (index))) return luaL_error(L, "%s: Argument %d is not a number.", func_name, (index)); \ value = lua_tonumber(L, (index)); \ if ((min_value) != -DBL_MAX && value<(min_value)) return luaL_error(L, "%s: Argument %d was too small, it had value of %f and minimum should be %f.", func_name, (index), value, (double)(min_value)); \ if ((max_value) != DBL_MAX && value>(max_value)) return luaL_error(L, "%s: Argument %d was too big, it had value of %f and maximum should be %f.", func_name, (index), value, (double)(max_value)); \ dest = value; \ } while(0) /// /// This macro reads a Lua argument into a string. /// If argument is invalid, it will break the caller and raise a verbose message. /// This macro uses 2 existing symbols: L for the context, and nb_args=lua_gettop(L) /// @param index Index of the argument to check, starting at 1. /// @param func_name The name of the lua callback, to display a message in case of error. /// @param dest Destination string pointer, ideally a const char *. #define LUA_ARG_STRING(index, func_name, dest) \ do { \ if (nb_args < (index)) return luaL_error(L, "%s: Argument %d is missing.", func_name, index); \ if (!lua_isstring(L, (index))) return luaL_error(L, "%s: Argument %d is not a string.", func_name, index); \ dest = lua_tostring(L, (index)); \ } while (0) /// /// This macro reads a Lua argument into a boolean. /// If argument is invalid, it will break the caller and raise a verbose message. /// This macro uses 2 existing symbols: L for the context, and nb_args=lua_gettop(L) /// @param index Index of the argument to check, starting at 1. /// @param func_name The name of the lua callback, to display a message in case of error. /// @param dest Destination variable, any numeric type. #define LUA_ARG_BOOL(index, func_name, dest) \ do { \ if (nb_args < (index)) return luaL_error(L, "%s: Argument %d is missing.", func_name, index); \ if (!lua_isboolean(L, (index))) return luaL_error(L, "%s: Argument %d is not a boolean.", func_name, index); \ dest = lua_toboolean(L, (index)); \ } while (0) /// /// This macro checks that a Lua argument is a function. /// If argument is invalid, it will break the caller and raise a verbose message. /// This macro uses 2 existing symbols: L for the context, and nb_args=lua_gettop(L) /// @param index Index of the argument to check, starting at 1. /// @param func_name The name of the lua callback, to display a message in case of error. #define LUA_ARG_FUNCTION(index, func_name) \ do { \ if (nb_args < (index)) return luaL_error(L, "%s: Argument %d is missing.", func_name, index); \ if (!lua_isfunction(L, (index))) return luaL_error(L, "%s: Argument %d is not a function.", func_name, index); \ } while (0) /// Check if 'num' arguments were provided exactly #define LUA_ARG_LIMIT(num, func_name) \ do { \ if (nb_args != (num)) \ return luaL_error(L, "%s: Expected %d arguments, but found %d.", func_name, (num), nb_args); \ } while(0) /// Declares a function in the form BIND_unsaved() : for example L_PutPicturePixel_unsaved() #define DECLARE_UNSAVED(BIND) \ int BIND ## _unsaved(lua_State* L) \ { \ Backup_if_necessary(L, Main_current_layer); \ Register_main_writable(L); \ return BIND(L); \ } // forward declarations void Register_main_readonly(lua_State* L); void Register_main_writable(lua_State* L); int L_SetColor(lua_State* L); int L_SetColor_unsaved(lua_State* L); // const char * Lua_version(void) { // LUA_RELEASE is only available since 5.2+, with format "Lua x.y.z" // The only version information available since Lua 5.0 is LUA_VERSION, // with the format "Lua x.y" #if defined(LUA_RELEASE) return LUA_RELEASE; #elif defined (LUA_VERSION) return LUA_VERSION; #else return "Unknown"; #endif } // Updates the screen colors after a running screen has modified the palette. void Update_colors_during_script(void) { if (Palette_has_changed) { Set_palette(Main_palette); Compute_optimal_menu_colors(Main_palette); Display_menu(); Palette_has_changed=0; } } /// Paint a pixel in image without updating the screen void Pixel_figure_no_screen(short x_pos,short y_pos,byte color) { if (x_pos>0 && y_pos >0 && x_posPages->Next; Main_backup_screen = Screen_backup; Register_main_writable(L); } } else { if (layer == LAYER_NONE) { // Already OK return; } if (Dup_layer_if_shared(Main_backups->Pages, layer)) { // Depth buffer etc to modify too ? Register_main_writable(L); } } } // Wrapper functions to call C from Lua int L_SetBrushSize(lua_State* L) { int i; int w; int h; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "setbrushsize"); LUA_ARG_NUMBER(1, "setbrushsize", w, 1, 10000); LUA_ARG_NUMBER(2, "setbrushsize", h, 1, 10000); if (Realloc_brush(w, h, NULL, NULL)) { return luaL_error(L, "setbrushsize: Resize failed"); } Brush_was_altered=1; // Fill with Back_color memset(Brush_original_pixels,Back_color,(long)Brush_width*Brush_height); memset(Brush,Back_color,(long)Brush_width*Brush_height); // Adopt the current palette. memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); for (i=0; i<256; i++) Brush_colormap[i]=i; //-- // Center the handle Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); return 0; } int L_GetBrushSize(lua_State* L) { lua_pushinteger(L, Brush_width); lua_pushinteger(L, Brush_height); return 2; } int L_PutBrushPixel(lua_State* L) { int x; int y; uint8_t c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (3, "putbrushpixel"); LUA_ARG_NUMBER(1, "putbrushpixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "putbrushpixel", y, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "putbrushpixel", c, INT_MIN, INT_MAX); if (!Brush_was_altered) { int i; // First time writing in brush: // Adopt the current palette. memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); memcpy(Brush_original_pixels, Brush, Brush_width*Brush_height); for (i=0; i<256; i++) Brush_colormap[i]=i; //-- Brush_was_altered=1; } if (x<0 || y<0 || x>=Brush_width || y>=Brush_height) ; else { Pixel_in_brush(x, y, c); } return 0; // no values returned for lua } int L_GetBrushPixel(lua_State* L) { int x; int y; uint8_t c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getbrushpixel"); LUA_ARG_NUMBER(1, "getbrushpixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getbrushpixel", y, INT_MIN, INT_MAX); if (x<0 || y<0 || x>=Brush_width || y>=Brush_height) { c = Back_color; // Return 'transparent' } else { c = Read_pixel_from_brush(x, y); } lua_pushinteger(L, c); return 1; } int L_GetBrushBackupPixel(lua_State* L) { int x; int y; uint8_t c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getbrushbackuppixel"); LUA_ARG_NUMBER(1, "getbrushbackuppixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getbrushbackuppixel", y, INT_MIN, INT_MAX); if (x<0 || y<0 || x>=Brush_backup_width || y>=Brush_backup_height) { c = Back_color; // Return 'transparent' } else { c = *(Brush_backup + y * Brush_backup_width + x); } lua_pushinteger(L, c); return 1; } int L_SetPictureSize(lua_State* L) { int w; int h; int nb_args=lua_gettop(L); int i; LUA_ARG_LIMIT (2, "setpicturesize"); LUA_ARG_NUMBER(1, "setpicturesize", w, 1, 9999); LUA_ARG_NUMBER(2, "setpicturesize", h, 1, 9999); if (w == Main_image_width && h == Main_image_height) { // nothing to do at all return 0; } if (Is_backed_up) { // Script has already modified pixels or palette : // Resize without counting an additional Undo step. Backup_in_place(w, h); } else { // Script has not modified the image/palette yet, so it's not backed up: // Make a backup that counts as a new Undo step. Backup_with_new_dimensions(w, h); } // part of Resize_image() : the pixel copy part. for (i=0; iPages->Nb_layers; i++) { Copy_part_of_image_to_another( Main_backups->Pages->Next->Image[i].Pixels,0,0,Min(Main_backups->Pages->Next->Width,Main_image_width), Min(Main_backups->Pages->Next->Height,Main_image_height),Main_backups->Pages->Next->Width, Main_backups->Pages->Image[i].Pixels,0,0,Main_image_width); } Redraw_layered_image(); Is_backed_up = 1; Main_backup_page = Main_backups->Pages->Next; Main_backup_screen = Screen_backup; Register_main_writable(L); lua_register(L,"setcolor",L_SetColor); return 0; } int L_SetSparePictureSize(lua_State* L) { int w; int h; int nb_args=lua_gettop(L); int i; LUA_ARG_LIMIT (2, "setsparepicturesize"); LUA_ARG_NUMBER(1, "setsparepicturesize", w, 1, 9999); LUA_ARG_NUMBER(2, "setsparepicturesize", h, 1, 9999); Backup_and_resize_the_spare(w, h); // part of Resize_image() : the pixel copy part. for (i=0; iPages->Nb_layers; i++) { Copy_part_of_image_to_another( Spare_backups->Pages->Next->Image[i].Pixels,0,0,Min(Spare_backups->Pages->Next->Width,Spare_image_width), Min(Spare_backups->Pages->Next->Height,Spare_image_height),Spare_backups->Pages->Next->Width, Spare_backups->Pages->Image[i].Pixels,0,0,Spare_image_width); } Redraw_spare_image(); return 0; } int L_GetPictureSize(lua_State* L) { lua_pushinteger(L, Main_image_width); lua_pushinteger(L, Main_image_height); return 2; } int L_ClearPicture(lua_State* L) { int c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "clearpicture"); LUA_ARG_NUMBER(1, "clearpicture", c, INT_MIN, INT_MAX); if (Stencil_mode && Config.Clear_with_stencil) Clear_current_image_with_stencil(c,Stencil); else Clear_current_image(c); Redraw_layered_image(); return 0; // no values returned for lua } int L_PutPicturePixel(lua_State* L) { int x; int y; int c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (3, "putpicturepixel"); LUA_ARG_NUMBER(1, "putpicturepixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "putpicturepixel", y, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "putpicturepixel", c, INT_MIN, INT_MAX); // Bound check if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height) { // Silently ignored return 0; } Pixel_in_current_screen(x, y, c); return 0; // no values returned for lua } int L_PutSparePicturePixel(lua_State* L) { int x; int y; int c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (3, "putsparepicturepixel"); LUA_ARG_NUMBER(1, "putsparepicturepixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "putsparepicturepixel", y, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "putsparepicturepixel", c, INT_MIN, INT_MAX); // Bound check if (x<0 || y<0 || x>=Spare_image_width || y>=Spare_image_height) { // Silently ignored return 0; } Pixel_in_spare(x, y, c); return 0; // no values returned for lua } int L_DrawLine(lua_State* L) { int x1, y1, x2, y2, c; int nb_args = lua_gettop(L); LUA_ARG_LIMIT(5, "drawline"); LUA_ARG_NUMBER(1, "drawline", x1, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "drawline", y1, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "drawline", x2, INT_MIN, INT_MAX); LUA_ARG_NUMBER(4, "drawline", y2, INT_MIN, INT_MAX); LUA_ARG_NUMBER(5, "drawline", c, INT_MIN, INT_MAX); Pixel_figure = (void (*) (word,word,byte))Pixel_figure_no_screen; Draw_line_general(x1, y1, x2, y2, c); return 0; } int L_DrawFilledRect(lua_State* L) { int x1, y1, x2, y2, c; int min_x,min_y,max_x,max_y, x_pos, y_pos; int nb_args = lua_gettop(L); LUA_ARG_LIMIT(5, "drawfilledrect"); LUA_ARG_NUMBER(1, "drawfilledrect", x1, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "drawfilledrect", y1, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "drawfilledrect", x2, INT_MIN, INT_MAX); LUA_ARG_NUMBER(4, "drawfilledrect", y2, INT_MIN, INT_MAX); LUA_ARG_NUMBER(5, "drawfilledrect", c, INT_MIN, INT_MAX); // Put bounds in ascending order if (x2>x1) { min_x=x1; max_x=x2; } else { min_x=x2; max_x=x1; } if (y2>y1) { min_y=y1; max_y=y2; } else { min_y=y2; max_y=y1; } // Clipping limits if (max_x>Main_image_width) max_x=Main_image_width-1; if (max_y>Main_image_height) max_y=Main_image_height-1; if (min_x<0) min_x=0; if (min_y<0) min_y=0; // Perform drawing for (y_pos=min_y; y_pos<=max_y;y_pos++) for (x_pos=min_x; x_pos<=max_x;x_pos++) Pixel_in_current_screen(x_pos,y_pos,c); return 0; } int L_DrawCircle(lua_State* L) { int x1, y1, r, c; int nb_args = lua_gettop(L); LUA_ARG_LIMIT(4, "drawcircle"); LUA_ARG_NUMBER(1, "drawcircle", x1, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "drawcircle", y1, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "drawcircle", r, INT_MIN, INT_MAX); LUA_ARG_NUMBER(4, "drawcircle", c, INT_MIN, INT_MAX); Pixel_figure = (void (*) (word,word,byte))Pixel_figure_no_screen; Circle_limit = r*r; Draw_empty_circle_general(x1, y1, r, c); return 0; } int L_DrawDisk(lua_State* L) { int center_x, center_y, diameter, c, r, even; long circle_limit; short x_pos,y_pos; short min_x,max_x,min_y,max_y; double r_float; int nb_args = lua_gettop(L); LUA_ARG_LIMIT(4, "drawdisk"); LUA_ARG_NUMBER(1, "drawdisk", center_x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "drawdisk", center_y, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "drawdisk", r_float, INT_MIN, INT_MAX); LUA_ARG_NUMBER(4, "drawdisk", c, INT_MIN, INT_MAX); if (r_float<0.0) return 0; diameter=(int)(floor(r_float*2.0+1.0)); r=diameter/2; even=!(diameter&1); circle_limit = Circle_squared_diameter(diameter); // Compute clipping limits min_x=center_x-r+even<0 ? 0 : center_x-r+even; max_x=center_x+r>=Main_image_width? Main_image_width-1 : center_x+r; min_y=center_y-r+even<0 ? 0 : center_y-r+even; max_y=center_y+r>=Main_image_height? Main_image_height-1 : center_y+r; for (y_pos=min_y;y_pos<=max_y;y_pos++) { short y=(y_pos-center_y)*2-even; for (x_pos=min_x;x_pos<=max_x;x_pos++) { short x=(x_pos-center_x)*2-even; if (x*x+y*y <= circle_limit) Pixel_in_current_screen(x_pos,y_pos,c); } } return 0; } int L_GetPicturePixel(lua_State* L) { int x; int y; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getpicturepixel"); LUA_ARG_NUMBER(1, "getpicturepixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getpicturepixel", y, INT_MIN, INT_MAX); // Bound check if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height) { // Silently return the image's transparent color lua_pushinteger(L, Main_backups->Pages->Transparent_color); return 1; } lua_pushinteger(L, Read_pixel_from_current_screen(x,y)); return 1; } int L_GetBackupPixel(lua_State* L) { int x; int y; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getbackuppixel"); LUA_ARG_NUMBER(1, "getbackuppixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getbackuppixel", y, INT_MIN, INT_MAX); // Bound check if (x<0 || y<0 || x>=Main_backup_page->Width || y>=Main_backup_page->Height) { // Silently return the image's transparent color lua_pushinteger(L, Main_backup_page->Transparent_color); return 1; } // Can't use Read_pixel_from_backup_screen(), because in a Lua script // the "backup" can use a different screen dimension. lua_pushinteger(L, *(Main_backup_screen + x + Main_backup_page->Width * y)); return 1; } int L_GetLayerPixel(lua_State* L) { int x; int y; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getlayerpixel"); LUA_ARG_NUMBER(1, "getlayerpixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getlayerpixel", y, INT_MIN, INT_MAX); // Bound check if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height) { // Silently return the image's transparent color lua_pushinteger(L, Main_backups->Pages->Transparent_color); return 1; } lua_pushinteger(L, Read_pixel_from_current_layer(x,y)); return 1; } // Spare int L_GetSparePictureSize(lua_State* L) { lua_pushinteger(L, Spare_image_width); lua_pushinteger(L, Spare_image_height); return 2; } int L_GetSpareLayerPixel(lua_State* L) { int x; int y; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getsparelayerpixel"); LUA_ARG_NUMBER(1, "getsparelayerpixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getsparelayerpixel", y, INT_MIN, INT_MAX); // Bound check if (x<0 || y<0 || x>=Spare_image_width || y>=Spare_image_height) { // Silently return the image's transparent color lua_pushinteger(L, Spare_backups->Pages->Transparent_color); return 1; } lua_pushinteger(L, *(Spare_backups->Pages->Image[Spare_current_layer].Pixels + y*Spare_image_width + x)); return 1; } int L_GetSparePicturePixel(lua_State* L) { int x; int y; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (2, "getsparepicturepixel"); LUA_ARG_NUMBER(1, "getsparepicturepixel", x, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "getsparepicturepixel", y, INT_MIN, INT_MAX); // Some bound checking is done by the function itself, here's the rest. if (x<0 || y<0) { // Silently return the image's transparent color lua_pushinteger(L, Spare_backups->Pages->Transparent_color); return 1; } lua_pushinteger(L, Read_pixel_from_spare_screen(x,y)); return 1; } int L_GetSpareColor(lua_State* L) { byte c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "getsparecolor"); LUA_ARG_NUMBER(1, "getsparecolor", c, INT_MIN, INT_MAX); lua_pushinteger(L, Spare_palette[c].R); lua_pushinteger(L, Spare_palette[c].G); lua_pushinteger(L, Spare_palette[c].B); return 3; } int L_GetSpareTransColor(lua_State* L) { lua_pushinteger(L, Spare_backups->Pages->Transparent_color); return 1; } int L_SetColor(lua_State* L) { byte c; double r, g, b; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (4, "setcolor"); LUA_ARG_NUMBER(1, "setcolor", c, INT_MIN, INT_MAX); LUA_ARG_NUMBER(2, "setcolor", r, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "setcolor", g, INT_MIN, INT_MAX); LUA_ARG_NUMBER(4, "setcolor", b, INT_MIN, INT_MAX); Main_palette[c].R=Round_palette_component(clamp_byte(r)); Main_palette[c].G=Round_palette_component(clamp_byte(g)); Main_palette[c].B=Round_palette_component(clamp_byte(b)); // Set_color(c, r, g, b); Not needed. Update screen when script is finished Palette_has_changed=1; return 0; } int L_SetColor_unsaved(lua_State* L) { Backup_if_necessary(L, LAYER_NONE); lua_register(L,"setcolor",L_SetColor); return L_SetColor(L); } int L_GetColor(lua_State* L) { byte c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "getcolor"); LUA_ARG_NUMBER(1, "getcolor", c, INT_MIN, INT_MAX); lua_pushinteger(L, Main_palette[c].R); lua_pushinteger(L, Main_palette[c].G); lua_pushinteger(L, Main_palette[c].B); return 3; } int L_GetBackupColor(lua_State* L) { byte c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "getbackupcolor"); LUA_ARG_NUMBER(1, "getbackupcolor", c, INT_MIN, INT_MAX); lua_pushinteger(L, Main_backup_page->Palette[c].R); lua_pushinteger(L, Main_backup_page->Palette[c].G); lua_pushinteger(L, Main_backup_page->Palette[c].B); return 3; } int L_MatchColor(lua_State* L) { double r, g, b; int c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (3, "matchcolor"); LUA_ARG_NUMBER(1, "matchcolor", r, -DBL_MAX, DBL_MAX); LUA_ARG_NUMBER(2, "matchcolor", g, -DBL_MAX, DBL_MAX); LUA_ARG_NUMBER(3, "matchcolor", b, -DBL_MAX, DBL_MAX); c = Best_color_nonexcluded(clamp_byte(r),clamp_byte(g),clamp_byte(b)); lua_pushinteger(L, c); return 1; } int L_MatchColor2(lua_State* L) { double r, g, b; double l_weight = 0.25; byte best_color = 0; int nb_args=lua_gettop(L); if (nb_args < 3 || nb_args > 4) { return luaL_error(L, "matchcolor2: Expected 3 or 4 arguments, but found %d.", nb_args); } LUA_ARG_NUMBER(1, "matchcolor2", r, -DBL_MAX, DBL_MAX); LUA_ARG_NUMBER(2, "matchcolor2", g, -DBL_MAX, DBL_MAX); LUA_ARG_NUMBER(3, "matchcolor2", b, -DBL_MAX, DBL_MAX); if (nb_args > 3) { LUA_ARG_NUMBER(4, "matchcolor2", l_weight, 0.0, 1.0); } // Similar to Best_color_perceptual(), but with floating point { int col; double best_diff=9e99; double target_bri; double bri; double diff_b, diff_c, diff; if (r<0.0) r=0; else if (r>255.0) r=255.0; if (g<0.0) g=0; else if (g>255.0) g=255.0; if (b<0.0) b=0; else if (b>255.0) b=255.0; // Similar to Perceptual_lightness(); target_bri = sqrt(0.26*r*0.26*r + 0.55*g*0.55*g + 0.19*b*0.19*b); for (col=0; col<256; col++) { if (Exclude_color[col]) continue; diff_c = sqrt( (0.26*(Main_palette[col].R-r))* (0.26*(Main_palette[col].R-r))+ (0.55*(Main_palette[col].G-g))* (0.55*(Main_palette[col].G-g))+ (0.19*(Main_palette[col].B-b))* (0.19*(Main_palette[col].B-b))); // Exact match if (diff_c<1.0) { lua_pushinteger(L, col); return 1; } bri = sqrt(0.26*0.26*(Main_palette[col].R*Main_palette[col].R) + 0.55*0.55*(Main_palette[col].G*Main_palette[col].G) + 0.19*0.19*(Main_palette[col].B*Main_palette[col].B)); diff_b = fabs(target_bri-bri); diff=l_weight*(diff_b-diff_c)+diff_c; if (diffPages->Transparent_color); return 1; } int L_SetForeColor(lua_State* L) { byte c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "setforecolor"); LUA_ARG_NUMBER(1, "setforecolor", c, -DBL_MAX, DBL_MAX); Fore_color = c; return 0; } int L_SetBackColor(lua_State* L) { byte c; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "setbackcolor"); LUA_ARG_NUMBER(1, "setbackcolor", c, -DBL_MAX, DBL_MAX); Back_color = c; return 0; } int L_InputBox(lua_State* L) { const int max_settings = 9; const int args_per_setting = 5; double min_value[max_settings]; double max_value[max_settings]; double decimal_places[max_settings]; double current_value[max_settings]; const char * label[max_settings]; unsigned short control[max_settings*3+1]; // Each value has at most 3 widgets. enum CONTROL_TYPE { CONTROL_OK = 0x0100, CONTROL_CANCEL = 0x0200, CONTROL_INPUT = 0x0300, CONTROL_INPUT_MINUS = 0x0400, CONTROL_INPUT_PLUS = 0x0500, CONTROL_CHECKBOX = 0x0600, CONTROL_VALUE_MASK = 0x00FF, CONTROL_TYPE_MASK = 0xFF00 }; const char * window_caption; int caption_length; int nb_settings; int nb_args; unsigned int max_label_length; int setting; short clicked_button; char str[40]; short close_window = 0; nb_args = lua_gettop (L); if (nb_args < 6) { return luaL_error(L, "inputbox: Less than 6 arguments"); } if ((nb_args - 1) % args_per_setting) { return luaL_error(L, "inputbox: Wrong number of arguments"); } nb_settings = (nb_args-1)/args_per_setting; if (nb_settings > max_settings) { return luaL_error(L, "inputbox: Too many settings, limit reached"); } max_label_length=4; // Minimum size to account for OK / Cancel buttons // First argument is window caption LUA_ARG_STRING(1, "inputbox", window_caption); caption_length = strlen(window_caption); if ( caption_length > 14) max_label_length = caption_length - 10; for (setting=0; setting 999999999999999.0) max_value[setting] = 999999999999999.0;*/ LUA_ARG_NUMBER(setting*args_per_setting+6, "inputbox", decimal_places[setting], -15.0, 15.0); if (decimal_places[setting]>15) decimal_places[setting]=15; if (min_value[setting]!=0 || max_value[setting]!=1) if (decimal_places[setting]<0) decimal_places[setting]=0; // Keep current value in range if (decimal_places[setting]>=0) current_value[setting] = Fround(current_value[setting], decimal_places[setting]); if (current_value[setting] < min_value[setting]) current_value[setting] = min_value[setting]; else if (current_value[setting] > max_value[setting]) current_value[setting] = max_value[setting]; if (min_value[setting]==0 && max_value[setting]==0) label_length-=12; if (label_length > (int)max_label_length) max_label_length = label_length; } // Max is 25 to keep window under 320 pixel wide if (max_label_length>25) max_label_length=25; Update_colors_during_script(); if (!Cursor_is_visible) Display_cursor(); Open_window(115+max_label_length*8,44+nb_settings*17,window_caption); // Normally this index is unused, but this initialization avoids // any weird behavior if it was used by mistake. control[0]=0; // OK Window_set_normal_button( 7, 25 + 17 * nb_settings, 51,14,"OK" , 0,1,SDLK_RETURN); control[Window_nb_buttons] = CONTROL_OK; // Cancel Window_set_normal_button( 64, 25 + 17 * nb_settings, 51,14,"Cancel" , 0,1,KEY_ESC); control[Window_nb_buttons] = CONTROL_CANCEL; for (setting=0; setting0) { setting = control[clicked_button] & (CONTROL_VALUE_MASK); switch (control[clicked_button] & CONTROL_TYPE_MASK) { case CONTROL_OK: close_window = CONTROL_OK; break; case CONTROL_CANCEL: close_window = CONTROL_CANCEL; break; case CONTROL_INPUT: Sprint_double(str,current_value[setting],decimal_places[setting],0); Readline_ex(12+max_label_length*8+23, 22+setting*17,str,7,40,INPUT_TYPE_DECIMAL,decimal_places[setting]); current_value[setting]=atof(str); if (current_value[setting] < min_value[setting]) current_value[setting] = min_value[setting]; else if (current_value[setting] > max_value[setting]) current_value[setting] = max_value[setting]; // Print editable value Sprint_double(str,current_value[setting],decimal_places[setting],7); Print_in_window_limited(12+max_label_length*8+23, 22+setting*17, str, 7,MC_Black,MC_Light); // Display_cursor(); break; case CONTROL_INPUT_MINUS: if (current_value[setting] > min_value[setting]) { current_value[setting]--; if (current_value[setting] < min_value[setting]) current_value[setting] = min_value[setting]; Hide_cursor(); // Print editable value Sprint_double(str,current_value[setting],decimal_places[setting],7); Print_in_window_limited(12+max_label_length*8+23, 22+setting*17, str, 7,MC_Black,MC_Light); // Display_cursor(); } break; case CONTROL_INPUT_PLUS: if (current_value[setting] < max_value[setting]) { current_value[setting]++; if (current_value[setting] > max_value[setting]) current_value[setting] = max_value[setting]; Hide_cursor(); // Print editable value Sprint_double(str,current_value[setting],decimal_places[setting],7); Print_in_window_limited(12+max_label_length*8+23, 22+setting*17, str, 7,MC_Black,MC_Light); // Display_cursor(); } break; case CONTROL_CHECKBOX: if (decimal_places[setting]==0 || current_value[setting]==0.0) { current_value[setting] = (current_value[setting]==0.0); Hide_cursor(); Print_in_window(12+max_label_length*8+46, 22+setting*17, current_value[setting]?"X":" ",MC_Black,MC_Light); // Uncheck other buttons of same family if (decimal_places[setting]<0) { byte button; for (button=3; button<=Window_nb_buttons; button++) { if (button != clicked_button && control[button] & CONTROL_CHECKBOX) { byte other_setting = control[button] & (CONTROL_VALUE_MASK); if (decimal_places[other_setting] == decimal_places[setting]) { // Same family: unset and uncheck current_value[other_setting]=0.0; Print_in_window(12+max_label_length*8+46, 22+other_setting*17, " ",MC_Black,MC_Light); } } } } Display_cursor(); } break; } } } Close_window(); Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Cursor_is_visible=1; // Return values: // One boolean to tell if user pressed ok or cancel lua_pushboolean(L, (close_window == CONTROL_OK)); // One value per control for (setting=0; setting max_label_length) max_label_length = caption_length; for (button=0; button max_label_length) max_label_length = strlen(label[button]); LUA_ARG_FUNCTION(button*2+3, "selectbox"); } // Max is 25 to keep window under 320 pixel wide if (max_label_length>25) max_label_length=25; Update_colors_during_script(); if (!Cursor_is_visible) Display_cursor(); Open_window(28+max_label_length*8,26+nb_buttons*17,window_caption); for (button=0; button= 3) { LUA_ARG_STRING(3, "windowopen", title); LUA_ARG_LIMIT (3, "windowopen"); } if (Windows_open>=7) { return luaL_error(L, "windowopen: Too many nested windows!"); } if (!Cursor_is_visible) Display_cursor(); Open_window(w,h,title); Cursor_is_visible=0; return 0; } int L_WindowClose(lua_State* L) { int nb_args = lua_gettop(L); LUA_ARG_LIMIT (0, "windowclose"); if (!Windows_open) return luaL_error(L, "windowclose: No window is open"); if (!Cursor_is_visible) Display_cursor(); Close_window(); Cursor_is_visible=0; return 0; } int L_WindowDoDialog(lua_State* L) { int button; int nb_args = lua_gettop(L); LUA_ARG_LIMIT (0, "windowdodialog"); if (!Windows_open) return luaL_error(L, "windowdodialog: No window is open"); //Update_window_area(0,0,Window_width, Window_height); if (!Cursor_is_visible) { Display_cursor(); Cursor_is_visible=1; } if (Window_needs_update) { Update_window_area(0,0,Window_width, Window_height); Window_needs_update=0; } button=Window_clicked_button(); lua_pushinteger(L, button); lua_pushinteger(L, Window_attribute2); lua_pushinteger(L, Key); return 3; } int L_WindowButton(lua_State* L) { int x, y, w, h, key=KEY_NONE; const char *text=""; int nb_args = lua_gettop(L); LUA_ARG_NUMBER(1, "windowbutton", x, 1, Window_width-1); LUA_ARG_NUMBER(2, "windowbutton", y, 1, Window_height-1); LUA_ARG_NUMBER(3, "windowbutton", w, 1, Window_width-1-x); LUA_ARG_NUMBER(4, "windowbutton", h, 1, Window_height-1-y); if (nb_args >= 5) { LUA_ARG_STRING(5, "windowbutton", text); } if (nb_args >= 6) { LUA_ARG_NUMBER(6, "windowbutton", key, -1, INT_MAX); LUA_ARG_LIMIT (6, "windowbutton"); } if (!Windows_open) return luaL_error(L, "windowbutton: No window is open"); if (Cursor_is_visible) { Hide_cursor(); Cursor_is_visible=0; } Window_set_normal_button(x, y, w, h, text, 0, 1, key); Window_needs_update=1; return 0; } int L_WindowRepeatButton(lua_State* L) { int x, y, w, h, key=KEY_NONE; const char *text=""; int nb_args = lua_gettop(L); LUA_ARG_NUMBER(1, "windowrepeatbutton", x, 1, Window_width-1); LUA_ARG_NUMBER(2, "windowrepeatbutton", y, 1, Window_height-1); LUA_ARG_NUMBER(3, "windowrepeatbutton", w, 1, Window_width-1-x); LUA_ARG_NUMBER(4, "windowrepeatbutton", h, 1, Window_height-1-y); if (nb_args >= 5) { LUA_ARG_STRING(5, "windowrepeatbutton", text); } if (nb_args >= 6) { LUA_ARG_NUMBER(6, "windowrepeatbutton", key, -1, INT_MAX); LUA_ARG_LIMIT (6, "windowrepeatbutton"); } if (!Windows_open) return luaL_error(L, "windowrepeatbutton: No window is open"); if (Cursor_is_visible) { Hide_cursor(); Cursor_is_visible=0; } Window_set_repeatable_button(x, y, w, h, text, 0, 1, key); Window_needs_update=1; return 0; } int L_WindowInput(lua_State* L) { int x, y, nbchar; const char *text=NULL; T_Special_button *button; int nb_args = lua_gettop(L); LUA_ARG_NUMBER(1, "windowinput", x, 3, Window_width-3-8); LUA_ARG_NUMBER(2, "windowinput", y, 3, Window_height-3-8); LUA_ARG_NUMBER(3, "windowinput", nbchar, 1, (Window_width-3-8-x)/8); if (nb_args >= 4) { LUA_ARG_STRING(4, "windowinput", text); LUA_ARG_LIMIT (4, "windowinput"); } if (!Windows_open) return luaL_error(L, "windowinput: No window is open"); if (Cursor_is_visible) { Hide_cursor(); Cursor_is_visible=0; } button = Window_set_input_button(x-2, y-2, nbchar); if (text!=NULL) Window_input_content(button, text); Window_needs_update=1; return 0; } int L_WindowReadline(lua_State* L) { int x, y, visible_size, max_size, decimal_places=0; const char *valuetext; double valuenumber; char text[255+1]=""; int result; int input_type=0; // see Readline_ex() int nb_args = lua_gettop(L); LUA_ARG_NUMBER(1, "windowreadline", x, 3, Window_width-3-8); LUA_ARG_NUMBER(2, "windowreadline", y, 3, Window_height-3-8); // arg 3 can be either string or number, it's checked below if (nb_args < (3)) return luaL_error(L, "%s: Argument %d is missing.", "windowreadline", (3)); LUA_ARG_NUMBER(4, "windowreadline", visible_size, 1, (Window_height-3-8)/8); LUA_ARG_NUMBER(5, "windowreadline", max_size, 1, 255); LUA_ARG_NUMBER(6, "windowreadline", decimal_places, 0, 16); LUA_ARG_NUMBER(7, "windowreadline", input_type, 0, 4); LUA_ARG_LIMIT (7, "windowreadline"); if (input_type == 3 || input_type == 1) { // expect number LUA_ARG_NUMBER(3, "windowreadline", valuenumber, -DBL_MAX, DBL_MAX); Sprint_double(text, valuenumber, decimal_places, 0); } else { // expect string LUA_ARG_STRING(3, "windowreadline", valuetext); if (strlen(valuetext)>255) return luaL_error(L, "%s: Argument %d, string too long.", "windowreadline", (3)); strcpy(text, valuetext); } if (!Windows_open) return luaL_error(L, "windowreadline: No window is open"); if (Cursor_is_visible) { Hide_cursor(); Cursor_is_visible=0; } result = Readline_ex(x, y, text, visible_size, max_size, input_type, decimal_places); Window_needs_update=1; lua_pushboolean(L, result); // 0=ESC, 1= confirm lua_pushstring(L, text); return 2; } int L_WindowPrint(lua_State* L) { int x, y, fg=0, bg=2; int colors[4] = {MC_Black, MC_Dark, MC_Light, MC_White}; const char *text=""; int nb_args = lua_gettop(L); LUA_ARG_NUMBER(1, "windowprint", x, 1, Window_width-8); LUA_ARG_NUMBER(2, "windowprint", y, 1, Window_height-8); LUA_ARG_STRING(3, "windowprint", text); if (nb_args >= 4) { LUA_ARG_NUMBER(4, "windowprint", fg, 0, 3); } if (nb_args >= 5) { LUA_ARG_NUMBER(5, "windowprint", bg, 0, 3); LUA_ARG_LIMIT (5, "windowprint"); } if (!Windows_open) return luaL_error(L, "windowprint: No window is open"); if (Cursor_is_visible) { Hide_cursor(); Cursor_is_visible=0; } Print_in_window_limited(x, y, text, (Window_width-x)/8,colors[fg], colors[bg]); Window_needs_update=1; return 0; } int L_WindowSlider(lua_State* L) { word x, y, height, nb_elements, nb_elements_visible, initial_position; int horizontal; int nb_args = lua_gettop(L); LUA_ARG_LIMIT (7, "windowslider"); LUA_ARG_BOOL (7, "windowslider", horizontal); if (horizontal) { LUA_ARG_NUMBER(1, "windowslider", x, 1, Window_width-27); LUA_ARG_NUMBER(2, "windowslider", y, 1, Window_height-13); LUA_ARG_NUMBER(3, "windowslider", height, 1, Window_width-27-x); } else { LUA_ARG_NUMBER(1, "windowslider", x, 1, Window_width-13); LUA_ARG_NUMBER(2, "windowslider", y, 1, Window_height-27); LUA_ARG_NUMBER(3, "windowslider", height, 1, Window_height-27-y); } LUA_ARG_NUMBER(4, "windowslider", nb_elements, 1, INT_MAX); LUA_ARG_NUMBER(5, "windowslider", nb_elements_visible, 1, nb_elements); LUA_ARG_NUMBER(6, "windowslider", initial_position, 0, nb_elements-nb_elements_visible); if (!Windows_open) return luaL_error(L, "windowslider: No window is open"); if (Cursor_is_visible) { Hide_cursor(); Cursor_is_visible=0; } if (horizontal) Window_set_horizontal_scroller_button(x, y, height+24, nb_elements, nb_elements_visible, initial_position); else Window_set_scroller_button(x, y, height+24, nb_elements, nb_elements_visible, initial_position); Window_needs_update=1; return 0; } int L_WindowMoveSlider(lua_State* L) { word nb_elements, nb_elements_visible, position; int slider_number; T_Scroller_button *button = Window_scroller_button_list; int nb_args = lua_gettop(L); if (!Windows_open) return luaL_error(L, "windowmoveslider: No window is open"); LUA_ARG_NUMBER(1, "windowmoveslider", slider_number, 1, 256); button = Window_scroller_button_list; if (! button) return luaL_error(L, "windowmoveslider: No slider to move"); while (slider_number>1) { slider_number--; button = button->Next; if (! button) return luaL_error(L, "windowmoveslider: Not so many sliders in this window"); } LUA_ARG_NUMBER(2, "windowmoveslider", nb_elements, 1, INT_MAX); LUA_ARG_NUMBER(3, "windowmoveslider", nb_elements_visible, 1, nb_elements); LUA_ARG_NUMBER(4, "windowmoveslider", position, 0, nb_elements-nb_elements_visible); LUA_ARG_LIMIT (4, "windowmoveslider"); if (Cursor_is_visible) { Hide_cursor(); Cursor_is_visible=0; } button->Nb_elements =nb_elements; button->Nb_visibles =nb_elements_visible; button->Position =position; Compute_slider_cursor_length(button); Window_draw_slider(button); Window_needs_update=1; return 0; } int L_UpdateScreen(lua_State* L) { int nb_args=lua_gettop(L); LUA_ARG_LIMIT (0, "updatescreen"); Update_colors_during_script(); if (Cursor_is_visible) Hide_cursor(); Display_all_screen(); Display_cursor(); Cursor_is_visible=1; //Flush_update(); return 0; } int L_StatusMessage(lua_State* L) { const char* msg; char msg2[25]; int len; int nb_args = lua_gettop(L); LUA_ARG_LIMIT(1,"statusmessage"); LUA_ARG_STRING(1, "statusmessage", msg); len=strlen(msg); if (len<=24) { strcpy(msg2, msg); // fill remainder with spaces for (;len<24;len++) msg2[len]=' '; } else { strncpy(msg2, msg, 24); } msg2[24]='\0'; if (Cursor_is_visible) Hide_cursor(); Print_in_menu(msg2,0); Cursor_is_visible=0; return 0; } int L_GetLayerCount(lua_State* L) { int nb_args=lua_gettop(L); LUA_ARG_LIMIT (0, "layercount"); lua_pushinteger(L, Main_backups->Pages->Nb_layers); return 1; } int L_GetSpareLayerCount(lua_State* L) { int nb_args=lua_gettop(L); LUA_ARG_LIMIT (0, "layercount"); lua_pushinteger(L, Spare_backups->Pages->Nb_layers); return 1; } int L_SelectSpareLayer(lua_State* L) { int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "selectsparelayer"); LUA_ARG_NUMBER(1, "selectsparelayer", Spare_current_layer, 0, Spare_backups->Pages->Nb_layers - 1); if (Spare_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { if (! ((1 << Spare_current_layer) & Spare_layers_visible)) { Spare_layers_visible |= (1 << Spare_current_layer); } } return 0; } int L_SelectLayer(lua_State* L) { int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "selectlayer"); LUA_ARG_NUMBER(1, "selectlayer", Main_current_layer, 0, Main_backups->Pages->Nb_layers - 1); Backup_if_necessary(L, Main_current_layer); // if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { if (! ((1 << Main_current_layer) & Main_layers_visible)) { Main_layers_visible |= (1 << Main_current_layer); Redraw_layered_image(); } else { Update_depth_buffer(); // Only need the depth buffer } } // Todo: mark the layer menu bar as 'needs to be refreshed' return 0; } int L_FinalizePicture(lua_State* L) { int nb_args=lua_gettop(L); LUA_ARG_LIMIT (0, "finalizepicture"); Update_colors_during_script(); if (Is_backed_up) { End_of_modification(); } Is_backed_up = 0; Main_backup_page = Main_backups->Pages; Main_backup_screen = Main_screen; Register_main_readonly(L); lua_register(L,"setcolor",L_SetColor_unsaved); return 0; } int L_GetFileName(lua_State* L) { int nb_args=lua_gettop(L); LUA_ARG_LIMIT (0, "getfilename"); lua_pushstring(L, Main_backups->Pages->Filename); lua_pushstring(L, Main_backups->Pages->File_directory); return 2; } /// Run a script while changing the current directory int L_Run(lua_State* L) { const char * script_arg; const char * message; char saved_directory[MAX_PATH_CHARACTERS]; // these are only needed before running script // (which may call L_Run() again recursively) // so it's safe to make them static to spare a few hundred bytes. static char full_path[MAX_PATH_CHARACTERS]; static char path_element[MAX_PATH_CHARACTERS]; static int nested_calls = 0; int nb_args=lua_gettop(L); LUA_ARG_LIMIT (1, "run"); LUA_ARG_STRING(1, "run", script_arg); if (strlen(script_arg)>=MAX_PATH_CHARACTERS) return luaL_error(L, "run: path is too long"); nested_calls++; if (nested_calls > 100) return luaL_error(L, "run: too many nested calls (100)"); // store the current directory (on the stack) getcwd(saved_directory,MAX_PATH_CHARACTERS); #if defined (__AROS__) // Convert path written on Linux/Windows norms to AROS norms : // Each element like ../ and ..\ is replaced by / // Each path separator \ is replaced by / { const char *src = script_arg; char *dst = full_path; char c; do { while (src[0]=='.' && src[1]=='.' && (src[2]=='/' || src[2]=='\\')) { *dst='/'; dst++; src+=3; } // copy until / or \ or NUL included do { c=*src; *dst=c=='\\' ? '/' : c; // Replace \ by / anyway src++; dst++; } while (c != '\0' && c != '/' && c != '\\'); } while (c!='\0'); } #else { // Convert any number of '\' in the path to '/' // It is not useful on Windows, but does no harm (both path separators work) // On Linux/Unix, this ensures that scripts written and tested on Windows // work similarly. char *pos; strcpy(full_path, script_arg); pos=strchr(full_path, '\\'); while (pos!=NULL) { *pos='/'; pos=strchr(full_path, '\\'); } } #endif Extract_path(path_element, full_path); if (path_element[0]!='\0') { if (!Directory_exists(path_element)) return luaL_error(L, "run: directory of script doesn't exist"); chdir(path_element); } Extract_filename(path_element, full_path); if (luaL_loadfile(L,path_element) != 0) { nb_args= lua_gettop(L); if (nb_args>0 && (message = lua_tostring(L, nb_args))!=NULL) return luaL_error(L, message); else return luaL_error(L, "run: Unknown error loading script %s", path_element); } else if (lua_pcall(L, 0, 0, 0) != 0) { nb_args= lua_gettop(L); // We COULD build the call stack, but I think this would be more // confusing than helpful. if (nb_args>0 && (message = lua_tostring(L, nb_args))!=NULL) return luaL_error(L, message); else return luaL_error(L, "run: Unknown error running script!"); } nested_calls--; // restore directory chdir(saved_directory); return 0; } // "unsaved" version of the bindings DECLARE_UNSAVED(L_ClearPicture) DECLARE_UNSAVED(L_DrawCircle) DECLARE_UNSAVED(L_DrawDisk) DECLARE_UNSAVED(L_DrawFilledRect) DECLARE_UNSAVED(L_DrawLine) DECLARE_UNSAVED(L_PutPicturePixel) /// Bindings for screen-drawing Lua functions, if the current image is backed up. void Register_main_writable(lua_State* L) { lua_register(L,"putpicturepixel",L_PutPicturePixel); lua_register(L,"drawline",L_DrawLine); lua_register(L,"drawfilledrect",L_DrawFilledRect); lua_register(L,"drawcircle",L_DrawCircle); lua_register(L,"drawdisk",L_DrawDisk); lua_register(L,"clearpicture",L_ClearPicture); } /// Bindings for screen-drawing Lua functions, if the current image is not backed up yet. void Register_main_readonly(lua_State* L) { lua_register(L,"putpicturepixel",L_PutPicturePixel_unsaved); lua_register(L,"drawline",L_DrawLine_unsaved); lua_register(L,"drawfilledrect",L_DrawFilledRect_unsaved); lua_register(L,"drawcircle",L_DrawCircle_unsaved); lua_register(L,"drawdisk",L_DrawDisk_unsaved); lua_register(L,"clearpicture",L_ClearPicture_unsaved); } // Handlers for window internals T_Fileselector Scripts_selector; // Callback to display a skin name in the list void Draw_script_name(word x, word y, word index, byte highlighted) { T_Fileselector_item * current_item; if (Scripts_selector.Nb_elements) { byte fg, bg; current_item = Get_item_by_index(&Scripts_selector, index); if (current_item->Type==0) // Files { fg=(highlighted)?MC_White:MC_Light; bg=(highlighted)?MC_Dark:MC_Black; } else if (current_item->Type==1) // Directories { fg=(highlighted)?MC_Light:MC_Dark; bg=(highlighted)?MC_Dark:MC_Black; } else // Drives { fg=(highlighted)?MC_Light:MC_Dark; bg=(highlighted)?MC_Dark:MC_Black; if (current_item->Icon != ICON_NONE) { Window_display_icon_sprite(x,y,current_item->Icon); x+=8; } } Print_in_window(x, y, current_item->Short_name, fg,bg); Update_window_area(x,y,NAME_WIDTH*8,8); } } /// /// Displays first lines of comments from a lua script in the window. void Draw_script_information(T_Fileselector_item * script_item, const char *full_directory) { FILE *script_file; char text_block[3][DESC_WIDTH+1]; int x, y; int i; // Blank the target area Window_rectangle(7, FILESEL_Y + 89, DESC_WIDTH*6+2, 4*8, MC_Black); if (script_item && script_item->Full_name && script_item->Full_name[0]!='\0') { char full_name[MAX_PATH_CHARACTERS]; strcpy(full_name, full_directory); Append_path(full_name, script_item->Full_name, NULL); x=0; y=0; text_block[0][0] = text_block[1][0] = text_block[2][0] = '\0'; if (script_item->Type == 0) { // Start reading script_file = fopen(full_name, "r"); if (script_file != NULL) { int c; c = fgetc(script_file); while (c != EOF && y<3) { if (c == '\n') { if (x<2) break; // Carriage return without comment: Stopping y++; x=0; } else if (x==0 || x==1) { if (c != '-') break; // Non-comment line was encountered. Stopping. x++; } else { if (x < DESC_WIDTH+2) { // Adding character text_block[y][x-2] = (c<32 || c>255) ? ' ' : c; text_block[y][x-1] = '\0'; } x++; } // Read next c = fgetc(script_file); } fclose(script_file); } Print_help(8, FILESEL_Y + 89 , text_block[0], 'N', 0, 0); Print_help(8, FILESEL_Y + 89+ 8, text_block[1], 'N', 0, 0); Print_help(8, FILESEL_Y + 89+16, text_block[2], 'N', 0, 0); // Display a line with the keyboard shortcut Print_help(8, FILESEL_Y + 89+24, "Key:", 'N', 0, 0); for (i=0; i<10; i++) if (Bound_script[i]!=NULL && !strcmp(Bound_script[i], full_name)) break; if (i<10) { const char *shortcut; shortcut=Keyboard_shortcut_value(SPECIAL_RUN_SCRIPT_1+i); Print_help(8+4*6, FILESEL_Y + 89+24, shortcut, 'K', 0, strlen(shortcut)); } else { Print_help(8+4*6, FILESEL_Y + 89+24, "None", 'K', 0, 4); } } } Update_window_area(8, FILESEL_Y + 89, DESC_WIDTH*6+2, 4*8); } // Add a script to the list void Add_script(const char *name, byte is_file, byte is_directory, byte is_hidden) { const char * file_name; int len; file_name=Find_last_separator(name)+1; if (is_file) { // Only files ending in ".lua" len=strlen(file_name); if (len<=4 || strcasecmp(file_name+len-4, ".lua")) return; // Hidden if (is_hidden && !Config.Show_hidden_files) return; Add_element_to_list(&Scripts_selector, file_name, Format_filename(file_name, NAME_WIDTH+1, 0), 0, ICON_NONE); } else if (is_directory) { // Ignore current directory if ( !strcmp(file_name, ".")) return; // Ignore parent directory entry if (!strcmp(file_name, PARENT_DIR)) return; // Hidden if (is_hidden && !Config.Show_hidden_directories) return; Add_element_to_list(&Scripts_selector, file_name, Format_filename(file_name, NAME_WIDTH+1, 1), 1, ICON_NONE); } } void Highlight_script(T_Fileselector *selector, T_List_button *list, const char *selected_file) { short index; index=Find_file_in_fileselector(selector, selected_file); Locate_list_item(list, index); } static char Last_run_script[MAX_PATH_CHARACTERS]=""; // Before: Cursor hidden // After: Cursor shown void Run_script(const char *script_subdirectory, const char *script_filename) { lua_State* L; const char* message; byte old_cursor_shape=Cursor_shape; char buf[MAX_PATH_CHARACTERS]; int original_image_width=Main_image_width; int original_image_height=Main_image_height; // Some scripts are slow Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Flush_update(); Cursor_is_visible=1; if (script_subdirectory && script_subdirectory[0]!='\0') { strcpy(Last_run_script, script_subdirectory); Append_path(Last_run_script, script_filename, NULL); } else { strcpy(Last_run_script, script_filename); } // This chdir is for the script's sake. Grafx2 itself will (try to) // not rely on what is the system's current directory. Extract_path(buf,Last_run_script); chdir(buf); L = luaL_newstate(); // used to be lua_open() on Lua 5.1, deprecated on 5.2 strcpy(buf, "LUA_PATH="); strcat(buf, Data_directory); Append_path(buf+9, SCRIPTS_SUBDIRECTORY, NULL); Append_path(buf+9, LUALIB_SUBDIRECTORY, NULL); Append_path(buf+9, "?.lua", NULL); putenv(buf); // Drawing lua_register(L,"putbrushpixel",L_PutBrushPixel); lua_register(L,"putsparepicturepixel",L_PutSparePicturePixel); Register_main_readonly(L); // Reading pixels lua_register(L,"getbrushpixel",L_GetBrushPixel); lua_register(L,"getbrushbackuppixel",L_GetBrushBackupPixel); lua_register(L,"getpicturepixel",L_GetPicturePixel); lua_register(L,"getlayerpixel",L_GetLayerPixel); lua_register(L,"getbackuppixel",L_GetBackupPixel); lua_register(L,"getsparelayerpixel",L_GetSpareLayerPixel); lua_register(L,"getsparepicturepixel",L_GetSparePicturePixel); // Sizes lua_register(L,"setbrushsize",L_SetBrushSize); lua_register(L,"setpicturesize",L_SetPictureSize); lua_register(L,"setsparepicturesize",L_SetSparePictureSize); lua_register(L,"getbrushsize",L_GetBrushSize); lua_register(L,"getpicturesize",L_GetPictureSize); lua_register(L,"getsparepicturesize",L_GetSparePictureSize); // color and palette lua_register(L,"getforecolor",L_GetForeColor); lua_register(L,"getbackcolor",L_GetBackColor); lua_register(L,"gettranscolor",L_GetTransColor); lua_register(L,"setcolor",L_SetColor_unsaved); lua_register(L,"setforecolor",L_SetForeColor); lua_register(L,"setbackcolor",L_SetBackColor); lua_register(L,"getcolor",L_GetColor); lua_register(L,"getbackupcolor",L_GetBackupColor); lua_register(L,"getsparecolor",L_GetSpareColor); lua_register(L,"getsparetranscolor",L_GetSpareTransColor); lua_register(L,"matchcolor",L_MatchColor); lua_register(L,"matchcolor2",L_MatchColor2); // layers lua_register(L,"selectlayer",L_SelectLayer); lua_register(L,"selectsparelayer",L_SelectSpareLayer); lua_register(L,"getlayercount",L_GetLayerCount); lua_register(L,"getsparelayercount",L_GetSpareLayerCount); // ui lua_register(L,"inputbox",L_InputBox); lua_register(L,"messagebox",L_MessageBox); lua_register(L,"statusmessage",L_StatusMessage); lua_register(L,"selectbox",L_SelectBox); // misc. stuff lua_register(L,"wait",L_Wait); lua_register(L,"waitbreak",L_WaitBreak); lua_register(L,"waitinput",L_WaitInput); lua_register(L,"updatescreen",L_UpdateScreen); lua_register(L,"finalizepicture",L_FinalizePicture); lua_register(L,"getfilename",L_GetFileName); lua_register(L,"run",L_Run); // dialog lua_register(L,"windowopen",L_WindowOpen); lua_register(L,"windowclose",L_WindowClose); lua_register(L,"windowdodialog",L_WindowDoDialog); lua_register(L,"windowbutton",L_WindowButton); lua_register(L,"windowrepeatbutton",L_WindowRepeatButton); lua_register(L,"windowinput",L_WindowInput); lua_register(L,"windowreadline",L_WindowReadline); lua_register(L,"windowprint",L_WindowPrint); lua_register(L,"windowslider",L_WindowSlider); lua_register(L,"windowmoveslider",L_WindowMoveSlider); // Load all standard libraries luaL_openlibs(L); /* luaopen_base(L); //luaopen_package(L); // crashes on Windows, for unknown reason luaopen_table(L); //luaopen_io(L); // crashes on Windows, for unknown reason //luaopen_os(L); luaopen_string(L); luaopen_math(L); //luaopen_debug(L); */ // TODO The script may modify the picture, so we do a backup here. // If the script is only touching the brush, this isn't needed... // The backup also allows the script to read from it to make something // like a feedback off effect (convolution matrix comes to mind). //Backup(); Is_backed_up = 0; Main_backup_page = Main_backups->Pages; Main_backup_screen = Main_screen; Backup_the_spare(LAYER_ALL); Palette_has_changed=0; Brush_was_altered=0; Original_back_color=Back_color; Original_fore_color=Fore_color; // Backup the brush Brush_backup=(byte *)malloc(((long)Brush_height)*Brush_width); Brush_backup_width = Brush_width; Brush_backup_height = Brush_height; if (Brush_backup == NULL) { Verbose_message("Error!", "Out of memory!"); } else { memcpy(Brush_backup, Brush, ((long)Brush_height)*Brush_width); if (luaL_loadfile(L,Last_run_script) != 0) { int stack_size; stack_size= lua_gettop(L); if (stack_size>0 && (message = lua_tostring(L, stack_size))!=NULL) Verbose_message("Error!", message); else Warning_message("Unknown error loading script!"); } else if (lua_pcall(L, 0, 0, 0) != 0) { int stack_size; stack_size= lua_gettop(L); Update_colors_during_script(); if (stack_size>0 && (message = lua_tostring(L, stack_size))!=NULL) Verbose_message("Error running script", message); else Warning_message("Unknown error running script!"); } // Clean up any remaining dialog windows while (Windows_open) { Close_window(); Display_cursor(); } } // Cleanup free(Brush_backup); Brush_backup=NULL; Update_colors_during_script(); if (Is_backed_up) End_of_modification(); Print_in_menu(" ",0); lua_close(L); if (Brush_was_altered) { // Copy Brush to original memcpy(Brush_original_pixels, Brush, (long)Brush_width*Brush_height); Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); } Hide_cursor(); Display_all_screen(); // Update tilemap if image size has changed if (original_image_width!=Main_image_width || original_image_height!=Main_image_height) { Tilemap_update(); } // Update changed pen colors. if (Back_color!=Original_back_color || Fore_color!=Original_fore_color) { // This is done at end of script, in case somebody would use the // functions in a custom window. if (Back_color!=Original_back_color) { byte new_color = Back_color; Back_color = Original_back_color; Set_back_color(new_color); } if (Fore_color!=Original_fore_color) { byte new_color = Fore_color; Fore_color = Original_fore_color; Set_fore_color(new_color); } } Cursor_shape=old_cursor_shape; Display_cursor(); } void Run_numbered_script(byte index) { if (index>=10) return; if (Bound_script[index]==NULL) return; Hide_cursor(); Run_script(NULL, Bound_script[index]); } void Repeat_script(void) { if (Last_run_script==NULL || Last_run_script[0]=='\0') { Warning_message("No script to repeat."); return; } Hide_cursor(); Run_script(NULL, Last_run_script); } void Set_script_shortcut(T_Fileselector_item * script_item, const char *full_directory) { int i; char full_name[MAX_PATH_CHARACTERS]; if (script_item && script_item->Full_name && script_item->Full_name[0]!='\0') { strcpy(full_name, full_directory); Append_path(full_name, script_item->Full_name, NULL); // Find if it already has a shortcut for (i=0; i<10; i++) if (Bound_script[i]!=NULL && !strcmp(Bound_script[i], full_name)) break; if (i<10) { // Existing shortcut } else { // Try to find a "free" one. for (i=0; i<10; i++) if (Bound_script[i]==NULL || !Has_shortcut(SPECIAL_RUN_SCRIPT_1+i) || !File_exists(full_name)) break; if (i<10) { free(Bound_script[i]); Bound_script[i]=strdup(full_name); } else { Warning_message("Already 10 scripts have shortcuts."); return; } } Window_set_shortcut(SPECIAL_RUN_SCRIPT_1+i); if (!Has_shortcut(SPECIAL_RUN_SCRIPT_1+i)) { // User cancelled or deleted all shortcuts free(Bound_script[i]); Bound_script[i]=NULL; } // Refresh display Hide_cursor(); Draw_script_information(script_item, full_directory); Display_cursor(); } } void Reload_scripts_list(void) { // Reinitialize the list Free_fileselector_list(&Scripts_selector); if (Config.Scripts_directory[0]=='\0') { Read_list_of_drives(&Scripts_selector,NAME_WIDTH+1); } else { Add_element_to_list(&Scripts_selector, PARENT_DIR, Format_filename(PARENT_DIR, NAME_WIDTH+1, 1), 1, ICON_NONE); // Add each found file to the list For_each_directory_entry(Config.Scripts_directory, Add_script); } // Sort it Sort_list_of_files(&Scripts_selector); // } void Button_Brush_Factory(void) { static char selected_file[MAX_PATH_CHARACTERS]=""; short clicked_button; T_List_button* scriptlist; T_Scroller_button* scriptscroll; T_Special_button* scriptarea; T_Fileselector_item *item; int last_selected_item=-1; char displayed_path[DESC_WIDTH+1]; int q; Reload_scripts_list(); Open_window(33+8*NAME_WIDTH, 180, "Brush Factory"); Window_set_normal_button(85, 161, 67, 14, "Cancel", 0, 1, KEY_ESC); // 1 Window_display_frame_in(6, FILESEL_Y - 2, NAME_WIDTH*8+4, 84); // File selector // Fileselector scriptarea=Window_set_special_button(8, FILESEL_Y + 0, NAME_WIDTH*8, 80); // 2 // Scroller for the fileselector scriptscroll = Window_set_scroller_button(NAME_WIDTH*8+14, FILESEL_Y - 1, 82, Scripts_selector.Nb_elements,10, 0); // 3 scriptlist = Window_set_list_button(scriptarea,scriptscroll,Draw_script_name, 0); // 4 Window_set_normal_button(10, 161, 67, 14, "Run", 0, 1, SDLK_RETURN); // 5 Window_display_frame_in(6, FILESEL_Y + 88, DESC_WIDTH*6+4, 4*8+2); // Descr. Window_set_special_button(7, FILESEL_Y + 89+24,DESC_WIDTH*6,8); // 6 // Box around path (slightly expands up left) Window_rectangle(8, FILESEL_Y - 13, DESC_WIDTH*6+2, 9, MC_Black); while (1) { // Locate selected file in view Highlight_script(&Scripts_selector, scriptlist, selected_file); // Update the scroller position scriptscroll->Position=scriptlist->List_start; Window_draw_slider(scriptscroll); Window_redraw_list(scriptlist); // Display current path: q = strlen(Config.Scripts_directory); if (q<=DESC_WIDTH) { strcpy(displayed_path, Config.Scripts_directory); for (; qList_start + scriptlist->Cursor_position), Config.Scripts_directory); Update_window_area(0, 0, Window_width, Window_height); Display_cursor(); // Wait for mouse release (needed for example after a double-click // that navigates to a subdirectory) while (last_selected_item==-1 && Mouse_K) { Get_input(20); } Reset_quicksearch(); do { clicked_button = Window_clicked_button(); if (Key==SDLK_BACKSPACE && Config.Scripts_directory[0]!='\0') { // Make it select first entry (parent directory) scriptlist->List_start=0; scriptlist->Cursor_position=0; clicked_button=5; } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_BRUSH_EFFECTS, "BRUSH FACTORY"); else if (Is_shortcut(Key,0x200+BUTTON_BRUSH_EFFECTS)) clicked_button=1; // Cancel // Quicksearch if (clicked_button==4) Reset_quicksearch(); else if (clicked_button==0 && Key_ANSI) clicked_button=Quicksearch_list(scriptlist, &Scripts_selector); switch (clicked_button) { case 2: // Double-click an entry in script list clicked_button=5; break; case 4: // Select script last_selected_item = scriptlist->List_start + scriptlist->Cursor_position; Hide_cursor(); Draw_script_information(Get_item_by_index(&Scripts_selector, scriptlist->List_start + scriptlist->Cursor_position), Config.Scripts_directory); Display_cursor(); break; case 6: Set_script_shortcut(Get_item_by_index(&Scripts_selector, scriptlist->List_start + scriptlist->Cursor_position), Config.Scripts_directory); break; default: break; } } while (clicked_button != 1 && clicked_button != 5); // Cancel if (clicked_button==1) break; // OK if (Scripts_selector.Nb_elements == 0) { // No items : same as Cancel clicked_button=1; break; } // Examine selected file item = Get_item_by_index(&Scripts_selector, scriptlist->List_start + scriptlist->Cursor_position); if (item->Type==0) // File { strcpy(selected_file, item->Full_name); break; } else if (item->Type==1 || item->Type==2) // Directory { if (item->Type==2) { // Selecting one drive root strcpy(selected_file, PARENT_DIR); strcat(Config.Scripts_directory, item->Full_name); } else { // Going down one or up by one directory Append_path(Config.Scripts_directory, item->Full_name, selected_file); } // No break: going back up to beginning of loop Reload_scripts_list(); scriptlist->Scroller->Nb_elements=Scripts_selector.Nb_elements; Compute_slider_cursor_length(scriptlist->Scroller); last_selected_item = -1; Hide_cursor(); } } Close_window(); Unselect_button(BUTTON_BRUSH_EFFECTS); if (clicked_button == 5) // Run the script { Run_script(Config.Scripts_directory, selected_file); } else { Display_cursor(); } } #else // NOLUA void Button_Brush_Factory(void) { Verbose_message("Error!", "The brush factory is not available in this build of GrafX2."); } /// /// Returns a string stating the included Lua engine version, /// or "Disabled" if Grafx2 is compiled without Lua. const char * Lua_version(void) { return "Disabled"; } #endif grafx2_2.4+git20180105/src/factory.h0000664000000000000000000000071013223665306015345 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ void Button_Brush_Factory(void); void Repeat_script(void); /// Lua scripts bound to shortcut keys. extern char * Bound_script[10]; /// /// Run a lua script linked to a shortcut, 0-9. /// Before: Cursor hidden /// After: Cursor shown void Run_numbered_script(byte index); /// /// Returns a string stating the included Lua engine version, /// or "Disabled" if Grafx2 is compiled without Lua. const char * Lua_version(void); grafx2_2.4+git20180105/src/pxdouble.h0000664000000000000000000000633413223665306015530 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file pxdouble.h /// Renderer for double pixels (2x2). ////////////////////////////////////////////////////////////////////////////// #include "struct.h" void Pixel_double (word x,word y,byte color); byte Read_pixel_double (word x,word y); void Block_double (word start_x,word start_y,word width,word height,byte color); void Pixel_preview_normal_double (word x,word y,byte color); void Pixel_preview_magnifier_double (word x,word y,byte color); void Horizontal_XOR_line_double (word x_pos,word y_pos,word width); void Vertical_XOR_line_double (word x_pos,word y_pos,word height); void Display_brush_color_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_brush_mono_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); void Clear_brush_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); void Remap_screen_double (word x_pos,word y_pos,word width,word height,byte * conversion_table); void Display_part_of_screen_double (word width,word height,word image_width); void Display_line_on_screen_double (word x_pos,word y_pos,word width,byte * line); void Read_line_screen_double (word x_pos,word y_pos,word width,byte * line); void Display_part_of_screen_scaled_double(word width,word height,word image_width,byte * buffer); void Display_brush_color_zoom_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); void Display_brush_mono_zoom_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); void Clear_brush_scaled_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); void Display_brush_double (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_line_on_screen_fast_double (word x_pos,word y_pos,word width,byte * line); grafx2_2.4+git20180105/src/keyboard.h0000664000000000000000000000632513223665306015506 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file keyboard.h /// Functions to convert bewteen the SDL key formats and the keycode we use /// in grafx2. /// The keycode we're using is generalized to handle mouse and joystick shortcuts /// as well. The format can be broken down as: /// - 0x0000 + a number between 0 and SDLK_LAST (about 324) : the SDL "sym" key number. /// - 0x0000 + SDLK_LAST+1: Mouse middle button. /// - 0x0000 + SDLK_LAST+2: Mouse wheel up. /// - 0x0000 + SDLK_LAST+3: Mouse wheel down. /// - 0x0000 + SDLK_LAST+4+B : Joystick button number "B", starting at B=0. /// - 0x0800 + a number between 0 and 0x7FF: The scancode key number, for keys which have no "sym", such as keys from multimedia keyboards, and "fn" and "Thinkpad" key for a laptop. /// Add 0x1000 for the Shift modifier MOD_SHIFT /// Add 0x2000 for the Control modifier ::MOD_CTRL /// Add 0x4000 for the Alt modifier ::MOD_ALT /// Add 0x8000 for the "Meta" modifier ::MOD_META (On MacOS X it's the CMD key) ////////////////////////////////////////////////////////////////////////////// /*! Convert an SDL keysym to an ANSI/ASCII character. This is used to type text and numeric values in input boxes. @param keysym SDL symbol to convert */ word Keysym_to_ANSI(SDL_keysym keysym); /*! Convert an SDL keysym to an internal keycode number. This is needed because SDL tends to split the information across the unicode sym, the regular sym, and the raw keycode. We also need to differenciate 1 (keypad) and 1 (regular keyboard), and some other things. See the notice at the beginning of keyboard.h for the format of a keycode. @param keysym SDL symbol to convert */ word Keysym_to_keycode(SDL_keysym keysym); /*! Helper function to convert between SDL system and the old coding for PC keycodes. This is only used to convert configuration files from the DOS version of Grafx2, where keyboard codes are in in the IBM PC AT form. @param scancode Scancode to convert */ word Key_for_scancode(word scancode); /*! Returns key name in a string. Used to display them in the helpscreens and in the keymapper window. @param key keycode of the key to translate, including modifiers */ const char * Key_name(word key); /*! Gets the modifiers in our format from the SDL_Mod information. Returns a combination of ::MOD_SHIFT, ::MOD_ALT, ::MOD_CTRL @param mod SDL modifiers state */ word Key_modifiers(SDLMod mod); grafx2_2.4+git20180105/src/filesel.c0000664000000000000000000020602013223665306015316 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2014 Sergii Pylypenko Copyright 2011 Pawel Gralski Copyright 2009 Franck Charlet Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include #include #include #elif defined (__MINT__) #include #include #elif defined(__WIN32__) #include #include #include #else #include #endif #include #include #include #include #include #include #include #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "errors.h" #include "io.h" #include "windows.h" #include "sdlscreen.h" #include "loadsave.h" #include "mountlist.h" #include "engine.h" #include "readline.h" #include "input.h" #include "help.h" #include "filesel.h" #define NORMAL_FILE_COLOR MC_Light // color du texte pour une ligne de // fichier non slectionn #define NORMAL_DIRECTORY_COLOR MC_Dark // color du texte pour une ligne de // rpertoire non slectionn #define NORMAL_BACKGROUND_COLOR MC_Black // color du fond pour une ligne // non slectionne #define SELECTED_FILE_COLOR MC_White // color du texte pour une ligne de // fichier slectionne #define SELECTED_DIRECTORY_COLOR MC_Light // color du texte pour une ligne de // reprtoire slectionne #define SELECTED_BACKGROUND_COLOR MC_Dark // color du fond pour une ligne // slectionne // -- Native fileselector for WIN32 // Returns 0 if all ok, something else if failed byte Native_filesel(byte load) { //load = load; #ifdef __WIN32__ OPENFILENAME ofn; char szFileName[MAX_PATH] = ""; SDL_SysWMinfo wminfo; HWND hwnd; SDL_VERSION(&wminfo.version); SDL_GetWMInfo(&wminfo); hwnd = wminfo.window; ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwnd; ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0"; ofn.lpstrFile = szFileName; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_EXPLORER; if(load) ofn.Flags |= OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrDefExt = "txt"; if(load) { if (GetOpenFileName(&ofn)) // Do something usefull with the filename stored in szFileName return 0; else // error - check if its just user pressing cancel or something else return CommDlgExtendedError(); } else if(GetSaveFileName(&ofn)) { return 0; } else { // Check if cancel return CommDlgExtendedError(); } #else (void)load; // unused #if 0 /* if the native fileselector is used, we should implement it where needed * OS X ? GTK ? etc. */ #ifndef __linux__ // This makes no sense on X11-oriented platforms. Nothing is really native there. #warning "EXPERIMENTAL function for native fileselector not available for this platform!" #endif #endif return 255; // fail ! #endif } // -- "Standard" fileselector for other platforms // -- Fileselector data T_Fileselector Filelist; /// Selector settings to use, for all functions called by Load_or_save T_Selector_settings * Selector; /// Name of the current directory //static char Selector_directory[1024]; /// Filename (without directory) of the highlighted file static char Selector_filename[256]; // Conventions: // // * Le fileselect modifie le rpertoire courant. Ceci permet de n'avoir // qu'un findfirst dans le rpertoire courant faire: void Recount_files(T_Fileselector *list) { T_Fileselector_item *item; list->Nb_files=0; list->Nb_directories=0; list->Nb_elements=0; for (item = list->First; item != NULL; item = item->Next) { if (item->Type == 0) list->Nb_files ++; else list->Nb_directories ++; list->Nb_elements ++; } if (list->Index) { free(list->Index); list->Index = NULL; } if (list->Nb_elements>0) { int i; list->Index = (T_Fileselector_item **) malloc(list->Nb_elements * sizeof(T_Fileselector_item **)); if (list->Index) { // Fill the index for (item = list->First, i=0; item != NULL; item = item->Next, i++) { list->Index[i] = item; } } // If the malloc failed, we're probably in trouble, but I don't know // how to recover from that..I'll just make the index bulletproof. } } // -- Destruction de la liste chane --------------------------------------- void Free_fileselector_list(T_Fileselector *list) // Cette procdure dtruit la chaine des fichiers. Elle doit tre appele // avant de rappeler la fonction Read_list_of_files, ainsi qu'en fin de // programme. { // Pointeur temporaire de destruction T_Fileselector_item * temp_item; while (list->First!=NULL) { // On mmorise l'adresse du premier lment de la liste temp_item =list->First; // On fait avancer la tte de la liste list->First=list->First->Next; // Et on efface l'ancien premier lment de la liste free(temp_item); temp_item = NULL; } Recount_files(list); } int Position_last_dot(const char * fname) { int pos_last_dot = -1; int c = 0; for (c = 0; fname[c]!='\0'; c++) if (fname[c]=='.') pos_last_dot = c; return pos_last_dot; } char * Format_filename(const char * fname, word max_length, int type) { static char result[40]; int c; int other_cursor; int pos_last_dot; #ifdef ENABLE_FILENAMES_ICONV /* convert file name from UTF8 to ANSI */ char converted_fname[MAX_PATH_CHARACTERS]; { char * input = (char *)fname; size_t inbytesleft = strlen(fname); char * output = converted_fname; size_t outbytesleft = sizeof(converted_fname)-1; if(cd != (iconv_t)-1 && (ssize_t)iconv(cd, &input, &inbytesleft, &output, &outbytesleft) >= 0) { *output = '\0'; fname = converted_fname; } } #endif /* ENABLE_FILENAMES_ICONV */ // safety if (max_length>40) max_length=40; if (strcmp(fname,PARENT_DIR)==0) { strcpy(result,"\x11 PARENT DIRECTORY"); // Append spaces for (c=18; c= max_length-1) result[max_length-2]=ELLIPSIS_CHARACTER; } else { // Initialize as all spaces for (c = 0; c max_length-6) { result[max_length-6]=ELLIPSIS_CHARACTER; break; } result[c]=fname[c]; } // Ensuite on recopie la partie qui suit le point (si ncessaire): if (pos_last_dot != -1) { for (c = pos_last_dot+1,other_cursor=max_length-4;fname[c]!='\0' && other_cursor < max_length-1;c++,other_cursor++) result[other_cursor]=fname[c]; } } return result; } // -- Rajouter a la liste des elements de la liste un element --------------- void Add_element_to_list(T_Fileselector *list, const char * full_name, const char *short_name, int type, byte icon) // Cette procedure ajoute a la liste chainee un fichier pass en argument. { // Working element T_Fileselector_item * temp_item; // Allocate enough room for one struct + the visible label temp_item=(T_Fileselector_item *)malloc(sizeof(T_Fileselector_item)+strlen(short_name)); // Initialize element strcpy(temp_item->Short_name,short_name); strcpy(temp_item->Full_name,full_name); temp_item->Type = type; temp_item->Icon = icon; // Doubly-linked temp_item->Next =list->First; temp_item->Previous=NULL; if (list->First!=NULL) list->First->Previous=temp_item; // Put new element at the beginning list->First=temp_item; } /// /// Checks if a file has the requested file extension. /// The extension string can end with a ';' (remainder is ignored) /// This function allows wildcard '?', and '*' if it's the only character. int Check_extension(const char *filename, const char * filter) { int pos_last_dot; int c = 0; if (filter[0] == '*') return 1; // On recherche la position du dernier . dans le nom pos_last_dot = Position_last_dot(filename); // Fichier sans extension (ca arrive) if (pos_last_dot == -1) return (filter[0] == '\0' || filter[0] == ';'); // Vrification caractre par caractre, case-insensitive. c = 0; while (1) { if (filter[c] == '\0' || filter[c] == ';') return filename[pos_last_dot + 1 + c] == '\0'; if (filter[c] != '?' && tolower(filter[c]) != tolower(filename[pos_last_dot + 1 + c])) return 0; c++; } } // -- Lecture d'une liste de fichiers --------------------------------------- void Read_list_of_files(T_Fileselector *list, byte selected_format) // Cette procdure charge dans la liste chaine les fichiers dont l'extension // correspond au format demand. { DIR* current_directory; //Rpertoire courant struct dirent* entry; // Structure de lecture des lments char * filter = "*"; // Extension demande struct stat Infos_enreg; char * current_path = NULL; char curdir[MAX_PATH_CHARACTERS]; #if defined (__MINT__) char path[1024]={0}; char path2[1024]={0}; char currentDrive=0; T_Fileselector_item *item=0; bool bFound=false; path[0]='\0'; path2[0]='\0'; #endif // Tout d'abord, on dduit du format demand un filtre utiliser: filter = Get_fileformat(selected_format)->Extensions; // Ensuite, on vide la liste actuelle: Free_fileselector_list(list); // Aprs effacement, il ne reste ni fichier ni rpertoire dans la liste // On lit tous les rpertoires: #if defined (__MINT__) currentDrive='A'; currentDrive=currentDrive+Dgetdrv(); Dgetpath(path,0); sprintf(path2,"%c:\%s",currentDrive,path); strcat(path2,PATH_SEPARATOR); current_directory=opendir(path2); #else current_path=getcwd(curdir,MAX_PATH_CHARACTERS); current_directory=opendir(current_path); #endif while ((entry=readdir(current_directory))) { // Ignore 'current directory' entry if ( !strcmp(entry->d_name, ".")) { continue; } stat(entry->d_name,&Infos_enreg); // entries tagged "directory" : if( S_ISDIR(Infos_enreg.st_mode)) { // On Windows, the presence of a "parent directory" entry has proven // unreliable on non-physical drives : // Sometimes it's missing, sometimes it's present even at root... // We skip it here and add a specific check after the loop #if defined(__WIN32__) if (!strcmp(entry->d_name, PARENT_DIR)) continue; #endif // Don't display hidden file, unless requested by options if (!Config.Show_hidden_directories && File_is_hidden(entry->d_name, entry->d_name)) { continue; } // Add to list Add_element_to_list(list, entry->d_name, Format_filename(entry->d_name, 19, 1), 1, ICON_NONE); list->Nb_directories++; } else if (S_ISREG(Infos_enreg.st_mode) && // It's a file (Config.Show_hidden_files || // Not hidden !File_is_hidden(entry->d_name, entry->d_name))) { const char * ext = filter; while (ext!=NULL) { if (Check_extension(entry->d_name, ext)) { // Add to list Add_element_to_list(list, entry->d_name, Format_filename(entry->d_name, 19, 0), 0, ICON_NONE); list->Nb_files++; // Stop searching ext=NULL; } else { ext = strchr(ext, ';'); if (ext) ext++; } } } } // Now here's OS-specific code to determine if "parent directory" entry // should appear. #if defined(__MORPHOS__) || defined(__AROS__) || defined (__amigaos4__) || defined(__amigaos__) // Amiga systems: always Add_element_to_list(list, PARENT_DIR, Format_filename(PARENT_DIR,19,1), 1, ICON_NONE); list->Nb_directories ++; #elif defined (__WIN32__) // Windows : if (((current_path[0]>='a'&¤t_path[0]<='z')||(current_path[0]>='A'&¤t_path[0]<='Z')) && current_path[1]==':' && ( (current_path[2]=='\0') || (current_path[2]=='/'&¤t_path[3]=='\0') || (current_path[2]=='\\'&¤t_path[3]=='\0') )) { // Path is X:\ or X:/ or X: // so don't display parent directory } else { Add_element_to_list(list, PARENT_DIR, Format_filename(PARENT_DIR,19,1), 1, ICON_NONE); list->Nb_directories ++; } #elif defined (__MINT__) // check if ".." exists if not add it // FreeMinT lists ".." already, but this is not so for TOS // simply adding it will cause double PARENT_DIR under FreeMiNT bFound= false; for (item = list->First; (((item != NULL) && (bFound==false))); item = item->Next){ if (item->Type == 1){ if(strncmp(item->Full_name,PARENT_DIR,(sizeof(char)*2))==0) bFound=true; } } if(!bFound){ Add_element_to_list(list,PARENT_DIR,Format_filename(PARENT_DIR,19,1),1,ICON_NONE); // add if not present list->Nb_directories ++; } #endif closedir(current_directory); current_path = NULL; if (list->Nb_files==0 && list->Nb_directories==0) { // This can happen on some empty network drives. // Add a dummy entry because the fileselector doesn't // seem to support empty list. Add_element_to_list(list, ".",Format_filename(".",19,1),1,ICON_NONE); } Recount_files(list); } #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) void bstrtostr( BSTR in, STRPTR out, TEXT max ) { STRPTR iptr; dword i; dword len; #if defined(__AROS__) iptr = AROS_BSTR_ADDR( in ); len = AROS_BSTR_strlen( in ); #else iptr = BADDR( in ); len = iptr[0]; iptr++; #endif if( max > len ) max = len; for( i=0; iNb_files=0; list->Nb_directories=0; #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) { struct DosList *dl; char tmp[256]; dl = LockDosList( LDF_VOLUMES | LDF_ASSIGNS | LDF_READ ); if( dl ) { while( ( dl = NextDosEntry( dl, LDF_VOLUMES | LDF_ASSIGNS | LDF_READ ) ) ) { bstrtostr( dl->dol_Name, tmp, 254 ); strcat( tmp, ":" ); Add_element_to_list(list, tmp, Format_filename(tmp, name_length, 2), 2, ICON_NONE ); list->Nb_directories++; } UnLockDosList( LDF_VOLUMES | LDF_ASSIGNS | LDF_READ ); } } #elif defined (__WIN32__) { char drive_name[]="A:\\"; int drive_bits = GetLogicalDrives(); int drive_index; int bit_index; byte icon; // Sous Windows, on a la totale, presque aussi bien que sous DOS: drive_index = 0; for (bit_index=0; bit_index<26 && drive_index<23; bit_index++) { if ( (1 << bit_index) & drive_bits ) { // On a ce lecteur, il faut maintenant dterminer son type "physique". // pour profiter des jolies icones de X-man. char drive_path[]="A:\\"; // Cette API Windows est trange, je dois m'y faire... drive_path[0]='A'+bit_index; switch (GetDriveType(drive_path)) { case DRIVE_CDROM: icon=ICON_CDROM; break; case DRIVE_REMOTE: icon=ICON_NETWORK; break; case DRIVE_REMOVABLE: icon=ICON_FLOPPY_3_5; break; case DRIVE_FIXED: icon=ICON_HDD; break; default: icon=ICON_NETWORK; break; } drive_name[0]='A'+bit_index; Add_element_to_list(list, drive_name, Format_filename(drive_name,name_length-1,2), 2, icon); list->Nb_directories++; drive_index++; } } } #elif defined(__MINT__) drive_bits = Drvmap(); //get drive map bitfield for (bit_index=0; bit_index<32; bit_index++) { if ( (1 << bit_index) & drive_bits ) { drive_name[0]='A'+bit_index; Add_element_to_list(list, drive_name,Format_filename(drive_name,name_length,2),2,ICON_NONE); list->Nb_directories++; drive_index++; } } #else { //Sous les diffrents unix, on va mettre // un disque dur qui pointera vers la racine, // et un autre vers le home directory de l'utilisateur. // Ensuite on utilise read_file_system_list pour complter struct mount_entry* mount_points_list; struct mount_entry* next; char * home_dir = getenv("HOME"); Add_element_to_list(list, "/", Format_filename("/",name_length,2), 2, ICON_NONE); list->Nb_directories++; if(home_dir) { Add_element_to_list(list, home_dir, Format_filename(home_dir, name_length, 2), 2, ICON_NONE); list->Nb_directories++; } mount_points_list = read_file_system_list(0); while(mount_points_list != NULL) { byte icon = ICON_NONE; if (strcmp(mount_points_list->me_type, "cd9660") == 0) icon = ICON_CDROM; else if (strcmp(mount_points_list->me_type, "nfs") == 0) icon = ICON_NETWORK; else if (strcmp(mount_points_list->me_type, "msdos") == 0) icon = ICON_FLOPPY_3_5; // Only a guess... else if (strcmp(mount_points_list->me_type, "ext2fs") == 0) icon = ICON_HDD; // Only a guess... if(mount_points_list->me_dummy == 0 && strcmp(mount_points_list->me_mountdir,"/") && strcmp(mount_points_list->me_mountdir,"/home")) { Add_element_to_list(list, mount_points_list->me_mountdir, Format_filename(mount_points_list->me_mountdir, name_length, 2), 2, icon); list->Nb_directories++; } next = mount_points_list -> me_next; #if !(defined(__macosx__) || defined(__FreeBSD__)) free(mount_points_list -> me_type); #endif free(mount_points_list -> me_devname); free(mount_points_list -> me_mountdir); free(mount_points_list); mount_points_list = next; } } #endif Recount_files(list); } // Comparison of file names: #ifdef WIN32 // case-insensitive #define FILENAME_COMPARE strcasecmp #else // case-sensitive #define FILENAME_COMPARE strcmp #endif // -- Tri de la liste des fichiers et rpertoires --------------------------- void Sort_list_of_files(T_Fileselector *list) // Tri la liste chaine existante dans l'ordre suivant: // // * Les rpertoires d'abord, dans l'ordre alphabtique de leur nom // * Les fichiers ensuite, dans l'ordre alphabtique de leur nom { byte list_is_sorted; // Boolen "La liste est trie" byte need_swap; // Boolen "Il faut inverser les lments" T_Fileselector_item * prev_item; T_Fileselector_item * current_item; T_Fileselector_item * next_item; T_Fileselector_item * next_to_next_item; // Check there are at least two elements before sorting if (list->First && list->First->Next) { do { // Par dfaut, on considre que la liste est trie list_is_sorted=1; current_item=list->First; next_item=current_item->Next; while ( (current_item!=NULL) && (next_item!=NULL) ) { // On commence par supposer qu'il n'y pas pas besoin d'inversion need_swap=0; // Ensuite, on vrifie si les deux lments sont bien dans l'ordre ou // non: // Drives go at the top of the list, and files go after them if ( current_item->Type < next_item->Type ) need_swap=1; // If both elements have the same type, compare the file names, if // current is alphabetically before, we need to swap, unless it is // parent directory, which should always go first else if ( (current_item->Type==next_item->Type) && (((FILENAME_COMPARE(current_item->Full_name,next_item->Full_name)>0) && (FILENAME_COMPARE(current_item->Full_name, PARENT_DIR) != 0)) || (FILENAME_COMPARE(next_item->Full_name, PARENT_DIR) == 0)) ) need_swap=1; if (need_swap) { // Si les deux lments ncessitent d'tre invers: // On les inverses: // On note avant tout les lments qui encapsulent nos deux amis prev_item =current_item->Previous; next_to_next_item=next_item->Next; // On permute le chanage des deux lments entree eux current_item->Next =next_to_next_item; current_item->Previous=next_item; next_item->Next =current_item; next_item->Previous=prev_item; // On tente un chanage des lments encapsulant les compres: if (prev_item!=NULL) prev_item->Next=next_item; if (next_to_next_item!=NULL) next_to_next_item->Previous=current_item; // On fait bien attention modifier la tte de liste en cas de besoin if (current_item==list->First) list->First=next_item; // Ensuite, on se prpare tudier les lments prcdents: current_item=prev_item; // Et on constate que la liste n'tait pas encore gnialement trie list_is_sorted=0; } else { // Si les deux lments sont dans l'ordre: // On passe aux suivants current_item=current_item->Next; next_item=next_item->Next; } } } while (!list_is_sorted); } // Force a recount / re-index Recount_files(list); } T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index) { // Safety if (index >= list->Nb_elements) index=list->Nb_elements-1; if (list->Index) { return list->Index[index]; } else { // Index not available. // Can only happen in case of malloc error. // Fall back anyway on iterative search T_Fileselector_item * item = list->First; for (;index>0;index--) item = item->Next; return item; } } // -- Affichage des lments de la liste de fichier / rpertoire ------------ void Display_file_list(T_Fileselector *list, short offset_first,short selector_offset) // // offset_first = Dcalage entre le premier fichier visible dans le // slecteur et le premier fichier de la liste // // selector_offset = Dcalage entre le premier fichier visible dans le // slecteur et le fichier slectionn dans la liste // { T_Fileselector_item * current_item; byte index; // index du fichier qu'on affiche (0 -> 9) byte text_color; byte background_color; // On vrifie s'il y a au moins 1 fichier dans la liste: if (list->Nb_elements>0) { // On commence par chercher pointer sur le premier fichier visible: current_item = Get_item_by_index(list, offset_first); // Pour chacun des 10 lments inscriptibles l'cran for (index=0;index<10;index++) { // S'il est slectionn: if (!selector_offset) { // Si c'est un fichier if (current_item->Type==0) text_color=SELECTED_FILE_COLOR; else text_color=SELECTED_DIRECTORY_COLOR; background_color=SELECTED_BACKGROUND_COLOR; } else { // Si c'est un fichier if (current_item->Type==0) text_color=NORMAL_FILE_COLOR; else text_color=NORMAL_DIRECTORY_COLOR; background_color=NORMAL_BACKGROUND_COLOR; } // On affiche l'lment if (current_item->Icon != ICON_NONE) { // Name preceded by an icon Print_in_window(16,95+index*8,current_item->Short_name,text_color,background_color); Window_display_icon_sprite(8,95+index*8,current_item->Icon); } else // Name without icon Print_in_window(8,95+index*8,current_item->Short_name,text_color,background_color); // On passe la ligne suivante selector_offset--; current_item=current_item->Next; if (!current_item) break; } // End de la boucle d'affichage } // End du test d'existence de fichiers } // -- Rcuprer le libell d'un lment de la liste ------------------------- void Get_selected_item(T_Fileselector *list, short offset_first,short selector_offset,char * label,int *type) // // offset_first = Dcalage entre le premier fichier visible dans le // slecteur et le premier fichier de la liste // // selector_offset = Dcalage entre le premier fichier visible dans le // slecteur et le fichier rcuprer // // label = str de rception du libell de l'lment // // type = Rcupration du type: 0 fichier, 1 repertoire, 2 lecteur. // Passer NULL si pas interess. { T_Fileselector_item * current_item; // On vrifie s'il y a au moins 1 fichier dans la liste: if (list->Nb_elements>0) { // On commence par chercher pointer sur le premier fichier visible: // Ensuite, on saute autant d'lments que le dcalage demand: current_item = Get_item_by_index(list, offset_first + selector_offset); // On recopie la chane strcpy(label, current_item->Full_name); if (type != NULL) *type=current_item->Type; } // End du test d'existence de fichiers } // ----------------- Dplacements dans la liste de fichiers ----------------- void Selector_scroll_down(short * offset_first,short * selector_offset) // Fait scroller vers le bas le slecteur de fichier... (si possible) { if ( ((*selector_offset)<9) && ( (*selector_offset)+1 < Filelist.Nb_elements ) ) // Si la slection peut descendre Display_file_list(&Filelist, *offset_first,++(*selector_offset)); else // Sinon, descendre la fentre (si possible) if ((*offset_first)+100) // Si la slection peut monter Display_file_list(&Filelist, *offset_first,--(*selector_offset)); else // Sinon, monter la fentre (si possible) if ((*offset_first)>0) Display_file_list(&Filelist, --(*offset_first),*selector_offset); } void Selector_page_down(short * offset_first,short * selector_offset, short lines) { if (Filelist.Nb_elements-1>*offset_first+*selector_offset) { if (*selector_offset<9) { if (Filelist.Nb_elements<10) { *offset_first=0; *selector_offset=Filelist.Nb_elements-1; } else *selector_offset=9; } else { if (Filelist.Nb_elements>*offset_first+18) *offset_first+=lines; else { *offset_first=Filelist.Nb_elements-10; *selector_offset=9; } } } Display_file_list(&Filelist, *offset_first,*selector_offset); } void Selector_page_up(short * offset_first,short * selector_offset, short lines) { if (*offset_first+*selector_offset>0) { if (*selector_offset>0) *selector_offset=0; else { if (*offset_first>lines) *offset_first-=lines; else *offset_first=0; } } Display_file_list(&Filelist, *offset_first,*selector_offset); } void Selector_end(short * offset_first,short * selector_offset) { if (Filelist.Nb_elements<10) { *offset_first=0; *selector_offset=Filelist.Nb_elements-1; } else { *offset_first=Filelist.Nb_elements-10; *selector_offset=9; } Display_file_list(&Filelist, *offset_first,*selector_offset); } void Selector_home(short * offset_first,short * selector_offset) { Display_file_list(&Filelist, (*offset_first)=0,(*selector_offset)=0); } short Compute_click_offset_in_fileselector(void) /* Renvoie le dcalage dans le slecteur de fichier sur lequel on a click. Renvoie le dcalage du dernier fichier si on a click au del. Renvoie -1 si le slecteur est vide. */ { short computed_offset; computed_offset=(((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-95)>>3; if (computed_offset>=Filelist.Nb_elements) computed_offset=Filelist.Nb_elements-1; return computed_offset; } void Display_bookmark(T_Dropdown_button * Button, int bookmark_number) { if (Config.Bookmark_directory[bookmark_number]) { int label_size; // Libell Print_in_window_limited(Button->Pos_X+3+10,Button->Pos_Y+2,Config.Bookmark_label[bookmark_number],8,MC_Black,MC_Light); label_size=strlen(Config.Bookmark_label[bookmark_number]); if (label_size<8) Window_rectangle(Button->Pos_X+3+10+label_size*8,Button->Pos_Y+2,(8-label_size)*8,8,MC_Light); // Menu apparait sur clic droit Button->Active_button=RIGHT_SIDE; // item actifs Window_dropdown_clear_items(Button); Window_dropdown_add_item(Button,0,"Set"); Window_dropdown_add_item(Button,1,"Rename"); Window_dropdown_add_item(Button,2,"Clear"); } else { // Libell Print_in_window(Button->Pos_X+3+10,Button->Pos_Y+2,"--------",MC_Dark,MC_Light); // Menu apparait sur clic droit ou gauche Button->Active_button=RIGHT_SIDE|LEFT_SIDE; // item actifs Window_dropdown_clear_items(Button); Window_dropdown_add_item(Button,0,"Set"); } } //------------------------ Chargements et sauvegardes ------------------------ void Print_current_directory(void) // // Affiche Selector->Directory sur 37 caractres // { char converted_name[MAX_PATH_CHARACTERS]; char temp_name[MAX_DISPLAYABLE_PATH+1]; // Nom tronqu int length; // length du rpertoire courant int index; // index de parcours de la chaine complte strncpy(converted_name,Selector->Directory,sizeof(converted_name)); converted_name[sizeof(converted_name)-1] = '\0'; #ifdef ENABLE_FILENAMES_ICONV { /* convert file name from UTF8 to ANSI */ char * input = Selector->Directory; size_t inbytesleft = strlen(input); char * output = converted_name; size_t outbytesleft = sizeof(converted_name)-1; if(cd != (iconv_t)-1 && (ssize_t)iconv(cd, &input, &inbytesleft, &output, &outbytesleft) >= 0) *output = '\0'; } #endif /* ENABLE_FILENAMES_ICONV */ Window_rectangle(10,84,37*8,8,MC_Light); length=strlen(converted_name); if (length>MAX_DISPLAYABLE_PATH) { // Doh! il va falloir tronquer le rpertoire (bouh !) // On commence par copier btement les 3 premiers caractres (e.g. "C:\") for (index=0;index<3;index++) temp_name[index]=converted_name[index]; // On y rajoute 3 petits points: strcpy(temp_name+3,"..."); // Ensuite, on cherche un endroit partir duquel on pourrait loger tout // le reste de la chaine (Ouaaaaaah!!! Vachement fort le mec!!) for (index++;index= 0) *output = '\0'; } #endif /* ENABLE_FILENAMES_ICONV */ Window_rectangle(82,48,27*8,8,MC_Light); Print_in_window_limited(82,48,filename,27,MC_Black,MC_Light); Update_window_area(82,48,27*8,8); } int Selected_type; // Utilis pour mmoriser le type d'entre choisi // dans le selecteur de fichier. void Prepare_and_display_filelist(short Position, short offset, T_Scroller_button * button) { button->Nb_elements=Filelist.Nb_elements; button->Position=Position; Compute_slider_cursor_length(button); Window_draw_slider(button); // On efface les anciens noms de fichier: Window_rectangle(8-1,95-1,144+2,80+2,MC_Black); // On affiche les nouveaux: Display_file_list(&Filelist, Position,offset); Update_window_area(8-1,95-1,144+2,80+2); // On rcupre le nom du schmilblick "accder" Get_selected_item(&Filelist, Position,offset,Selector_filename,&Selected_type); // On affiche le nouveau nom de fichier Print_filename_in_fileselector(); // On affiche le nom du rpertoire courant Print_current_directory(); } void Reload_list_of_files(byte filter, T_Scroller_button * button) { Read_list_of_files(&Filelist, filter); Sort_list_of_files(&Filelist); // // Check and fix the fileselector positions, because // the directory content may have changed. // // Make the offset absolute Selector->Offset += Selector->Position; // Ensure it's within limits if (Selector->Offset >= Filelist.Nb_elements) { Selector->Offset = Filelist.Nb_elements-1; } // Ensure the position doesn't show "too many files" if (Selector->Position!=0 && Selector->Position>(Filelist.Nb_elements-10)) { if (Filelist.Nb_elements<10) { Selector->Position=0; } else { Selector->Position=Filelist.Nb_elements-10; } } // Restore the offset as relative to the position. Selector->Offset -= Selector->Position; Prepare_and_display_filelist(Selector->Position,Selector->Offset,button); } void Scroll_fileselector(T_Scroller_button * file_scroller) { char old_filename[MAX_PATH_CHARACTERS]; strcpy(old_filename,Selector_filename); // On regarde si la liste a boug if (file_scroller->Position!=Selector->Position) { // Si c'est le cas, il faut mettre jour la jauge file_scroller->Position=Selector->Position; Window_draw_slider(file_scroller); } // On rcupre le nom du schmilblick "accder" Get_selected_item(&Filelist, Selector->Position,Selector->Offset,Selector_filename,&Selected_type); if (strcmp(old_filename,Selector_filename)) New_preview_is_needed=1; // On affiche le nouveau nom de fichier Print_filename_in_fileselector(); Display_cursor(); } short Find_file_in_fileselector(T_Fileselector *list, const char * fname) { T_Fileselector_item * item; short index; short close_match=0; index=0; for (item=list->First; item!=NULL; item=item->Next) { if (strcmp(item->Full_name,fname)==0) return index; if (strcasecmp(item->Full_name,fname)==0) close_match=index; index++; } return close_match; } void Highlight_file(short index) { if ((Filelist.Nb_elements<=10) || (index<5)) { Selector->Position=0; Selector->Offset=index; } else { if (index>=Filelist.Nb_elements-5) { Selector->Position=Filelist.Nb_elements-10; Selector->Offset=index-Selector->Position; } else { Selector->Position=index-4; Selector->Offset=4; } } } short Find_filename_match(T_Fileselector *list, char * fname) { short best_match; T_Fileselector_item * current_item; short item_number; byte matching_letters=0; byte counter; best_match=-1; item_number=0; for (current_item=list->First; current_item!=NULL; current_item=current_item->Next) { if ( (!Config.Find_file_fast) || (Config.Find_file_fast==(current_item->Type+1)) ) { // On compare et si c'est mieux, on stocke dans Meilleur_nom for (counter=0; fname[counter]!='\0' && tolower(current_item->Full_name[counter])==tolower(fname[counter]); counter++); if (counter>matching_letters) { matching_letters=counter; best_match=item_number; } } item_number++; } return best_match; } // Quicksearch system char quicksearch_filename[MAX_PATH_CHARACTERS]=""; void Reset_quicksearch(void) { quicksearch_filename[0]='\0'; } short Quicksearch(T_Fileselector *selector) { int len; short most_matching_item; // Autre => On se place sur le nom de fichier qui correspond len=strlen(quicksearch_filename); if (Key_ANSI>= ' ' && Key_ANSI < 255 && len<50) { quicksearch_filename[len]=Key_ANSI; quicksearch_filename[len+1]='\0'; most_matching_item=Find_filename_match(selector, quicksearch_filename); if ( most_matching_item >= 0 ) { return most_matching_item; } *quicksearch_filename=0; } return -1; } // Translated from Highlight_file void Locate_list_item(T_List_button * list, short selected_item) { // Safety bounds if (selected_item<0) selected_item=0; else if (selected_item>=list->Scroller->Nb_elements) selected_item=list->Scroller->Nb_elements-1; if ((list->Scroller->Nb_elements<=list->Scroller->Nb_visibles) || (selected_item<(list->Scroller->Nb_visibles/2))) { list->List_start=0; list->Cursor_position=selected_item; } else { if (selected_item>=list->Scroller->Nb_elements-(list->Scroller->Nb_visibles/2)) { list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; list->Cursor_position=selected_item-list->List_start; } else { list->List_start=selected_item-(list->Scroller->Nb_visibles/2-1); list->Cursor_position=(list->Scroller->Nb_visibles/2-1); } } } int Quicksearch_list(T_List_button * list, T_Fileselector * selector) { // Try Quicksearch short selected_item=Quicksearch(selector); if (selected_item>=0 && selected_item!=list->Cursor_position+list->List_start) { Locate_list_item(list, selected_item); Hide_cursor(); // Mise jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); Window_redraw_list(list); Display_cursor(); // Store the selected value as attribute2 Window_attribute2=list->List_start + list->Cursor_position; // Return the control ID of the list. return list->Number; } return 0; } byte Button_Load_or_Save(T_Selector_settings *settings, byte load, T_IO_Context *context) // load=1 => On affiche le menu du bouton LOAD // load=0 => On affiche le menu du bouton SAVE { short clicked_button; T_Scroller_button * file_scroller; T_Dropdown_button * formats_dropdown; T_Dropdown_button * bookmark_dropdown[4]; short temp; unsigned int format; int dummy=0; // Sert appeler SDL_GetKeyState byte save_or_load_image=0; byte has_clicked_ok=0;// Indique si on a click sur Load ou Save ou sur //un bouton enclenchant Load ou Save juste aprs. byte initial_back_color; // preview destroys it (how nice) char previous_directory[MAX_PATH_CHARACTERS]; // Rpertoire d'o l'on vient aprs un CHDIR char save_filename[MAX_PATH_CHARACTERS]; char initial_comment[COMMENT_SIZE+1]; short window_shortcut; Selector=settings; Reset_quicksearch(); //if (Native_filesel(load) != 0); // TODO : handle this if (context->Type == CONTEXT_MAIN_IMAGE) window_shortcut = load?(0x100+BUTTON_LOAD):(0x100+BUTTON_SAVE); else window_shortcut = load?SPECIAL_LOAD_BRUSH:SPECIAL_SAVE_BRUSH; // Backup data that needs be restored on "cancel" initial_back_color=Back_color; strcpy(initial_comment,context->Comment); if (load) { if (context->Type == CONTEXT_MAIN_IMAGE) Open_window(310,200,"Load picture"); else Open_window(310,200,"Load brush"); Window_set_normal_button(198,180,51,14,"Load",0,1,SDLK_RETURN); // 1 } else { if (context->Type == CONTEXT_MAIN_IMAGE) Open_window(310,200,"Save picture"); else if (context->Type == CONTEXT_BRUSH) Open_window(310,200,"Save brush"); else if (context->Type == CONTEXT_PALETTE) Open_window(310,200,"Save palette"); else assert(false); Window_set_normal_button(198,180,51,14,"Save",0,1,SDLK_RETURN); // 1 if (Selector->Format_filter<=FORMAT_ALL_FILES) // Correction du *.* { Selector->Format_filter=context->Format; Selector->Position=0; Selector->Offset=0; } if (Get_fileformat(Selector->Format_filter)->Save == NULL) // Correction d'un format insauvable { Selector->Format_filter=DEFAULT_FILEFORMAT; Selector->Position=0; Selector->Offset=0; } // Affichage du commentaire if (Get_fileformat(Selector->Format_filter)->Comment) Print_in_window(45,70,context->Comment,MC_Black,MC_Light); } Window_set_normal_button(253,180,51,14,"Cancel",0,1,KEY_ESC); // 2 Window_set_normal_button(7,180,51,14,"Delete",0,1,SDLK_DELETE); // 3 // Frame autour des infos sur le fichier de dessin Window_display_frame_in(6, 44,299, 37); // Frame autour de la preview Window_display_frame_in(181,93,124,84); // Frame autour du fileselector Window_display_frame_in(6,93,148,84); // Fileselector Window_set_special_button(9,95,144,80); // 4 // Scroller du fileselector file_scroller = Window_set_scroller_button(160,94,82,1,10,0); // 5 // Dropdown pour les formats de fichier formats_dropdown= Window_set_dropdown_button(68,28,52,11,0, Get_fileformat(Selector->Format_filter)->Label, 1,0,1,RIGHT_SIDE|LEFT_SIDE,0); // 6 for (format=0; format < Nb_known_formats(); format++) { if (((context->Type == CONTEXT_PALETTE) == File_formats[format].Palette_only) && ((load && (File_formats[format].Load || File_formats[format].Identifier <= FORMAT_ALL_FILES)) || (!load && File_formats[format].Save))) Window_dropdown_add_item(formats_dropdown,File_formats[format].Identifier,File_formats[format].Label); } Print_in_window(70,18,"Format",MC_Dark,MC_Light); // Texte de commentaire des dessins Print_in_window(9,70,"Txt:",MC_Dark,MC_Light); Window_set_input_button(43,68,COMMENT_SIZE); // 7 // Saisie du nom de fichier Window_set_input_button(80,46,27); // 8 Print_in_window(9,47,"Filename",MC_Dark,MC_Light); Print_in_window(9,59,"Image:",MC_Dark,MC_Light); Print_in_window(101,59,"Size:",MC_Dark,MC_Light); Print_in_window(228,59,"(",MC_Dark,MC_Light); Print_in_window(292,59,")",MC_Dark,MC_Light); // Selecteur de Lecteur / Volume Window_set_normal_button(7,18,53,23,"",0,1,SDLK_LAST); // 9 Print_in_window(10,22,"Select",MC_Black,MC_Light); Print_in_window(14,30,"drive",MC_Black,MC_Light); // Bookmarks for (temp=0;tempPos_X+3,bookmark_dropdown[temp]->Pos_Y+2,ICON_STAR); Display_bookmark(bookmark_dropdown[temp],temp); } #if defined(__MINT__) { static char path[1024]={0}; chdir(context->File_directory); Dgetpath(path,0); strcat(path,PATH_SEPARATOR); strcpy(Selector->Directory,path); } #else { chdir(context->File_directory); getcwd(Selector->Directory,MAX_PATH_CHARACTERS); } #endif // Affichage des premiers fichiers visibles: Reload_list_of_files(Selector->Format_filter,file_scroller); if (!load) { Highlight_file(Find_file_in_fileselector(&Filelist, context->File_name)); Prepare_and_display_filelist(Selector->Position,Selector->Offset,file_scroller); // On initialise le nom de fichier celui en cours et non pas celui sous // la barre de slection strcpy(Selector_filename,context->File_name); // On affiche le nouveau nom de fichier Print_filename_in_fileselector(); } New_preview_is_needed=1; Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); switch (clicked_button) { case -1 : case 0 : break; case 1 : // Load ou Save if(load) { // Determine the type if(File_exists(Selector_filename)) { Selected_type = 0; if(Directory_exists(Selector_filename)) Selected_type = 1; } else { Selected_type = 1; } } else { if(Directory_exists(Selector_filename)) Selected_type = 1; else Selected_type = 0; } has_clicked_ok=1; break; case 2 : // Cancel break; case 3 : // Delete if (Filelist.Nb_elements && (*Selector_filename!='.') && Selected_type!=2) { char * message; Hide_cursor(); // On affiche une demande de confirmation if (Selector->Position+Selector->Offset>=Filelist.Nb_directories) { message="Delete file ?"; } else { message="Remove directory ?"; } if (Confirmation_box(message)) { // Si c'est un fichier if (Selector->Position+Selector->Offset>=Filelist.Nb_directories) // On efface le fichier (si on peut) temp=(!remove(Selector_filename)); else // Si c'est un repertoire // On efface le repertoire (si on peut) temp=(!rmdir(Selector_filename)); if (temp) // temp indique si l'effacement s'est bien pass { // On remonte si c'tait le dernier lment de la liste if (Selector->Position+Selector->Offset==Filelist.Nb_elements-1) { if (Selector->Position) Selector->Position--; else if (Selector->Offset) Selector->Offset--; } else // Si ce n'tait pas le dernier, il faut faire gaffe ce { // que ses copains d'en dessous ne remontent pas trop. if ( (Selector->Position) && (Selector->Position+10==Filelist.Nb_elements) ) { Selector->Position--; Selector->Offset++; } } // On relit les informations Reload_list_of_files(Selector->Format_filter,file_scroller); // On demande la preview du nouveau fichier sur lequel on se trouve New_preview_is_needed=1; } else Error(0); } } break; case 4 : // Zone d'affichage de la liste de fichiers Hide_cursor(); temp=Compute_click_offset_in_fileselector(); if (temp>=0) { if (temp!=Selector->Offset) { // On met jour le dcalage Selector->Offset=temp; // On rcupre le nom du schmilblick "accder" Get_selected_item(&Filelist, Selector->Position,Selector->Offset,Selector_filename,&Selected_type); // On affiche le nouveau nom de fichier Print_filename_in_fileselector(); // On affiche nouveau la liste Display_file_list(&Filelist, Selector->Position,Selector->Offset); // On vient de changer de nom de fichier, donc on doit s'appreter // a rafficher une preview New_preview_is_needed=1; Reset_quicksearch(); } else { // En sauvegarde, si on a double-click sur un rpertoire, il // faut mettre le nom de fichier au nom du rpertoire. Sinon, dans // certains cas, on risque de sauvegarder avec le nom du fichier // actuel au lieu de changer de rpertoire. if (Selector->Position+Selector->OffsetPosition,Selector->Offset,Selector_filename,&Selected_type); has_clicked_ok=1; New_preview_is_needed=1; Reset_quicksearch(); } } Display_cursor(); Wait_end_of_click(); break; case 5 : // Scroller de fichiers Hide_cursor(); Selector->Position=Window_attribute2; // On rcupre le nom du schmilblick "accder" Get_selected_item(&Filelist, Selector->Position,Selector->Offset,Selector_filename,&Selected_type); // On affiche le nouveau nom de fichier Print_filename_in_fileselector(); // On affiche nouveau la liste Display_file_list(&Filelist, Selector->Position,Selector->Offset); Display_cursor(); New_preview_is_needed=1; Reset_quicksearch(); break; case 6 : // File Format dropdown // Refresh fileselector according to new filter if (Selector->Format_filter != Window_attribute2) { int pos_last_dot; char* savename = NULL; Selector->Format_filter = Window_attribute2; if (Filelist.Nb_elements>0) { T_Fileselector_item * current_item; current_item = Get_item_by_index(&Filelist, Selector->Position + Selector->Offset); // In "save" box, if current name is a (possible) filename // with extension, set it to new format's extension if (!load && current_item->Type == 0 && Get_fileformat(Selector->Format_filter)->Default_extension[0] != '\0' && (pos_last_dot=Position_last_dot(Selector_filename))!=-1 && Selector_filename[pos_last_dot+1]!='\0') { strcpy(Selector_filename + pos_last_dot + 1, Get_fileformat(Selector->Format_filter)->Default_extension); } } savename = (char *)strdup(Selector_filename); // By default, position list at the beginning Selector->Position = 0; Selector->Offset = 0; // Print the first visible files Hide_cursor(); Reload_list_of_files(Selector->Format_filter, file_scroller); New_preview_is_needed = 1; Reset_quicksearch(); if (savename != NULL) { // attempt to find the file name in new list int pos=Find_file_in_fileselector(&Filelist, savename); if (pos!=0) { Highlight_file(pos); Prepare_and_display_filelist(Selector->Position,Selector->Offset,file_scroller); } // If the file is (still present) or it's a name with new // extension, set it as the proposed file name. if (pos!=0 || !load) strcpy(Selector_filename, savename); free(savename); } Print_filename_in_fileselector(); Display_cursor(); } break; case 7 : // Saisie d'un commentaire pour la sauvegarde if ( (!load) && (Get_fileformat(Selector->Format_filter)->Comment) ) { Readline(45, 70, context->Comment, 32, INPUT_TYPE_STRING); Display_cursor(); } break; case 8 : // Saisie du nom de fichier { char filename_ansi[256]; // Save the filename strcpy(save_filename, Selector_filename); // Check if the selected entry is a drive/directory : // in, this case, clear the filename if (Filelist.Nb_elements>0) { T_Fileselector_item * current_item; current_item = Get_item_by_index(&Filelist, Selector->Position + Selector->Offset); if (current_item->Type != 0 && !FILENAME_COMPARE(current_item->Full_name,Selector_filename)) // current name is a highlighted directory Selector_filename[0]='\0'; } strncpy(filename_ansi, Selector_filename, sizeof(filename_ansi)); #ifdef ENABLE_FILENAMES_ICONV { /* convert from UTF8 to ANSI */ char * input = (char *)Selector_filename; size_t inbytesleft = strlen(input); char * output = filename_ansi; size_t outbytesleft = sizeof(filename_ansi)-1; if(cd != (iconv_t)-1 && (ssize_t)iconv(cd, &input, &inbytesleft, &output, &outbytesleft) >= 0) *output = '\0'; } #endif /* ENABLE_FILENAMES_ICONV */ if (Readline(82,48,filename_ansi,27,INPUT_TYPE_FILENAME)) { #ifdef ENABLE_FILENAMES_ICONV /* convert back from ANSI to UTF8 */ char * input = (char *)filename_ansi; size_t inbytesleft = strlen(input); char * output = Selector_filename; size_t outbytesleft = sizeof(Selector_filename)-1; if(cd_inv != (iconv_t)-1 && (ssize_t)iconv(cd_inv, &input, &inbytesleft, &output, &outbytesleft) >= 0) *output = '\0'; else #endif /* ENABLE_FILENAMES_ICONV */ strncpy(Selector_filename, filename_ansi, sizeof(Selector_filename)); // On regarde s'il faut rajouter une extension. C'est--dire s'il // n'y a pas de '.' dans le nom du fichier. for(temp=0,dummy=0; ((Selector_filename[temp]) && (!dummy)); temp++) if (Selector_filename[temp]=='.') dummy=1; if (!dummy) { if (Get_fileformat(Selector->Format_filter)->Default_extension) { if(!Directory_exists(Selector_filename)) { strcat(Selector_filename, "."); strcat(Selector_filename, Get_fileformat(Selector->Format_filter)->Default_extension); } } else { // put default extension // (but maybe we should browse through all available ones until we find // something suitable ?) if(!Directory_exists(Selector_filename)) { strcat(Selector_filename, ".pkm"); } } } if(load) { // Determine the type if(File_exists(Selector_filename)) { Selected_type = 0; if(Directory_exists(Selector_filename)) Selected_type = 1; } else { Selected_type = 1; } } else { if(Directory_exists(Selector_filename)) Selected_type = 1; else Selected_type = 0; } // Now load immediately, but only if the user exited readline by pressing ENTER if (Mouse_K == 0) has_clicked_ok = 1; } else { // Restore the old filename strcpy(Selector_filename, save_filename); Print_filename_in_fileselector(); } Display_cursor(); break; } case 9 : // Volume Select Hide_cursor(); // Comme on tombe sur un disque qu'on connait pas, on se place en // dbut de liste: Selector->Position=0; Selector->Offset=0; // Affichage des premiers fichiers visibles: Read_list_of_drives(&Filelist,19); Sort_list_of_files(&Filelist); Prepare_and_display_filelist(Selector->Position,Selector->Offset,file_scroller); Display_cursor(); New_preview_is_needed=1; Reset_quicksearch(); break; default: if (clicked_button>=10 && clicked_button<10+NB_BOOKMARKS) { // Bookmark char * directory_name; switch(Window_attribute2) { case -1: // bouton lui-mme: aller au rpertoire mmoris if (Config.Bookmark_directory[clicked_button-10]) { strcpy(Selector_filename,Config.Bookmark_directory[clicked_button-10]); Selected_type=1; has_clicked_ok=1; Reset_quicksearch(); } break; case 0: // Set free(Config.Bookmark_directory[clicked_button-10]); Config.Bookmark_directory[clicked_button-10] = NULL; Config.Bookmark_label[clicked_button-10][0]='\0'; temp=strlen(Selector->Directory); Config.Bookmark_directory[clicked_button-10]=malloc(temp+1); strcpy(Config.Bookmark_directory[clicked_button-10],Selector->Directory); directory_name=Find_last_separator(Selector->Directory); if (directory_name && directory_name[1]!='\0') directory_name++; else directory_name=Selector->Directory; temp=strlen(directory_name); strncpy(Config.Bookmark_label[clicked_button-10],directory_name,8); if (temp>8) { Config.Bookmark_label[clicked_button-10][7]=ELLIPSIS_CHARACTER; Config.Bookmark_label[clicked_button-10][8]='\0'; } Display_bookmark(bookmark_dropdown[clicked_button-10],clicked_button-10); break; case 1: // Rename if (Config.Bookmark_directory[clicked_button-10]) { // On enlve les "..." avant l'dition char bookmark_label[8+1]; strcpy(bookmark_label, Config.Bookmark_label[clicked_button-10]); if (bookmark_label[7]==ELLIPSIS_CHARACTER) bookmark_label[7]='\0'; if (Readline_ex(bookmark_dropdown[clicked_button-10]->Pos_X+3+10,bookmark_dropdown[clicked_button-10]->Pos_Y+2,bookmark_label,8,8,INPUT_TYPE_STRING,0)) strcpy(Config.Bookmark_label[clicked_button-10],bookmark_label); Display_bookmark(bookmark_dropdown[clicked_button-10],clicked_button-10); Display_cursor(); } break; case 2: // Clear if (Config.Bookmark_directory[clicked_button-10] && Confirmation_box("Erase bookmark ?")) { free(Config.Bookmark_directory[clicked_button-10]); Config.Bookmark_directory[clicked_button-10]=NULL; Config.Bookmark_label[clicked_button-10][0]='\0'; Display_bookmark(bookmark_dropdown[clicked_button-10],clicked_button-10); } break; } } break; } switch (Key) { case SDLK_UNKNOWN : break; case SDLK_DOWN : // Bas Reset_quicksearch(); Hide_cursor(); Selector_scroll_down(&Selector->Position,&Selector->Offset); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_UP : // Haut Reset_quicksearch(); Hide_cursor(); Selector_scroll_up(&Selector->Position,&Selector->Offset); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_PAGEDOWN : // PageDown Reset_quicksearch(); Hide_cursor(); Selector_page_down(&Selector->Position,&Selector->Offset,9); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_PAGEUP : // PageUp Reset_quicksearch(); Hide_cursor(); Selector_page_up(&Selector->Position,&Selector->Offset,9); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_END : // End Reset_quicksearch(); Hide_cursor(); Selector_end(&Selector->Position,&Selector->Offset); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_HOME : // Home Reset_quicksearch(); Hide_cursor(); Selector_home(&Selector->Position,&Selector->Offset); Scroll_fileselector(file_scroller); Key=0; break; case KEY_MOUSEWHEELDOWN : Reset_quicksearch(); Hide_cursor(); Selector_page_down(&Selector->Position,&Selector->Offset,3); Scroll_fileselector(file_scroller); Key=0; break; case KEY_MOUSEWHEELUP : Reset_quicksearch(); Hide_cursor(); Selector_page_up(&Selector->Position,&Selector->Offset,3); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_BACKSPACE : // Backspace Reset_quicksearch(); // Si le choix ".." est bien en tte des propositions... if (Filelist.Nb_elements && !strcmp(Filelist.First->Full_name,PARENT_DIR)) { // On va dans le rpertoire parent. strcpy(Selector_filename,PARENT_DIR); Selected_type=1; has_clicked_ok=1; } Key=0; break; default: if (clicked_button<=0) { short selected_item; if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Window_help(load?BUTTON_LOAD:BUTTON_SAVE, NULL); break; } if (Is_shortcut(Key,window_shortcut)) { clicked_button=2; break; } selected_item=Quicksearch(&Filelist); if (selected_item>=0) { temp=Selector->Position+Selector->Offset; Hide_cursor(); Highlight_file(selected_item); Prepare_and_display_filelist(Selector->Position,Selector->Offset,file_scroller); Display_cursor(); if (temp!=Selector->Position+Selector->Offset) New_preview_is_needed=1; } // Key=0; ? } else Reset_quicksearch(); } if (has_clicked_ok) { // Si c'est un rpertoire, on annule "has_clicked_ok" et on passe // dedans. if (Selected_type!=0) { Hide_cursor(); has_clicked_ok=0; // On mmorise le rpertoire dans lequel on tait if (strcmp(Selector_filename,PARENT_DIR)) { strcpy(previous_directory,PARENT_DIR); } else { Extract_filename(previous_directory, Selector->Directory); } // On doit rentrer dans le rpertoire: if (!chdir(Selector_filename)) { #if defined (__MINT__) static char path[1024]={0}; char currentDrive='A'; currentDrive=currentDrive+Dgetdrv(); Dgetpath(path,0); sprintf(Selector->Directory,"%c:\%s",currentDrive,path); #else getcwd(Selector->Directory,MAX_PATH_CHARACTERS); #endif // On lit le nouveau rpertoire Read_list_of_files(&Filelist, Selector->Format_filter); Sort_list_of_files(&Filelist); // On place la barre de slection sur le rpertoire d'o l'on vient Highlight_file(Find_file_in_fileselector(&Filelist, previous_directory)); } else Error(0); // Affichage des premiers fichiers visibles: Prepare_and_display_filelist(Selector->Position,Selector->Offset,file_scroller); Display_cursor(); New_preview_is_needed=1; // On est dans un nouveau rpertoire, donc on remet le quicksearch 0 Reset_quicksearch(); } else // Sinon on essaye de charger ou sauver le fichier { strcpy(context->File_directory,Selector->Directory); context->Format = Selector->Format_filter; save_or_load_image=1; } } // Gestion du chrono et des previews if (New_preview_is_needed) { // On efface les infos de la preview prcdente s'il y en a une // d'affiche if (Timer_state==2) { Hide_cursor(); // On efface le commentaire prcdent Window_rectangle(45,70,32*8,8,MC_Light); // On nettoie la zone o va s'afficher la preview: Window_rectangle(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT,MC_Light); // On efface les dimensions de l'image Window_rectangle(143,59,72,8,MC_Light); // On efface la taille du fichier Window_rectangle(236,59,56,8,MC_Light); // On efface le format du fichier Window_rectangle(59,59,5*8,8,MC_Light); // Affichage du commentaire if ( (!load) && (Get_fileformat(Selector->Format_filter)->Comment) ) { Print_in_window(45,70,context->Comment,MC_Black,MC_Light); } Display_cursor(); // Un update pour couvrir les 4 zones: 3 libells plus le commentaire Update_window_area(45,48,256,30); // Zone de preview Update_window_area(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT); } New_preview_is_needed=0; Timer_state=0; // State du chrono = Attente d'un Xme de seconde // On lit le temps de dpart du chrono Init_chrono(Config.Timer_delay); } if (!Timer_state) // Prendre une nouvelle mesure du chrono et regarder Check_timer(); // s'il ne faut pas afficher la preview if (Timer_state==1) // Il faut afficher la preview { if ( (Selector->Position+Selector->Offset>=Filelist.Nb_directories) && (Filelist.Nb_elements) ) { T_IO_Context preview_context; Init_context_preview(&preview_context, Selector_filename, Selector->Directory); Hide_cursor(); Load_image(&preview_context); Destroy_context(&preview_context); Update_window_area(0,0,Window_width,Window_height); Display_cursor(); } Timer_state=2; // On arrte le chrono } } while ( (!has_clicked_ok) && (clicked_button!=2) ); if (has_clicked_ok) { strcpy(context->File_name, Selector_filename); strcpy(context->File_directory, Selector->Directory); if (!load) context->Format = Selector->Format_filter; } else { // Data to restore strcpy(context->Comment, initial_comment); } // On restaure les donnes de l'image qui ont certainement t modifies // par la preview. Set_palette(Main_palette); Back_color=initial_back_color; Compute_optimal_menu_colors(Main_palette); temp=(Window_pos_Y+(Window_height*Menu_factor_Y) */ ////////////////////////////////////////////////////////////////////////////// ///@file pxtall2.h /// Renderer for double-tall pixels (2x4). ////////////////////////////////////////////////////////////////////////////// #include "struct.h" void Pixel_tall2 (word x,word y,byte color); byte Read_pixel_tall2 (word x,word y); void Block_tall2 (word start_x,word start_y,word width,word height,byte color); void Pixel_preview_normal_tall2 (word x,word y,byte color); void Pixel_preview_magnifier_tall2 (word x,word y,byte color); void Horizontal_XOR_line_tall2 (word x_pos,word y_pos,word width); void Vertical_XOR_line_tall2 (word x_pos,word y_pos,word height); void Display_brush_color_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_brush_mono_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); void Clear_brush_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); void Remap_screen_tall2 (word x_pos,word y_pos,word width,word height,byte * conversion_table); void Display_part_of_screen_tall2 (word width,word height,word image_width); void Display_line_on_screen_tall2 (word x_pos,word y_pos,word width,byte * line); void Read_line_screen_tall2 (word x_pos,word y_pos,word width,byte * line); void Display_part_of_screen_scaled_tall2(word width,word height,word image_width,byte * buffer); void Display_brush_color_zoom_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); void Display_brush_mono_zoom_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); void Clear_brush_scaled_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); void Display_brush_tall2 (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_line_on_screen_fast_tall2 (word x_pos,word y_pos,word width,byte * line); grafx2_2.4+git20180105/src/keyboard.c0000664000000000000000000011234713223665306015503 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2010 Alexander Filyanov Copyright 2009 Franck Charlet Copyright 2008 Yves Rizoud Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include "global.h" #include "keyboard.h" #if defined(__macosx__) // Apple's "command" character is not present in the ANSI table, so we // recycled an ANSI value that doesn't have any displayable character // associated. #define META_KEY_PREFIX "\201" #elif defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) // 'Amiga' key: an outlined uppercase A. Drawn on 2 unused characters. #define META_KEY_PREFIX "\215\216" #else // All other platforms #define META_KEY_PREFIX "Super+" #endif // Table de correspondance des scancode de clavier IBM PC AT vers // les symboles de touches SDL (sym). // La correspondance est bonne si le clavier est QWERTY US, ou si // l'utilisateur est sous Windows. // Dans l'ordre des colonnes: Normal, +Shift, +Control, +Alt const word Scancode_to_sym[256][4] = { /* 00 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 01 Esc */ { SDLK_ESCAPE ,SDLK_ESCAPE ,SDLK_ESCAPE ,SDLK_ESCAPE }, /* 02 1 ! */ { SDLK_1 ,SDLK_1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 03 2 @ */ { SDLK_2 ,SDLK_2 ,SDLK_2 ,SDLK_UNKNOWN }, /* 04 3 # */ { SDLK_3 ,SDLK_3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 05 4 $ */ { SDLK_4 ,SDLK_4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 06 5 % */ { SDLK_5 ,SDLK_5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 07 6 ^ */ { SDLK_6 ,SDLK_6 ,SDLK_6 ,SDLK_UNKNOWN }, /* 08 7 & */ { SDLK_7 ,SDLK_7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 09 8 * */ { SDLK_8 ,SDLK_8 ,SDLK_8 ,SDLK_UNKNOWN }, /* 0A 9 ( */ { SDLK_9 ,SDLK_9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 0B 0 ) */ { SDLK_0 ,SDLK_0 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 0C - _ */ { SDLK_MINUS ,SDLK_MINUS ,SDLK_MINUS ,SDLK_UNKNOWN }, /* 0D = + */ { SDLK_EQUALS ,SDLK_EQUALS ,SDLK_EQUALS ,SDLK_UNKNOWN }, /* 0E BkSpc */ { SDLK_BACKSPACE ,SDLK_BACKSPACE ,SDLK_BACKSPACE ,SDLK_BACKSPACE }, /* 0F Tab */ { SDLK_TAB ,SDLK_TAB ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 10 Q */ { SDLK_q ,SDLK_q ,SDLK_q ,SDLK_q }, /* 11 W */ { SDLK_w ,SDLK_w ,SDLK_w ,SDLK_w }, /* 12 E */ { SDLK_e ,SDLK_e ,SDLK_e ,SDLK_e }, /* 13 R */ { SDLK_r ,SDLK_r ,SDLK_r ,SDLK_r }, /* 14 T */ { SDLK_t ,SDLK_t ,SDLK_t ,SDLK_t }, /* 15 Y */ { SDLK_y ,SDLK_y ,SDLK_y ,SDLK_y }, /* 16 U */ { SDLK_u ,SDLK_u ,SDLK_u ,SDLK_u }, /* 17 I */ { SDLK_i ,SDLK_i ,SDLK_i ,SDLK_i }, /* 18 O */ { SDLK_o ,SDLK_o ,SDLK_o ,SDLK_o }, /* 19 P */ { SDLK_p ,SDLK_p ,SDLK_p ,SDLK_p }, /* 1A [ */ { SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET }, /* 1B ] */ { SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET}, /* 1C Retrn */ { SDLK_RETURN ,SDLK_RETURN ,SDLK_RETURN ,SDLK_RETURN }, /* 1D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 1E A */ { SDLK_a ,SDLK_a ,SDLK_a ,SDLK_a }, /* 1F S */ { SDLK_s ,SDLK_s ,SDLK_s ,SDLK_s }, /* 20 D */ { SDLK_d ,SDLK_d ,SDLK_d ,SDLK_d }, /* 21 F */ { SDLK_f ,SDLK_f ,SDLK_f ,SDLK_f }, /* 22 G */ { SDLK_g ,SDLK_g ,SDLK_g ,SDLK_g }, /* 23 H */ { SDLK_h ,SDLK_h ,SDLK_h ,SDLK_h }, /* 24 J */ { SDLK_j ,SDLK_j ,SDLK_j ,SDLK_j }, /* 25 K */ { SDLK_k ,SDLK_k ,SDLK_k ,SDLK_k }, /* 26 L */ { SDLK_l ,SDLK_l ,SDLK_l ,SDLK_l }, /* 27 ; : */ { SDLK_SEMICOLON ,SDLK_SEMICOLON ,SDLK_SEMICOLON ,SDLK_SEMICOLON }, /* 28 ' */ { SDLK_QUOTE ,SDLK_QUOTE ,SDLK_UNKNOWN ,SDLK_QUOTE }, /* 29 ` ~ */ { SDLK_BACKQUOTE ,SDLK_BACKQUOTE ,SDLK_UNKNOWN ,SDLK_BACKQUOTE }, /* 2A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 2B \\ */ { SDLK_BACKSLASH ,SDLK_BACKSLASH ,SDLK_BACKSLASH ,SDLK_BACKSLASH }, /* 2C Z */ { SDLK_z ,SDLK_z ,SDLK_z ,SDLK_z }, /* 2D X */ { SDLK_x ,SDLK_x ,SDLK_x ,SDLK_x }, /* 2E C */ { SDLK_c ,SDLK_c ,SDLK_c ,SDLK_c }, /* 2F V */ { SDLK_v ,SDLK_v ,SDLK_v ,SDLK_v }, /* 30 B */ { SDLK_b ,SDLK_b ,SDLK_b ,SDLK_b }, /* 31 N */ { SDLK_n ,SDLK_n ,SDLK_n ,SDLK_n }, /* 32 M */ { SDLK_m ,SDLK_m ,SDLK_m ,SDLK_m }, /* 33 , < */ { SDLK_COMMA ,SDLK_COMMA ,SDLK_UNKNOWN ,SDLK_COMMA }, /* 34 . > */ { SDLK_PERIOD ,SDLK_PERIOD ,SDLK_UNKNOWN ,SDLK_PERIOD }, /* 35 / ? */ { SDLK_SLASH ,SDLK_SLASH ,SDLK_UNKNOWN ,SDLK_SLASH }, /* 36 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 37 Grey* */ { SDLK_KP_MULTIPLY ,SDLK_KP_MULTIPLY ,SDLK_UNKNOWN ,SDLK_KP_MULTIPLY }, /* 38 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 39 Space */ { SDLK_SPACE ,SDLK_SPACE ,SDLK_SPACE ,SDLK_SPACE }, /* 3A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 3B F1 */ { SDLK_F1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 3C F2 */ { SDLK_F2 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 3D F3 */ { SDLK_F3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 3E F4 */ { SDLK_F4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 3F F5 */ { SDLK_F5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 40 F6 */ { SDLK_F6 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 41 F7 */ { SDLK_F7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 42 F8 */ { SDLK_F8 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 43 F9 */ { SDLK_F9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 44 F10 */ { SDLK_F10 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 45 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 46 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 47 Home */ { SDLK_HOME ,SDLK_HOME ,SDLK_UNKNOWN ,SDLK_HOME }, /* 48 Up */ { SDLK_UP ,SDLK_UP ,SDLK_UNKNOWN ,SDLK_UP }, /* 49 PgUp */ { SDLK_PAGEUP ,SDLK_PAGEUP ,SDLK_UNKNOWN ,SDLK_PAGEUP }, /* 4A Grey- */ { SDLK_KP_MINUS ,SDLK_KP_MINUS ,SDLK_UNKNOWN ,SDLK_KP_MINUS }, /* 4B Left */ { SDLK_LEFT ,SDLK_LEFT ,SDLK_UNKNOWN ,SDLK_LEFT }, /* 4C Kpad5 */ { SDLK_KP5 ,SDLK_KP5 ,SDLK_UNKNOWN ,SDLK_KP5 }, /* 4D Right */ { SDLK_RIGHT ,SDLK_RIGHT ,SDLK_UNKNOWN ,SDLK_RIGHT }, /* 4E Grey+ */ { SDLK_KP_PLUS ,SDLK_KP_PLUS ,SDLK_UNKNOWN ,SDLK_KP_PLUS }, /* 4F End */ { SDLK_END ,SDLK_END ,SDLK_UNKNOWN ,SDLK_END }, /* 50 Down */ { SDLK_DOWN ,SDLK_DOWN ,SDLK_UNKNOWN ,SDLK_DOWN }, /* 51 PgDn */ { SDLK_PAGEDOWN ,SDLK_PAGEDOWN ,SDLK_UNKNOWN ,SDLK_PAGEDOWN }, /* 52 Ins */ { SDLK_INSERT ,SDLK_INSERT ,SDLK_UNKNOWN ,SDLK_INSERT }, /* 53 Del */ { SDLK_DELETE ,SDLK_DELETE ,SDLK_UNKNOWN ,SDLK_DELETE }, /* 54 ??? */ { SDLK_UNKNOWN ,SDLK_F1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 55 ??? */ { SDLK_UNKNOWN ,SDLK_F2 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 56 Lft| */ { SDLK_UNKNOWN ,SDLK_F3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 57 ??? */ { SDLK_UNKNOWN ,SDLK_F4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 58 ??? */ { SDLK_UNKNOWN ,SDLK_F5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 59 ??? */ { SDLK_UNKNOWN ,SDLK_F6 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 5A ??? */ { SDLK_UNKNOWN ,SDLK_F7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 5B ??? */ { SDLK_UNKNOWN ,SDLK_F8 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 5C ??? */ { SDLK_UNKNOWN ,SDLK_F9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 5D ??? */ { SDLK_UNKNOWN ,SDLK_F10 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 5E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F1 ,SDLK_UNKNOWN }, /* 5F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F2 ,SDLK_UNKNOWN }, /* 60 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F3 ,SDLK_UNKNOWN }, /* 61 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F4 ,SDLK_UNKNOWN }, /* 62 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F5 ,SDLK_UNKNOWN }, /* 63 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F6 ,SDLK_UNKNOWN }, /* 64 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F7 ,SDLK_UNKNOWN }, /* 65 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F8 ,SDLK_UNKNOWN }, /* 66 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F9 ,SDLK_UNKNOWN }, /* 67 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F10 ,SDLK_UNKNOWN }, /* 68 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F1 }, /* 69 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F2 }, /* 6A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F3 }, /* 6B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F4 }, /* 6C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F5 }, /* 6D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F6 }, /* 6E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F7 }, /* 6F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F8 }, /* 70 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F9 }, /* 71 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F10 }, /* 72 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 73 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LEFT ,SDLK_UNKNOWN }, /* 74 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RIGHT ,SDLK_UNKNOWN }, /* 75 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_END ,SDLK_UNKNOWN }, /* 76 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEDOWN ,SDLK_UNKNOWN }, /* 77 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_HOME ,SDLK_UNKNOWN }, /* 78 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_1 }, /* 79 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_2 }, /* 7A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_3 }, /* 7B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_4 }, /* 7C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_5 }, /* 7D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_6 }, /* 7E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_7 }, /* 7F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_8 }, /* 80 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_9 }, /* 81 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_0 }, /* 82 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MINUS }, /* 83 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_EQUALS }, /* 84 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP ,SDLK_UNKNOWN }, /* 85 F11 */ { SDLK_F11 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 86 F12 */ { SDLK_F12 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 87 ??? */ { SDLK_UNKNOWN ,SDLK_F11 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 88 ??? */ { SDLK_UNKNOWN ,SDLK_F12 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 89 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F11 ,SDLK_UNKNOWN }, /* 8A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F12 ,SDLK_UNKNOWN }, /* 8B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F11 }, /* 8C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F12 }, /* 8D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UP ,SDLK_UNKNOWN }, /* 8E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_MINUS ,SDLK_UNKNOWN }, /* 8F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP5 ,SDLK_UNKNOWN }, /* 90 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_PLUS ,SDLK_UNKNOWN }, /* 91 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DOWN ,SDLK_UNKNOWN }, /* 92 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_INSERT ,SDLK_UNKNOWN }, /* 93 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DELETE ,SDLK_UNKNOWN }, /* 94 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_TAB ,SDLK_UNKNOWN }, /* 95 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_DIVIDE ,SDLK_UNKNOWN }, /* 96 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_MULTIPLY ,SDLK_UNKNOWN }, /* 97 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_HOME }, /* 98 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UP }, /* 99 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP }, /* 9A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 9B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LEFT }, /* 9C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 9D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RIGHT }, /* 9E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* 9F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_END }, /* A0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DOWN }, /* A1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP }, /* A2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_INSERT }, /* A3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DELETE }, /* A4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_DIVIDE }, /* A5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_TAB }, /* A6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_ENTER }, /* A7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* A8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* A9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* AA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* AB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* AC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* AD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* AE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* AF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B6 Win L */ { SDLK_LSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B7 Win R */ { SDLK_RSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B8 Win M */ { SDLK_MENU ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* B9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* BA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* BB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* BC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* BD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* BE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* BF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C2 ??? */ { SDLK_UNKNOWN ,SDLK_LSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C3 ??? */ { SDLK_UNKNOWN ,SDLK_RSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* C9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* CA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* CB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* CC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* CD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* CE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LSUPER ,SDLK_UNKNOWN }, /* CF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RSUPER ,SDLK_UNKNOWN }, /* D0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MENU ,SDLK_UNKNOWN }, /* D1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* D9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* DA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LSUPER }, /* DB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RSUPER }, /* DC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MENU }, /* DD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* DE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* DF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E0 Enter */ { SDLK_KP_ENTER ,SDLK_KP_ENTER ,SDLK_KP_ENTER ,SDLK_UNKNOWN }, /* E1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* E9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* EA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* EB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* EC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* ED ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* EE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* EF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* F9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* FA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* FB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* FC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* FD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* FE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, /* FF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, }; // Conversion de l'ancien codage des touches: // 0x00FF le scancode (maintenant code sym sur 0x0FFF) // 0x0100 shift (maintenant 0x1000) // 0x0200 control (maintenant 0x2000) // 0x0400 alt (maintenant 0x4000) word Key_for_scancode(word scancode) { if (scancode & 0x0400) return Scancode_to_sym[scancode & 0xFF][3] | (scancode & 0x0700) << 4; else if (scancode & 0x0200) return Scancode_to_sym[scancode & 0xFF][2] | (scancode & 0x0700) << 4; else if (scancode & 0x0100) return Scancode_to_sym[scancode & 0xFF][1] | (scancode & 0x0700) << 4; else return Scancode_to_sym[scancode & 0xFF][0]; } // Convertit des modificateurs de touches SDL en modificateurs GrafX2 word Key_modifiers(SDLMod mod) { word modifiers=0; if (mod & KMOD_CTRL ) modifiers|=MOD_CTRL; if (mod & KMOD_SHIFT ) modifiers|=MOD_SHIFT; if (mod & (KMOD_ALT|KMOD_MODE)) modifiers|=MOD_ALT; if (mod & (KMOD_META)) modifiers|=MOD_META; return modifiers; } word Keysym_to_keycode(SDL_keysym keysym) { word key_code = 0; word mod; // On ignore shift, alt et control isols. if (keysym.sym == SDLK_RSHIFT || keysym.sym == SDLK_LSHIFT || keysym.sym == SDLK_RCTRL || keysym.sym == SDLK_LCTRL || keysym.sym == SDLK_RALT || keysym.sym == SDLK_LALT || keysym.sym == SDLK_RMETA || keysym.sym == SDLK_LMETA || keysym.sym == SDLK_MODE) // AltGr return 0; // Les touches qui n'ont qu'une valeur unicode (trs rares) // seront codes sur 11 bits, le 12e bit est mis 1 (0x0800) if (keysym.sym != 0) key_code = keysym.sym; else if (keysym.scancode != 0) { key_code = (keysym.scancode & 0x07FF) | 0x0800; } // Normally I should test keysym.mod here, but on windows the implementation // is buggy: if you release a modifier key, the following keys (when they repeat) // still name the original modifiers. mod=Key_modifiers(SDL_GetModState()); // SDL_GetModState() seems to get the right up-to-date info. key_code |= mod; return key_code; } const char * Key_name(word key) { typedef struct { word keysym; char *Key_name; } T_key_label; T_key_label key_labels[] = { #ifdef GCWZERO { SDLK_BACKSPACE , "Right-SP" }, { SDLK_TAB , "Left-SP" }, { SDLK_CLEAR , "Clear" }, { SDLK_RETURN , "START" }, { SDLK_PAUSE , "Power-Down" }, { SDLK_ESCAPE , "SELECT" }, #else { SDLK_BACKSPACE , "Backspace" }, { SDLK_TAB , "Tab" }, { SDLK_CLEAR , "Clear" }, { SDLK_RETURN , "Return" }, { SDLK_PAUSE , "Pause" }, { SDLK_ESCAPE , "Esc" }, #endif { SDLK_DELETE , "Del" }, { SDLK_KP0 , "KP 0" }, { SDLK_KP1 , "KP 1" }, { SDLK_KP2 , "KP 2" }, { SDLK_KP3 , "KP 3" }, { SDLK_KP4 , "KP 4" }, { SDLK_KP5 , "KP 5" }, { SDLK_KP6 , "KP 6" }, { SDLK_KP7 , "KP 7" }, { SDLK_KP8 , "KP 8" }, { SDLK_KP9 , "KP 9" }, { SDLK_KP_PERIOD , "KP ." }, { SDLK_KP_DIVIDE , "KP /" }, { SDLK_KP_MULTIPLY, "KP *" }, { SDLK_KP_MINUS , "KP -" }, { SDLK_KP_PLUS , "KP +" }, { SDLK_KP_ENTER , "KP Enter" }, { SDLK_KP_EQUALS , "KP =" }, { SDLK_UP , "Up" }, { SDLK_DOWN , "Down" }, { SDLK_RIGHT , "Right" }, { SDLK_LEFT , "Left" }, { SDLK_INSERT , "Ins" }, { SDLK_HOME , "Home" }, { SDLK_END , "End" }, { SDLK_PAGEUP , "PgUp" }, { SDLK_PAGEDOWN , "PgDn" }, { SDLK_F1 , "F1" }, { SDLK_F2 , "F2" }, { SDLK_F3 , "F3" }, { SDLK_F4 , "F4" }, { SDLK_F5 , "F5" }, { SDLK_F6 , "F6" }, { SDLK_F7 , "F7" }, { SDLK_F8 , "F8" }, { SDLK_F9 , "F9" }, { SDLK_F10 , "F10" }, { SDLK_F11 , "F11" }, { SDLK_F12 , "F12" }, { SDLK_F13 , "F13" }, { SDLK_F14 , "F14" }, { SDLK_F15 , "F15" }, { SDLK_NUMLOCK , "NumLock" }, { SDLK_CAPSLOCK , "CapsLck" }, { SDLK_SCROLLOCK , "ScrlLock" }, { SDLK_RSHIFT , "RShift" }, #ifdef GCWZERO { SDLK_LSHIFT , "X" }, { SDLK_RCTRL , "RCtrl" }, { SDLK_LCTRL , "A" }, { SDLK_RALT , "RAlt" }, { SDLK_LALT , "B" }, #else { SDLK_LSHIFT , "LShift" }, { SDLK_RCTRL , "RCtrl" }, { SDLK_LCTRL , "LCtrl" }, { SDLK_RALT , "RAlt" }, { SDLK_LALT , "LAlt" }, #endif { SDLK_RMETA , "RMeta" }, { SDLK_LMETA , "LMeta" }, { SDLK_LSUPER , "LWin" }, { SDLK_RSUPER , "RWin" }, { SDLK_MODE , "AltGr" }, { SDLK_COMPOSE , "Comp" }, { SDLK_HELP , "Help" }, { SDLK_PRINT , "Print" }, { SDLK_SYSREQ , "SysReq" }, { SDLK_BREAK , "Break" }, { SDLK_MENU , "Menu" }, { SDLK_POWER , "Power" }, { SDLK_EURO , "Euro" }, { SDLK_UNDO , "Undo" }, { KEY_MOUSEMIDDLE, "Mouse3" }, { KEY_MOUSEWHEELUP, "WheelUp" }, { KEY_MOUSEWHEELDOWN, "WheelDown" } }; int index; static char buffer[41]; buffer[0] = '\0'; if (key == SDLK_UNKNOWN) return "None"; #ifdef GCWZERO if (key & MOD_CTRL) strcat(buffer, "A+"); if (key & MOD_ALT) strcat(buffer, "B+"); if (key & MOD_SHIFT) strcat(buffer, "X+"); #else if (key & MOD_CTRL) strcat(buffer, "Ctl+"); if (key & MOD_ALT) strcat(buffer, "Alt+"); if (key & MOD_SHIFT) strcat(buffer, "Shift+"); #endif if (key & MOD_META) strcat(buffer, META_KEY_PREFIX); key=key & ~(MOD_CTRL|MOD_ALT|MOD_SHIFT); // 99 is only a sanity check if (key>=KEY_JOYBUTTON && key<=KEY_JOYBUTTON+99) { char *button_name; switch(key-KEY_JOYBUTTON) { #ifdef JOY_BUTTON_UP case JOY_BUTTON_UP: button_name="[UP]"; break; #endif #ifdef JOY_BUTTON_DOWN case JOY_BUTTON_DOWN: button_name="[DOWN]"; break; #endif #ifdef JOY_BUTTON_LEFT case JOY_BUTTON_LEFT: button_name="[LEFT]"; break; #endif #ifdef JOY_BUTTON_RIGHT case JOY_BUTTON_RIGHT: button_name="[RIGHT]"; break; #endif #ifdef JOY_BUTTON_UPLEFT case JOY_BUTTON_UPLEFT: button_name="[UP-LEFT]"; break; #endif #ifdef JOY_BUTTON_UPRIGHT case JOY_BUTTON_UPRIGHT: button_name="[UP-RIGHT]"; break; #endif #ifdef JOY_BUTTON_DOWNLEFT case JOY_BUTTON_DOWNLEFT: button_name="[DOWN-LEFT]"; break; #endif #ifdef JOY_BUTTON_DOWNRIGHT case JOY_BUTTON_DOWNRIGHT: button_name="[DOWN-RIGHT]"; break; #endif #ifdef JOY_BUTTON_CLICK case JOY_BUTTON_CLICK: button_name="[CLICK]"; break; #endif #ifdef JOY_BUTTON_A case JOY_BUTTON_A: button_name="[A]"; break; #endif #ifdef JOY_BUTTON_B case JOY_BUTTON_B: button_name="[B]"; break; #endif #ifdef JOY_BUTTON_X case JOY_BUTTON_X: button_name="[X]"; break; #endif #ifdef JOY_BUTTON_Y case JOY_BUTTON_Y: button_name="[Y]"; break; #endif #ifdef JOY_BUTTON_L case JOY_BUTTON_L: button_name="[L]"; break; #endif #ifdef JOY_BUTTON_R case JOY_BUTTON_R: button_name="[R]"; break; #endif #ifdef JOY_BUTTON_START case JOY_BUTTON_START: button_name="[START]"; break; #endif #ifdef JOY_BUTTON_SELECT case JOY_BUTTON_SELECT: button_name="[SELECT]"; break; #endif #ifdef JOY_BUTTON_VOLUP case JOY_BUTTON_VOLUP: button_name="[VOL UP]"; break; #endif #ifdef JOY_BUTTON_VOLDOWN case JOY_BUTTON_VOLDOWN: button_name="[VOL DOWN]"; break; #endif #ifdef JOY_BUTTON_MENU case JOY_BUTTON_MENU: button_name="[MENU]"; break; #endif #ifdef JOY_BUTTON_HOME case JOY_BUTTON_HOME: button_name="[HOME]"; break; #endif #ifdef JOY_BUTTON_HOLD case JOY_BUTTON_HOLD: button_name="[HOLD]"; break; #endif #ifdef JOY_BUTTON_I case JOY_BUTTON_I: button_name="[BUTTON I]"; break; #endif #ifdef JOY_BUTTON_II case JOY_BUTTON_II: button_name="[BUTTON II]"; break; #endif #ifdef JOY_BUTTON_JOY case JOY_BUTTON_JOY: button_name="[THUMB JOY]"; break; #endif default: sprintf(buffer+strlen(buffer), "[B%d]", key-KEY_JOYBUTTON);return buffer; } strcat(buffer,button_name); return buffer; } if (key & 0x800) { sprintf(buffer+strlen(buffer), "[%d]", key & 0x7FF); return buffer; } key = key & 0x7FF; // Touches ASCII if (key>=' ' && key < 127) { sprintf(buffer+strlen(buffer), "'%c'", toupper(key)); return buffer; } // Touches 'World' if (key>=SDLK_WORLD_0 && key <= SDLK_WORLD_95) { sprintf(buffer+strlen(buffer), "w%d", key - SDLK_WORLD_0); return buffer; } // Touches au libell connu for (index=0; index < (long)sizeof(key_labels)/(long)sizeof(T_key_label);index++) { if (key == key_labels[index].keysym) { sprintf(buffer+strlen(buffer), "%s", key_labels[index].Key_name); return buffer; } } // Autres touches inconnues sprintf(buffer+strlen(buffer), "0x%X", key & 0x7FF); return buffer; } // Obtient le caractre ANSI tap, partir d'un keysym. // (Valeur 32 255) // Renvoie 0 s'il n'y a pas de caractre associ (shift, backspace, etc) word Keysym_to_ANSI(SDL_keysym keysym) { // This part was removed from the MacOSX port, but I put it back for others // as on Linux and Windows, it's what allows editing a text line with the keys // SDLK_LEFT, SDLK_RIGHT, SDLK_HOME, SDLK_END etc. #if !(defined(__macosx__) || defined(__FreeBSD__)) if ( keysym.unicode == 0) { switch(keysym.sym) { case SDLK_DELETE: case SDLK_LEFT: case SDLK_RIGHT: case SDLK_HOME: case SDLK_END: case SDLK_BACKSPACE: case KEY_ESC: return keysym.sym; case SDLK_RETURN: // Case alt-enter if (SDL_GetModState() & (KMOD_ALT|KMOD_META)) return '\n'; return keysym.sym; default: return 0; } } #endif // if ( keysym.unicode > 32 && keysym.unicode < 127) { return keysym.unicode; // Pas de souci, on est en ASCII standard } // Quelques conversions Unicode-ANSI switch(keysym.unicode) { case 0x8100: return ''; // case 0x1A20: return ''; // case 0x201A: return ''; // case 0x9201: return ''; // case 0x1E20: return ''; // case 0x2620: return ''; // case 0x2020: return ''; // case 0x2120: return ''; // case 0xC602: return ''; // case 0x3020: return ''; // case 0x6001: return ''; // case 0x3920: return ''; // case 0x5201: return ''; // case 0x8D00: return ''; // case 0x1C20: return ''; // case 0x1D20: return ''; // case 0x2220: return ''; // case 0x1320: return ''; // case 0x1420: return ''; // case 0xDC02: return ''; // case 0x5301: return ''; // case 0xA000: return ''; // case 0xA100: return ''; // case 0xA200: return ''; // case 0xA300: return ''; // case 0xA400: return ''; // case 0xA700: return ''; // case 0xC600: return ''; // } // Key entre 127 et 255 if (keysym.unicode<256) { #if defined(__macosx__) || defined(__FreeBSD__) // fc: Looks like there's a mismatch with delete & backspace // i don't why SDLK_DELETE was returned instead of SDLK_BACKSPACE if(keysym.unicode == 127) { return(SDLK_BACKSPACE); } // We don't make any difference between return & enter in the app context. if(keysym.unicode == 3) { return(SDLK_RETURN); } #endif return keysym.unicode; } // Sinon c'est une touche spciale, on retourne son scancode return keysym.sym; } grafx2_2.4+git20180105/src/pxquad.h0000664000000000000000000000626513223665306015213 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file pxquad.h /// Renderer for quadruple pixels (4x4). ////////////////////////////////////////////////////////////////////////////// #include "struct.h" void Pixel_quad (word x,word y,byte color); byte Read_pixel_quad (word x,word y); void Block_quad (word start_x,word start_y,word width,word height,byte color); void Pixel_preview_normal_quad (word x,word y,byte color); void Pixel_preview_magnifier_quad (word x,word y,byte color); void Horizontal_XOR_line_quad (word x_pos,word y_pos,word width); void Vertical_XOR_line_quad (word x_pos,word y_pos,word height); void Display_brush_color_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_brush_mono_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); void Clear_brush_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); void Remap_screen_quad (word x_pos,word y_pos,word width,word height,byte * conversion_table); void Display_part_of_screen_quad (word width,word height,word image_width); void Display_line_on_screen_quad (word x_pos,word y_pos,word width,byte * line); void Read_line_screen_quad (word x_pos,word y_pos,word width,byte * line); void Display_part_of_screen_scaled_quad(word width,word height,word image_width,byte * buffer); void Display_brush_color_zoom_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); void Display_brush_mono_zoom_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); void Clear_brush_scaled_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); void Display_brush_quad (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_line_on_screen_fast_quad (word x_pos,word y_pos,word width,byte * line); grafx2_2.4+git20180105/src/haiku.cpp0000664000000000000000000000251313223665306015335 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include "struct.h" #ifdef __HAIKU__ #include #include #include #include extern "C" qword haiku_get_free_space(char* path); extern "C" char* haiku_get_clipboard(); qword haiku_get_free_space(char* path) { BEntry bpath(path); entry_ref ref; bpath.GetRef(&ref); BVolume disk(ref.device); return (qword) disk.Capacity(); } char* haiku_get_clipboard() { if (be_clipboard->Lock()) { const char* value; ssize_t len; be_clipboard->Data()->FindData("text/plain", B_MIME_TYPE, (const void **)&value, &len); be_clipboard->Unlock(); return strdup(value); } return NULL; } #endif grafx2_2.4+git20180105/src/input.c0000664000000000000000000007754113223665306015050 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2009 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #ifdef __WIN32__ #include #include #endif #include "global.h" #include "keyboard.h" #include "sdlscreen.h" #include "windows.h" #include "errors.h" #include "misc.h" #include "buttons.h" #include "input.h" #include "loadsave.h" #define RSUPER_EMULATES_META_MOD // Keyboards with a Super key never seem to have a Meta key at the same time. // This setting allows the right 'Super' key (the one with a 'Windows' or // 'Amiga' label to be used as a modifier instead of a normal key. // This feature is especially useful for AROS where applications should use // generic defaults like "Right Amiga+Q = Quit". // In case this is annoying for some platforms, disable it. void Handle_window_resize(SDL_ResizeEvent event); void Handle_window_exit(SDL_QuitEvent event); int Color_cycling(void); // public Globals (available as extern) int Input_sticky_control = 0; int Snap_axis = 0; int Snap_axis_origin_X; int Snap_axis_origin_Y; char * Drop_file_name = NULL; // -- // Digital joystick state byte Directional_up; byte Directional_up_right; byte Directional_right; byte Directional_down_right; byte Directional_down; byte Directional_down_left; byte Directional_left; byte Directional_up_left; byte Directional_click; // Emulated directional controller. // This has a distinct state from Directional_, because some joysticks send // "I'm not moving" SDL events when idle, thus stopping the emulated one. byte Directional_emulated_up; byte Directional_emulated_right; byte Directional_emulated_down; byte Directional_emulated_left; long Directional_first_move; long Directional_last_move; int Mouse_moved; ///< Boolean, Set to true if any cursor movement occurs. word Input_new_mouse_X; word Input_new_mouse_Y; byte Input_new_mouse_K; byte Button_inverter=0; // State of the key that swaps mouse buttons. byte Pan_shortcut_pressed; // Joystick/pad configurations for the various console ports. // See the #else for the documentation of fields. // TODO: Make these user-settable somehow. #if defined(__GP2X__) #define JOYSTICK_THRESHOLD (4096) short Joybutton_shift= JOY_BUTTON_L; short Joybutton_control= JOY_BUTTON_R; short Joybutton_alt= JOY_BUTTON_CLICK; short Joybutton_left_click= JOY_BUTTON_B; short Joybutton_right_click=JOY_BUTTON_Y; #elif defined(__WIZ__) #define JOYSTICK_THRESHOLD (4096) short Joybutton_shift= JOY_BUTTON_X; short Joybutton_control= JOY_BUTTON_SELECT; short Joybutton_alt= JOY_BUTTON_Y; short Joybutton_left_click= JOY_BUTTON_A; short Joybutton_right_click=JOY_BUTTON_B; #elif defined(__CAANOO__) #define JOYSTICK_THRESHOLD (4096) short Joybutton_shift= JOY_BUTTON_L; short Joybutton_control= JOY_BUTTON_R; short Joybutton_alt= JOY_BUTTON_Y; short Joybutton_left_click= JOY_BUTTON_A; short Joybutton_right_click=JOY_BUTTON_B; #else // Default : Any joystick on a computer platform /// /// This is the sensitivity threshold for the directional /// pad of a cheap digital joypad on the PC. It has been set through /// trial and error : If value is too large then the movement is /// randomly interrupted; if the value is too low the cursor will /// move by itself, controlled by parasits. /// YR 04/11/2010: I just observed a -8700 when joystick is idle. #define JOYSTICK_THRESHOLD (10000) /// A button that is marked as "modifier" will short Joybutton_shift=-1; ///< Button number that serves as a "shift" modifier; -1 for none short Joybutton_control=-1; ///< Button number that serves as a "ctrl" modifier; -1 for none short Joybutton_alt=-1; ///< Button number that serves as a "alt" modifier; -1 for none short Joybutton_left_click=0; ///< Button number that serves as left click; -1 for none short Joybutton_right_click=1; ///< Button number that serves as right-click; -1 for none #endif int Has_shortcut(word function) { if (function == 0xFFFF) return 0; if (function & 0x100) { if (Buttons_Pool[function&0xFF].Left_shortcut[0]!=KEY_NONE) return 1; if (Buttons_Pool[function&0xFF].Left_shortcut[1]!=KEY_NONE) return 1; return 0; } if (function & 0x200) { if (Buttons_Pool[function&0xFF].Right_shortcut[0]!=KEY_NONE) return 1; if (Buttons_Pool[function&0xFF].Right_shortcut[1]!=KEY_NONE) return 1; return 0; } if(Config_Key[function][0]!=KEY_NONE) return 1; if(Config_Key[function][1]!=KEY_NONE) return 1; return 0; } int Is_shortcut(word key, word function) { if (key == 0 || function == 0xFFFF) return 0; if (function & 0x100) { if (Buttons_Pool[function&0xFF].Left_shortcut[0]==key) return 1; if (Buttons_Pool[function&0xFF].Left_shortcut[1]==key) return 1; return 0; } if (function & 0x200) { if (Buttons_Pool[function&0xFF].Right_shortcut[0]==key) return 1; if (Buttons_Pool[function&0xFF].Right_shortcut[1]==key) return 1; return 0; } if(key == Config_Key[function][0]) return 1; if(key == Config_Key[function][1]) return 1; return 0; } // Called each time there is a cursor move, either triggered by mouse or keyboard shortcuts int Move_cursor_with_constraints() { int feedback=0; int mouse_blocked=0; ///< Boolean, Set to true if mouse movement was clipped. // Clip mouse to the editing area. There can be a border when using big // pixels, if the SDL screen dimensions are not factors of the pixel size. if (Input_new_mouse_Y>=Screen_height) { Input_new_mouse_Y=Screen_height-1; mouse_blocked=1; } if (Input_new_mouse_X>=Screen_width) { Input_new_mouse_X=Screen_width-1; mouse_blocked=1; } //Gestion "avance" du curseur: interdire la descente du curseur dans le //menu lorsqu'on est en train de travailler dans l'image if (Operation_stack_size != 0) { //Si le curseur ne se trouve plus dans l'image if(Menu_Y<=Input_new_mouse_Y) { //On bloque le curseur en fin d'image mouse_blocked=1; Input_new_mouse_Y=Menu_Y-1; //La ligne !!au-dessus!! du menu } if(Main_magnifier_mode) { if(Operation_in_magnifier==0) { if(Input_new_mouse_X>=Main_separator_position) { mouse_blocked=1; Input_new_mouse_X=Main_separator_position-1; } } else { if(Input_new_mouse_X Config.Mouse_merge_movement && !Operation[Current_operation][Mouse_K_unique] [Operation_stack_size].Fast_mouse) feedback=1; } if (mouse_blocked) Set_mouse_position(); return feedback; } // WM events management void Handle_window_resize(SDL_ResizeEvent event) { Resize_width = event.w; Resize_height = event.h; } void Handle_window_exit(SDL_QuitEvent event) { (void)event, // unused Quit_is_required = 1; } // Mouse events management int Handle_mouse_move(SDL_MouseMotionEvent event) { Input_new_mouse_X = event.x/Pixel_width; Input_new_mouse_Y = event.y/Pixel_height; return Move_cursor_with_constraints(); } int Handle_mouse_click(SDL_MouseButtonEvent event) { switch(event.button) { case SDL_BUTTON_LEFT: if (Button_inverter) Input_new_mouse_K |= 2; else Input_new_mouse_K |= 1; break; case SDL_BUTTON_RIGHT: if (Button_inverter) Input_new_mouse_K |= 1; else Input_new_mouse_K |= 2; break; case SDL_BUTTON_MIDDLE: Key = KEY_MOUSEMIDDLE|Key_modifiers(SDL_GetModState()); // TODO: repeat system maybe? return 0; case SDL_BUTTON_WHEELUP: Key = KEY_MOUSEWHEELUP|Key_modifiers(SDL_GetModState()); return 0; case SDL_BUTTON_WHEELDOWN: Key = KEY_MOUSEWHEELDOWN|Key_modifiers(SDL_GetModState()); return 0; default: return 0; } return Move_cursor_with_constraints(); } int Handle_mouse_release(SDL_MouseButtonEvent event) { switch(event.button) { case SDL_BUTTON_LEFT: if (Button_inverter) Input_new_mouse_K &= ~2; else Input_new_mouse_K &= ~1; break; case SDL_BUTTON_RIGHT: if (Button_inverter) Input_new_mouse_K &= ~1; else Input_new_mouse_K &= ~2; break; } return Move_cursor_with_constraints(); } // Keyboard management int Handle_key_press(SDL_KeyboardEvent event) { //Appui sur une touche du clavier int modifier; Key = Keysym_to_keycode(event.keysym); Key_ANSI = Keysym_to_ANSI(event.keysym); switch(event.keysym.sym) { case SDLK_RSHIFT: case SDLK_LSHIFT: modifier=MOD_SHIFT; break; case SDLK_RCTRL: case SDLK_LCTRL: modifier=MOD_CTRL; break; case SDLK_RALT: case SDLK_LALT: case SDLK_MODE: modifier=MOD_ALT; break; case SDLK_RMETA: case SDLK_LMETA: modifier=MOD_META; break; default: modifier=0; } if (Config.Swap_buttons && modifier == Config.Swap_buttons && Button_inverter==0) { Button_inverter=1; if (Input_new_mouse_K) { Input_new_mouse_K ^= 3; // Flip bits 0 and 1 return Move_cursor_with_constraints(); } } #ifdef RSUPER_EMULATES_META_MOD if (Key==SDLK_RSUPER) { SDL_SetModState(SDL_GetModState() | KMOD_META); Key=0; } #endif if(Is_shortcut(Key,SPECIAL_MOUSE_UP)) { Directional_emulated_up=1; return 0; } else if(Is_shortcut(Key,SPECIAL_MOUSE_DOWN)) { Directional_emulated_down=1; return 0; } else if(Is_shortcut(Key,SPECIAL_MOUSE_LEFT)) { Directional_emulated_left=1; return 0; } else if(Is_shortcut(Key,SPECIAL_MOUSE_RIGHT)) { Directional_emulated_right=1; return 0; } else if(Is_shortcut(Key,SPECIAL_CLICK_LEFT) && Keyboard_click_allowed > 0) { Input_new_mouse_K=1; Directional_click=1; return Move_cursor_with_constraints(); } else if(Is_shortcut(Key,SPECIAL_CLICK_RIGHT) && Keyboard_click_allowed > 0) { Input_new_mouse_K=2; Directional_click=2; return Move_cursor_with_constraints(); } else if(Is_shortcut(Key,SPECIAL_HOLD_PAN)) { Pan_shortcut_pressed=1; return 0; } return 0; } int Release_control(int key_code, int modifier) { int need_feedback = 0; if (modifier == MOD_SHIFT) { // Disable "snap axis" mode Snap_axis = 0; need_feedback = 1; } if (Config.Swap_buttons && modifier == Config.Swap_buttons && Button_inverter==1) { Button_inverter=0; if (Input_new_mouse_K) { Input_new_mouse_K ^= 3; // Flip bits 0 and 1 return Move_cursor_with_constraints(); } } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_UP][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_UP][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_UP][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_UP][1]&modifier)) { Directional_emulated_up=0; } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_DOWN][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_DOWN][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_DOWN][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_DOWN][1]&modifier)) { Directional_emulated_down=0; } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_LEFT][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_LEFT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_LEFT][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_LEFT][1]&modifier)) { Directional_emulated_left=0; } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_RIGHT][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_RIGHT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_RIGHT][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_RIGHT][1]&modifier)) { Directional_emulated_right=0; } if((key_code && key_code == (Config_Key[SPECIAL_CLICK_LEFT][0]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_LEFT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_CLICK_LEFT][1]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_LEFT][1]&modifier)) { if (Directional_click & 1) { Directional_click &= ~1; Input_new_mouse_K &= ~1; return Move_cursor_with_constraints() || need_feedback; } } if((key_code && key_code == (Config_Key[SPECIAL_CLICK_RIGHT][0]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_RIGHT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_CLICK_RIGHT][1]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_RIGHT][1]&modifier)) { if (Directional_click & 2) { Directional_click &= ~2; Input_new_mouse_K &= ~2; return Move_cursor_with_constraints() || need_feedback; } } if((key_code && key_code == (Config_Key[SPECIAL_HOLD_PAN][0]&0x0FFF)) || (Config_Key[SPECIAL_HOLD_PAN][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_HOLD_PAN][1]&0x0FFF)) || (Config_Key[SPECIAL_HOLD_PAN][1]&modifier)) { Pan_shortcut_pressed=0; need_feedback = 1; } // Other keys don't need to be released : they are handled as "events" and procesed only once. // These clicks are apart because they need to be continuous (ie move while key pressed) // We are relying on "hardware" keyrepeat to achieve that. return need_feedback; } int Handle_key_release(SDL_KeyboardEvent event) { int modifier; int released_key = Keysym_to_keycode(event.keysym) & 0x0FFF; switch(event.keysym.sym) { case SDLK_RSHIFT: case SDLK_LSHIFT: modifier=MOD_SHIFT; break; case SDLK_RCTRL: case SDLK_LCTRL: modifier=MOD_CTRL; break; case SDLK_RALT: case SDLK_LALT: case SDLK_MODE: modifier=MOD_ALT; break; #ifdef RSUPER_EMULATES_META_MOD case SDLK_RSUPER: SDL_SetModState(SDL_GetModState() & ~KMOD_META); modifier=MOD_META; break; #endif case SDLK_RMETA: case SDLK_LMETA: modifier=MOD_META; break; default: modifier=0; } return Release_control(released_key, modifier); } // Joystick management int Handle_joystick_press(SDL_JoyButtonEvent event) { if (event.button == Joybutton_shift) { SDL_SetModState(SDL_GetModState() | KMOD_SHIFT); return 0; } if (event.button == Joybutton_control) { SDL_SetModState(SDL_GetModState() | KMOD_CTRL); if (Config.Swap_buttons == MOD_CTRL && Button_inverter==0) { Button_inverter=1; if (Input_new_mouse_K) { Input_new_mouse_K ^= 3; // Flip bits 0 and 1 return Move_cursor_with_constraints(); } } return 0; } if (event.button == Joybutton_alt) { SDL_SetModState(SDL_GetModState() | (KMOD_ALT|KMOD_META)); if (Config.Swap_buttons == MOD_ALT && Button_inverter==0) { Button_inverter=1; if (Input_new_mouse_K) { Input_new_mouse_K ^= 3; // Flip bits 0 and 1 return Move_cursor_with_constraints(); } } return 0; } if (event.button == Joybutton_left_click) { Input_new_mouse_K = Button_inverter ? 2 : 1; return Move_cursor_with_constraints(); } if (event.button == Joybutton_right_click) { Input_new_mouse_K = Button_inverter ? 1 : 2; return Move_cursor_with_constraints(); } switch(event.button) { #ifdef JOY_BUTTON_UP case JOY_BUTTON_UP: Directional_up=1; break; #endif #ifdef JOY_BUTTON_UPRIGHT case JOY_BUTTON_UPRIGHT: Directional_up_right=1; break; #endif #ifdef JOY_BUTTON_RIGHT case JOY_BUTTON_RIGHT: Directional_right=1; break; #endif #ifdef JOY_BUTTON_DOWNRIGHT case JOY_BUTTON_DOWNRIGHT: Directional_down_right=1; break; #endif #ifdef JOY_BUTTON_DOWN case JOY_BUTTON_DOWN: Directional_down=1; break; #endif #ifdef JOY_BUTTON_DOWNLEFT case JOY_BUTTON_DOWNLEFT: Directional_down_left=1; break; #endif #ifdef JOY_BUTTON_LEFT case JOY_BUTTON_LEFT: Directional_left=1; break; #endif #ifdef JOY_BUTTON_UPLEFT case JOY_BUTTON_UPLEFT: Directional_up_left=1; break; #endif default: break; } Key = (KEY_JOYBUTTON+event.button)|Key_modifiers(SDL_GetModState()); // TODO: systeme de rptition return Move_cursor_with_constraints(); } int Handle_joystick_release(SDL_JoyButtonEvent event) { if (event.button == Joybutton_shift) { SDL_SetModState(SDL_GetModState() & ~KMOD_SHIFT); return Release_control(0,MOD_SHIFT); } if (event.button == Joybutton_control) { SDL_SetModState(SDL_GetModState() & ~KMOD_CTRL); return Release_control(0,MOD_CTRL); } if (event.button == Joybutton_alt) { SDL_SetModState(SDL_GetModState() & ~(KMOD_ALT|KMOD_META)); return Release_control(0,MOD_ALT); } if (event.button == Joybutton_left_click) { Input_new_mouse_K &= ~1; return Move_cursor_with_constraints(); } if (event.button == Joybutton_right_click) { Input_new_mouse_K &= ~2; return Move_cursor_with_constraints(); } switch(event.button) { #ifdef JOY_BUTTON_UP case JOY_BUTTON_UP: Directional_up=1; break; #endif #ifdef JOY_BUTTON_UPRIGHT case JOY_BUTTON_UPRIGHT: Directional_up_right=1; break; #endif #ifdef JOY_BUTTON_RIGHT case JOY_BUTTON_RIGHT: Directional_right=1; break; #endif #ifdef JOY_BUTTON_DOWNRIGHT case JOY_BUTTON_DOWNRIGHT: Directional_down_right=1; break; #endif #ifdef JOY_BUTTON_DOWN case JOY_BUTTON_DOWN: Directional_down=1; break; #endif #ifdef JOY_BUTTON_DOWNLEFT case JOY_BUTTON_DOWNLEFT: Directional_down_left=1; break; #endif #ifdef JOY_BUTTON_LEFT case JOY_BUTTON_LEFT: Directional_left=1; break; #endif #ifdef JOY_BUTTON_UPLEFT case JOY_BUTTON_UPLEFT: Directional_up_left=1; break; #endif default: break; } return Move_cursor_with_constraints(); } void Handle_joystick_movement(SDL_JoyAxisEvent event) { if (event.axis==JOYSTICK_AXIS_X) { Directional_right=Directional_left=0; if (event.value<-JOYSTICK_THRESHOLD) { Directional_left=1; } else if (event.value>JOYSTICK_THRESHOLD) Directional_right=1; } else if (event.axis==JOYSTICK_AXIS_Y) { Directional_up=Directional_down=0; if (event.value<-JOYSTICK_THRESHOLD) { Directional_up=1; } else if (event.value>JOYSTICK_THRESHOLD) Directional_down=1; } } // Attempts to move the mouse cursor by the given deltas (may be more than 1 pixel at a time) int Cursor_displace(short delta_x, short delta_y) { short x=Input_new_mouse_X; short y=Input_new_mouse_Y; if(Main_magnifier_mode && Input_new_mouse_Y < Menu_Y && Input_new_mouse_X > Main_separator_position) { // Cursor in zoomed area if (delta_x<0) Input_new_mouse_X = Max(Main_separator_position, x-Main_magnifier_factor); else if (delta_x>0) Input_new_mouse_X = Min(Screen_width-1, x+Main_magnifier_factor); if (delta_y<0) Input_new_mouse_Y = Max(0, y-Main_magnifier_factor); else if (delta_y>0) Input_new_mouse_Y = Min(Screen_height-1, y+Main_magnifier_factor); } else { if (delta_x<0) Input_new_mouse_X = Max(0, x+delta_x); else if (delta_x>0) Input_new_mouse_X = Min(Screen_width-1, x+delta_x); if (delta_y<0) Input_new_mouse_Y = Max(0, y+delta_y); else if (delta_y>0) Input_new_mouse_Y = Min(Screen_height-1, y+delta_y); } return Move_cursor_with_constraints(); } // This function is the acceleration profile for directional (digital) cursor // controllers. int Directional_acceleration(int msec) { const int initial_delay = 250; const int linear_factor = 200; const int accel_factor = 10000; // At beginning there is 1 pixel move, then nothing for N milliseconds if (msecmsg == WM_DROPFILES) { int file_count; HDROP hdrop = (HDROP)(event.syswm.msg->wParam); if((file_count = DragQueryFile(hdrop,(UINT)-1,(LPTSTR) NULL ,(UINT) 0)) > 0) { long len; // Query filename length len = DragQueryFile(hdrop,0 ,NULL ,0); if (len) { Drop_file_name=calloc(len+1,1); if (Drop_file_name) { if (DragQueryFile(hdrop,0 ,(LPTSTR) Drop_file_name ,(UINT) MAX_PATH)) { // Success } else { free(Drop_file_name); // Don't report name copy error } } else { // Don't report alloc error (for a file name? :/ ) } } else { // Don't report weird Windows error } } else { // Drop of zero files. Thanks for the information, Bill. } } #endif break; default: //DEBUG("Unhandled SDL event number : ",event.type); break; } } // Directional controller if (!(Directional_up||Directional_up_right||Directional_right|| Directional_down_right||Directional_down||Directional_down_left|| Directional_left||Directional_up_left||Directional_emulated_up|| Directional_emulated_right||Directional_emulated_down|| Directional_emulated_left)) { Directional_first_move=0; } else { long time_now; int step=0; time_now=SDL_GetTicks(); if (Directional_first_move==0) { Directional_first_move=time_now; step=1; } else { // Compute how much the cursor has moved since last call. // This tries to make smooth cursor movement // no matter the frequency of calls to Get_input() step = Directional_acceleration(time_now - Directional_first_move) - Directional_acceleration(Directional_last_move - Directional_first_move); // Clip speed at 3 pixel per visible frame. if (step > 3) step=3; } Directional_last_move = time_now; if (step) { // Directional controller UP if ((Directional_up||Directional_emulated_up||Directional_up_left||Directional_up_right) && !(Directional_down_right||Directional_down||Directional_emulated_down||Directional_down_left)) { Cursor_displace(0, -step); } // Directional controller RIGHT if ((Directional_up_right||Directional_right||Directional_emulated_right||Directional_down_right) && !(Directional_down_left||Directional_left||Directional_emulated_left||Directional_up_left)) { Cursor_displace(step,0); } // Directional controller DOWN if ((Directional_down_right||Directional_down||Directional_emulated_down||Directional_down_left) && !(Directional_up_left||Directional_up||Directional_emulated_up||Directional_up_right)) { Cursor_displace(0, step); } // Directional controller LEFT if ((Directional_down_left||Directional_left||Directional_emulated_left||Directional_up_left) && !(Directional_up_right||Directional_right||Directional_emulated_right||Directional_down_right)) { Cursor_displace(-step,0); } } } // If the cursor was moved since last update, // it was erased, so we need to redraw it (with the preview brush) if (Mouse_moved) { Compute_paintbrush_coordinates(); Display_cursor(); return 1; } if (user_feedback_required) return 1; // Nothing significant happened if (sleep_time) SDL_Delay(sleep_time); return 0; } void Adjust_mouse_sensitivity(word fullscreen) { // Deprecated (void)fullscreen; } void Set_mouse_position(void) { SDL_WarpMouse(Mouse_X*Pixel_width, Mouse_Y*Pixel_height); } int Color_cycling(void) { static byte offset[16]; int i, color; static SDL_Color PaletteSDL[256]; int changed; // boolean : true if the palette needs a change in this tick. long now; static long start=0; if (start==0) { // First run start = SDL_GetTicks(); return 1; } if (!Allow_colorcycling || !Cycling_mode) return 1; now = SDL_GetTicks(); changed=0; // Check all cycles for a change at this tick for (i=0; i<16; i++) { int len; len=Main_backups->Pages->Gradients->Range[i].End-Main_backups->Pages->Gradients->Range[i].Start+1; if (len>1 && Main_backups->Pages->Gradients->Range[i].Speed) { int new_offset; new_offset=(now-start)/(int)(1000.0/(Main_backups->Pages->Gradients->Range[i].Speed*0.2856)) % len; if (!Main_backups->Pages->Gradients->Range[i].Inverse) new_offset=len - new_offset; if (new_offset!=offset[i]) changed=1; offset[i]=new_offset; } } if (changed) { // Initialize the palette for(color=0;color<256;color++) { PaletteSDL[color].r=Main_palette[color].R; PaletteSDL[color].g=Main_palette[color].G; PaletteSDL[color].b=Main_palette[color].B; } for (i=0; i<16; i++) { int len; len=Main_backups->Pages->Gradients->Range[i].End-Main_backups->Pages->Gradients->Range[i].Start+1; if (len>1 && Main_backups->Pages->Gradients->Range[i].Speed) { for(color=Main_backups->Pages->Gradients->Range[i].Start;color<=Main_backups->Pages->Gradients->Range[i].End;color++) { PaletteSDL[color].r=Main_palette[Main_backups->Pages->Gradients->Range[i].Start+((color-Main_backups->Pages->Gradients->Range[i].Start+offset[i])%len)].R; PaletteSDL[color].g=Main_palette[Main_backups->Pages->Gradients->Range[i].Start+((color-Main_backups->Pages->Gradients->Range[i].Start+offset[i])%len)].G; PaletteSDL[color].b=Main_palette[Main_backups->Pages->Gradients->Range[i].Start+((color-Main_backups->Pages->Gradients->Range[i].Start+offset[i])%len)].B; } } } SDL_SetPalette(Screen_SDL, SDL_PHYSPAL | SDL_LOGPAL, PaletteSDL,0,256); } return 0; } grafx2_2.4+git20180105/src/pxtall2.c0000664000000000000000000004112013223665306015257 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxtall2.h" #define ZOOMX 2 #define ZOOMY 4 void Pixel_tall2 (word x,word y,byte color) /* Affiche un pixel de la color aux coords x;y l'cran */ { *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 1)=color; } byte Read_pixel_tall2 (word x,word y) /* On retourne la couleur du pixel aux coords donnes */ { return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); } void Block_tall2 (word start_x,word start_y,word width,word height,byte color) /* On affiche un rectangle de la couleur donne */ { SDL_Rect rectangle; rectangle.x=start_x*ZOOMX; rectangle.y=start_y*ZOOMY; rectangle.w=width*ZOOMX; rectangle.h=height*ZOOMY; SDL_FillRect(Screen_SDL,&rectangle,color); } void Display_part_of_screen_tall2 (word width,word height,word image_width) /* Afficher une partie de l'image telle quelle sur l'cran */ { byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'cran (dest) byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de dpart ds la source (src) int y; int dy; for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne for (dy=width;dy>0;dy--) { *(dest+1)=*dest=*src; src++; dest+=ZOOMX; } // On double la ligne qu'on vient de copier memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On la triple memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On la quadruple memcpy(dest-width*ZOOMX+3*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } //Update_rect(0,0,width,height); } void Pixel_preview_normal_tall2 (word x,word y,byte color) /* Affichage d'un pixel dans l'cran, par rapport au dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure Pixel_Preview_Loupe_SDL. */ { // if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) Pixel_tall2(x-Main_offset_X,y-Main_offset_Y,color); } void Pixel_preview_magnifier_tall2 (word x,word y,byte color) { // Affiche le pixel dans la partie non zoome Pixel_tall2(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) { // On est dedans int height; int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_tall2( Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, y_zoom, Main_magnifier_factor, height, color ); } } void Horizontal_XOR_line_tall2(word x_pos,word y_pos,word width) { //On calcule la valeur initiale de dest: byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; int x; for (x=0;x0;i--) { *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=xor_lut[*(dest)]; dest+=VIDEO_LINE_WIDTH*ZOOMY; } } void Display_brush_color_tall2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = Brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+3*VIDEO_LINE_WIDTH+1) = *(dest+3*VIDEO_LINE_WIDTH) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+1) = *dest = *src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } Update_rect(x_pos,y_pos,width,height); } void Display_brush_mono_tall2(word x_pos, word y_pos, word x_offset, word y_offset, word width, word height, byte transp_color, byte color, word brush_width) /* On affiche la brosse en monochrome */ { byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination // l'cran byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds // la brosse int x,y; for(y=height;y!=0;y--) //Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { if (*src!=transp_color) *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=color; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=brush_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Clear_brush_tall2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width) { byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'cran (dest) byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de dpart ds la source (src) int y; int x; (void)x_offset; // unused (void)y_offset; // unused (void)transp_color; // unused for(y=height;y!=0;y--) // Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*src; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } // Affiche une brosse (arbitraire) l'cran void Display_brush_tall2(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } } void Remap_screen_tall2(word x_pos,word y_pos,word width,word height,byte * conversion_table) { // dest = coords a l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; int x,y; // Pour chaque ligne for(y=height;y>0;y--) { // Pour chaque pixel for(x=width;x>0;x--) { *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)= conversion_table[*dest]; dest +=ZOOMX; } dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Display_line_on_screen_fast_tall2(word x_pos,word y_pos,word width,byte * line) /* On affiche toute une ligne de pixels telle quelle. */ /* Utilise si le buffer contient dja des pixel doubls. */ { memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+3)*VIDEO_LINE_WIDTH,line,width*ZOOMX); } void Display_line_on_screen_tall2(word x_pos,word y_pos,word width,byte * line) /* On affiche une ligne de pixels en les doublant. */ { int x; byte *dest; dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; for(x=width;x>0;x--) { *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*line; dest+=ZOOMX; line++; } } void Display_transparent_mono_line_on_screen_tall2( word x_pos, word y_pos, word width, byte* line, byte transp_color, byte color) // Affiche une ligne l'cran avec une couleur + transparence. // Utilis par les brosses en mode zoom { byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; int x; // Pour chaque pixel for(x=0;x 0); src += image_width; } // ATTENTION on n'arrive jamais ici ! } // Affiche une partie de la brosse couleur zoome void Display_brush_color_zoom_tall2(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle de la brosse byte * buffer) { byte* src = Brush+y_offset*brush_width + x_offset; word y = y_pos; byte bx; // Pour chaque ligne while(1) { Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche facteur fois la ligne zoome for(bx=Main_magnifier_factor;bx>0;bx--) { byte* line_src = buffer; byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; word x; // Pour chaque pixel de la ligne for(x = width*Main_magnifier_factor;x > 0;x--) { if(*line_src!=transp_color) { *(dest+1)=*dest = *line_src; } line_src++; dest+=ZOOMX; } // Double the line memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); // Triple the line memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); // Quadruple it memcpy(Screen_pixels + (y*ZOOMY+3)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); y++; if(y==end_y_pos) { return; } } src += brush_width; } // ATTENTION zone jamais atteinte } void Display_brush_mono_zoom_tall2(word x_pos, word y_pos, word x_offset, word y_offset, word width, // width non zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle de la brosse byte * buffer ) { byte* src = Brush + y_offset * brush_width + x_offset; int y=y_pos*ZOOMY; //Pour chaque ligne zoomer : while(1) { int bx; // src = Ligne originale // On clate la ligne Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche la ligne Facteur fois l'cran (sur des // lignes conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome Display_transparent_mono_line_on_screen_tall2( x_pos, y, width * Main_magnifier_factor, buffer, transp_color, color ); // On passe la ligne suivante y++; // On vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); Update_rect( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); return; } bx --; } while (bx > 0); // Passage la ligne suivante dans la brosse aussi src+=brush_width; } } void Clear_brush_scaled_tall2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer) { // En fait on va recopier l'image non zoome dans la partie zoome ! byte* src = Main_screen + y_offset * image_width + x_offset; int y = y_pos; int bx; (void)transp_color; // unused // Pour chaque ligne zoomer while(1){ Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); bx=Main_magnifier_factor; // Pour chaque ligne do{ // TODO a verifier Display_line_on_screen_fast_tall2(x_pos,y, width * Main_magnifier_factor,buffer); // Ligne suivante y++; if(y==end_y_pos) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); Update_rect(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); return; } bx--; }while(bx!=0); src+= image_width; } } grafx2_2.4+git20180105/src/const.h0000664000000000000000000005265213223665306015040 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2014 Sergii Pylypenko Copyright 2008 Yves Rizoud Copyright 2007-2017 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file const.h /// Constants (preprocessor defines) and enumerations used anywhere. ////////////////////////////////////////////////////////////////////////////// #ifndef _CONST_H_ #define _CONST_H_ #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(__amigaos__) // These platforms don't seem to have PATH_MAX #undef PATH_MAX #define PATH_MAX 260 #elif defined(__ANDROID__) #include // for PATH_MAX #else #include // for PATH_MAX #endif #ifndef M_2PI #define M_2PI 6.28318530717958647692528676656 ///< Hmm, pie... #endif #define VERSION1 2 ///< Version number for gfx2.cfg (1/4) #define VERSION2 0 ///< Version number for gfx2.cfg (2/4) #define BETA1 98 ///< Version number for gfx2.cfg (3/4) #define BETA2 0 ///< Version number for gfx2.cfg (4/4) #define MAX_VIDEO_MODES 200 ///< Maximum number of video modes Grafx2 can propose. #define NB_ZOOM_FACTORS 15 ///< Number of zoom levels available in the magnifier. #define MENU_WIDTH 254 ///< Width of the menu (not counting the palette) #define MENU_HEIGHT 44 ///< Height of the menu. #define NB_CURSOR_SPRITES 9 ///< Number of available mouse cursor sprites. #define CURSOR_SPRITE_WIDTH 16 ///< Width of a mouse cursor sprite. #define CURSOR_SPRITE_HEIGHT 16 ///< Height of a mouse cursor sprite. #define MENU_SPRITE_WIDTH 16 ///< Width of a menu sprite in pixels #define MENU_SPRITE_HEIGHT 16 ///< Height of a menu sprite in pixels #define EFFECT_SPRITE_WIDTH 14 ///< Width of an effect sprite in pixels #define EFFECT_SPRITE_HEIGHT 14 ///< Height of an effect sprite in pixels #define LAYER_SPRITE_WIDTH 14 ///< Width of a layer button in pixels #define LAYER_SPRITE_HEIGHT 10 ///< Height of a layer button in pixels #define PAINTBRUSH_WIDTH 16 ///< Width of a preset paintbrush sprite #define PAINTBRUSH_HEIGHT 16 ///< Height of a preset paintbrush sprite #define MAX_PAINTBRUSH_SIZE 127 ///< Max size for a resizable paintbrush #define ICON_SPRITE_WIDTH 8 ///< Width of an icon in pixels #define ICON_SPRITE_HEIGHT 8 ///< Height of an icon in pixels #define NB_PAINTBRUSH_SPRITES 48 ///< Number of preset paintbrushes #define NB_PRESET_SIEVE 12 ///< Number of preset sieve patterns #define OPERATION_STACK_SIZE 16 ///< Max number of parameters in the operation stack. #define MAX_DISPLAYABLE_PATH 37 ///< Max number of characters to display directory name, in Save/Load screens. #define COMMENT_SIZE 32 ///< Max number of characters for a comment in PKM or PNG file. #define NB_MAX_PAGES_UNDO 99 ///< Max number of undo pages #define DEFAULT_ZOOM_FACTOR 4 ///< Initial zoom factor for the magnifier. #define MAX_PATH_CHARACTERS PATH_MAX ///< Number of characters for a file+complete path. Adapt to your OS... #define NB_BOOKMARKS 4 ///< Number of bookmark buttons in Save/Load screen. // Character to show a right arrow, used when editing long strings. It's present in ::Gfx->System_font #define RIGHT_TRIANGLE_CHARACTER 16 // Character to show a left arrow, used when editing long strings. It's present in ::Gfx->System_font #define LEFT_TRIANGLE_CHARACTER 17 /// Character to display in menus for an ellipsis. #define ELLIPSIS_CHARACTER '' #define NB_LAYERS 1 ///< Initial number of layers for a new image #define MAX_NB_FRAMES 999 ///< Maximum number of frames that can be used in a grafx2 animation. #define MAX_NB_LAYERS 16 ///< Maximum number of layers that can be used in grafx2. Note that 32 is upper limit because of a few bit fields. #define BRUSH_CONTAINER_PREVIEW_WIDTH 16 ///< Size for preview of a brush in Brush container #define BRUSH_CONTAINER_PREVIEW_HEIGHT 16 ///< Size for preview of a brush in Brush container #define BRUSH_CONTAINER_COLUMNS 4 ///< Number of columns in the Brush container #define BRUSH_CONTAINER_ROWS 3 ///< Number of rows in the Brush container /// /// We force the dynamic backup page allocation to leave a minimum of /// 256Kb of free memory, to allow the rest of the program to work safely. /// Note: This is a remainder of the DOS version. This system might not work /// so well on other OSes, where the "available memory" changes due to external /// factors. #define MINIMAL_MEMORY_TO_RESERVE (256*1024) #define LEFT_SIDE 1 ///< Indicates a left side or left-click #define RIGHT_SIDE 2 ///< Indicates a right side or right-click #define SEPARATOR_WIDTH 6 ///< Width of the separator between the normal and the zoomed view #define INITIAL_SEPARATOR_PROPORTION 0.3 ///< Proportion of the normal view width, relative to the whole screen width. #define NB_ZOOMED_PIXELS_MIN 4 ///< Minimal number of pixel shown (in width) by the zoomed view. (Note: below 4, you can't scroll!) #if defined(__MORPHOS__) || defined(__amigaos4__) || defined(__amigaos__) || defined(__AROS__) #define PARENT_DIR "/" #else /// Filename that means "parent directory" for your operating system. #define PARENT_DIR ".." #endif /// List of file formats recognized by grafx2 enum FILE_FORMATS { FORMAT_ALL_IMAGES=0, ///< This is not really a file format, it's reserverd for a compilation of all image file extensions FORMAT_ALL_PALETTES=1, ///< This is not really a file format, it's reserverd for a compilation of all palette file extensions FORMAT_ALL_FILES=2, ///< This is not really a file format, it's reserverd for the "*.*" filter option. FORMAT_PNG, FORMAT_GIF, FORMAT_BMP, FORMAT_PCX, FORMAT_PKM, FORMAT_LBM, FORMAT_PBM, FORMAT_IMG, FORMAT_SCx, FORMAT_PI1, FORMAT_PC1, FORMAT_CEL, FORMAT_NEO, FORMAT_C64, FORMAT_KCF, FORMAT_PAL, FORMAT_GPL, FORMAT_SCR, FORMAT_CM5, FORMAT_PPH, FORMAT_XPM, FORMAT_MISC, ///< Must be last of enum: others formats recognized by SDL_image }; /// Default format for 'save as' #define DEFAULT_FILEFORMAT FORMAT_GIF /// Error codes for ::Error() enum ERROR_CODES { ERROR_WARNING=0, ///< Red flash on screen, non-fatal error ERROR_GUI_MISSING, ///< The graphics file is missing ERROR_GUI_CORRUPTED, ///< The graphics file cannot be parsed for GUI elements ERROR_INI_MISSING, ///< File gfx2def.ini is missing ERROR_CFG_MISSING, ///< File gfx2.cfg is missing (non-fatal) ERROR_CFG_CORRUPTED, ///< File gfx2.cfg couldn't be parsed (non-fatal) ERROR_CFG_OLD, ///< Unknown version of gfx2.cfg : either VERY old or wrong file (non-fatal) ERROR_MEMORY, ///< Out of memory ERROR_COMMAND_LINE, ///< Error in command-line arguments (syntax, or couldn't find the file to open) ERROR_FORBIDDEN_MODE, ///< Graphics mode requested is not supported ERROR_SAVING_CFG, ///< Error while writing gfx2.cfg ERROR_MISSING_DIRECTORY, ///< Unable to return to the original "current directory" on program exit ERROR_INI_CORRUPTED, ///< File gfx2.ini couldn't be parsed ERROR_SAVING_INI, ///< Error while writing gfx2.ini ERROR_SORRY_SORRY_SORRY ///< (Page allocation error that shouldn't ever happen, now) }; /// Available pixel scalers enum PIXEL_RATIO { PIXEL_SIMPLE=0, ///< Use real pixels PIXEL_WIDE, ///< Use wide pixels (2x1) like on Amstrad CPC mode 0 PIXEL_TALL, ///< Use tall pixels (1x2) like on Amstrad CPC mode 2 PIXEL_DOUBLE, ///< Use big pixels (2x2) if your LCD screen can't do lowres by itself PIXEL_TRIPLE, ///< Use really big pixels (3x3) PIXEL_WIDE2, ///< Use big wide pixels (4x2) PIXEL_TALL2, ///< Use big tall pixels (2x4) PIXEL_TALL3, ///< Use big tall pixels (3x4) PIXEL_QUAD, ///< Use really giant pixels (4x4). You need to have a screen resolution at least 1280x800 to use this one PIXEL_MAX ///< Number of elements in enum }; /// Different kinds of menu button behavior. enum FAMILY_OF_BUTTONS { FAMILY_TOOL=1, ///< Drawing tools (example : Freehand draw) FAMILY_INTERRUPTION, ///< Temporary operation (example : choosing paintbrush) > Interrupts the current operation to do something, then come back. FAMILY_INSTANT, ///< Single-click action (example : choose a color in palette) > It will be over as soon as we exit the called function. FAMILY_TOOLBAR, ///< Hide/show the menu FAMILY_EFFECTS ///< Effects }; /// The different kinds of buttons in menus or windows. enum BUTTON_SHAPES { BUTTON_SHAPE_NO_FRAME, ///< Ex: the palette BUTTON_SHAPE_RECTANGLE, ///< Ex: Most buttons. BUTTON_SHAPE_TRIANGLE_TOP_LEFT, ///< Ex: Empty rectangles. BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT ///< Ex: Filled rectangles. }; /// The different "mouse cursor" shapes enum CURSOR_SHAPES { // Sprite based cursors first (also used as index in cursor sprite array) CURSOR_SHAPE_ARROW, CURSOR_SHAPE_TARGET, ///< This one uses the paintbrush CURSOR_SHAPE_COLORPICKER, CURSOR_SHAPE_HOURGLASS, CURSOR_SHAPE_MULTIDIRECTIONAL, CURSOR_SHAPE_HORIZONTAL, CURSOR_SHAPE_THIN_TARGET, ///< This one uses the paintbrush CURSOR_SHAPE_THIN_COLORPICKER, ///< This one uses the paintbrush CURSOR_SHAPE_BUCKET, // XOR/runtime-generated cursors last CURSOR_SHAPE_XOR_TARGET, CURSOR_SHAPE_XOR_RECTANGLE, CURSOR_SHAPE_XOR_ROTATION, }; /// The different shapes that can be used as a paintbrush (paintbrush types go in the beginning) enum PAINTBRUSH_SHAPES { PAINTBRUSH_SHAPE_ROUND, PAINTBRUSH_SHAPE_SQUARE, PAINTBRUSH_SHAPE_HORIZONTAL_BAR, PAINTBRUSH_SHAPE_VERTICAL_BAR, PAINTBRUSH_SHAPE_SLASH, PAINTBRUSH_SHAPE_ANTISLASH, PAINTBRUSH_SHAPE_RANDOM, ///< Random pixels in a circle shape, like an airbrush. PAINTBRUSH_SHAPE_CROSS, PAINTBRUSH_SHAPE_PLUS, PAINTBRUSH_SHAPE_DIAMOND, PAINTBRUSH_SHAPE_SIEVE_ROUND, PAINTBRUSH_SHAPE_SIEVE_SQUARE, PAINTBRUSH_SHAPE_RESERVED1, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED2, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED3, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED4, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED5, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED6, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED7, ///< Reserved for future use PAINTBRUSH_SHAPE_RESERVED8, ///< Reserved for future use PAINTBRUSH_SHAPE_MISC, ///< A raw monochrome bitmap, can't be resized. This must be the last of the preset paintbrush types. PAINTBRUSH_SHAPE_POINT, ///< Used to reduce the paintbrush to a single pixel, during operations like floodfill. PAINTBRUSH_SHAPE_NONE, ///< Used to display no cursor at all (colorpicker) PAINTBRUSH_SHAPE_COLOR_BRUSH, ///< User's brush, in color mode PAINTBRUSH_SHAPE_MONO_BRUSH, ///< User's brush, in mono mode PAINTBRUSH_SHAPE_MAX ///< Upper limit. }; /// Normal resting state for a menu button. #define BUTTON_RELEASED 0 /// State of a menu button that is being pressed. #define BUTTON_PRESSED 1 /// State of a button temporarily highligted #define BUTTON_HIGHLIGHTED 2 /// The different modes of the Shade enum SHADE_MODES { SHADE_MODE_NORMAL, SHADE_MODE_LOOP, SHADE_MODE_NOSAT }; /// Identifiers for the chunks (data blocks) of gfx2.cfg enum CHUNKS_CFG { CHUNK_KEYS = 0, ///< Shortcut keys definitions CHUNK_VIDEO_MODES = 1, ///< List of video modes CHUNK_SHADE = 2, ///< Shade settings CHUNK_MASK = 3, ///< Mask settings CHUNK_STENCIL = 4, ///< Stencil settings CHUNK_GRADIENTS = 5, ///< Gradients CHUNK_SMOOTH = 6, ///< Smooth effect settings CHUNK_EXCLUDE_COLORS = 7, ///< List of excluded colors CHUNK_QUICK_SHADE = 8, ///< QShade effect settings CHUNK_GRID = 9, ///< Grid settings CHUNK_BRUSH =10, ///< Paintbrushes CHUNK_SCRIPTS =11, ///< Callable scripts CHUNK_MAX }; /// Identifiers for the 8x8 icons of ::Gfx->Icon_sprite (most are unused now) enum ICON_TYPES { ICON_FLOPPY_3_5=0, ///< 3.5 Floppy disk ICON_FLOPPY_5_25, ///< 5.25 Floppy disk ICON_HDD, ///< Hard disk drive ICON_CDROM, ///< CD-ROM ICON_NETWORK, ///< "Network" drive ICON_STAR, ///< Star (favorite) ICON_DROPDOWN, ///< Dropdown arrow NB_ICON_SPRITES, ///< Number of 8x8 icons ICON_NONE ///< None of the above }; enum EFFECT_SPRITES { EFFECTS_SPRITE_SHADE, EFFECTS_SPRITE_TRANSP, EFFECTS_SPRITE_SMOOTH, EFFECTS_SPRITE_TILING, EFFECTS_SPRITE_STENCIL, EFFECTS_SPRITE_SIEVE, EFFECTS_SPRITE_GRID, EFFECTS_SPRITE_MASK, EFFECTS_SPRITE_SMEAR, EFFECTS_SPRITE_8BIT, NB_EFFECTS_SPRITES ///< Number of effect sprites. }; /// Identifiers for the buttons in the menu. enum BUTTON_NUMBERS { // Status bar BUTTON_HIDE = 0, // Anim bar BUTTON_LAYER_MENU2, BUTTON_ANIM_TIME, BUTTON_ANIM_FIRST_FRAME, BUTTON_ANIM_PREV_FRAME, BUTTON_ANIM_NEXT_FRAME, BUTTON_ANIM_LAST_FRAME, BUTTON_ANIM_ADD_FRAME, BUTTON_ANIM_REMOVE_FRAME, BUTTON_ANIM_UP_FRAME, BUTTON_ANIM_DOWN_FRAME, BUTTON_ANIM_PLAY, // unused at this time // Layer bar BUTTON_LAYER_MENU, BUTTON_LAYER_COLOR, BUTTON_LAYER_MERGE, BUTTON_LAYER_ADD, BUTTON_LAYER_REMOVE, BUTTON_LAYER_UP, BUTTON_LAYER_DOWN, BUTTON_LAYER_SELECT, // Main menu BUTTON_PAINTBRUSHES, BUTTON_ADJUST, BUTTON_DRAW, BUTTON_CURVES, BUTTON_LINES, BUTTON_AIRBRUSH, BUTTON_FLOODFILL, BUTTON_POLYGONS, BUTTON_POLYFILL, BUTTON_RECTANGLES, BUTTON_FILLRECT, BUTTON_CIRCLES, BUTTON_FILLCIRC, BUTTON_GRADRECT, BUTTON_SPHERES, BUTTON_BRUSH, BUTTON_POLYBRUSH, BUTTON_BRUSH_EFFECTS, BUTTON_EFFECTS, BUTTON_TEXT, BUTTON_MAGNIFIER, BUTTON_COLORPICKER, BUTTON_RESOL, BUTTON_PAGE, BUTTON_SAVE, BUTTON_LOAD, BUTTON_SETTINGS, BUTTON_CLEAR, BUTTON_HELP, BUTTON_UNDO, BUTTON_KILL, BUTTON_QUIT, BUTTON_PALETTE, BUTTON_PAL_LEFT, BUTTON_PAL_RIGHT, BUTTON_CHOOSE_COL, NB_BUTTONS ///< Number of buttons in the menu bar. }; enum MENU_SPRITE { MENU_SPRITE_COLOR_BRUSH=0, MENU_SPRITE_MONO_BRUSH, MENU_SPRITE_DISCONTINUOUS_DRAW, MENU_SPRITE_POINT_DRAW, MENU_SPRITE_CONTOUR_DRAW, MENU_SPRITE_4_POINTS_CURVE, MENU_SPRITE_K_LINE, MENU_SPRITE_CENTERED_LINES, MENU_SPRITE_ELLIPSES, MENU_SPRITE_POLYFORM, MENU_SPRITE_REPLACE, MENU_SPRITE_GRAD_ELLIPSE, MENU_SPRITE_VERTICAL_PALETTE_SCROLL, NB_MENU_SPRITES ///< Number of menu sprites. }; /// /// Identifiers of special actions that can have a keyboard shortcut. /// They are special in the sense that there's no button in the menu for them, /// so it requires a specific handling. enum SPECIAL_ACTIONS { SPECIAL_MOUSE_UP=0, SPECIAL_MOUSE_DOWN, SPECIAL_MOUSE_LEFT, SPECIAL_MOUSE_RIGHT, SPECIAL_CLICK_LEFT, SPECIAL_CLICK_RIGHT, SPECIAL_NEXT_FORECOLOR, SPECIAL_PREVIOUS_FORECOLOR, SPECIAL_NEXT_BACKCOLOR, SPECIAL_PREVIOUS_BACKCOLOR, SPECIAL_SMALLER_PAINTBRUSH, SPECIAL_BIGGER_PAINTBRUSH, SPECIAL_NEXT_USER_FORECOLOR, SPECIAL_PREVIOUS_USER_FORECOLOR, SPECIAL_NEXT_USER_BACKCOLOR, SPECIAL_PREVIOUS_USER_BACKCOLOR, SPECIAL_SCROLL_UP, SPECIAL_SCROLL_DOWN, SPECIAL_SCROLL_LEFT, SPECIAL_SCROLL_RIGHT, SPECIAL_SCROLL_UP_FAST, SPECIAL_SCROLL_DOWN_FAST, SPECIAL_SCROLL_LEFT_FAST, SPECIAL_SCROLL_RIGHT_FAST, SPECIAL_SCROLL_UP_SLOW, SPECIAL_SCROLL_DOWN_SLOW, SPECIAL_SCROLL_LEFT_SLOW, SPECIAL_SCROLL_RIGHT_SLOW, SPECIAL_SHOW_HIDE_CURSOR, SPECIAL_DOT_PAINTBRUSH, SPECIAL_CONTINUOUS_DRAW, SPECIAL_FLIP_X, SPECIAL_FLIP_Y, SPECIAL_ROTATE_90, SPECIAL_ROTATE_180, SPECIAL_STRETCH, SPECIAL_DISTORT, SPECIAL_OUTLINE, SPECIAL_NIBBLE, SPECIAL_GET_BRUSH_COLORS, SPECIAL_RECOLORIZE_BRUSH, SPECIAL_ROTATE_ANY_ANGLE, SPECIAL_BRUSH_DOUBLE, SPECIAL_BRUSH_DOUBLE_WIDTH, SPECIAL_BRUSH_DOUBLE_HEIGHT, SPECIAL_BRUSH_HALVE, SPECIAL_LOAD_BRUSH, SPECIAL_SAVE_BRUSH, SPECIAL_INVERT_SIEVE, SPECIAL_ZOOM_IN, SPECIAL_ZOOM_OUT, SPECIAL_CENTER_ATTACHMENT, SPECIAL_TOP_LEFT_ATTACHMENT, SPECIAL_TOP_RIGHT_ATTACHMENT, SPECIAL_BOTTOM_LEFT_ATTACHMENT, SPECIAL_BOTTOM_RIGHT_ATTACHMENT, SPECIAL_EXCLUDE_COLORS_MENU, SPECIAL_SHADE_MODE, SPECIAL_SHADE_MENU, SPECIAL_QUICK_SHADE_MODE, ///< This must be the first of the "effects" family SPECIAL_QUICK_SHADE_MENU, SPECIAL_STENCIL_MODE, SPECIAL_STENCIL_MENU, SPECIAL_MASK_MODE, SPECIAL_MASK_MENU, SPECIAL_GRID_MODE, SPECIAL_GRID_MENU, SPECIAL_SIEVE_MODE, SPECIAL_SIEVE_MENU, SPECIAL_COLORIZE_MODE, SPECIAL_COLORIZE_MENU, SPECIAL_SMOOTH_MODE, SPECIAL_SMOOTH_MENU, SPECIAL_SMEAR_MODE, SPECIAL_EFFECTS_OFF, SPECIAL_TILING_MODE, SPECIAL_TRANSPARENCY_1, SPECIAL_TRANSPARENCY_2, SPECIAL_TRANSPARENCY_3, SPECIAL_TRANSPARENCY_4, SPECIAL_TRANSPARENCY_5, SPECIAL_TRANSPARENCY_6, SPECIAL_TRANSPARENCY_7, SPECIAL_TRANSPARENCY_8, SPECIAL_TRANSPARENCY_9, SPECIAL_TRANSPARENCY_0, SPECIAL_TILEMAP_MODE, SPECIAL_TILEMAP_MENU, SPECIAL_TILING_MENU, ///< This must be the last of the "effects" family SPECIAL_ZOOM_1, SPECIAL_ZOOM_2, SPECIAL_ZOOM_3, SPECIAL_ZOOM_4, SPECIAL_ZOOM_5, SPECIAL_ZOOM_6, SPECIAL_ZOOM_8, SPECIAL_ZOOM_10, SPECIAL_ZOOM_12, SPECIAL_ZOOM_14, SPECIAL_ZOOM_16, SPECIAL_ZOOM_18, SPECIAL_ZOOM_20, SPECIAL_SHOW_GRID, SPECIAL_LAYER1_SELECT, SPECIAL_LAYER1_TOGGLE, SPECIAL_LAYER2_SELECT, SPECIAL_LAYER2_TOGGLE, SPECIAL_LAYER3_SELECT, SPECIAL_LAYER3_TOGGLE, SPECIAL_LAYER4_SELECT, SPECIAL_LAYER4_TOGGLE, SPECIAL_LAYER5_SELECT, SPECIAL_LAYER5_TOGGLE, SPECIAL_LAYER6_SELECT, SPECIAL_LAYER6_TOGGLE, SPECIAL_LAYER7_SELECT, SPECIAL_LAYER7_TOGGLE, SPECIAL_LAYER8_SELECT, SPECIAL_LAYER8_TOGGLE, SPECIAL_REPEAT_SCRIPT, SPECIAL_RUN_SCRIPT_1, SPECIAL_RUN_SCRIPT_2, SPECIAL_RUN_SCRIPT_3, SPECIAL_RUN_SCRIPT_4, SPECIAL_RUN_SCRIPT_5, SPECIAL_RUN_SCRIPT_6, SPECIAL_RUN_SCRIPT_7, SPECIAL_RUN_SCRIPT_8, SPECIAL_RUN_SCRIPT_9, SPECIAL_RUN_SCRIPT_10, SPECIAL_CYCLE_MODE, SPECIAL_FORMAT_CHECKER, SPECIAL_FORMAT_CHECKER_MENU, SPECIAL_HOLD_PAN, NB_SPECIAL_SHORTCUTS ///< Number of special shortcuts }; /// Identifiers of the operations, ie tools you use on the image. enum OPERATIONS { OPERATION_CONTINUOUS_DRAW=0, ///< Freehand continuous draw OPERATION_DISCONTINUOUS_DRAW,///< Freehand discontinuous draw OPERATION_POINT_DRAW, ///< Freehand point-by-point draw OPERATION_FILLED_CONTOUR, ///< Filled contour OPERATION_LINE, ///< Lines OPERATION_K_LINE, ///< Linked lines OPERATION_CENTERED_LINES, ///< Centered lines OPERATION_EMPTY_RECTANGLE, ///< Empty rectangle OPERATION_FILLED_RECTANGLE, ///< Filled rectangle OPERATION_EMPTY_CIRCLE, ///< Empty circle OPERATION_FILLED_CIRCLE, ///< Filled circle OPERATION_EMPTY_ELLIPSE, ///< Empty ellipse OPERATION_FILLED_ELLIPSE, ///< Filled ellipse OPERATION_FILL, ///< Fill OPERATION_REPLACE, ///< Color replacer OPERATION_GRAB_BRUSH, ///< Rectangular brush grabbing OPERATION_POLYBRUSH, ///< Polygonal brush grabbing OPERATION_COLORPICK, ///< Colorpicker OPERATION_MAGNIFY, ///< Position the magnify window OPERATION_3_POINTS_CURVE, ///< Curve with 3 control points OPERATION_4_POINTS_CURVE, ///< Curve with 4 control points OPERATION_AIRBRUSH, ///< Airbrush OPERATION_POLYGON, ///< Polygon OPERATION_POLYFORM, ///< Polyform OPERATION_POLYFILL, ///< Filled polygon OPERATION_FILLED_POLYFORM, ///< Filled polyform OPERATION_SCROLL, ///< Scroll (pan) OPERATION_GRAD_CIRCLE, ///< Gradient-filled circle OPERATION_GRAD_ELLIPSE, ///< Gradient-filled ellipse OPERATION_ROTATE_BRUSH, ///< Rotate brush OPERATION_STRETCH_BRUSH, ///< Stretch brush OPERATION_DISTORT_BRUSH, ///< Distort brush OPERATION_GRAD_RECTANGLE, ///< Gradient-filled rectangle OPERATION_RMB_COLORPICK, ///< Colorpick on right mouse button OPERATION_PAN_VIEW, ///< Pan view NB_OPERATIONS ///< Number of operations handled by the engine }; enum IMAGE_MODES { IMAGE_MODE_LAYERED=0, ///< Layered image IMAGE_MODE_ANIMATION, ///< Animation IMAGE_MODE_ZX, ///< ZX Spectrum (note "SPECTRUM" is kept for later... Spectrum 512 anyone?) IMAGE_MODE_GBC, ///< Game Boy Color IMAGE_MODE_THOMSON, ///< "40 columns" mode on Thomson machines IMAGE_MODE_EGX, ///< CPC EGX IMAGE_MODE_EGX2, ///< CPC EGX2 IMAGE_MODE_MODE5, ///< CPC mode 5 }; #endif grafx2_2.4+git20180105/src/realpath.h0000664000000000000000000000240313223665306015477 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Adrien Destugues Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file realpath.h /// Implementation of realpath() that is portable on all our platforms. ////////////////////////////////////////////////////////////////////////////// #ifndef _REALPATH_H #define _REALPATH_H /// /// Makes an absolute filename, resolving symbolic links etc. /// @param _path Input path /// @param resolved_path Output path, allocated by caller /// @return (points to resolved_path) char *Realpath(const char *_path, char *resolved_path); #endif grafx2_2.4+git20180105/src/loadsave.c0000664000000000000000000014450013223665306015475 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2010 Alexander Filyanov Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include #include #include #include #include #include "buttons.h" #include "const.h" #include "errors.h" #include "global.h" #include "io.h" #include "loadsave.h" #include "misc.h" #include "graph.h" #include "op_c.h" #include "pages.h" #include "palette.h" #include "sdlscreen.h" #include "struct.h" #include "windows.h" #include "engine.h" #include "brush.h" #include "setup.h" #include "filesel.h" // -- PKM ------------------------------------------------------------------- void Test_PKM(T_IO_Context *); void Load_PKM(T_IO_Context *); void Save_PKM(T_IO_Context *); // -- IFF ------------------------------------------------------------------- void Test_LBM(T_IO_Context *); void Test_PBM(T_IO_Context *); void Load_IFF(T_IO_Context *); void Save_IFF(T_IO_Context *); // -- GIF ------------------------------------------------------------------- void Test_GIF(T_IO_Context *); void Load_GIF(T_IO_Context *); void Save_GIF(T_IO_Context *); // -- PCX ------------------------------------------------------------------- void Test_PCX(T_IO_Context *); void Load_PCX(T_IO_Context *); void Save_PCX(T_IO_Context *); // -- BMP ------------------------------------------------------------------- void Test_BMP(T_IO_Context *); void Load_BMP(T_IO_Context *); void Save_BMP(T_IO_Context *); // -- IMG ------------------------------------------------------------------- void Test_IMG(T_IO_Context *); void Load_IMG(T_IO_Context *); void Save_IMG(T_IO_Context *); // -- SCx ------------------------------------------------------------------- void Test_SCx(T_IO_Context *); void Load_SCx(T_IO_Context *); void Save_SCx(T_IO_Context *); // -- CEL ------------------------------------------------------------------- void Test_CEL(T_IO_Context *); void Load_CEL(T_IO_Context *); void Save_CEL(T_IO_Context *); // -- KCF ------------------------------------------------------------------- void Test_KCF(T_IO_Context *); void Load_KCF(T_IO_Context *); void Save_KCF(T_IO_Context *); // -- PAL ------------------------------------------------------------------- void Test_PAL(T_IO_Context *); void Load_PAL(T_IO_Context *); void Save_PAL(T_IO_Context *); // -- GPL ------------------------------------------------------------------- void Test_GPL(T_IO_Context *); void Load_GPL(T_IO_Context *); void Save_GPL(T_IO_Context *); // -- PI1 ------------------------------------------------------------------- void Test_PI1(T_IO_Context *); void Load_PI1(T_IO_Context *); void Save_PI1(T_IO_Context *); // -- PC1 ------------------------------------------------------------------- void Test_PC1(T_IO_Context *); void Load_PC1(T_IO_Context *); void Save_PC1(T_IO_Context *); // -- NEO ------------------------------------------------------------------- void Test_NEO(T_IO_Context *); void Load_NEO(T_IO_Context *); void Save_NEO(T_IO_Context *); // -- C64 ------------------------------------------------------------------- void Test_C64(T_IO_Context *); void Load_C64(T_IO_Context *); void Save_C64(T_IO_Context *); // -- SCR (Amstrad CPC) void Save_SCR(T_IO_Context *); // -- CM5 (Amstrad CPC) void Test_CM5(T_IO_Context *); void Load_CM5(T_IO_Context *); void Save_CM5(T_IO_Context *); // -- PPH (Amstrad CPC) void Test_PPH(T_IO_Context *); void Load_PPH(T_IO_Context *); void Save_PPH(T_IO_Context *); // -- XPM (X PixMap) // Loading is done through SDL_Image void Save_XPM(T_IO_Context*); // -- PNG ------------------------------------------------------------------- #ifndef __no_pnglib__ void Test_PNG(T_IO_Context *); void Load_PNG(T_IO_Context *); void Save_PNG(T_IO_Context *); #endif // -- SDL_Image ------------------------------------------------------------- // (TGA, BMP, PNM, XPM, XCF, PCX, GIF, JPG, TIF, IFF, PNG, ICO) void Load_SDL_Image(T_IO_Context *); // ENUM Name TestFunc LoadFunc SaveFunc PalOnly Comment Layers Ext Exts T_Format File_formats[] = { {FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "", "gif;png;bmp;pcx;pkm;iff;lbm;ilbm;img;sci;scq;scf;scn;sco;pi1;pc1;cel;neo;c64;koa;koala;fli;bml;cdu;prg;tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico;cm5;pph"}, {FORMAT_ALL_PALETTES, "(all)", NULL, NULL, NULL, 1, 0, 0, "", "kcf;pal;gpl"}, {FORMAT_ALL_FILES, "(*.*)", NULL, NULL, NULL, 0, 0, 0, "", "*"}, {FORMAT_GIF, " gif", Test_GIF, Load_GIF, Save_GIF, 0, 1, 1, "gif", "gif"}, #ifndef __no_pnglib__ {FORMAT_PNG, " png", Test_PNG, Load_PNG, Save_PNG, 0, 1, 0, "png", "png"}, #endif {FORMAT_BMP, " bmp", Test_BMP, Load_BMP, Save_BMP, 0, 0, 0, "bmp", "bmp"}, {FORMAT_PCX, " pcx", Test_PCX, Load_PCX, Save_PCX, 0, 0, 0, "pcx", "pcx"}, {FORMAT_PKM, " pkm", Test_PKM, Load_PKM, Save_PKM, 0, 1, 0, "pkm", "pkm"}, {FORMAT_LBM, " lbm", Test_LBM, Load_IFF, Save_IFF, 0, 0, 0, "iff", "iff;lbm;ilbm"}, {FORMAT_PBM, " pbm", Test_PBM, Load_IFF, Save_IFF, 0, 0, 0, "iff", "iff;pbm"}, {FORMAT_IMG, " img", Test_IMG, Load_IMG, Save_IMG, 0, 0, 0, "img", "img"}, {FORMAT_SCx, " sc?", Test_SCx, Load_SCx, Save_SCx, 0, 0, 0, "sc?", "sci;scq;scf;scn;sco"}, {FORMAT_PI1, " pi1", Test_PI1, Load_PI1, Save_PI1, 0, 0, 0, "pi1", "pi1"}, {FORMAT_PC1, " pc1", Test_PC1, Load_PC1, Save_PC1, 0, 0, 0, "pc1", "pc1"}, {FORMAT_CEL, " cel", Test_CEL, Load_CEL, Save_CEL, 0, 0, 0, "cel", "cel"}, {FORMAT_NEO, " neo", Test_NEO, Load_NEO, Save_NEO, 0, 0, 0, "neo", "neo"}, {FORMAT_KCF, " kcf", Test_KCF, Load_KCF, Save_KCF, 1, 0, 0, "kcf", "kcf"}, {FORMAT_PAL, " pal", Test_PAL, Load_PAL, Save_PAL, 1, 0, 0, "pal", "pal"}, {FORMAT_GPL, " gpl", Test_GPL, Load_GPL, Save_GPL, 1, 0, 0, "gpl", "gpl"}, {FORMAT_C64, " c64", Test_C64, Load_C64, Save_C64, 0, 1, 0, "c64", "c64;koa;koala;fli;bml;cdu;prg"}, {FORMAT_SCR, " cpc", NULL, NULL, Save_SCR, 0, 0, 0, "cpc", "cpc;scr"}, {FORMAT_CM5, " cm5", Test_CM5, Load_CM5, Save_CM5, 0, 0, 1, "cm5", "cm5"}, {FORMAT_PPH, " pph", Test_PPH, Load_PPH, Save_PPH, 0, 0, 1, "pph", "pph"}, {FORMAT_XPM, " xpm", NULL, NULL, Save_XPM, 0, 0, 0, "xpm", "xpm"}, {FORMAT_MISC,"misc.",NULL, NULL, NULL, 0, 0, 0, "", "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, }; /// Total number of known file formats unsigned int Nb_known_formats(void) { return sizeof(File_formats)/sizeof(File_formats[0]); } /// Set the color of a pixel (on load) void Set_pixel(T_IO_Context *context, short x_pos, short y_pos, byte color) { // Clipping if ((x_pos>=context->Width) || (y_pos>=context->Height)) return; switch (context->Type) { // Chargement des pixels dans l'cran principal case CONTEXT_MAIN_IMAGE: Pixel_in_current_screen(x_pos,y_pos,color); break; // Chargement des pixels dans la brosse case CONTEXT_BRUSH: //Pixel_in_brush(x_pos,y_pos,color); *(context->Buffer_image + y_pos * context->Pitch + x_pos)=color; break; // Chargement des pixels dans la preview case CONTEXT_PREVIEW: // Skip pixels of transparent index if : // it's a layer above the first one if (color == context->Transparent_color && context->Current_layer > 0) break; if (((x_pos % context->Preview_factor_X)==0) && ((y_pos % context->Preview_factor_Y)==0)) { // Tag the color as 'used' context->Preview_usage[color]=1; // Store pixel if (context->Ratio == PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) { context->Preview_bitmap[x_pos/context->Preview_factor_X*2 + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; context->Preview_bitmap[x_pos/context->Preview_factor_X*2+1 + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; } else if (context->Ratio == PIXEL_TALL && Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2 && Pixel_ratio != PIXEL_TALL3) { context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y*2)*PREVIEW_WIDTH*Menu_factor_X]=color; context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y*2+1)*PREVIEW_WIDTH*Menu_factor_X]=color; } else context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; } break; // Load pixels in a SDL_Surface case CONTEXT_SURFACE: if (x_pos>=0 && y_pos>=0 && x_posSurface->w && y_posSurface->h) *(((byte *)(context->Surface->pixels)) + context->Surface->pitch * y_pos + x_pos) = color; break; case CONTEXT_PALETTE: break; } } void Fill_canvas(T_IO_Context *context, byte color) { switch (context->Type) { case CONTEXT_PREVIEW: if (context->Current_layer!=0) return; memset(context->Preview_bitmap, color, PREVIEW_WIDTH*PREVIEW_HEIGHT*Menu_factor_X*Menu_factor_Y); break; case CONTEXT_MAIN_IMAGE: memset( Main_backups->Pages->Image[Main_current_layer].Pixels, color, Main_backups->Pages->Width*Main_backups->Pages->Height); break; case CONTEXT_BRUSH: memset(context->Buffer_image, color, (long)context->Height*context->Pitch); break; case CONTEXT_SURFACE: break; case CONTEXT_PALETTE: break; } } // Chargement des pixels dans le buffer 24b void Set_pixel_24b(T_IO_Context *context, short x_pos, short y_pos, byte r, byte g, byte b) { byte color; // Clipping if (x_pos<0 || y_pos<0 || x_pos>=context->Width || y_pos>=context->Height) return; switch(context->Type) { case CONTEXT_MAIN_IMAGE: case CONTEXT_BRUSH: case CONTEXT_SURFACE: { int index; index=(y_pos*context->Width)+x_pos; context->Buffer_image_24b[index].R=r; context->Buffer_image_24b[index].G=g; context->Buffer_image_24b[index].B=b; } break; case CONTEXT_PREVIEW: if (((x_pos % context->Preview_factor_X)==0) && ((y_pos % context->Preview_factor_Y)==0)) { color=((r >> 5) << 5) | ((g >> 5) << 2) | ((b >> 6)); // Tag the color as 'used' context->Preview_usage[color]=1; context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; } break; case CONTEXT_PALETTE: // In a palette, there are no pixels! break; } } // Cration d'une palette fake void Set_palette_fake_24b(T_Palette palette) { int color; // Gnration de la palette for (color=0;color<256;color++) { palette[color].R=((color & 0xE0)>>5)<<5; palette[color].G=((color & 0x1C)>>2)<<5; palette[color].B=((color & 0x03)>>0)<<6; } } void Set_frame_duration(T_IO_Context *context, int duration) { switch(context->Type) { case CONTEXT_MAIN_IMAGE: Main_backups->Pages->Image[context->Current_layer].Duration = duration; break; default: break; } } int Get_frame_duration(T_IO_Context *context) { switch(context->Type) { case CONTEXT_MAIN_IMAGE: return Main_backups->Pages->Image[context->Current_layer].Duration; default: return 0; } } /// /// Generic allocation and similar stuff, done at beginning of image load, /// as soon as size is known. void Pre_load(T_IO_Context *context, short width, short height, long file_size, int format, enum PIXEL_RATIO ratio, byte truecolor) { char str[10]; context->Pitch = width; // default context->Width = width; context->Height = height; context->Ratio = ratio; context->Nb_layers = 1; context->Transparent_color=0; context->Background_transparent=0; switch(context->Type) { // Preview case CONTEXT_PREVIEW: // Prparation du chargement d'une preview: context->Preview_bitmap=calloc(1, PREVIEW_WIDTH*PREVIEW_HEIGHT*Menu_factor_X*Menu_factor_Y); if (!context->Preview_bitmap) File_error=1; // Affichage des donnes "Image size:" if ((width<10000) && (height<10000)) { Num2str(width,str,4); Num2str(height,str+5,4); str[4]='x'; Print_in_window(143,59,str,MC_Black,MC_Light); } else { Print_in_window(143,59,"VERY BIG!",MC_Black,MC_Light); } // Affichage de la taille du fichier if (file_size<1048576) { // Le fichier fait moins d'un Mega, on affiche sa taille direct Num2str(file_size,str,7); Print_in_window(236,59,str,MC_Black,MC_Light); } else if ((file_size/1024)<100000) { // Le fichier fait plus d'un Mega, on peut afficher sa taille en Ko Num2str(file_size/1024,str,5); strcpy(str+5,"Kb"); Print_in_window(236,59,str,MC_Black,MC_Light); } else { // Le fichier fait plus de 100 Mega octets (cas trs rare :)) Print_in_window(236,59,"LARGE!!",MC_Black,MC_Light); } // Affichage du vrai format if (format!=Selector->Format_filter) { Print_in_window( 59,59,Get_fileformat(format)->Label,MC_Black,MC_Light); } // On efface le commentaire prcdent Window_rectangle(45,70,32*8,8,MC_Light); // Calcul des donnes ncessaires l'affichage de la preview: if (ratio == PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) width*=2; else if (ratio == PIXEL_TALL && Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2 && Pixel_ratio != PIXEL_TALL3) height*=2; context->Preview_factor_X=Round_div_max(width,120*Menu_factor_X); context->Preview_factor_Y=Round_div_max(height, 80*Menu_factor_Y); if ( (!Config.Maximize_preview) && (context->Preview_factor_X!=context->Preview_factor_Y) ) { if (context->Preview_factor_X>context->Preview_factor_Y) context->Preview_factor_Y=context->Preview_factor_X; else context->Preview_factor_X=context->Preview_factor_Y; } context->Preview_pos_X=Window_pos_X+183*Menu_factor_X; context->Preview_pos_Y=Window_pos_Y+ 95*Menu_factor_Y; // On nettoie la zone o va s'afficher la preview: Window_rectangle(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT,MC_Light); // Un update pour couvrir les 4 zones: 3 libells plus le commentaire Update_window_area(45,48,256,30); // Zone de preview Update_window_area(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT); break; // Other loading case CONTEXT_MAIN_IMAGE: if (Backup_new_image(1,width,height)) { // La nouvelle page a pu tre alloue, elle est pour l'instant pleine // de 0s. Elle fait Main_image_width de large. // Normalement tout va bien, tout est sous contrle... // Load into layer 0, by default. context->Nb_layers=1; Main_current_layer=0; Main_layers_visible=1<<0; Set_loading_layer(context,0); // Remove previous comment, unless we load just a palette if (! Get_fileformat(context->Format)->Palette_only) context->Comment[0]='\0'; } else { // Afficher un message d'erreur // Pour tre sr que ce soit lisible. Compute_optimal_menu_colors(context->Palette); Message_out_of_memory(); File_error=1; // 1 => On n'a pas perdu l'image courante } break; case CONTEXT_BRUSH: context->Buffer_image = (byte *)malloc(width*height); if (! context->Buffer_image) { File_error=3; return; } context->Target_address=context->Buffer_image; break; case CONTEXT_SURFACE: context->Surface = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCCOLORKEY, width, height, 8, 0, 0, 0, 0); if (! context->Surface) { File_error=1; return; } //context->Pitch = context->Surface->pitch; //context->Target_address = context->Surface->pixels; break; case CONTEXT_PALETTE: // In a palette, there are no pixels! break; } if (File_error) return; // Extra process for truecolor images if (truecolor) { //context->Is_truecolor = 1; switch(context->Type) { case CONTEXT_MAIN_IMAGE: case CONTEXT_BRUSH: case CONTEXT_SURFACE: // Allocate 24bit buffer context->Buffer_image_24b= (T_Components *)malloc(width*height*sizeof(T_Components)); if (!context->Buffer_image_24b) { // Print an error message // The following is to be sure the message is readable Compute_optimal_menu_colors(context->Palette); Message_out_of_memory(); File_error=1; } break; case CONTEXT_PREVIEW: // Load palette Set_palette_fake_24b(context->Palette); break; case CONTEXT_PALETTE: // In a palette, there are no pixels! break; } } } ///////////////////////////////////////////////////////////////////////////// // Gestion des lectures et critures // ///////////////////////////////////////////////////////////////////////////// void Write_one_byte(FILE *file, byte b) { if (! Write_byte(file,b)) File_error=1; } ///////////////////////////////////////////////////////////////////////////// // -------- Modifier la valeur du code d'erreur d'accs un fichier -------- // On n'est pas oblig d'utiliser cette fonction chaque fois mais il est // important de l'utiliser dans les cas du type: // if (!File_error) *** else File_error=***; // En fait, dans le cas o l'on modifie File_error alors qu'elle contient // dj un code d'erreur. void Set_file_error(int value) { if (File_error>=0) File_error=value; } // -- Charger n'importe connu quel type de fichier d'image (ou palette) ----- void Load_image(T_IO_Context *context) { unsigned int index; // index de balayage des formats T_Format *format = &(File_formats[FORMAT_ALL_FILES+1]); // Format du fichier charger int i; byte old_cursor_shape; // Not sure it's the best place... context->Color_cycles=0; // On place par dfaut File_error vrai au cas o on ne sache pas // charger le format du fichier: File_error=1; if (context->Format>FORMAT_ALL_FILES) { format = Get_fileformat(context->Format); if (format->Test) format->Test(context); } if (File_error) { // Sinon, on va devoir scanner les diffrents formats qu'on connait pour // savoir quel format est le fichier: for (index=0; index < Nb_known_formats(); index++) { format = Get_fileformat(index); // Loadable format if (format->Test == NULL) continue; // On appelle le testeur du format: format->Test(context); // On s'arrte si le fichier est au bon format: if (File_error==0) break; } } if (File_error) { context->Format = DEFAULT_FILEFORMAT; // Last try: with SDL_image Load_SDL_Image(context); if (File_error) { // Sinon, l'appelant sera au courant de l'chec grace File_error; // et si on s'apprtait faire un chargement dfinitif de l'image (pas // une preview), alors on flash l'utilisateur. //if (Pixel_load_function!=Pixel_load_in_preview) // Error(0); return; } } else // Si on a su dterminer avec succs le format du fichier: { context->Format = format->Identifier; // On peut charger le fichier: // Dans certains cas il est possible que le chargement plante // aprs avoir modifi la palette. TODO format->Load(context); } if (File_error>0) { fprintf(stderr,"Unable to load file %s (error %d)!\n",context->File_name, File_error); if (context->Type!=CONTEXT_SURFACE) Error(0); } // Post-load if (context->Buffer_image_24b) { // On vient de charger une image 24b if (!File_error) { switch(context->Type) { case CONTEXT_MAIN_IMAGE: // Cas d'un chargement dans l'image old_cursor_shape=Cursor_shape; Hide_cursor(); Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Flush_update(); if (Convert_24b_bitmap_to_256(Main_backups->Pages->Image[0].Pixels,context->Buffer_image_24b,context->Width,context->Height,context->Palette)) File_error=2; Hide_cursor(); Cursor_shape=old_cursor_shape; Display_cursor(); break; case CONTEXT_BRUSH: // Cas d'un chargement dans la brosse old_cursor_shape=Cursor_shape; Hide_cursor(); Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); Flush_update(); if (Convert_24b_bitmap_to_256(context->Buffer_image,context->Buffer_image_24b,context->Width,context->Height,context->Palette)) File_error=2; Hide_cursor(); Cursor_shape=old_cursor_shape; Display_cursor(); break; case CONTEXT_PREVIEW: // nothing to do break; case CONTEXT_SURFACE: if (Convert_24b_bitmap_to_256(context->Surface->pixels,context->Buffer_image_24b,context->Width,context->Height,context->Palette)) File_error=1; break; case CONTEXT_PALETTE: // In a palette, there are no pixels! break; } } free(context->Buffer_image_24b); context->Buffer_image_24b = NULL; } else if (context->Type == CONTEXT_MAIN_IMAGE) { // Non-24b main image: Add menu colors if (Config.Safety_colors) { dword color_usage[256]; memset(color_usage,0,sizeof(color_usage)); if (Count_used_colors(color_usage)<252) { int gui_index; // From white to black for (gui_index=3; gui_index>=0; gui_index--) { int c; T_Components gui_color; gui_color=*Favorite_GUI_color(gui_index); // Try find a very close match (ignore last 2 bits) for (c=255; c>=0; c--) { if ((context->Palette[c].R|3) == (gui_color.R|3) && (context->Palette[c].G|3) == (gui_color.G|3) && (context->Palette[c].B|3) == (gui_color.B|3) ) break; } if (c<0) // Not found { // Find an unused slot at end of palette for (c=255; c>=0; c--) { if (color_usage[c]==0) { context->Palette[c]=gui_color; // Tag as a used color color_usage[c]=1; break; } } } } } } } if (context->Type == CONTEXT_MAIN_IMAGE) { if ( File_error!=1) { Set_palette(context->Palette); if (format->Palette_only) { // Make a backup step Backup_layers(LAYER_NONE); } // Copy the loaded palette memcpy(Main_palette, context->Palette, sizeof(T_Palette)); memcpy(Main_backups->Pages->Palette, context->Palette, sizeof(T_Palette)); // For formats that handle more than just the palette: // Transfer the data to main image. if (!format->Palette_only) { if (context->Original_file_name && context->Original_file_name[0] && context->Original_file_directory && context->Original_file_directory[0]) { strcpy(Main_backups->Pages->Filename,context->Original_file_name); strcpy(Main_backups->Pages->File_directory,context->Original_file_directory); } else { strcpy(Main_backups->Pages->Filename,context->File_name); strcpy(Main_backups->Pages->File_directory,context->File_directory); } // On considre que l'image charge n'est plus modifie Main_image_is_modified=0; // Et on documente la variable Main_fileformat avec la valeur: Main_fileformat=format->Identifier; // already done initially on Backup_with_new_dimensions //Main_image_width= context->Width; //Main_image_height= context->Height; if (Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION) { Main_current_layer = 0; } else { Main_current_layer = context->Nb_layers - 1; Main_layers_visible = (2<Pages->Transparent_color = context->Transparent_color; Main_backups->Pages->Background_transparent = context->Background_transparent; // Correction des dimensions if (Main_image_width<1) Main_image_width=1; if (Main_image_height<1) Main_image_height=1; // Color cyling ranges: for (i=0; i<16; i++) Main_backups->Pages->Gradients->Range[i].Speed=0; for (i=0; iColor_cycles; i++) { Main_backups->Pages->Gradients->Range[i].Start=context->Cycle_range[i].Start; Main_backups->Pages->Gradients->Range[i].End=context->Cycle_range[i].End; Main_backups->Pages->Gradients->Range[i].Inverse=context->Cycle_range[i].Inverse; Main_backups->Pages->Gradients->Range[i].Speed=context->Cycle_range[i].Speed; } // Comment strcpy(Main_backups->Pages->Comment, context->Comment); } } else if (File_error!=1) { // On considre que l'image charge est encore modifie Main_image_is_modified=1; // Et on documente la variable Main_fileformat avec la valeur: Main_fileformat=format->Identifier; } else { // Dans ce cas, on sait que l'image n'a pas chang, mais ses // paramtres (dimension, palette, ...) si. Donc on les restaures. Download_infos_page_main(Main_backups->Pages); } } else if (context->Type == CONTEXT_BRUSH && File_error==0) { if (Realloc_brush(context->Width, context->Height, context->Buffer_image, NULL)) { File_error=3; free(context->Buffer_image); } memcpy(Brush_original_palette, context->Palette, sizeof(T_Palette)); Remap_brush(); context->Buffer_image = NULL; } else if (context->Type == CONTEXT_SURFACE) { if (File_error == 0) { // Copy the palette SDL_Color colors[256]; int i; for (i=0; i<256; i++) { colors[i].r=context->Palette[i].R; colors[i].g=context->Palette[i].G; colors[i].b=context->Palette[i].B; } SDL_SetColors(context->Surface, colors, 0, 256); } } else if (context->Type == CONTEXT_PREVIEW /*&& !context->Buffer_image_24b*/ /*&& !Get_fileformat(context->Format)->Palette_only*/) { // Try to adapt the palette to accomodate the GUI. int c; int count_unused; byte unused_color[4]; count_unused=0; // Try find 4 unused colors and insert good colors there for (c=255; c>=0 && count_unused<4; c--) { if (!context->Preview_usage[c]) { unused_color[count_unused]=c; count_unused++; } } // Found! replace them with some favorites if (count_unused==4) { int gui_index; for (gui_index=0; gui_index<4; gui_index++) { context->Palette[unused_color[gui_index]]=*Favorite_GUI_color(gui_index); } } // All preview display is here // Update palette and screen first Compute_optimal_menu_colors(context->Palette); Remap_screen_after_menu_colors_change(); Set_palette(context->Palette); // Display palette preview if (Get_fileformat(context->Format)->Palette_only) { short index; if (context->Type == CONTEXT_PREVIEW) for (index=0; index<256; index++) Window_rectangle(183+(index/16)*7,95+(index&15)*5,5,5,index); } // Display normal image else if (context->Preview_bitmap) { int x_pos,y_pos; int width,height; width=context->Width/context->Preview_factor_X; height=context->Height/context->Preview_factor_Y; if (context->Ratio == PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) width*=2; else if (context->Ratio == PIXEL_TALL && Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2 && Pixel_ratio != PIXEL_TALL3) height*=2; for (y_pos=0; y_posPreview_bitmap[x_pos+y_pos*PREVIEW_WIDTH*Menu_factor_X]; // Skip transparent if image has transparent background. if (color == context->Transparent_color && context->Background_transparent) color=MC_Window; Pixel(context->Preview_pos_X+x_pos, context->Preview_pos_Y+y_pos, color); } } // Refresh modified part Update_window_area(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT); // Preview comment Print_in_window(45,70,context->Comment,MC_Black,MC_Light); //Update_window_area(45,70,32*8,8); } } // -- Sauver n'importe quel type connu de fichier d'image (ou palette) ------ void Save_image(T_IO_Context *context) { T_Format *format; // On place par dfaut File_error vrai au cas o on ne sache pas // sauver le format du fichier: (Est-ce vraiment utile??? Je ne crois pas!) File_error=1; switch (context->Type) { case CONTEXT_MAIN_IMAGE: if ((!Get_fileformat(context->Format)->Supports_layers) && (Main_backups->Pages->Nb_layers > 1) && (!Get_fileformat(context->Format)->Palette_only)) { if (Main_backups->Pages->Image_mode == IMAGE_MODE_ANIMATION) { if (! Confirmation_box("This format doesn't support\nanimation and will save only\ncurrent frame. Proceed?")) { // File_error is already set to 1. return; } // current layer context->Nb_layers=1; context->Target_address=Main_backups->Pages->Image[Main_current_layer].Pixels; } else // all other layer-based formats { int clicked_button; Open_window(208,100,"Format warning"); Print_in_window( 8, 20,"This file format doesn't",MC_Black,MC_Light); Print_in_window( 8, 30,"support layers.",MC_Black,MC_Light); Window_set_normal_button(23,44, 162,14,"Save flattened copy",0,1,KEY_NONE); // 1 Window_set_normal_button(23,62, 162,14,"Save current frame" ,0,1,KEY_NONE); // 2 Window_set_normal_button(23,80, 162,14,"Cancel" ,0,1,KEY_ESC); // 3 Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); // Some help on file formats ? //if (Is_shortcut(Key,0x100+BUTTON_HELP)) //{ // Key=0; // Window_help(???, NULL); //} } while (clicked_button<=0); Close_window(); Display_cursor(); switch(clicked_button) { case 1: // flatten context->Nb_layers=1; context->Target_address=Main_visible_image.Image; break; case 2: // current layer context->Nb_layers=1; context->Target_address=Main_backups->Pages->Image[Main_current_layer].Pixels; break; default: // Cancel // File_error is already set to 1. return; } } } break; case CONTEXT_BRUSH: break; case CONTEXT_PREVIEW: break; case CONTEXT_SURFACE: break; case CONTEXT_PALETTE: // In a palette, there are no pixels! break; } format = Get_fileformat(context->Format); if (format->Save) format->Save(context); if (File_error) { Error(0); return; } } void Load_SDL_Image(T_IO_Context *context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier word x_pos,y_pos; // long file_size; dword pixel; long file_size; SDL_Surface * surface; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; surface = IMG_Load(filename); if (!surface) { File_error=1; return; } file_size=File_length(filename); if (surface->format->BytesPerPixel == 1) { // 8bpp image Pre_load(context, surface->w, surface->h, file_size ,FORMAT_MISC, PIXEL_SIMPLE, 0); // Read palette if (surface->format->palette) { Get_SDL_Palette(surface->format->palette, context->Palette); } for (y_pos=0; y_posHeight; y_pos++) { for (x_pos=0; x_posWidth; x_pos++) { Set_pixel(context, x_pos, y_pos, Get_SDL_pixel_8(surface, x_pos, y_pos)); } } } else { { // Hi/Trucolor Pre_load(context, surface->w, surface->h, file_size ,FORMAT_ALL_IMAGES, PIXEL_SIMPLE, 1); } for (y_pos=0; y_posHeight; y_pos++) { for (x_pos=0; x_posWidth; x_pos++) { pixel = Get_SDL_pixel_hicolor(surface, x_pos, y_pos); Set_pixel_24b( context, x_pos, y_pos, ((pixel & surface->format->Rmask) >> surface->format->Rshift) << surface->format->Rloss, ((pixel & surface->format->Gmask) >> surface->format->Gshift) << surface->format->Gloss, ((pixel & surface->format->Bmask) >> surface->format->Bshift) << surface->format->Bloss); } } } SDL_FreeSurface(surface); } /// /// Load an arbitrary SDL_Surface. /// @param full_name Full (absolute) path of the file to load. /// @param gradients Pass the address of a target T_Gradient_array if you want the gradients, NULL otherwise SDL_Surface * Load_surface(char *full_name, T_Gradient_array *gradients) { SDL_Surface * bmp=NULL; T_IO_Context context; Init_context_surface(&context, full_name, ""); Load_image(&context); if (context.Surface) { bmp=context.Surface; // Caller wants the gradients: if (gradients != NULL) { int i; memset(gradients, 0, sizeof(T_Gradient_array)); for (i=0; iRange[i].Start=context.Cycle_range[i].Start; gradients->Range[i].End=context.Cycle_range[i].End; gradients->Range[i].Inverse=context.Cycle_range[i].Inverse; gradients->Range[i].Speed=context.Cycle_range[i].Speed; } } } Destroy_context(&context); return bmp; } /// Saves an image. /// This routine will only be called when all hope is lost, memory thrashed, etc /// It's the last chance to save anything, but the code has to be extremely /// careful, anything could happen. /// The chosen format is IMG since it's extremely simple, difficult to make it /// create an unusable image. void Emergency_backup(const char *fname, byte *source, int width, int height, T_Palette *palette) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; short x_pos,y_pos; T_IMG_Header IMG_header; if (width == 0 || height == 0 || source == NULL) return; strcpy(filename,Config_directory); strcat(filename,fname); // Ouverture du fichier file=fopen(filename,"wb"); if (!file) return; memcpy(IMG_header.Filler1,"\x01\x00\x47\x12\x6D\xB0",6); memset(IMG_header.Filler2,0,118); IMG_header.Filler2[4]=0xFF; IMG_header.Filler2[22]=64; // Lo(Longueur de la signature) IMG_header.Filler2[23]=0; // Hi(Longueur de la signature) memcpy(IMG_header.Filler2+23,"GRAFX2 by SunsetDesign (IMG format taken from PV (c)W.Wiedmann)",64); if (!Write_bytes(file,IMG_header.Filler1,6) || !Write_word_le(file,width) || !Write_word_le(file,height) || !Write_bytes(file,IMG_header.Filler2,118) || !Write_bytes(file,palette,sizeof(T_Palette))) { fclose(file); return; } for (y_pos=0; ((y_posPages && Main_backups->Pages->Nb_layers == 1) Emergency_backup(SAFETYBACKUP_PREFIX_A "999999" BACKUP_FILE_EXTENSION,Main_screen, Main_image_width, Main_image_height, &Main_palette); if (Spare_backups && Spare_backups->Pages && Spare_backups->Pages->Nb_layers == 1) Emergency_backup(SAFETYBACKUP_PREFIX_B "999999" BACKUP_FILE_EXTENSION,Spare_visible_image.Image, Spare_image_width, Spare_image_height, &Spare_palette); } T_Format * Get_fileformat(byte format) { unsigned int i; T_Format * safe_default = File_formats; for (i=0; i < Nb_known_formats(); i++) { if (File_formats[i].Identifier == format) return &(File_formats[i]); if (File_formats[i].Identifier == FORMAT_GIF) safe_default=&(File_formats[i]); } // Normally impossible to reach this point, unless called with an invalid // enum.... return safe_default; } /// Query the color of a pixel (to save) byte Get_pixel(T_IO_Context *context, short x, short y) { return *(context->Target_address + y*context->Pitch + x); } /// Cleans up resources void Destroy_context(T_IO_Context *context) { free(context->Buffer_image_24b); free(context->Buffer_image); free(context->Preview_bitmap); memset(context, 0, sizeof(T_IO_Context)); } /// Setup for loading a preview in fileselector void Init_context_preview(T_IO_Context * context, char *file_name, char *file_directory) { memset(context, 0, sizeof(T_IO_Context)); context->Type = CONTEXT_PREVIEW; context->File_name = file_name; context->File_directory = file_directory; context->Format = Main_fileformat; // FIXME ? } // Setup for loading/saving an intermediate backup void Init_context_backup_image(T_IO_Context * context, char *file_name, char *file_directory) { Init_context_layered_image(context, file_name, file_directory); } /// Setup for loading/saving the current main image void Init_context_layered_image(T_IO_Context * context, char *file_name, char *file_directory) { int i; memset(context, 0, sizeof(T_IO_Context)); context->Type = CONTEXT_MAIN_IMAGE; context->File_name = file_name; context->File_directory = file_directory; context->Format = Main_fileformat; memcpy(context->Palette, Main_palette, sizeof(T_Palette)); context->Width = Main_image_width; context->Height = Main_image_height; context->Nb_layers = Main_backups->Pages->Nb_layers; strcpy(context->Comment, Main_backups->Pages->Comment); context->Transparent_color=Main_backups->Pages->Transparent_color; context->Background_transparent=Main_backups->Pages->Background_transparent; if (Pixel_ratio == PIXEL_WIDE || Pixel_ratio == PIXEL_WIDE2) context->Ratio=PIXEL_WIDE; else if (Pixel_ratio == PIXEL_TALL || Pixel_ratio == PIXEL_TALL2 || Pixel_ratio == PIXEL_TALL3) context->Ratio=PIXEL_TALL; else context->Ratio=PIXEL_SIMPLE; context->Target_address=Main_backups->Pages->Image[0].Pixels; context->Pitch=Main_image_width; // Color cyling ranges: for (i=0; i<16; i++) { if (Main_backups->Pages->Gradients->Range[i].Start!=Main_backups->Pages->Gradients->Range[i].End) { context->Cycle_range[context->Color_cycles].Start=Main_backups->Pages->Gradients->Range[i].Start; context->Cycle_range[context->Color_cycles].End=Main_backups->Pages->Gradients->Range[i].End; context->Cycle_range[context->Color_cycles].Inverse=Main_backups->Pages->Gradients->Range[i].Inverse; context->Cycle_range[context->Color_cycles].Speed=Main_backups->Pages->Gradients->Range[i].Speed; context->Color_cycles++; } } } /// Setup for loading/saving the flattened version of current main image //void Init_context_flat_image(T_IO_Context * context, char *file_name, char *file_directory) //{ //} /// Setup for loading/saving the user's brush void Init_context_brush(T_IO_Context * context, char *file_name, char *file_directory) { memset(context, 0, sizeof(T_IO_Context)); context->Type = CONTEXT_BRUSH; context->File_name = file_name; context->File_directory = file_directory; context->Format = Brush_fileformat; // Use main screen's palette memcpy(context->Palette, Main_palette, sizeof(T_Palette)); context->Width = Brush_width; context->Height = Brush_height; context->Nb_layers = 1; // Solid save... could use BG color maybe context->Transparent_color=0; context->Background_transparent=0; context->Ratio=PIXEL_SIMPLE; context->Target_address=Brush; context->Pitch=Brush_width; } // Setup for loading an image into a new SDL surface. void Init_context_surface(T_IO_Context * context, char *file_name, char *file_directory) { memset(context, 0, sizeof(T_IO_Context)); context->Type = CONTEXT_SURFACE; context->File_name = file_name; context->File_directory = file_directory; context->Format = DEFAULT_FILEFORMAT; // context->Palette // context->Width // context->Height context->Nb_layers = 1; context->Transparent_color=0; context->Background_transparent=0; context->Ratio=PIXEL_SIMPLE; //context->Target_address //context->Pitch } /// Function to call when need to switch layers. void Set_saving_layer(T_IO_Context *context, int layer) { context->Current_layer = layer; if (context->Type == CONTEXT_MAIN_IMAGE) { if (context->Nb_layers==1 && Main_backups->Pages->Nb_layers!=1) { // Context is set to saving a single layer: do nothing } else { context->Target_address=Main_backups->Pages->Image[layer].Pixels; } } } /// Function to call when need to switch layers. void Set_loading_layer(T_IO_Context *context, int layer) { context->Current_layer = layer; if (context->Type == CONTEXT_MAIN_IMAGE) { // This awful thing is the part that happens on load while (layer >= context->Nb_layers) { if (Add_layer(Main_backups, layer)) { // Failure to add a layer on load: // Position on last layer layer = context->Nb_layers-1; break; } context->Nb_layers = Main_backups->Pages->Nb_layers; Main_layers_visible = (2<Target_address=Main_backups->Pages->Image[layer].Pixels; Update_pixel_renderer(); } } // ============================================ // Safety backups // ============================================ typedef struct T_String_list { char * String; struct T_String_list * Next; } T_String_list; /// A list of files, used for scanning a directory T_String_list *Backups_main = NULL; /// A list of files, used for scanning a directory T_String_list *Backups_spare = NULL; // Settings for safety backup (frequency, numbers, etc) const int Rotation_safety_backup = 8; const int Min_interval_for_safety_backup = 30000; const int Min_edits_for_safety_backup = 10; const int Max_interval_for_safety_backup = 60000; const int Max_edits_for_safety_backup = 30; /// /// Adds a file to Backups_main or Backups_spare lists, if it's a backup. /// void Add_backup_file(const char *name) { T_String_list ** list; T_String_list * elem; int i; char file_name[MAX_PATH_CHARACTERS]; // Only files names of the form a0000000.* and b0000000.* are expected Extract_filename(file_name, name); // Check first character if (file_name[0]==Main_safety_backup_prefix) list = &Backups_main; else if (file_name[0]==Spare_safety_backup_prefix) list = &Backups_spare; else { // Not a good file return; } // Check next characters till file extension i = 1; while (file_name[i]!='\0' && file_name[i]!='.') { if (file_name[i]< '0' || file_name[i] > '9') { // Not a good file return; } i++; } // Add to list (top insertion) elem = (T_String_list *)malloc(sizeof(T_String_list)); elem->String=strdup(file_name); elem->Next=*list; *list=elem; } /// String comparer for sorting int String_compare (const void * a, const void * b) { return strcmp(*(char**)a,*(char**)b); } /// /// Reload safety backups, by loading several files in the right order. /// byte Process_backups(T_String_list **list) { int nb_files; int i; char ** files_vector; T_String_list *element; byte backup_max_undo_pages; if (*list == NULL) return 0; // Save the maximum number of pages // (It's used in Create_new_page() which gets called on each Load_image) backup_max_undo_pages = Config.Max_undo_pages; Config.Max_undo_pages = 99; // Count files nb_files=0; element=*list; while (element != NULL) { nb_files++; element = element->Next; } // Allocate a vector files_vector = (char **)malloc(sizeof(char *) * nb_files); // Copy from list to vector for (i=0;iString; next = (*list)->Next; free(*list); *list = next; } // Sort the vector qsort (files_vector, nb_files , sizeof(char **), String_compare); for (i=0; i < nb_files; i++) { // Load this file T_IO_Context context; char file_name[MAX_PATH_CHARACTERS]=""; char file_directory[MAX_PATH_CHARACTERS]=""; Init_context_backup_image(&context, files_vector[i], Config_directory); // Provide buffers to read original location context.Original_file_name = file_name; context.Original_file_directory = file_directory; Load_image(&context); Main_image_is_modified=1; Destroy_context(&context); Redraw_layered_image(); Display_all_screen(); } // Done with the vector for (i=0; i < nb_files; i++) { free(files_vector[i]); } free(files_vector); files_vector = NULL; // Restore the maximum number of pages Config.Max_undo_pages = backup_max_undo_pages; return nb_files; } /// Global indicator that tells if the safety backup system is active byte Safety_backup_active = 0; /// /// Checks if there are any pending safety backups, and then opens them. /// @return 0 if no problem, -1 if the backup system cannot be activated, >=1 if some backups are restored int Check_recovery(void) { int restored_spare; int restored_main; // First check if can write backups #if defined (__MINT__) //TODO: enable file lock under Freemint only return 0; #else if (Create_lock_file(Config_directory)) return -1; #endif Safety_backup_active=1; Backups_main = NULL; Backups_spare = NULL; For_each_file(Config_directory, Add_backup_file); // Do the processing twice: once for possible backups of the main page, // once for possible backups of the spare. restored_spare = Process_backups(&Backups_spare); if (restored_spare) { Main_offset_X=0; Main_offset_Y=0; Compute_limits(); Compute_paintbrush_coordinates(); if (Backups_main) Button_Page(); } restored_main = Process_backups(&Backups_main); if (restored_main) { Main_offset_X=0; Main_offset_Y=0; Compute_limits(); Compute_paintbrush_coordinates(); } return restored_main + restored_spare; } void Rotate_safety_backups(void) { Uint32 now; T_IO_Context context; char file_name[12+1]; char deleted_file[MAX_PATH_CHARACTERS]; if (!Safety_backup_active) return; now = SDL_GetTicks(); // It's time to save if either: // - Many edits have taken place // - A minimum number of edits have taken place AND a minimum time has passed // - At least one edit was done, and a maximum time has passed if ((Main_edits_since_safety_backup > Max_edits_for_safety_backup) || (Main_edits_since_safety_backup > Min_edits_for_safety_backup && now > Main_time_of_safety_backup + Min_interval_for_safety_backup) || (Main_edits_since_safety_backup > 1 && now > Main_time_of_safety_backup + Max_interval_for_safety_backup)) { // Clear a previous save (rotating saves) sprintf(deleted_file, "%s%c%6.6d" BACKUP_FILE_EXTENSION, Config_directory, Main_safety_backup_prefix, (Uint32)(Main_safety_number + 1000000l - Rotation_safety_backup) % (Uint32)1000000l); remove(deleted_file); // no matter if fail // Reset counters Main_edits_since_safety_backup=0; Main_time_of_safety_backup=now; // Create a new file name and save sprintf(file_name, "%c%6.6d" BACKUP_FILE_EXTENSION, Main_safety_backup_prefix, (Uint32)Main_safety_number); Init_context_backup_image(&context, file_name, Config_directory); context.Format=FORMAT_GIF; // Provide original file data, to store as a GIF Application Extension context.Original_file_name = Main_backups->Pages->Filename; context.Original_file_directory = Main_backups->Pages->File_directory; Save_image(&context); Destroy_context(&context); Main_safety_number++; } } /// Remove safety backups. Need to call on normal program exit. void Delete_safety_backups(void) { T_String_list *element; if (!Safety_backup_active) return; Backups_main = NULL; Backups_spare = NULL; For_each_file(Config_directory, Add_backup_file); chdir(Config_directory); for (element=Backups_main; element!=NULL; element=element->Next) { if(remove(element->String)) printf("Failed to delete %s\n",element->String); } for (element=Backups_spare; element!=NULL; element=element->Next) { if(remove(element->String)) printf("Failed to delete %s\n",element->String); } // Release lock file #if defined (__MINT__) //TODO: release file lock under Freemint only #else Release_lock_file(Config_directory); #endif } grafx2_2.4+git20180105/src/miscfileformats.c0000664000000000000000000033431013223665306017066 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007-2011 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ///@file miscfileformats.c /// Formats that aren't fully saving, either because of palette restrictions or other things #include #include #include #include "engine.h" #include "errors.h" #include "global.h" #include "io.h" #include "libraw2crtc.h" #include "loadsave.h" #include "misc.h" #include "sdlscreen.h" #include "struct.h" #include "windows.h" #include "oldies.h" //////////////////////////////////// PAL //////////////////////////////////// // // -- Test wether a file is in PAL format -------------------------------- void Test_PAL(T_IO_Context * context) { FILE *file; char filename[MAX_PATH_CHARACTERS]; long file_size; Get_full_filename(filename, context->File_name, context->File_directory); File_error = 1; if ((file = fopen(filename, "rb"))) { file_size = File_length_file(file); // First check for GrafX2 legacy palette format. The simplest one, 768 bytes // of RGB data. It is a raw dump of the T_Palette structure. There is no // header at all, so we check for the file size. if (file_size == sizeof(T_Palette)) File_error = 0; else { // Bigger (or smaller ?) files may be in other formats. These have an // header, so look for it. fread(filename, 1, 8, file); if (strncmp(filename,"JASC-PAL",8) == 0) { // JASC file format, used by Paint Shop Pro and GIMP. This is also the // one used for saving, as it brings greater interoperability. File_error = 0; } else if(strncmp(filename,"RIFF", 4) == 0) { // Microsoft RIFF file // This is a data container (similar to IFF). We only check the first // chunk header, and give up if that's not a palette. fseek(file, 8, SEEK_SET); fread(filename, 1, 8, file); if (strncmp(filename, "PAL data", 8) == 0) { File_error = 0; } } } fclose(file); } } void Test_GPL(T_IO_Context * context) { FILE *file; char filename[MAX_PATH_CHARACTERS]; long file_size; Get_full_filename(filename, context->File_name, context->File_directory); File_error = 1; if ((file = fopen(filename, "rb"))) { file_size = File_length_file(file); if (file_size > 33) { // minimum header length == 33 // "GIMP Palette" == 12 fread(filename, 1, 12, file); if (strncmp(filename,"GIMP Palette",12) == 0) File_error = 0; } } fclose(file); } // skip the padding before a space-padded field. static int skip_padding(FILE *file, int max_chars) { char buffer[1]; int chars_read = 0; int latest_chars_read = 0; size_t tmp; buffer[0] = ' '; while (buffer[0] == ' '){ latest_chars_read = fread(buffer, 1, 1, file); if ((latest_chars_read != 1) || (chars_read == max_chars)) return chars_read; // eof chars_read += latest_chars_read; } if (chars_read > 0){ tmp = ftell(file); // printf ("rewinding to %d", tmp - 1); fseek(file, tmp - 1, SEEK_SET); } return chars_read; } // -- Load file with format GPL ----------------------------------------- void Load_GPL(T_IO_Context * context) { FILE *file; char filename[MAX_PATH_CHARACTERS]; // full filename long pos; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Open file if ((file=fopen(filename, "rb"))) { fread(filename, 1, 13, file); if (strncmp(filename,"GIMP Palette\n",13) == 0) { int i, j, r, g, b, columns, chars_read; fscanf(file, "Name: %s\n", filename); printf("DBG: Escaped nominal destruction ~%s~\n", filename); // y fscanf(file, "Columns: %d\n", &columns); // TODO: set grafx2 columns setting to match. printf("DBG: Escaped architectural destruction %d\n", columns); // y // # fread(filename,1, 2, file); filename[2] = 0; printf("DBG: Escaped grammatical destruction ~%s~\n", filename); for (i = 0; i < 256; i++) { pos = ftell(file); skip_padding(file, 32); fscanf(file, "%d", &r); skip_padding(file, 32); fscanf(file, "%d", &g); skip_padding(file, 32); fscanf(file, "%d\t", &b); filename[0] = 0; j = 0; do { chars_read = fscanf(file, "%s", filename+j); if (chars_read > 0){ j += chars_read; // space or newline follows. fread(filename+j, 1, 1, file); } else{ filename[j] = '\n'; } } while (filename[j] != '\n'); filename[j] = 0; if (ftell(file) == pos) break; // no more colors. // TODO: analyze color names to build shade table printf("DBG: %d: %s\n", i, filename); context->Palette[i].R = r; context->Palette[i].G = g; context->Palette[i].B = b; } } else File_error = 2; // close the file fclose(file); } else // Si on n'a pas russi ouvrir le fichier, alors il y a eu une erreur File_error=1; } void Save_GPL (T_IO_Context * context) { FILE *file; char filename[MAX_PATH_CHARACTERS]; // full filename Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Open output file if ((file=fopen(filename,"w"))){ int i; fprintf (file, "GIMP Palette\n"); fprintf (file, "Name: %s\n", context->File_name); // TODO: use actual columns value fprintf (file, "Columns: %d\n#\n", 16); for (i = 0; i < 256 && File_error==0; i++) { // TODO: build names from shade table data if (fprintf(file,"%d %d %d\tUntitled\n",context->Palette[i].R, context->Palette[i].G, context->Palette[i].B) <= 0) File_error=1; } fclose(file); if (File_error) remove(filename); } else { // unable to open output file, nothing saved. File_error=1; } } // -- Lire un fichier au format PAL ----------------------------------------- void Load_PAL(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier //long file_size; // Taille du fichier Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { long file_size = File_length_file(file); // Le fichier ne peut tre au format PAL que si sa taille vaut 768 octets if (file_size == sizeof(T_Palette)) { T_Palette palette_64; // Pre_load(context, ?); // Pas possible... pas d'image... // Lecture du fichier dans context->Palette if (Read_bytes(file, palette_64, sizeof(T_Palette))) { Palette_64_to_256(palette_64); memcpy(context->Palette, palette_64, sizeof(T_Palette)); } else File_error = 2; } else { fread(filename, 1, 8, file); if (strncmp(filename,"JASC-PAL",8) == 0) { int i, n, r, g, b; fscanf(file, "%d",&n); if(n != 100) { File_error = 2; fclose(file); return; } // Read color count fscanf(file, "%d",&n); for (i = 0; i < n; i++) { fscanf(file, "%d %d %d",&r, &g, &b); context->Palette[i].R = r; context->Palette[i].G = g; context->Palette[i].B = b; } } else if(strncmp(filename, "RIFF", 4) == 0) { // Microsoft RIFF format. fseek(file, 8, SEEK_SET); fread(filename, 1, 8, file); if (strncmp(filename, "PAL data", 8) == 0) { char buffer[4]; word color_count; word i = 0; fseek(file, 22, SEEK_SET); Read_word_le(file, &color_count); for(i = 0; i < color_count; i++) { Read_bytes(file, buffer, 4); context->Palette[i].R = buffer[0]; context->Palette[i].G = buffer[1]; context->Palette[i].B = buffer[2]; } } else File_error = 2; } else File_error = 2; } // Fermeture du fichier fclose(file); } else // Si on n'a pas russi ouvrir le fichier, alors il y a eu une erreur File_error=1; } // -- Sauver un fichier au format PAL --------------------------------------- void Save_PAL(T_IO_Context * context) { FILE *file; char filename[MAX_PATH_CHARACTERS]; ///< full filename Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Open output file if ((file=fopen(filename,"w"))) { int i; setvbuf(file, NULL, _IOFBF, 64*1024); if (fputs("JASC-PAL\n0100\n256\n", file)==EOF) File_error=1; for (i = 0; i < 256 && File_error==0; i++) { if (fprintf(file,"%d %d %d\n",context->Palette[i].R, context->Palette[i].G, context->Palette[i].B) <= 0) File_error=1; } fclose(file); if (File_error) remove(filename); } else { // unable to open output file, nothing saved. File_error=1; } } //////////////////////////////////// PKM //////////////////////////////////// typedef struct { char Ident[3]; // String "PKM" } byte Method; // Compression method // 0 = per-line compression (c)KM // others = unknown at the moment byte Recog1; // Recognition byte 1 byte Recog2; // Recognition byte 2 word Width; // Image width word Height; // Image height T_Palette Palette;// RGB Palette 256*3, on a 1-64 scale for each component word Jump; // Size of the jump between header and image: // Used to insert a comment } T_PKM_Header; // -- Tester si un fichier est au format PKM -------------------------------- void Test_PKM(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier T_PKM_Header header; Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Lecture du header du fichier if (Read_bytes(file,&header.Ident,3) && Read_byte(file,&header.Method) && Read_byte(file,&header.Recog1) && Read_byte(file,&header.Recog2) && Read_word_le(file,&header.Width) && Read_word_le(file,&header.Height) && Read_bytes(file,&header.Palette,sizeof(T_Palette)) && Read_word_le(file,&header.Jump)) { // On regarde s'il y a la signature PKM suivie de la mthode 0. // La constante "PKM" tant un chane, elle se termine toujours par 0. // Donc pas la peine de s'emm...er regarder si la mthode est 0. if ( (!memcmp(&header,"PKM",4)) && header.Width && header.Height) File_error=0; } fclose(file); } } // -- Lire un fichier au format PKM ----------------------------------------- void Load_PKM(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier T_PKM_Header header; byte color; byte temp_byte; word len; word index; dword Compteur_de_pixels; dword Compteur_de_donnees_packees; dword image_size; dword Taille_pack; long file_size; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (Read_bytes(file,&header.Ident,3) && Read_byte(file,&header.Method) && Read_byte(file,&header.Recog1) && Read_byte(file,&header.Recog2) && Read_word_le(file,&header.Width) && Read_word_le(file,&header.Height) && Read_bytes(file,&header.Palette,sizeof(T_Palette)) && Read_word_le(file,&header.Jump)) { context->Comment[0]='\0'; // On efface le commentaire if (header.Jump) { index=0; while ( (indexCOMMENT_SIZE) { color=temp_byte; // On se sert de color comme temp_byte=COMMENT_SIZE; // variable temporaire color-=COMMENT_SIZE; } else color=0; if (Read_bytes(file,context->Comment,temp_byte)) { index+=temp_byte; context->Comment[temp_byte]='\0'; if (color) if (fseek(file,color,SEEK_CUR)) File_error=2; } else File_error=2; } else File_error=2; break; case 1 : // Dimensions de l'cran d'origine if (Read_byte(file,&temp_byte)) { if (temp_byte==4) { index+=4; if ( ! Read_word_le(file,(word *) &Original_screen_X) || !Read_word_le(file,(word *) &Original_screen_Y) ) File_error=2; } else File_error=2; } else File_error=2; break; case 2 : // color de transparence if (Read_byte(file,&temp_byte)) { if (temp_byte==1) { index++; if (! Read_byte(file,&Back_color)) File_error=2; } else File_error=2; } else File_error=2; break; default: if (Read_byte(file,&temp_byte)) { index+=temp_byte; if (fseek(file,temp_byte,SEEK_CUR)) File_error=2; } else File_error=2; } } else File_error=2; } if ( (!File_error) && (index!=header.Jump) ) File_error=2; } /*Init_lecture();*/ if (!File_error) { Pre_load(context, header.Width,header.Height,file_size,FORMAT_PKM,PIXEL_SIMPLE,0); if (File_error==0) { context->Width=header.Width; context->Height=header.Height; image_size=(dword)(context->Width*context->Height); // Palette lue en 64 memcpy(context->Palette,header.Palette,sizeof(T_Palette)); Palette_64_to_256(context->Palette); Compteur_de_donnees_packees=0; Compteur_de_pixels=0; // Header size is 780 Taille_pack=(file_size)-780-header.Jump; // Boucle de dcompression: while ( (Compteur_de_pixelsWidth, Compteur_de_pixels / context->Width, temp_byte); Compteur_de_donnees_packees++; Compteur_de_pixels++; } else // Sinon, On regarde si on va dcompacter un... { // ... nombre de pixels tenant sur un byte if (temp_byte==header.Recog1) { if(Read_byte(file, &color)!=1) { File_error=2; break; } if(Read_byte(file, &temp_byte)!=1) { File_error=2; break; } for (index=0; indexWidth, (Compteur_de_pixels+index) / context->Width, color); Compteur_de_pixels+=temp_byte; Compteur_de_donnees_packees+=3; } else // ... nombre de pixels tenant sur un word { if(Read_byte(file, &color)!=1) { File_error=2; break; } Read_word_be(file, &len); for (index=0; indexWidth, (Compteur_de_pixels+index) / context->Width, color); Compteur_de_pixels+=len; Compteur_de_donnees_packees+=4; } } } } } /*Close_lecture();*/ } else // Lecture header impossible: Error ne modifiant pas l'image File_error=1; fclose(file); } else // Ouv. fichier impossible: Error ne modifiant pas l'image File_error=1; } // -- Sauver un fichier au format PKM --------------------------------------- // Trouver quels sont les octets de reconnaissance void Find_recog(byte * recog1, byte * recog2) { dword Find_recon[256]; // Table d'utilisation de couleurs byte best; // Meilleure couleur pour recon (recon1 puis recon2) dword NBest; // Nombre d'occurences de cette couleur word index; // On commence par compter l'utilisation de chaque couleurs Count_used_colors(Find_recon); // Ensuite recog1 devient celle la moins utilise de celles-ci *recog1=0; best=1; NBest=INT_MAX; // Une mme couleur ne pourra jamais tre utilise 1M de fois. for (index=1;index<=255;index++) if (Find_recon[index]Width; header.Height=context->Height; memcpy(header.Palette,context->Palette,sizeof(T_Palette)); Palette_256_to_64(header.Palette); // Calcul de la taille du Post-header header.Jump=9; // 6 pour les dimensions de l'ecran + 3 pour la back-color comment_size=strlen(context->Comment); if (comment_size) header.Jump+=comment_size+2; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { setvbuf(file, NULL, _IOFBF, 64*1024); // Ecriture du header if (Write_bytes(file,&header.Ident,3) && Write_byte(file,header.Method) && Write_byte(file,header.Recog1) && Write_byte(file,header.Recog2) && Write_word_le(file,header.Width) && Write_word_le(file,header.Height) && Write_bytes(file,&header.Palette,sizeof(T_Palette)) && Write_word_le(file,header.Jump)) { // Ecriture du commentaire // (Compteur_de_pixels est utilis ici comme simple index de comptage) if (comment_size) { Write_one_byte(file,0); Write_one_byte(file,comment_size); for (Compteur_de_pixels=0; Compteur_de_pixelsComment[Compteur_de_pixels]); } // Ecriture des dimensions de l'cran Write_one_byte(file,1); Write_one_byte(file,4); Write_one_byte(file,Screen_width&0xFF); Write_one_byte(file,Screen_width>>8); Write_one_byte(file,Screen_height&0xFF); Write_one_byte(file,Screen_height>>8); // Ecriture de la back-color Write_one_byte(file,2); Write_one_byte(file,1); Write_one_byte(file,Back_color); // Routine de compression PKM de l'image image_size=(dword)(context->Width*context->Height); Compteur_de_pixels=0; pixel_value=Get_pixel(context, 0,0); while ( (Compteur_de_pixelsWidth,Compteur_de_pixels / context->Width); } while ( (pixel_value==last_color) && (Compteur_de_pixels=image_size) break; pixel_value=Get_pixel(context, Compteur_de_pixels % context->Width,Compteur_de_pixels / context->Width); } if ( (last_color!=header.Recog1) && (last_color!=header.Recog2) ) { if (repetitions==1) Write_one_byte(file,last_color); else if (repetitions==2) { Write_one_byte(file,last_color); Write_one_byte(file,last_color); } else if ( (repetitions>2) && (repetitions<256) ) { // RECON1/couleur/nombre Write_one_byte(file,header.Recog1); Write_one_byte(file,last_color); Write_one_byte(file,repetitions&0xFF); } else if (repetitions>=256) { // RECON2/couleur/hi(nombre)/lo(nombre) Write_one_byte(file,header.Recog2); Write_one_byte(file,last_color); Write_one_byte(file,repetitions>>8); Write_one_byte(file,repetitions&0xFF); } } else { if (repetitions<256) { Write_one_byte(file,header.Recog1); Write_one_byte(file,last_color); Write_one_byte(file,repetitions&0xFF); } else { Write_one_byte(file,header.Recog2); Write_one_byte(file,last_color); Write_one_byte(file,repetitions>>8); Write_one_byte(file,repetitions&0xFF); } } } } else File_error=1; fclose(file); } else { File_error=1; fclose(file); } // S'il y a eu une erreur de sauvegarde, on ne va tout de mme pas laisser // ce fichier pourri traner... Ca fait pas propre. if (File_error) remove(filename); } //////////////////////////////////// CEL //////////////////////////////////// typedef struct { word Width; // width de l'image word Height; // height de l'image } T_CEL_Header1; typedef struct { byte Signature[4]; // Signature du format byte Kind; // Type de fichier ($10=PALette $20=BitMaP) byte Nb_bits; // Nombre de bits word Filler1; // ??? word Width; // width de l'image word Height; // height de l'image word X_offset; // Offset en X de l'image word Y_offset; // Offset en Y de l'image byte Filler2[16]; // ??? } T_CEL_Header2; // -- Tester si un fichier est au format CEL -------------------------------- void Test_CEL(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; int size; FILE *file; T_CEL_Header1 header1; T_CEL_Header2 header2; int file_size; File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); file_size=File_length(filename); if (file_size==0) { File_error = 1; // Si on ne peut pas faire de stat il vaut mieux laisser tomber return; } if (! (file=fopen(filename, "rb"))) { File_error = 1; return; } if (Read_word_le(file,&header1.Width) && Read_word_le(file,&header1.Height) ) { // Vu que ce header n'a pas de signature, il va falloir tester la // cohrence de la dimension de l'image avec celle du fichier. size=file_size-4; if ( (!size) || ( (((header1.Width+1)>>1)*header1.Height)!=size ) ) { // Tentative de reconnaissance de la signature des nouveaux fichiers fseek(file,0,SEEK_SET); if (Read_bytes(file,&header2.Signature,4) && !memcmp(header2.Signature,"KiSS",4) && Read_byte(file,&header2.Kind) && (header2.Kind==0x20) && Read_byte(file,&header2.Nb_bits) && Read_word_le(file,&header2.Filler1) && Read_word_le(file,&header2.Width) && Read_word_le(file,&header2.Height) && Read_word_le(file,&header2.X_offset) && Read_word_le(file,&header2.Y_offset) && Read_bytes(file,&header2.Filler2,16)) { // ok } else File_error=1; } else File_error=1; } else { File_error=1; } fclose(file); } // -- Lire un fichier au format CEL ----------------------------------------- void Load_CEL(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_CEL_Header1 header1; T_CEL_Header2 header2; short x_pos; short y_pos; byte last_byte=0; long file_size; const long int header_size = 4; File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); if ((file=fopen(filename, "rb"))) { if (Read_word_le(file,&(header1.Width)) && Read_word_le(file,&(header1.Height))) { file_size=File_length_file(file); if ( (file_size>header_size) && ( (((header1.Width+1)>>1)*header1.Height)==(file_size-header_size) ) ) { // Chargement d'un fichier CEL sans signature (vieux fichiers) context->Width=header1.Width; context->Height=header1.Height; Original_screen_X=context->Width; Original_screen_Y=context->Height; Pre_load(context, context->Width,context->Height,file_size,FORMAT_CEL,PIXEL_SIMPLE,0); if (File_error==0) { // Chargement de l'image /*Init_lecture();*/ for (y_pos=0;((y_posHeight) && (!File_error));y_pos++) for (x_pos=0;((x_posWidth) && (!File_error));x_pos++) if ((x_pos & 1)==0) { if(Read_byte(file,&last_byte)!=1) File_error = 2; Set_pixel(context, x_pos,y_pos,(last_byte >> 4)); } else Set_pixel(context, x_pos,y_pos,(last_byte & 15)); /*Close_lecture();*/ } } else { // On ressaye avec le nouveau format fseek(file,0,SEEK_SET); if (Read_bytes(file,header2.Signature,4) && Read_byte(file,&(header2.Kind)) && Read_byte(file,&(header2.Nb_bits)) && Read_word_le(file,&(header2.Filler1)) && Read_word_le(file,&(header2.Width)) && Read_word_le(file,&(header2.Height)) && Read_word_le(file,&(header2.X_offset)) && Read_word_le(file,&(header2.Y_offset)) && Read_bytes(file,header2.Filler2,16) ) { // Chargement d'un fichier CEL avec signature (nouveaux fichiers) context->Width=header2.Width+header2.X_offset; context->Height=header2.Height+header2.Y_offset; Original_screen_X=context->Width; Original_screen_Y=context->Height; Pre_load(context, context->Width,context->Height,file_size,FORMAT_CEL,PIXEL_SIMPLE,0); if (File_error==0) { // Chargement de l'image /*Init_lecture();*/ if (!File_error) { // Effacement du dcalage for (y_pos=0;y_posWidth;x_pos++) Set_pixel(context, x_pos,y_pos,0); for (y_pos=header2.Y_offset;y_posHeight;y_pos++) for (x_pos=0;x_pos> 4)); } else Set_pixel(context, x_pos+header2.X_offset,y_pos+header2.Y_offset,(last_byte & 15)); break; case 8: for (y_pos=0;((y_posFile_name, context->File_directory); if ((file=fopen(filename,"wb"))) { setvbuf(file, NULL, _IOFBF, 64*1024); // On regarde si des couleurs >16 sont utilises dans l'image for (x_pos=16;((x_pos<256) && (!color_usage[x_pos]));x_pos++); if (x_pos==256) { // Cas d'une image 16 couleurs (criture l'ancien format) header1.Width =context->Width; header1.Height=context->Height; if (Write_word_le(file,header1.Width) && Write_word_le(file,header1.Height) ) { // Sauvegarde de l'image for (y_pos=0;((y_posHeight) && (!File_error));y_pos++) { for (x_pos=0;((x_posWidth) && (!File_error));x_pos++) if ((x_pos & 1)==0) last_byte=(Get_pixel(context, x_pos,y_pos) << 4); else { last_byte=last_byte | (Get_pixel(context, x_pos,y_pos) & 15); Write_one_byte(file,last_byte); } if ((x_pos & 1)==1) Write_one_byte(file,last_byte); } } else File_error=1; fclose(file); } else { // Cas d'une image 256 couleurs (criture au nouveau format) // Recherche du dcalage for (y_pos=0;y_posHeight;y_pos++) { for (x_pos=0;x_posWidth;x_pos++) if (Get_pixel(context, x_pos,y_pos)!=0) break; if (Get_pixel(context, x_pos,y_pos)!=0) break; } header2.Y_offset=y_pos; for (x_pos=0;x_posWidth;x_pos++) { for (y_pos=0;y_posHeight;y_pos++) if (Get_pixel(context, x_pos,y_pos)!=0) break; if (Get_pixel(context, x_pos,y_pos)!=0) break; } header2.X_offset=x_pos; memcpy(header2.Signature,"KiSS",4); // Initialisation de la signature header2.Kind=0x20; // Initialisation du type (BitMaP) header2.Nb_bits=8; // Initialisation du nombre de bits header2.Filler1=0; // Initialisation du filler 1 (?) header2.Width=context->Width-header2.X_offset; // Initialisation de la largeur header2.Height=context->Height-header2.Y_offset; // Initialisation de la hauteur for (x_pos=0;x_pos<16;x_pos++) // Initialisation du filler 2 (?) header2.Filler2[x_pos]=0; if (Write_bytes(file,header2.Signature,4) && Write_byte(file,header2.Kind) && Write_byte(file,header2.Nb_bits) && Write_word_le(file,header2.Filler1) && Write_word_le(file,header2.Width) && Write_word_le(file,header2.Height) && Write_word_le(file,header2.X_offset) && Write_word_le(file,header2.Y_offset) && Write_bytes(file,header2.Filler2,14) ) { // Sauvegarde de l'image for (y_pos=0;((y_posFile_name, context->File_directory); if ((file=fopen(filename, "rb"))) { if (File_length_file(file)==320) { for (pal_index=0;pal_index<10 && !File_error;pal_index++) for (color_index=0;color_index<16 && !File_error;color_index++) if (!Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte1) || !Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte2)) File_error=1; // On vrifie une proprit de la structure de palette: for (pal_index=0;pal_index<10;pal_index++) for (color_index=0;color_index<16;color_index++) if ((header1.Palette[pal_index].color[color_index].Byte2>>4)!=0) File_error=1; } else { if (Read_bytes(file,header2.Signature,4) && Read_byte(file,&(header2.Kind)) && Read_byte(file,&(header2.Nb_bits)) && Read_word_le(file,&(header2.Filler1)) && Read_word_le(file,&(header2.Width)) && Read_word_le(file,&(header2.Height)) && Read_word_le(file,&(header2.X_offset)) && Read_word_le(file,&(header2.Y_offset)) && Read_bytes(file,header2.Filler2,14) ) { if (memcmp(header2.Signature,"KiSS",4)==0) { if (header2.Kind!=0x10) File_error=1; } else File_error=1; } else File_error=1; } fclose(file); } else File_error=1; } // -- Lire un fichier au format KCF ----------------------------------------- void Load_KCF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_KCF_Header header1; T_CEL_Header2 header2; byte bytes[3]; int pal_index; int color_index; int index; long file_size; File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); if (file_size==320) { // Fichier KCF l'ancien format for (pal_index=0;pal_index<10 && !File_error;pal_index++) for (color_index=0;color_index<16 && !File_error;color_index++) if (!Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte1) || !Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte2)) File_error=1; if (!File_error) { // Pre_load(context, ?); // Pas possible... pas d'image... if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); // Chargement de la palette for (pal_index=0;pal_index<10;pal_index++) for (color_index=0;color_index<16;color_index++) { index=16+(pal_index*16)+color_index; context->Palette[index].R=((header1.Palette[pal_index].color[color_index].Byte1 >> 4) << 4); context->Palette[index].B=((header1.Palette[pal_index].color[color_index].Byte1 & 15) << 4); context->Palette[index].G=((header1.Palette[pal_index].color[color_index].Byte2 & 15) << 4); } for (index=0;index<16;index++) { context->Palette[index].R=context->Palette[index+16].R; context->Palette[index].G=context->Palette[index+16].G; context->Palette[index].B=context->Palette[index+16].B; } } else File_error=1; } else { // Fichier KCF au nouveau format if (Read_bytes(file,header2.Signature,4) && Read_byte(file,&(header2.Kind)) && Read_byte(file,&(header2.Nb_bits)) && Read_word_le(file,&(header2.Filler1)) && Read_word_le(file,&(header2.Width)) && Read_word_le(file,&(header2.Height)) && Read_word_le(file,&(header2.X_offset)) && Read_word_le(file,&(header2.Y_offset)) && Read_bytes(file,header2.Filler2,14) ) { // Pre_load(context, ?); // Pas possible... pas d'image... index=(header2.Nb_bits==12)?16:0; for (pal_index=0;pal_indexPalette[index].R=(bytes[0] >> 4) << 4; context->Palette[index].B=(bytes[0] & 15) << 4; context->Palette[index].G=(bytes[1] & 15) << 4; break; case 24: // RRRR RRRR | VVVV VVVV | BBBB BBBB Read_bytes(file,bytes,3); context->Palette[index].R=bytes[0]; context->Palette[index].G=bytes[1]; context->Palette[index].B=bytes[2]; } index++; } } if (header2.Nb_bits==12) for (index=0;index<16;index++) { context->Palette[index].R=context->Palette[index+16].R; context->Palette[index].G=context->Palette[index+16].G; context->Palette[index].B=context->Palette[index+16].B; } } else File_error=1; } fclose(file); } else File_error=1; } // -- Ecrire un fichier au format KCF --------------------------------------- void Save_KCF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; T_KCF_Header header1; T_CEL_Header2 header2; byte bytes[3]; int pal_index; int color_index; int index; dword color_usage[256]; // Table d'utilisation de couleurs // On commence par compter l'utilisation de chaque couleurs Count_used_colors(color_usage); File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); if ((file=fopen(filename,"wb"))) { setvbuf(file, NULL, _IOFBF, 64*1024); // Sauvegarde de la palette // On regarde si des couleurs >16 sont utilises dans l'image for (index=16;((index<256) && (!color_usage[index]));index++); if (index==256) { // Cas d'une image 16 couleurs (criture l'ancien format) for (pal_index=0;pal_index<10;pal_index++) for (color_index=0;color_index<16;color_index++) { index=16+(pal_index*16)+color_index; header1.Palette[pal_index].color[color_index].Byte1=((context->Palette[index].R>>4)<<4) | (context->Palette[index].B>>4); header1.Palette[pal_index].color[color_index].Byte2=context->Palette[index].G>>4; } // Write all for (pal_index=0;pal_index<10 && !File_error;pal_index++) for (color_index=0;color_index<16 && !File_error;color_index++) if (!Write_byte(file,header1.Palette[pal_index].color[color_index].Byte1) || !Write_byte(file,header1.Palette[pal_index].color[color_index].Byte2)) File_error=1; } else { // Cas d'une image 256 couleurs (criture au nouveau format) memcpy(header2.Signature,"KiSS",4); // Initialisation de la signature header2.Kind=0x10; // Initialisation du type (PALette) header2.Nb_bits=24; // Initialisation du nombre de bits header2.Filler1=0; // Initialisation du filler 1 (?) header2.Width=256; // Initialisation du nombre de couleurs header2.Height=1; // Initialisation du nombre de palettes header2.X_offset=0; // Initialisation du dcalage X header2.Y_offset=0; // Initialisation du dcalage Y for (index=0;index<16;index++) // Initialisation du filler 2 (?) header2.Filler2[index]=0; if (!Write_bytes(file,header2.Signature,4) || !Write_byte(file,header2.Kind) || !Write_byte(file,header2.Nb_bits) || !Write_word_le(file,header2.Filler1) || !Write_word_le(file,header2.Width) || !Write_word_le(file,header2.Height) || !Write_word_le(file,header2.X_offset) || !Write_word_le(file,header2.Y_offset) || !Write_bytes(file,header2.Filler2,14) ) File_error=1; for (index=0;(index<256) && (!File_error);index++) { bytes[0]=context->Palette[index].R; bytes[1]=context->Palette[index].G; bytes[2]=context->Palette[index].B; if (! Write_bytes(file,bytes,3)) File_error=1; } } fclose(file); if (File_error) remove(filename); } else File_error=1; } //////////////////////////////////// PI1 //////////////////////////////////// //// DECODAGE d'une partie d'IMAGE //// void PI1_8b_to_16p(byte * src,byte * dest) { int i; // index du pixel calculer word byte_mask; // Masque de decodage word w0,w1,w2,w3; // Les 4 words bien ordonns de la source byte_mask=0x8000; w0=(((word)src[0])<<8) | src[1]; w1=(((word)src[2])<<8) | src[3]; w2=(((word)src[4])<<8) | src[5]; w3=(((word)src[6])<<8) | src[7]; for (i=0;i<16;i++) { // Pour dcoder le pixel ni, il faut traiter les 4 words sur leur bit // correspondant celui du masque dest[i]=((w0 & byte_mask)?0x01:0x00) | ((w1 & byte_mask)?0x02:0x00) | ((w2 & byte_mask)?0x04:0x00) | ((w3 & byte_mask)?0x08:0x00); byte_mask>>=1; } } //// CODAGE d'une partie d'IMAGE //// void PI1_16p_to_8b(byte * src,byte * dest) { int i; // index du pixel calculer word byte_mask; // Masque de codage word w0,w1,w2,w3; // Les 4 words bien ordonns de la destination byte_mask=0x8000; w0=w1=w2=w3=0; for (i=0;i<16;i++) { // Pour coder le pixel ni, il faut modifier les 4 words sur leur bit // correspondant celui du masque w0|=(src[i] & 0x01)?byte_mask:0x00; w1|=(src[i] & 0x02)?byte_mask:0x00; w2|=(src[i] & 0x04)?byte_mask:0x00; w3|=(src[i] & 0x08)?byte_mask:0x00; byte_mask>>=1; } dest[0]=w0 >> 8; dest[1]=w0 & 0x00FF; dest[2]=w1 >> 8; dest[3]=w1 & 0x00FF; dest[4]=w2 >> 8; dest[5]=w2 & 0x00FF; dest[6]=w3 >> 8; dest[7]=w3 & 0x00FF; } //// DECODAGE de la PALETTE //// void PI1_decode_palette(byte * src,byte * palette) { int i; // Numro de la couleur traite int ip; // index dans la palette word w; // Word contenant le code // Schma d'un word = // // Low High // VVVV RRRR | 0000 BBBB // 0321 0321 | 0321 ip=0; for (i=0;i<16;i++) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN w=(((word)src[(i*2)+1]<<8) | (src[(i*2)+0])); // Traitement des couleurs rouge, verte et bleue: palette[ip++]=(((w & 0x0007) << 1) | ((w & 0x0008) >> 3)) << 4; palette[ip++]=(((w & 0x7000) >> 11) | ((w & 0x8000) >> 15)) << 4; palette[ip++]=(((w & 0x0700) >> 7) | ((w & 0x0800) >> 11)) << 4; #else w=(((word)src[(i*2+1)])|(((word)src[(i*2)])<<8)); palette[ip++] = (((w & 0x0700)>>7) | ((w & 0x0800) >> 7))<<4 ; palette[ip++]=(((w & 0x0070)>>3) | ((w & 0x0080) >> 3))<<4 ; palette[ip++] = (((w & 0x0007)<<1) | ((w & 0x0008)))<<4 ; #endif } } //// CODAGE de la PALETTE //// void PI1_code_palette(byte * palette,byte * dest) { int i; // Numro de la couleur traite int ip; // index dans la palette word w; // Word contenant le code // Schma d'un word = // // Low High // VVVV RRRR | 0000 BBBB // 0321 0321 | 0321 ip=0; for (i=0;i<16;i++) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN // Traitement des couleurs rouge, verte et bleue: w =(((word)(palette[ip]>>2) & 0x38) >> 3) | (((word)(palette[ip]>>2) & 0x04) << 1); ip++; w|=(((word)(palette[ip]>>2) & 0x38) << 9) | (((word)(palette[ip]>>2) & 0x04) << 13); ip++; w|=(((word)(palette[ip]>>2) & 0x38) << 5) | (((word)(palette[ip]>>2) & 0x04) << 9); ip++; dest[(i*2)+0]=w & 0x00FF; dest[(i*2)+1]=(w>>8); #else w=(((word)(palette[ip]<<3))&0x0700);ip++; w|=(((word)(palette[ip]>>1))&0x0070);ip++; w|=(((word)(palette[ip]>>5))&0x0007);ip++; dest[(i*2)+1]=w & 0x00FF; dest[(i*2)+0]=(w>>8); #endif } } /// Load color ranges from a PI1 or PC1 image (Degas Elite format) void PI1_load_ranges(T_IO_Context * context, const byte * buffer, int size) { int range; if (buffer==NULL || size<32) return; for (range=0; range < 4; range ++) { word min_col, max_col, direction, delay; min_col = (buffer[size - 32 + range*2 + 0] << 8) | buffer[size - 32 + range*2 + 1]; max_col = (buffer[size - 32 + range*2 + 8] << 8) | buffer[size - 32 + range*2 + 9]; direction = (buffer[size - 32 + range*2 + 16] << 8) | buffer[size - 32 + range*2 + 17]; delay = (buffer[size - 32 + range*2 + 24] << 8) | buffer[size - 32 + range*2 + 25]; if (max_col < min_col) SWAP_WORDS(min_col,max_col) // Sanity checks if (min_col < 256 && max_col < 256 && direction < 3 && (direction == 1 || delay < 128)) { int speed = 210/(128-delay); // Grafx2's slider has a limit of 105 if (speed>105) speed = 105; context->Cycle_range[context->Color_cycles].Start=min_col; context->Cycle_range[context->Color_cycles].End=max_col; context->Cycle_range[context->Color_cycles].Inverse= (direction==0); context->Cycle_range[context->Color_cycles].Speed=direction == 1 ? 0 : speed; context->Color_cycles++; } } } /// Saves color ranges from a PI1 or PC1 image (Degas Elite format) void PI1_save_ranges(T_IO_Context * context, byte * buffer, int size) { // empty by default memset(buffer+size - 32, 0, 32); if (context->Color_cycles) { int i; // index in context->Cycle_range[] : < context->Color_cycles int saved_range; // index in resulting buffer : < 4 for (i=0, saved_range=0; iColor_cycles && saved_range<4; i++) { if (context->Cycle_range[i].Start < 16 && context->Cycle_range[i].End < 16) { int speed; if (context->Cycle_range[i].Speed == 0) speed = 0; else if (context->Cycle_range[i].Speed == 1) // has to "round" manually to closest valid number for this format speed = 1; else speed = 128 - 210 / context->Cycle_range[i].Speed; buffer[size - 32 + saved_range*2 + 1] = context->Cycle_range[i].Start; buffer[size - 32 + saved_range*2 + 9] = context->Cycle_range[i].End; buffer[size - 32 + saved_range*2 + 17] = (context->Cycle_range[i].Speed == 0) ? 1 : (context->Cycle_range[i].Inverse ? 0 : 2); buffer[size - 32 + saved_range*2 + 25] = speed; saved_range ++; } } } } // -- Tester si un fichier est au format PI1 -------------------------------- void Test_PI1(T_IO_Context * context) { FILE * file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier int size; // Taille du fichier word resolution; // Rsolution de l'image Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Vrification de la taille size=File_length_file(file); if ((size==32034) || (size==32066)) { // Lecture et vrification de la rsolution if (Read_word_le(file,&resolution)) { if (resolution==0x0000) File_error=0; } } // Fermeture du fichier fclose(file); } } // -- Lire un fichier au format PI1 ----------------------------------------- void Load_PI1(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; word x_pos,y_pos; byte * buffer; byte * ptr; byte pixels[320]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { // allocation d'un buffer mmoire buffer=(byte *)malloc(32034); if (buffer!=NULL) { // Lecture du fichier dans le buffer if (Read_bytes(file,buffer,32034)) { // Initialisation de la preview Pre_load(context, 320,200,File_length_file(file),FORMAT_PI1,PIXEL_SIMPLE,0); if (File_error==0) { // Initialisation de la palette if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); PI1_decode_palette(buffer+2,(byte *)context->Palette); context->Width=320; context->Height=200; // Chargement/dcompression de l'image ptr=buffer+34; for (y_pos=0;y_pos<200;y_pos++) { for (x_pos=0;x_pos<(320>>4);x_pos++) { PI1_8b_to_16p(ptr,pixels+(x_pos<<4)); ptr+=8; } for (x_pos=0;x_pos<320;x_pos++) Set_pixel(context, x_pos,y_pos,pixels[x_pos]); } PI1_load_ranges(context, buffer, 32034); } } else File_error=1; free(buffer); buffer = NULL; } else File_error=1; fclose(file); } else File_error=1; } // -- Sauver un fichier au format PI1 --------------------------------------- void Save_PI1(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; short x_pos,y_pos; byte * buffer; byte * ptr; byte pixels[320]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { setvbuf(file, NULL, _IOFBF, 64*1024); // allocation d'un buffer mmoire buffer=(byte *)malloc(32034); // Codage de la rsolution buffer[0]=0x00; buffer[1]=0x00; // Codage de la palette PI1_code_palette((byte *)context->Palette,buffer+2); // Codage de l'image ptr=buffer+34; for (y_pos=0;y_pos<200;y_pos++) { // Codage de la ligne memset(pixels,0,320); if (y_posHeight) { for (x_pos=0;(x_pos<320) && (x_posWidth);x_pos++) pixels[x_pos]=Get_pixel(context, x_pos,y_pos); } for (x_pos=0;x_pos<(320>>4);x_pos++) { PI1_16p_to_8b(pixels+(x_pos<<4),ptr); ptr+=8; } } PI1_save_ranges(context, buffer, 32034); if (Write_bytes(file,buffer,32034)) { fclose(file); } else // Error d'criture (disque plein ou protg) { fclose(file); remove(filename); File_error=1; } // Libration du buffer mmoire free(buffer); buffer = NULL; } else { fclose(file); remove(filename); File_error=1; } } //////////////////////////////////// PC1 //////////////////////////////////// //// DECOMPRESSION d'un buffer selon la mthode PACKBITS //// void PC1_uncompress_packbits(byte * src,byte * dest) { int is,id; // Les indices de parcour des buffers int n; // Octet de contrle for (is=id=0;id<32000;) { n=src[is++]; if (n & 0x80) { // Recopier src[is] -n+1 fois n=257-n; for (;(n>0) && (id<32000);n--) dest[id++]=src[is]; is++; } else { // Recopier n+1 octets littralement n=n+1; for (;(n>0) && (id<32000);n--) dest[id++]=src[is++]; } // Contrle des erreurs if (n>0) File_error=1; } } //// COMPRESSION d'un buffer selon la mthode PACKBITS //// void PC1_compress_packbits(byte * src,byte * dest,int source_size,int * dest_size) { *dest_size = 0; while (source_size > 0) { int is = 0; // index dans la source int id = 0; // index dans la destination int ir; // index de la rptition int n; // Taille des squences int repet; // "Il y a rptition" while(is<40) { // On recherche le 1er endroit o il y a rptition d'au moins 3 valeurs // identiques repet=0; for (ir=is;ir<40-2;ir++) { if ((src[ir]==src[ir+1]) && (src[ir+1]==src[ir+2])) { repet=1; break; } } // On code la partie sans rptitions if (!repet || ir!=is) { n=(ir-is)+1; dest[id++]=n-1; for (;n>0;n--) dest[id++]=src[is++]; } // On code la partie sans rptitions if (repet) { // On compte la quantit de fois qu'il faut rpter la valeur for (ir+=3;ir<40;ir++) { if (src[ir]!=src[is]) break; } n=(ir-is); dest[id++]=257-n; dest[id++]=src[is]; is=ir; } } // On renseigne la taille du buffer compress *dest_size+=id; // Move for next 40-byte block src += 40; dest += id; source_size -= 40; } } //// DECODAGE d'une partie d'IMAGE //// // Transformation de 4 plans de bits en 1 ligne de pixels void PC1_4bp_to_1line(byte * src0,byte * src1,byte * src2,byte * src3,byte * dest) { int i,j; // Compteurs int ip; // index du pixel calculer byte byte_mask; // Masque de decodage byte b0,b1,b2,b3; // Les 4 octets des plans bits sources ip=0; // Pour chacun des 40 octets des plans de bits for (i=0;i<40;i++) { b0=src0[i]; b1=src1[i]; b2=src2[i]; b3=src3[i]; // Pour chacun des 8 bits des octets byte_mask=0x80; for (j=0;j<8;j++) { dest[ip++]=((b0 & byte_mask)?0x01:0x00) | ((b1 & byte_mask)?0x02:0x00) | ((b2 & byte_mask)?0x04:0x00) | ((b3 & byte_mask)?0x08:0x00); byte_mask>>=1; } } } //// CODAGE d'une partie d'IMAGE //// // Transformation d'1 ligne de pixels en 4 plans de bits void PC1_1line_to_4bp(byte * src,byte * dst0,byte * dst1,byte * dst2,byte * dst3) { int i,j; // Compteurs int ip; // index du pixel calculer byte byte_mask; // Masque de decodage byte b0,b1,b2,b3; // Les 4 octets des plans bits sources ip=0; // Pour chacun des 40 octets des plans de bits for (i=0;i<40;i++) { // Pour chacun des 8 bits des octets byte_mask=0x80; b0=b1=b2=b3=0; for (j=0;j<8;j++) { b0|=(src[ip] & 0x01)?byte_mask:0x00; b1|=(src[ip] & 0x02)?byte_mask:0x00; b2|=(src[ip] & 0x04)?byte_mask:0x00; b3|=(src[ip] & 0x08)?byte_mask:0x00; ip++; byte_mask>>=1; } dst0[i]=b0; dst1[i]=b1; dst2[i]=b2; dst3[i]=b3; } } // -- Tester si un fichier est au format PC1 -------------------------------- void Test_PC1(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier int size; // Taille du fichier word resolution; // Rsolution de l'image Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Vrification de la taille size=File_length_file(file); if ((size<=32066)) { // Lecture et vrification de la rsolution if (Read_word_le(file,&resolution)) { if (resolution==0x0080) File_error=0; } } // Fermeture du fichier fclose(file); } } // -- Lire un fichier au format PC1 ----------------------------------------- void Load_PC1(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; int size; word x_pos,y_pos; byte * buffercomp; byte * bufferdecomp; byte * ptr; byte pixels[320]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { size=File_length_file(file); // allocation des buffers mmoire buffercomp=(byte *)malloc(size); bufferdecomp=(byte *)malloc(32000); if ( (buffercomp!=NULL) && (bufferdecomp!=NULL) ) { // Lecture du fichier dans le buffer if (Read_bytes(file,buffercomp,size)) { // Initialisation de la preview Pre_load(context, 320,200,File_length_file(file),FORMAT_PC1,PIXEL_SIMPLE,0); if (File_error==0) { // Initialisation de la palette if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); PI1_decode_palette(buffercomp+2,(byte *)context->Palette); context->Width=320; context->Height=200; // Dcompression du buffer PC1_uncompress_packbits(buffercomp+34,bufferdecomp); // Dcodage de l'image ptr=bufferdecomp; for (y_pos=0;y_pos<200;y_pos++) { // Dcodage de la scanline PC1_4bp_to_1line(ptr,ptr+40,ptr+80,ptr+120,pixels); ptr+=160; // Chargement de la ligne for (x_pos=0;x_pos<320;x_pos++) Set_pixel(context, x_pos,y_pos,pixels[x_pos]); } if (!File_error) { PI1_load_ranges(context, buffercomp, size); } } } else File_error=1; free(bufferdecomp); free(buffercomp); buffercomp = bufferdecomp = NULL; } else { File_error=1; free(bufferdecomp); free(buffercomp); buffercomp = bufferdecomp = NULL; } fclose(file); } else File_error=1; } // -- Sauver un fichier au format PC1 --------------------------------------- void Save_PC1(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; int size; short x_pos,y_pos; byte * buffercomp; byte * bufferdecomp; byte * ptr; byte pixels[320]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { setvbuf(file, NULL, _IOFBF, 64*1024); // Allocation des buffers mmoire bufferdecomp=(byte *)malloc(32000); buffercomp =(byte *)malloc(64066); // Codage de la rsolution buffercomp[0]=0x80; buffercomp[1]=0x00; // Codage de la palette PI1_code_palette((byte *)context->Palette,buffercomp+2); // Codage de l'image ptr=bufferdecomp; for (y_pos=0;y_pos<200;y_pos++) { // Codage de la ligne memset(pixels,0,320); if (y_posHeight) { for (x_pos=0;(x_pos<320) && (x_posWidth);x_pos++) pixels[x_pos]=Get_pixel(context, x_pos,y_pos); } // Encodage de la scanline PC1_1line_to_4bp(pixels,ptr,ptr+40,ptr+80,ptr+120); ptr+=160; } // Compression du buffer PC1_compress_packbits(bufferdecomp,buffercomp+34,32000,&size); size += 34; size += 32; PI1_save_ranges(context, buffercomp,size); if (Write_bytes(file,buffercomp,size)) { fclose(file); } else // Error d'criture (disque plein ou protg) { fclose(file); remove(filename); File_error=1; } // Libration des buffers mmoire free(bufferdecomp); free(buffercomp); buffercomp = bufferdecomp = NULL; } else { fclose(file); remove(filename); File_error=1; } } //////////////////////////////////// NEO //////////////////////////////////// void Test_NEO(T_IO_Context * context) { FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier int size; // Taille du fichier word resolution; // Rsolution de l'image Get_full_filename(filename, context->File_name, context->File_directory); File_error=1; // Ouverture du fichier if ((file=fopen(filename, "rb"))) { // Vrification de la taille size=File_length_file(file); if ((size==32128)) { // Flag word : toujours 0 if (Read_word_le(file,&resolution)) { if (resolution == 0) File_error = 0; } // Lecture et vrification de la rsolution if (Read_word_le(file,&resolution)) { if (resolution==0 || resolution==1 || resolution==2) File_error |= 0; } } // Fermeture du fichier fclose(file); } } void Load_NEO(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; word x_pos,y_pos; byte * buffer; byte * ptr; byte pixels[320]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; if ((file=fopen(filename, "rb"))) { // allocation d'un buffer mmoire buffer=(byte *)malloc(32128); if (buffer!=NULL) { // Lecture du fichier dans le buffer if (Read_bytes(file,buffer,32128)) { // Initialisation de la preview Pre_load(context, 320,200,File_length_file(file),FORMAT_NEO,PIXEL_SIMPLE,0); if (File_error==0) { // Initialisation de la palette if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); // on saute la rsolution et le flag, chacun 2 bits PI1_decode_palette(buffer+4,(byte *)context->Palette); context->Width=320; context->Height=200; // Chargement/dcompression de l'image ptr=buffer+128; for (y_pos=0;y_pos<200;y_pos++) { for (x_pos=0;x_pos<(320>>4);x_pos++) { PI1_8b_to_16p(ptr,pixels+(x_pos<<4)); ptr+=8; } for (x_pos=0;x_pos<320;x_pos++) Set_pixel(context, x_pos,y_pos,pixels[x_pos]); } } } else File_error=1; free(buffer); buffer = NULL; } else File_error=1; fclose(file); } else File_error=1; } void Save_NEO(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier FILE *file; short x_pos,y_pos; byte * buffer; byte * ptr; byte pixels[320]; Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; // Ouverture du fichier if ((file=fopen(filename,"wb"))) { setvbuf(file, NULL, _IOFBF, 64*1024); // allocation d'un buffer mmoire buffer=(byte *)malloc(32128); // Codage de la rsolution buffer[0]=0x00; buffer[1]=0x00; buffer[2]=0x00; buffer[3]=0x00; // Codage de la palette PI1_code_palette((byte *)context->Palette,buffer+4); // Codage de l'image ptr=buffer+128; for (y_pos=0;y_pos<200;y_pos++) { // Codage de la ligne memset(pixels,0,320); if (y_posHeight) { for (x_pos=0;(x_pos<320) && (x_posWidth);x_pos++) pixels[x_pos]=Get_pixel(context, x_pos,y_pos); } for (x_pos=0;x_pos<(320>>4);x_pos++) { PI1_16p_to_8b(pixels+(x_pos<<4),ptr); ptr+=8; } } if (Write_bytes(file,buffer,32128)) { fclose(file); } else // Error d'criture (disque plein ou protg) { fclose(file); remove(filename); File_error=1; } // Libration du buffer mmoire free(buffer); buffer = NULL; } else { fclose(file); remove(filename); File_error=1; } } //////////////////////////////////// C64 //////////////////////////////////// void Test_C64(T_IO_Context * context) { FILE* file; char filename[MAX_PATH_CHARACTERS]; long file_size; Get_full_filename(filename, context->File_name, context->File_directory); file = fopen(filename,"rb"); if (file) { file_size = File_length_file(file); switch (file_size) { // case 1000: // screen or color // case 1002: // (screen or color) + loadaddr case 8000: // raw bitmap case 8002: // raw bitmap with loadaddr case 9000: // bitmap + ScreenRAM case 9002: // bitmap + ScreenRAM + loadaddr case 10001: // multicolor case 10003: // multicolor + loadaddr case 17472: // FLI (BlackMail) case 17474: // FLI (BlackMail) + loadaddr case 10277: // multicolor CDU-Paint + loadaddr File_error = 0; break; default: // then we don't know for now. File_error = 1; } fclose (file); } else { File_error = 1; } } void Load_C64_hires(T_IO_Context *context, byte *bitmap, byte *screen_ram) { int cx,cy,x,y,c[4],pixel,color; for(cy=0; cy<25; cy++) { for(cx=0; cx<40; cx++) { c[0]=screen_ram[cy*40+cx]&15; c[1]=screen_ram[cy*40+cx]>>4; for(y=0; y<8; y++) { pixel=bitmap[cy*320+cx*8+y]; for(x=0; x<8; x++) { color=c[pixel&(1<<(7-x))?1:0]; Set_pixel(context, cx*8+x,cy*8+y,color); } } } } } void Load_C64_multi(T_IO_Context *context, byte *bitmap, byte *screen_ram, byte *color_ram, byte background) { int cx,cy,x,y,c[4],pixel,color; c[0]=background&15; for(cy=0; cy<25; cy++) { for(cx=0; cx<40; cx++) { c[1]=screen_ram[cy*40+cx]>>4; c[2]=screen_ram[cy*40+cx]&15; c[3]=color_ram[cy*40+cx]&15; for(y=0; y<8; y++) { pixel=bitmap[cy*320+cx*8+y]; for(x=0; x<4; x++) { color=c[(pixel&3)]; pixel>>=2; Set_pixel(context, cx*4+(3-x),cy*8+y,color); } } } } } void Load_C64_fli(T_IO_Context *context, byte *bitmap, byte *screen_ram, byte *color_ram, byte *background) { // Thanks to MagerValp for complement of specifications. // // background : length: 200 (+ padding 56) // These are the BG colors for lines 0-199 (top to bottom) // Low nybble: the color. // High nybble: garbage. ignore it. // color_ram : length: 1000 (+ padding 24) // Color RAM. Contains one color per 4x8 block. // There are 40x25 such blocks, arranged from top left to bottom // right, starting in right direction. For each block there is one byte. // Low nybble: the color. // High nybble: garbage. ignore it. // screen_ram : length: 8192 // Screen RAMs. The s is important. // This is actually 8 blocks of 1000 bytes, each separated by a filler of // 24 bytes. Each byte contains data for a 4x1 pixel group, and a complete // block will contain 40x25 of them. 40 is from left to right, and 25 is from // top to bottom, spacing them 8 lines apart. // The second block start at y=1, the third block starts at y=2, etc... // Each byte contains 2 colors that *can* be used by the 4x1 pixel group: // Low nybble: Color 1 // High nybble: Color 2 // // bitmap : length: 8000 // This is the final structure that refers to all others. It describes // 160x200 pixels linearly, from top left to bottom right, starting in // right direction. For each pixel, two bits say which color is displayed // (So 4 pixels are described by the same byte) // 00 Use the BG color of the current line (background[y]) // 01 Use the Color 2 from the current 4x8 block of Screen RAM // ((screen_ram[y/8][x/4] & 0xF0) >> 8) // 10 Use the Color 1 from the current 4x8 block of Screen RAM // (screen_ram[y/8][x/4] & 0x0F) // 11 Use the color from Color RAM // (color_ram[y/8][x/4] & 0x0F) // int cx,cy,x,y,c[4]; for(y=0; y<200; y++) { for(x=0; x<160; x++) { Set_pixel(context, x,y,background[y]); } } Set_loading_layer(context, 1); for(cy=0; cy<25; cy++) { for(cx=0; cx<40; cx++) { c[3]=color_ram[cy*40+cx]&15; for(y=0; y<8; y++) { for(x=0; x<4; x++) { Set_pixel(context, cx*4+(3-x),cy*8+y,c[3]); } } } } Set_loading_layer(context, 2); for(cy=0; cy<25; cy++) { for(cx=0; cx<40; cx++) { c[3]=color_ram[cy*40+cx]&15; for(y=0; y<8; y++) { int pixel=bitmap[cy*320+cx*8+y]; c[0]=background[cy*8+y]&15; c[1]=screen_ram[y*1024+cy*40+cx]>>4; c[2]=screen_ram[y*1024+cy*40+cx]&15; for(x=0; x<4; x++) { int color=c[(pixel&3)]; pixel>>=2; Set_pixel(context, cx*4+(3-x),cy*8+y,color); } } } } Set_loading_layer(context, 3); for(y=0; y<200; y++) { for(x=0; x<160; x++) { Set_pixel(context, x,y,16); } } } void Load_C64(T_IO_Context * context) { FILE* file; char filename[MAX_PATH_CHARACTERS]; long file_size; byte hasLoadAddr=0; int loadFormat=0; enum c64_format {F_hires,F_multi,F_bitmap,F_fli}; const char *c64_format_names[]={"Hires","Multicolor","Bitmap","FLI"}; // Palette from http://www.pepto.de/projects/colorvic/ byte pal[48]={ 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x68, 0x37, 0x2B, 0x70, 0xA4, 0xB2, 0x6F, 0x3D, 0x86, 0x58, 0x8D, 0x43, 0x35, 0x28, 0x79, 0xB8, 0xC7, 0x6F, 0x6F, 0x4F, 0x25, 0x43, 0x39, 0x00, 0x9A, 0x67, 0x59, 0x44, 0x44, 0x44, 0x6C, 0x6C, 0x6C, 0x9A, 0xD2, 0x84, 0x6C, 0x5E, 0xB5, 0x95, 0x95, 0x95}; byte *file_buffer; byte *bitmap, *screen_ram, *color_ram=NULL, *background=NULL; // Only pointers to existing data word width=320, height=200; static byte dummy_screen[1000]; Get_full_filename(filename, context->File_name, context->File_directory); file = fopen(filename,"rb"); if (file) { File_error=0; file_size = File_length_file(file); // Check for known file sizes switch (file_size) { case 8000: // raw bitmap case 8002: // raw bitmap with loadaddr case 9000: // bitmap + ScreenRAM case 9002: // bitmap + ScreenRAM + loadaddr case 10001: // multicolor case 10003: // multicolor + loadaddr case 10277: // multicolor CDU-Paint + loadaddr case 17472: // FLI (BlackMail) case 17474: // FLI (BlackMail) + loadaddr break; default: File_error = 1; fclose(file); return; } // Load entire file in memory file_buffer=(byte *)malloc(file_size); if (!file_buffer) { File_error = 1; fclose(file); return; } if (!Read_bytes(file,file_buffer,file_size)) { File_error = 1; free(file_buffer); fclose(file); return; } fclose(file); memset(dummy_screen,1,1000); switch (file_size) { case 8000: // raw bitmap hasLoadAddr=0; loadFormat=F_bitmap; bitmap=file_buffer+0; // length: 8000 screen_ram=dummy_screen; break; case 8002: // raw bitmap with loadaddr hasLoadAddr=1; loadFormat=F_bitmap; bitmap=file_buffer+2; // length: 8000 screen_ram=dummy_screen; break; case 9000: // bitmap + ScreenRAM hasLoadAddr=0; loadFormat=F_hires; bitmap=file_buffer+0; // length: 8000 screen_ram=file_buffer+8000; // length: 1000 break; case 9002: // bitmap + ScreenRAM + loadaddr hasLoadAddr=1; loadFormat=F_hires; bitmap=file_buffer+2; // length: 8000 screen_ram=file_buffer+8002; // length: 1000 break; case 10001: // multicolor hasLoadAddr=0; loadFormat=F_multi; context->Ratio = PIXEL_WIDE; bitmap=file_buffer+0; // length: 8000 screen_ram=file_buffer+8000; // length: 1000 color_ram=file_buffer+9000; // length: 1000 background=file_buffer+10000; // only 1 break; case 10003: // multicolor + loadaddr hasLoadAddr=1; loadFormat=F_multi; context->Ratio = PIXEL_WIDE; bitmap=file_buffer+2; // length: 8000 screen_ram=file_buffer+8002; // length: 1000 color_ram=file_buffer+9002; // length: 1000 background=file_buffer+10002; // only 1 break; case 10277: // multicolor CDU-Paint + loadaddr hasLoadAddr=1; loadFormat=F_multi; context->Ratio = PIXEL_WIDE; // 273 bytes of display routine bitmap=file_buffer+275; // length: 8000 screen_ram=file_buffer+8275; // length: 1000 color_ram=file_buffer+9275; // length: 1000 background=file_buffer+10275; // only 1 break; case 17472: // FLI (BlackMail) hasLoadAddr=0; loadFormat=F_fli; context->Ratio = PIXEL_WIDE; background=file_buffer+0; // length: 200 (+ padding 56) color_ram=file_buffer+256; // length: 1000 (+ padding 24) screen_ram=file_buffer+1280; // length: 8192 bitmap=file_buffer+9472; // length: 8000 break; case 17474: // FLI (BlackMail) + loadaddr hasLoadAddr=1; loadFormat=F_fli; context->Ratio = PIXEL_WIDE; background=file_buffer+2; // length: 200 (+ padding 56) color_ram=file_buffer+258; // length: 1000 (+ padding 24) screen_ram=file_buffer+1282; // length: 8192 bitmap=file_buffer+9474; // length: 8000 break; default: File_error = 1; free(file_buffer); return; } if (context->Ratio == PIXEL_WIDE) width=160; // Write detailed format in comment strcpy(context->Comment, c64_format_names[loadFormat]); if (hasLoadAddr) { // get load address word load_addr; load_addr = file_buffer[0] | (file_buffer[1] << 8); sprintf(context->Comment+strlen(context->Comment),", load at $%4.4X",load_addr); } else { sprintf(context->Comment+strlen(context->Comment),", no addr"); } Pre_load(context, width, height, file_size, FORMAT_C64, context->Ratio,0); // Do this as soon as you can memcpy(context->Palette,pal,48); // this set the software palette for grafx2 // Transparent color "16" is a dark grey that is distinguishable // from black, but darker than normal colors. context->Palette[16].R=20; context->Palette[16].G=20; context->Palette[16].B=20; context->Width = width ; context->Height = height; context->Transparent_color=16; if(loadFormat==F_fli) { Load_C64_fli(context,bitmap,screen_ram,color_ram,background); } else if(loadFormat==F_multi) { Load_C64_multi(context,bitmap,screen_ram,color_ram,*background); } else { Load_C64_hires(context,bitmap,screen_ram); } File_error = 0; free(file_buffer); } else File_error = 1; } int Save_C64_window(byte *saveWhat, byte *loadAddr) { int button; unsigned int i; T_Dropdown_button *what, *addr; char * what_label[] = { "All", "Bitmap", "Screen", "Color" }; char * address_label[] = { "None", "$2000", "$4000", "$6000", "$8000", "$A000", "$C000", "$E000" }; Open_window(200,120,"c64 settings"); Window_set_normal_button(110,100,80,15,"Save",1,1,SDLK_RETURN); // 1 Window_set_normal_button(10,100,80,15,"Cancel",1,1,SDLK_ESCAPE); // 2 Print_in_window(13,18,"Data:",MC_Dark,MC_Light); what=Window_set_dropdown_button(10,28,90,15,70,what_label[*saveWhat],1, 0, 1, LEFT_SIDE,0); // 3 Window_dropdown_clear_items(what); for (i=0; i2) { Warning_message("More than 2 colors in 8x8 pixels"); // TODO here we should hilite the offending block printf("\nerror at %dx%d (%d colors)\n",cx*8,cy*8,numcolors); return 1; } c1 = 0; c2 = 0; for(i=0;i<16;i++) { if(cusage[i]) { c2=i; break; } } c1=c2+1; for(i=c2;i<16;i++) { if(cusage[i]) { c1=i; } } screen_ram[cx+cy*40]=(c2<<4)|c1; for(y=0; y<8; y++) { bits=0; for(x=0; x<8; x++) { pixel=Get_pixel(context, x+cx*8,y+cy*8); if(pixel>15) { Warning_message("Color above 15 used"); // TODO hilite offending block here too? // or make it smarter with color allocation? // However, the palette is fixed to the 16 first colors return 1; } bits=bits<<1; if (pixel==c2) bits|=1; } bitmap[pos++]=bits; //Write_byte(file,bits&255); } } } file = fopen(filename,"wb"); if(!file) { Warning_message("File open failed"); File_error = 1; return 1; } setvbuf(file, NULL, _IOFBF, 64*1024); if (loadAddr) { Write_byte(file,0); Write_byte(file,loadAddr); } if (saveWhat==0 || saveWhat==1) Write_bytes(file,bitmap,8000); if (saveWhat==0 || saveWhat==2) Write_bytes(file,screen_ram,1000); fclose(file); return 0; } int Save_C64_multi(T_IO_Context *context, char *filename, byte saveWhat, byte loadAddr) { /* BITS COLOR INFORMATION COMES FROM 00 Background color #0 (screen color) 01 Upper 4 bits of Screen RAM 10 Lower 4 bits of Screen RAM 11 Color RAM nybble (nybble = 1/2 byte = 4 bits) */ int cx,cy,x,y,c[4]={0,0,0,0},color,lut[16],bits,pixel,pos=0; int cand,n,used; word cols, candidates = 0, invalids = 0; // FIXME allocating this on the stack is not a good idea. On some platforms // the stack has a rather small size... byte bitmap[8000],screen_ram[1000],color_ram[1000]; word numcolors; dword cusage[256]; byte i,background=0; FILE *file; // Detect the ackground color the image should be using. It's the one that's // used on all tiles having 4 colors. for(y=0;y<200;y=y+8) { for (x = 0; x<160; x=x+4) { cols = 0; // Compute the usage count of each color in the tile for (cy=0;cy<8;cy++) for (cx=0;cx<4;cx++) { pixel=Get_pixel(context, x+cx,y+cy); cols |= (1 << pixel); } cand = 0; used = 0; // Count the number of used colors in the tile for (n = 0; n<16; n++) { if (cols & (1 << pixel)) used++; } if (used>3) { // This is a tile that uses the background color (and 3 others) // Try to guess which color is most likely the background one for (n = 0; n<16; n++) { if ((cols & (1 << n)) && !((candidates | invalids) & (1 << n))) { // This color was not used in any other tile yet, // but it could be the background one. candidates |= 1 << n; } if ((cols & 1 << n) == 0 ) { // This color isn't used at all in this tile: // Can't be the global invalids |= 1 << n; } if (candidates & (1 << n)) { // We have a candidate, mark it as such cand++; } } // After checking the constraints for this tile, do we have // candidate background colors left ? if (cand==0) { Warning_message("No possible global background color found"); return 1; } } } } // Now just pick the first valid candidate for (n = 0; n<16; n++) { if (candidates & (1 << n)) { background = n; break; } } // Now that we know which color is the background, we can encode the cells for(cy=0; cy<25; cy++) { //printf("\ny:%2d ",cy); for(cx=0; cx<40; cx++) { numcolors=Count_used_colors_area(cusage,cx*4,cy*8,4,8); if(numcolors>4) { Warning_message("More than 4 colors in 4x8"); // TODO hilite offending block return 1; } color=1; c[0]=background; for(i=0; i<16; i++) { lut[i]=0; if(cusage[i]) { if(i!=background) { lut[i]=color; c[color]=i; color++; } else { lut[i]=0; } } } // add to screen_ram and color_ram screen_ram[cx+cy*40]=c[1]<<4|c[2]; color_ram[cx+cy*40]=c[3]; //printf("%x%x%x ",c[1],c[2],c[3]); for(y=0;y<8;y++) { bits=0; for(x=0;x<4;x++) { pixel=Get_pixel(context, cx*4+x,cy*8+y); if(pixel>15) { Warning_message("Color above 15 used"); // TODO hilite as in hires, you should stay to // the fixed 16 color palette return 1; } bits=bits<<2; bits|=lut[pixel]; } //Write_byte(file,bits&255); bitmap[pos++]=bits; } } } file = fopen(filename,"wb"); if(!file) { Warning_message("File open failed"); File_error = 2; return 2; } setvbuf(file, NULL, _IOFBF, 64*1024); if (loadAddr) { Write_byte(file,0); Write_byte(file,loadAddr); } if (saveWhat==0 || saveWhat==1) Write_bytes(file,bitmap,8000); if (saveWhat==0 || saveWhat==2) Write_bytes(file,screen_ram,1000); if (saveWhat==0 || saveWhat==3) Write_bytes(file,color_ram,1000); if (saveWhat==0) Write_byte(file,background); fclose(file); //printf("\nbg:%d\n",background); return 0; } int Save_C64_fli(char *filename, byte saveWhat, byte loadAddr) { FILE *file; byte file_buffer[17474]; memset(file_buffer,0,sizeof(file_buffer)); if (C64_FLI(file_buffer+9474, file_buffer+1282, file_buffer+258, file_buffer+2)) { File_error=1; return 1; } file = fopen(filename,"wb"); if(!file) { Warning_message("File open failed"); File_error = 1; return 1; } setvbuf(file, NULL, _IOFBF, 64*1024); if (loadAddr) { file_buffer[0]=0; file_buffer[1]=loadAddr; Write_bytes(file,file_buffer,2); } if (saveWhat==0) Write_bytes(file,file_buffer+2,256); if (saveWhat==0 || saveWhat==3) Write_bytes(file,file_buffer+258,1024); if (saveWhat==0 || saveWhat==1) Write_bytes(file,file_buffer+1282,8192); if (saveWhat==0 || saveWhat==2) Write_bytes(file,file_buffer+9474,8000); fclose(file); //printf("\nbg:%d\n",background); return 0; } void Save_C64(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; static byte saveWhat=0, loadAddr=0; Get_full_filename(filename, context->File_name, context->File_directory); if (((context->Width!=320) && (context->Width!=160)) || context->Height!=200) { Warning_message("must be 320x200 or 160x200"); File_error = 1; return; } if(!Save_C64_window(&saveWhat,&loadAddr)) { File_error = 1; return; } if (strcasecmp(filename + strlen(filename) - 4, ".fli") == 0) { // FIXME moving FLI to a separate format in the fileselector would be smarter File_error = Save_C64_fli(filename,saveWhat,loadAddr); } else if (context->Width==320) File_error = Save_C64_hires(context,filename,saveWhat,loadAddr); else { File_error = Save_C64_multi(context, filename,saveWhat,loadAddr); } } // SCR (Amstrad CPC) void Test_SCR(T_IO_Context * context) { // Mmh... not sure what we could test. Any idea ? // The palette file can be tested, if it exists and have the right size it's // ok. But if it's not there the pixel data may still be valid. And we can't // use the filesize as this depends on the screen format. // An AMSDOS header would be a good indication but in some cases it may not // be there (void)context; // unused } void Load_SCR(T_IO_Context * context) { // The Amstrad CPC screen memory is mapped in a weird mode, somewhere // between bitmap and textmode. Basically the only way to decode this is to // emulate the video chip and read the bytes as needed... // Moreover, the hardware allows the screen to have any size from 8x1 to // 800x273 pixels, and there is no indication of that in the file besides // its size. It can also use any of the 3 screen modes. Fortunately this // last bit of information is stored in the palette file. // Oh, and BTW, the picture can be offset, and it's even usual to do it, // because letting 128 pixels unused at the beginning of the file make it a // lot easier to handle screens using more than 16K of VRam. // The pixel encoding change with the video mode so we have to know that // before attempting to load anything... // As if this wasn't enough, Advanced OCP Art Studio, the reference tool on // Amstrad, can use RLE packing when saving files, meaning we also have to // handle that. // All this mess enforces us to load (and unpack if needed) the file to a // temporary 32k buffer before actually decoding it. // 1) Seek for a palette // 2) If palette found get screenmode from there, else ask user // 3) ask user for screen size (or register values) // 4) Load color data from palette (if found) // 5) Close palette // 6) Open the file // 7) Run around the screen to untangle the pixeldata // 8) Close the file (void)context; // unused } void Save_SCR(T_IO_Context * context) { // TODO : Add possibility to set R9, R12, R13 values // TODO : Add OCP packing support // TODO : Add possibility to include AMSDOS header, with proper loading // address guessed from r12/r13 values. unsigned char* output; unsigned long outsize; unsigned char r1; int cpc_mode; FILE* file; char filename[MAX_PATH_CHARACTERS]; Get_full_filename(filename, context->File_name, context->File_directory); switch(Pixel_ratio) { case PIXEL_WIDE: case PIXEL_WIDE2: cpc_mode = 0; break; case PIXEL_TALL: case PIXEL_TALL2: case PIXEL_TALL3: cpc_mode = 2; break; default: cpc_mode = 1; break; } output = raw2crtc(context, cpc_mode, 7, &outsize, &r1, 0x0C, 0); file = fopen(filename,"wb"); Write_bytes(file, output, outsize); fclose(file); free (output); output = NULL; File_error = 0; } // CM5 - Amstrad CPC "Mode 5" picture // This is a format designed by SyX. There is one .SCR file in the usual amstrad format, // and a .CM5 file with the palette, which varies over time. void Test_CM5(T_IO_Context * context) { // check cm5 file size == 2049 bytes FILE *file; char filename[MAX_PATH_CHARACTERS]; long file_size; Get_full_filename(filename, context->File_name, context->File_directory); File_error = 1; if ((file = fopen(filename, "rb"))) { file_size = File_length_file(file); if (file_size == 2049) File_error = 0; } fclose(file); // TODO: check existence of a .SCR file with the same name } void Load_CM5(T_IO_Context* context) { // Ensure "8bit" constraint mode is switched on // Set palette to the CPC hardware colors // Load the palette data to the 4 colorlayers FILE *file; char filename[MAX_PATH_CHARACTERS]; byte value = 0; int mod=0; short line = 0; int tx, ty; byte buffer[48*6/4]; Get_full_filename(filename, context->File_name, context->File_directory); if (!(file = fopen(filename, "rb"))) { File_error = 1; return; } Pre_load(context, 48*6, 256, 2049, FORMAT_CM5, PIXEL_SIMPLE, 0); context->Width=48*6; context->Height=256; // Setup the palette (amstrad hardware palette) context->Palette[0x40].R = 0x6E; context->Palette[0x40].G = 0x7D; context->Palette[0x40].B = 0x6B; context->Palette[0x41].R = 0x6E; context->Palette[0x41].G = 0x7B; context->Palette[0x41].B = 0x6B; context->Palette[0x42].R = 0; context->Palette[0x42].G = 0xF3; context->Palette[0x42].B = 0x6B; context->Palette[0x43].R = 0xF3; context->Palette[0x43].G = 0xF3; context->Palette[0x43].B = 0x6D; context->Palette[0x44].R = 0; context->Palette[0x44].G = 2; context->Palette[0x44].B = 0x6B; context->Palette[0x45].R = 0xF0; context->Palette[0x45].G = 2; context->Palette[0x45].B = 0x68; context->Palette[0x46].R = 0; context->Palette[0x46].G = 0x78; context->Palette[0x46].B = 0x68; context->Palette[0x47].R = 0xF3; context->Palette[0x47].G = 0x7D; context->Palette[0x47].B = 0x6B; context->Palette[0x48].R = 0xF3; context->Palette[0x48].G = 0x02; context->Palette[0x48].B = 0x68; context->Palette[0x49].R = 0xF3; context->Palette[0x49].G = 0xF3; context->Palette[0x49].B = 0x6B; context->Palette[0x4A].R = 0xF3; context->Palette[0x4A].G = 0xF3; context->Palette[0x4A].B = 0xD; context->Palette[0x4B].R = 255; context->Palette[0x4B].G = 0xF3; context->Palette[0x4B].B = 0xF9; context->Palette[0x4C].R = 0xF3; context->Palette[0x4C].G = 5; context->Palette[0x4C].B = 6; context->Palette[0x4D].R = 0xF3; context->Palette[0x4D].G = 2; context->Palette[0x4D].B = 0xF4; context->Palette[0x4E].R = 0xF3; context->Palette[0x4E].G = 0x7D; context->Palette[0x4E].B = 0xD; context->Palette[0x4F].R = 0xFA; context->Palette[0x4F].G = 0x80; context->Palette[0x4F].B = 0xF9; context->Palette[0x50].R = 0x00; context->Palette[0x50].G = 0x02; context->Palette[0x50].B = 0x68; context->Palette[0x51].R = 0x02; context->Palette[0x51].G = 0xF3; context->Palette[0x51].B = 0x6B; context->Palette[0x52].R = 2; context->Palette[0x52].G = 0xF0; context->Palette[0x52].B = 1; context->Palette[0x53].R = 0xF; context->Palette[0x53].G = 0xF3; context->Palette[0x53].B = 0xF2; context->Palette[0x54].R = 0; context->Palette[0x54].G = 2; context->Palette[0x54].B = 1; context->Palette[0x55].R = 0x0C; context->Palette[0x55].G = 2; context->Palette[0x55].B = 0xF4; context->Palette[0x56].R = 2; context->Palette[0x56].G = 0x78; context->Palette[0x56].B = 1; context->Palette[0x57].R = 0xC; context->Palette[0x57].G = 0x7B; context->Palette[0x57].B = 0xF4; context->Palette[0x58].R = 0x69; context->Palette[0x58].G = 2; context->Palette[0x58].B = 0x68; context->Palette[0x59].R = 0x71; context->Palette[0x59].G = 0xF3; context->Palette[0x59].B = 0x6B; context->Palette[0x5A].R = 0x71; context->Palette[0x5A].G = 0xF5; context->Palette[0x5A].B = 4; context->Palette[0x5B].R = 0x71; context->Palette[0x5B].G = 0xF3; context->Palette[0x5B].B = 0xF4; context->Palette[0x5C].R = 0x6C; context->Palette[0x5C].G = 2; context->Palette[0x5C].B = 1; context->Palette[0x5D].R = 0x6C; context->Palette[0x5D].G = 2; context->Palette[0x5D].B = 0xF2; context->Palette[0x5E].R = 0x6E; context->Palette[0x5E].G = 0x7B; context->Palette[0x5E].B = 1; context->Palette[0x5F].R = 0x6E; context->Palette[0x5F].G = 0x7B; context->Palette[0x5F].B = 0xF6; if (Read_byte(file, &value)!=1) File_error = 2; // This forces the creation of 5 layers total : // Needed because the "pixel" functions will seek layer 4 Set_loading_layer(context, 4); // Now select layer 0 again Set_loading_layer(context, 0); if (context->Type == CONTEXT_MAIN_IMAGE) Main_backups->Pages->Image_mode = IMAGE_MODE_MODE5; for(ty=0; tyHeight; ty++) for(tx=0; txWidth; tx++) { Set_pixel(context, tx, ty, value); } // Fill layer with color we just read while(Read_byte(file, &value) == 1) { switch(mod) { case 0: // This is color for layer 1 Set_loading_layer(context, 1); for(tx=0; txWidth; tx++) Set_pixel(context, tx, line, value); break; case 1: // This is color for layer 2 Set_loading_layer(context, 2); for(tx=0; txWidth; tx++) Set_pixel(context, tx, line, value); break; default: // This is color for a block in layer 4 Set_loading_layer(context, 3); for(tx=(mod-2)*48; tx<(mod-1)*48; tx++) Set_pixel(context, tx, line, value); break; } mod = mod + 1; if (mod > 7) { mod = 0; line ++; } } fclose(file); // Load the pixeldata to the 5th layer { char* ext = filename + strlen(filename) - 3; int idx = 8; do { if (-- idx < 0) { File_error = 1; return; } ext[0] = (idx & 1) ? 'g':'G'; ext[1] = (idx & 2) ? 'f':'F'; ext[2] = (idx & 4) ? 'x':'X'; file = fopen(filename, "rb"); } while(file == NULL); } Set_loading_layer(context, 4); for (ty = 0; ty < 256; ty++) { Read_bytes(file, buffer, 48*6/4); for (tx = 0; tx < 48*6; tx+=4) { Set_pixel(context, tx+0, ty, 3-(((buffer[tx/4]&0x80) >> 7) |((buffer[tx/4]&0x8)>>2))); Set_pixel(context, tx+1, ty, 3-(((buffer[tx/4]&0x40) >> 6) |((buffer[tx/4]&0x4)>>1))); Set_pixel(context, tx+2, ty, 3-(((buffer[tx/4]&0x20) >> 5) |((buffer[tx/4]&0x2)>>0))); Set_pixel(context, tx+3, ty, 3-(((buffer[tx/4]&0x10) >> 4) |((buffer[tx/4]&0x1)<<1))); } } fclose(file); } void Save_CM5(T_IO_Context* context) { char filename[MAX_PATH_CHARACTERS]; FILE* file; int tx, ty; Get_full_filename(filename, context->File_name, context->File_directory); // TODO: Check picture has 5 layers // TODO: Check the constraints on the layers // Layer 1 : 1 color Only // Layer 2 and 3 : 1 color/line // Layer 4 : 1 color / 48x1 block // TODO: handle filesize if (!(file = fopen(filename,"wb"))) { File_error = 1; return; } setvbuf(file, NULL, _IOFBF, 64*1024); // Write layer 0 Set_saving_layer(context, 0); Write_byte(file, Get_pixel(context, 0, 0)); for(ty = 0; ty < 256; ty++) { Set_saving_layer(context, 1); Write_byte(file, Get_pixel(context, 0, ty)); Set_saving_layer(context, 2); Write_byte(file, Get_pixel(context, 0, ty)); Set_saving_layer(context, 3); for(tx = 0; tx < 6; tx++) { Write_byte(file, Get_pixel(context, tx*48, ty)); } } fclose(file); // Now the pixeldata filename[strlen(filename) - 3] = 0; strcat(filename,"gfx"); if (!(file = fopen(filename, "wb"))) { File_error = 2; return; } setvbuf(file, NULL, _IOFBF, 64*1024); Set_saving_layer(context, 4); for (ty = 0; ty < 256; ty++) { for (tx = 0; tx < 48*6; tx+=4) { byte code = 0; byte pixel; pixel = 3-Get_pixel(context, tx+3, ty); code |= (pixel&2)>>1 | ((pixel & 1)<<4); pixel = 3-Get_pixel(context, tx+2, ty); code |= ((pixel&2)<<0) | ((pixel & 1)<<5); pixel = 3-Get_pixel(context, tx+1, ty); code |= ((pixel&2)<<1) | ((pixel & 1)<<6); pixel = 3-Get_pixel(context, tx, ty); code |= ((pixel&2)<<2) | ((pixel & 1)<<7); Write_byte(file, code); } } fclose(file); File_error = 0; } /* Amstrad CPC 'PPH' for Perfect Pix. // This is a format designed by Rhino. // There are 3 modes: // - Mode 'R': 1:1 pixels, 16 colors from the CPC 27 color palette. // (this is implemented on CPC as two pictures with wide pixels, the "odd" one // being shifted half a pixel to the right), and flipping) // - Mode 'B0': wide pixels, up to 126 out of 378 colors. // (this is implemented as two pictures with wide pixels, sharing the same 16 // color palette, and flipping) // - Mode 'B1': 1:1 pixels, 1 fixed color, up to 34 palettes of 9 colors // (actually 4 colors + flipping) // // - The standard CPC formats can also be encapsulated into a PPH file. */ void Test_PPH(T_IO_Context * context) { FILE *file; char buffer[MAX_PATH_CHARACTERS]; long file_size; int w; int expected; Get_full_filename(buffer, context->File_name, context->File_directory); File_error = 1; if ((file = fopen(buffer, "rb"))) { // First check file size is large enough to hold the header file_size = File_length_file(file); if (file_size < 11) { File_error = 1; goto abort; } // File is large enough for the header, now check if the data makes some sense fread(buffer, 1, 6, file); if (buffer[0] > 5) { // Unknown mode File_error = 2; goto abort; } w = buffer[1] | (buffer[2] << 8); if (w < 2 || w > 384) { // Invalid width File_error = 3; goto abort; } w = buffer[3] | (buffer[4] << 8); if (w < 1 || w > 272) { // Invalid height File_error = 4; goto abort; } if (buffer[5] < 1 || buffer[5] > 28) { // Invalid palettes count File_error = 5; goto abort; } expected = 6; // Size of header switch(buffer[0]) { case 0: case 3: case 4: // Palette size should be 16 bytes, only 1 palette. if (buffer[5] != 1) { File_error = 7; goto abort; } expected += 16; break; case 1: case 5: expected += buffer[5] * 5 - 1; break; case 2: // Palete size should be 2 bytes if (buffer[5] != 1) { File_error = 7; goto abort; } expected += 2; break; } if (file_size != expected) { File_error = 6; goto abort; } File_error = 0; } else { File_error = 8; } abort: fclose(file); // TODO: check existence of .ODD/.EVE files with the same name } static uint8_t pph_blend(uint8_t a, uint8_t b) { uint32_t h,l; if (a > b) { h = a; l = b; } else { h = b; l = a; } return (23 * h + 9 * l) / 32; } void Load_PPH(T_IO_Context* context) { FILE *file; FILE *feven; char filename[MAX_PATH_CHARACTERS]; // Read in the header uint8_t mode; uint16_t width; uint16_t height; uint8_t npal; int i,j; uint8_t a,b,c,d; int file_size; char* ext; uint8_t pl[16]; static const T_Components CPCPAL[27] = { { 0x00, 0x02, 0x01 }, { 0x00, 0x02, 0x6B }, { 0x0C, 0x02, 0xF4 }, { 0x6C, 0x02, 0x01 }, { 0x69, 0x02, 0x68 }, { 0x6C, 0x02, 0xF2 }, { 0xF3, 0x05, 0x06 }, { 0xF0, 0x02, 0x68 }, { 0xF3, 0x02, 0xF4 }, { 0x02, 0x78, 0x01 }, { 0x00, 0x78, 0x68 }, { 0x0C, 0x7B, 0xF4 }, { 0x6E, 0x7B, 0x01 }, { 0x6E, 0x7D, 0x6B }, { 0x6E, 0x7B, 0xF6 }, { 0xF3, 0x7D, 0x0D }, { 0xF3, 0x7D, 0x6B }, { 0xFA, 0x80, 0xF9 }, { 0x02, 0xF0, 0x01 }, { 0x00, 0xF3, 0x6B }, { 0x0F, 0xF3, 0xF2 }, { 0x71, 0xF5, 0x04 }, { 0x71, 0xF3, 0x6B }, { 0x71, 0xF3, 0xF4 }, { 0xF3, 0xF3, 0x0D }, { 0xF3, 0xF3, 0x6D }, { 0xFF, 0xF3, 0xF9 } }; Get_full_filename(filename, context->File_name, context->File_directory); if (!(file = fopen(filename, "rb"))) { File_error = 1; return; } file_size=File_length_file(file); Read_byte(file, &mode); Read_word_le(file, &width); Read_word_le(file, &height); Read_byte(file, &npal); if (npal > 16) npal = 16; // Switch to the proper aspect ratio switch (mode) { case 0: case 4: context->Ratio = PIXEL_WIDE; width /= 2; break; case 2: context->Ratio = PIXEL_TALL; break; case 1: case 5: case 3: context->Ratio = PIXEL_SIMPLE; break; } Pre_load(context, width, height, file_size, FORMAT_PPH, context->Ratio, 0); context->Width = width; context->Height = height; // First of all, detect the mode // 0, 1, 2 > Load as with SCR files? // R(3) > Load as single layer, square pixels, 16 colors // B0(4) > Load as single layer, wide pixels, expand palette with colorcycling // B1(5) > Load as ??? // Maybe special mode similar to mode5, with 2 layers + auto-flicker? switch (mode) { case 0: case 3: // R // 16-color palette for (i = 0; i < 16; i++) { uint8_t color; Read_byte(file, &color); context->Palette[i] = CPCPAL[color]; } break; case 1: case 5: // B1 { // Single or multiple 4-color palettes uint8_t base[4]; for (j = 0; j < npal; j++) { for (i = 0; i < 4; i++) { Read_byte(file,&base[i]); } for (i = 0; i < 16; i++) { context->Palette[i + 16*j].R = pph_blend( CPCPAL[base[i & 3]].R, CPCPAL[base[i >> 2]].R); context->Palette[i + 16*j].G = pph_blend( CPCPAL[base[i & 3]].G, CPCPAL[base[i >> 2]].G); context->Palette[i + 16*j].B = pph_blend( CPCPAL[base[i & 3]].B, CPCPAL[base[i >> 2]].B); } // TODO this byte marks where this palette stops being used and the // next starts. We must handle this! Read_byte(file,&pl[j]); } pl[npal - 1] = 255; break; } case 2: // Single 2-color palette break; case 4: // B0 { // Single 16-color palette + flipping, need to expand palette and // setup colorcycling ranges. uint8_t base[16]; for (i = 0; i < 16; i++) { Read_byte(file,&base[i]); } for (i = 0; i < 256; i++) { context->Palette[i].R = pph_blend( CPCPAL[base[i & 15]].R, CPCPAL[base[i >> 4]].R); context->Palette[i].G = pph_blend( CPCPAL[base[i & 15]].G, CPCPAL[base[i >> 4]].G); context->Palette[i].B = pph_blend( CPCPAL[base[i & 15]].B, CPCPAL[base[i >> 4]].B); } } break; } fclose(file); // Load the picture data // There are two pages, each storing bytes in the CPC vram format but lines in // linear order. ext = filename + strlen(filename) - 3; ext[0] = 'O'; ext[1] = 'D'; ext[2] = 'D'; file = fopen(filename, "rb"); ext[0] = 'E'; ext[1] = 'V'; ext[2] = 'E'; feven = fopen(filename, "rb"); c = 0; d = 0; for (j = 0; j < height; j++) { for (i = 0; i < width;) { uint8_t even, odd; Read_byte(feven, &even); Read_byte(file, &odd); switch (mode) { case 4: a = ((even & 0x02) << 2) | ((even & 0x08) >> 2) | ((even & 0x20) >> 3) | ((even & 0x80) >> 7); a <<= 4; a |= ((odd & 0x02) << 2) | (( odd & 0x08) >> 2) | (( odd & 0x20) >> 3) | (( odd & 0x80) >> 7); b = ((even & 0x01) << 3) | ((even & 0x04) >> 1) | ((even & 0x10) >> 2) | ((even & 0x40) >> 6); b <<= 4; b |= ((odd & 0x01) << 3) | (( odd & 0x04) >> 1) | (( odd & 0x10) >> 2) | (( odd & 0x40) >> 6); Set_pixel(context, i++, j, a); Set_pixel(context, i++, j, b); break; case 3: a = ((even & 0x02) << 2) | ((even & 0x08) >> 2) | ((even & 0x20) >> 3) | ((even & 0x80) >> 7); b = (( odd & 0x02) << 2) | (( odd & 0x08) >> 2) | (( odd & 0x20) >> 3) | (( odd & 0x80) >> 7); c = ((even & 0x01) << 3) | ((even & 0x04) >> 1) | ((even & 0x10) >> 2) | ((even & 0x40) >> 6); d = (( odd & 0x01) << 3) | (( odd & 0x04) >> 1) | (( odd & 0x10) >> 2) | (( odd & 0x40) >> 6); Set_pixel(context, i++, j, j & 1 ? b : a); Set_pixel(context, i++, j, j & 1 ? a : b); Set_pixel(context, i++, j, j & 1 ? d : c); Set_pixel(context, i++, j, j & 1 ? c : d); break; case 5: if (d >= pl[c]) { d = 0; c++; } a = ((even & 0x80) >> 6) | ((even & 0x08) >> 3); b = (( odd & 0x80) >> 6) | (( odd & 0x08) >> 3); Set_pixel(context, i++, j, a + (b << 2) + c * 16); a = ((even & 0x40) >> 5) | ((even & 0x04) >> 2); b = (( odd & 0x40) >> 5) | (( odd & 0x04) >> 2); Set_pixel(context, i++, j, a + (b << 2) + c * 16); a = ((even & 0x20) >> 4) | ((even & 0x02) >> 1); b = (( odd & 0x20) >> 4) | (( odd & 0x02) >> 1); Set_pixel(context, i++, j, a + (b << 2) + c * 16); a = ((even & 0x10) >> 3) | ((even & 0x01) >> 0); b = (( odd & 0x10) >> 3) | (( odd & 0x01) >> 0); Set_pixel(context, i++, j, a + (b << 2) + c * 16); break; default: File_error = 2; return; } } d++; } fclose(file); fclose(feven); File_error = 0; } void Save_PPH(T_IO_Context* context) { (void)context; // unused // TODO // Detect mode // Wide pixels => B0 (4) // Square pixels: // - 16 colors used => R // - more colors used => B1 (if <16 colors per line) // Check palette // B0: use diagonal: 0, 17, 34, ... (assume the other are mixes) // R: use 16 used colors (or 16 first?) // B1: find the 16 colors used in a line? Or assume they are in-order already? } grafx2_2.4+git20180105/src/buttons.h0000664000000000000000000003471613223665306015411 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ //////////////////////////////////////////////////////////////////////////// ///@file buttons.h /// Almost all the editor actions that are called by the menu are here. //////////////////////////////////////////////////////////////////////////// #ifndef __BOUTONS_H_ #define __BOUTONS_H_ #include "struct.h" #include "loadsave.h" void Stencil_update_color(byte color); void Stencil_tag_color(byte color, byte tag_color); /*! Displays an error message when there is no more memory for the requested operation. */ void Message_out_of_memory(void); /*! Displays the splash screen at program startup. */ void Button_Message_initial(void); /*! Changes brush shape. This function saves the current brush shape and swith to the default one (single pixel brush) for the filler and the color picker. These functions don't need (and will not work with) a custom brush. */ void Change_paintbrush_shape(byte shape); // Boutons relatifs aux couleurs /*! Callback for the palette scroller buttons left click. Scrolls the menubar palette one column to the left. */ void Button_Pal_left(void); /*! Callback for the palette scroller buttons right click. Scrolls the menubar palette faster to the left. */ void Button_Pal_left_fast(void); /*! Callback for the palette scroller buttons left click. Scrolls the menubar palette one column to the right. */ void Button_Pal_right(void); /*! Callback for the palette scroller buttons right click. Scrolls the menubar palette faster to the right. */ void Button_Pal_right_fast(void); /*! Callback for the palette color buttons left click. Selects the foreground drawing color when clicking on the menubar palette. */ void Button_Select_forecolor(void); /*! Callback for the palette color buttons right click. Selects the background drawing color when clicking on the menubar palette. */ void Button_Select_backcolor(void); // Boutons relatifs au pinceaux /*! Callback for the brush button left click. Selects the monochrome brush mode when right clicking on the brush button. */ void Button_Brush_monochrome(void); /*! Callback for the brush button right click. Displays the "Paintbrush menu". */ void Button_Paintbrush_menu(void); // Boutons relatifs au mode de dessin main leve /*! Callback for the freehand draw button left click. Selects freehand drawing mode, depending on the current state of the freehand button. */ void Button_Draw(void); /*! Callback for the freehand draw button right click. Cycles the drawing modes for the freehand tool. */ void Button_Draw_switch_mode(void); // Dessin par ligne /*! Callback for the lines button left click. Selects lines drawing mode, depending on the current state of the lines button. */ void Button_Lines(void); /*! Callback for the lines button right click. Cycles the drawing modes for the lines tool. */ void Button_Lines_switch_mode(void); // Button relatif au remplissage /*! Callback for the fill button left click. Start the filling operation. */ void Button_Fill(void); /*! Callback for the fill button right click. Start the color replace operation. */ void Button_Replace(void); /*! Disable and release the fill button. Restores the cursor (custom brushes are disabled for the fill operation). Cleans the status bar if the color replacement tool put a preview color inside it. */ void Button_Unselect_fill(void); // Spray /*! Callback for the spray button left click. Start the spray operation. */ void Button_Airbrush(void); /*! Callback for the spray button right click. Opens the spray's setup menu. */ void Button_Airbrush_menu(void); // Courbes de Bzier /*! Callback for the curves button left click. Start curve operation according to the selected mode. */ void Button_Curves(void); /*! Callback for the curves button right click. Select the curve mode (1-point, 2-point) */ void Button_Curves_switch_mode(void); // Boutons relatifs aux rectangles pleins et vides /*! Callback for the empty rectangle button. Start the rectangle operation. */ void Button_Empty_rectangle(void); /*! Callback for the filled rectangle button. Start the filled rectangle operation. */ void Button_Filled_rectangle(void); // Boutons relatifs au texte /*! Callback for the text button. Opens the text setup window. */ void Button_Text(void); // Boutons relatifs aux dgrads /*! Callback for the gradation button. Opens the "Gradation menu". */ void Button_Gradients(void); /*! Gets the informations from the gradations table and set the global vars for the current gradation. @param index index of the selected gradation */ void Load_gradient_data(int index); // Boutons relatifs aux cercles (ellipses) dgrad(e)s /*! Callback for the gradation circle button left click. Starts drawing a gradation circle. */ void Button_Grad_circle(void); /*! Callback for the gradation circle right click. Starts drawing a gradation ellipsis. */ void Button_Grad_ellipse(void); /*! Callback for the gradation rectangle button. Starts the gradation rectangle drawing operation. */ void Button_Grad_rectangle(void); // Boutons relatifs aux cercles (ellipses) plein(e)s et vides /*! Callback for the circle button left click. Starts drawing an empty circle */ void Button_Empty_circle(void); /*! Callback for the circle button left click. Starts drawing an empty ellipsis */ void Button_Empty_ellipse(void); /*! Callback for the filled circle button ledt click. Starts drawing a filled circle. */ void Button_Filled_circle(void); /*! Callback for the filled circle right click. Starts drawing a filled ellipsis. */ void Button_Filled_ellipse(void); // Boutons relatifs aux polygones vides et pleins /*! Callback for the polyline button left click. Starts drawing a polygon. */ void Button_polygon(void); /*! Callback for the polyline right click. Starts drawing a polyform. */ void Button_Polyform(void); /*! Callback for the polyfill button left click. Starts drawing a filled polygon. */ void Button_Polyfill(void); /*! Callback for the polyfill button right click. Starts drawing a filled polyform. */ void Button_Filled_polyform(void); // Boutons d'ajustement de l'image /*! Callback for the adjust picture button. Start the adjust picture operation. */ void Button_Adjust(void); // Gestion du mode Shade /*! Callback for the shade button (in the FX window). Toogle the shade mode. */ void Button_Shade_mode(void); /*! Callback for the QSHade button (in the FX window). Toogle the Quick Shade effect. */ void Button_Quick_shade_mode(void); /*! Callback for the Shade button (in the FX window) right click. Displays the shade setup menu. */ void Button_Shade_menu(void); // Gestion du Stencil /*! Callback for the Stencil button (in the FX window) left click. Toogle stencil mode. */ void Button_Stencil_mode(void); /*! Callback for the Stencil button (in the FX window) right click. Displays the stencil setup menu. */ void Button_Stencil_menu(void); // Gestion du Masque /*! Callback for the Mask button (in the FX window) left click. Toogles the mask mode/ */ void Button_Mask_mode(void); /*! Callback for the Mask button (in the FX window) right click. Displays the mask setup menu. */ void Button_Mask_menu(void); // Mode grille (Snap) /*! Callback for the Grid button (in the FX window) left click. Toogle the grid. */ void Button_Snap_mode(void); /*! Callback for the Grid button (in the FX window) right click. Displays the grid setup menu. */ void Button_Grid_menu(void); /*! Callback to toggle the grid visible in the magnified view. */ void Button_Show_grid(void); // Mode trame (Sieve) /*! In the sieve window, copy one of the presets patterns to the current one. @param index Index of the pattern to copy */ void Copy_preset_sieve(byte index); /*! In the sieve window, swaps black and white in the current pattern. */ void Invert_trame(void); /*! Callback for the Sieve button (in the FX window) left click. Toogle sieve mode. */ void Button_Sieve_mode(void); /*! Callback for the Sieve button (in the FX window) right click. Displays the sieve setup menu. */ void Button_Sieve_menu(void); // Mode Smooth /*! Callback for the smooth button (in the FX window) left click. Toogles smooth mode. */ void Button_Smooth_mode(void); /*! Callback for the Smooth button (in the FX window) right click. Displays the smooth setup menu. */ void Button_Smooth_mode(void); // Boutons relatifs au mode Colorize /*! Computes the tables used by the transparency/colorize mode. These tables are used to match the drawing color*picture color to the color that is painted on screen. */ void Compute_colorize_table(void); /*! Callback for the Tranparency button (in the FX window) left click. Toogles transparent drawing mode. */ void Button_Colorize_mode(void); /*! Callback for the Transparency button (in the FX window) right click. Displays the tranparency setup menu. */ void Button_Colorize_menu(void); // Boutons relatifs au mode Tiling /*! Callback for the Tiling button (in the FX window) left click. Toogles tiling mode. */ void Button_Tiling_mode(void); /*! Callback for the Tiling button (in the FX window) right click. Displays the tiling setup menu. */ void Button_Tiling_menu(void); void Button_Constraint_mode(void); void Button_Constraint_menu(void); void Button_Tilemap_mode(void); void Button_Tilemap_menu(void); /*! Callback for the command that turns off all drawaing effects. */ void Effects_off(void); // Menu des effets /*! Callback for the effects button click. Displays the effect selection menu. */ void Button_Effects(void); // Prise de brosse /*! Callback for the brush button left click. Start the brush picking operation. */ void Button_Brush(void); /*! Callback for the brush button right click. Activates the last captured custom brush. */ void Button_Restore_brush(void); /*! Disables the custom brush and set back a regular one. */ void Button_Unselect_brush(void); // Prise de brosse au lasso /*! Callback for the freehand brush pick button left click. Starts freehand brush picking operation. */ void Button_Lasso(void); /*! Disables the custom freehand brush and set back a regular one. */ void Button_Unselect_lasso(void); // Button relatifs la pipette /*! Starts the color picking operation. */ void Button_Colorpicker(void); /*! Disables the color picker button and get back to the previously selected drawing mode. */ void Button_Unselect_colorpicker(void); /*! Swap fore- and background colors. */ void Button_Invert_foreback(void); // Mode loupe /*! Enters magnify mode. */ void Button_Magnify(void); /*! Displays magnify menu. */ void Button_Magnify_menu(void); /*! Exit magnify mode. */ void Button_Unselect_magnifier(void); // Les diffrents effets sur la brosse /*! Display the Brush effects window. */ void Button_Brush_FX(void); // Boutons relatifs aux diffrentes pages /*! Swap main and spare drawing pages. */ void Button_Page(void); /*! Copy main page to spare page. */ void Button_Copy_page(void); /*! Copy only pixel data from main page to spare page (no palette copy). */ void Copy_image_only(void); /*! Kill (free from memory) the current page. */ void Button_Kill(void); // Boutons relatifs aux changements de rsolution et de taille d'image /*! Display the screenmode menu. */ void Button_Resolution(void); /*! Set the screen to the "safe resolution" (320x200 pixel window). */ void Button_Safety_resolution(void); // Boutons relatifs aux chargements et sauvegardes /*! Opens the load file dialog. */ void Button_Load(void); /*! Reload current picture from disk. */ void Button_Reload(void); /*! Open the save file dialog. */ void Button_Save(void); /*! Saves the current file without asking for a new name. */ void Button_Autosave(void); // Rglage des paramtres de l'utilisateur /*! Display the setting menu. */ void Button_Settings(void); /*! Display the skin selector window. */ void Button_Skins(void); // Annulation de la dernire modification /*! Undo the last modification to the picture. */ void Button_Undo(void); /*! Redo an operation that has been undone. */ void Button_Redo(void); // Boutons relatifs aux effacements d'images /*! Clear the whole screen with black (color index 0). */ void Button_Clear(void); /*! Clear the screen with the selected backcolor. */ void Button_Clear_with_backcolor(void); // Quitter le programme /*! Quits the program. Display a requester to save the changes to the picture before exiting if the pic was modified since last save. */ void Button_Quit(void); // Cacher le menu /*! Hides the menubar. */ void Button_Hide_menu(void); /*! Shows a dropdown panel where you can choose which toolbars are visible */ void Button_Toggle_toolbar(void); /*! Hides all toolbars (except status) or shows them again */ void Button_Toggle_all_toolbars(void); /*! Load picture from file. */ void Load_picture(byte image); /*! Save picture to file. */ void Save_picture(enum CONTEXT_TYPE type); /*! Generic color tagging menu, for various effects. */ void Menu_tag_colors(char * window_title, byte * table, byte * mode, byte can_cancel, const char *help_section, word close_shortcut ); /*! Display the menu for the smooth effect. */ void Button_Smooth_menu(void); /*! Toogles the smear mode. */ void Button_Smear_mode(void); void Button_Brush_container(void); byte Store_paintbrush(int index); void Select_paintbrush(int index); byte Any_effect_active(void); #endif grafx2_2.4+git20180105/src/setup.h0000664000000000000000000001207313223665307015044 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file setup.h /// Functions that determine where grafx2 is running, finds its data, and /// reads and writes configuration files. ////////////////////////////////////////////////////////////////////////////// /// /// Determine which directory contains the executable. /// - IN: Main's argv[0], some platforms need it, some don't. /// - OUT: Write into program_dir. Trailing / or \ is kept. /// Note : in fact this is only used to check for the datafiles and fonts in this same directory. void Set_program_directory(const char * argv0,char * program_dir); /// /// Determine which directory contains the read-only data. /// IN: The directory containing the executable /// OUT: Write into data_dir. Trailing / or \ is kept. void Set_data_directory(const char * program_dir, char * data_dir); /// /// Determine which directory should store the user's configuration. /// For most Unix and Windows platforms: /// If a config file already exists in program_dir, it will return it in priority /// (Useful for development, and possibly for upgrading from DOS version) /// If the standard directory doesn't exist yet, this function will attempt /// to create it ($(HOME)/.grafx2, or %APPDATA%\\GrafX2) /// If it cannot be created, this function will return the executable's /// own directory. /// IN: The directory containing the executable /// OUT: Write into config_dir. Trailing / or \ is kept. void Set_config_directory(const char * program_dir, char * config_dir); /// Name of the subdirectory containing fonts, under the data directory (::Set_data_directory()) #if defined (__MINT__) #define FONTS_SUBDIRECTORY "FONTS" #else #define FONTS_SUBDIRECTORY "fonts" #endif /// Name of the subdirectory containing fonts, under the data directory (::Set_data_directory()) #if defined (__MINT__) #define SKINS_SUBDIRECTORY "SKINS" #else #define SKINS_SUBDIRECTORY "skins" #endif /// Name of the subdirectory containing scripts #if defined (__MINT__) #define SCRIPTS_SUBDIRECTORY "SCRIPTS" #else #define SCRIPTS_SUBDIRECTORY "scripts" #endif /// LUA directory prefix #if defined (__MINT__) #define LUALIB_SUBDIRECTORY "LIBS" #else #define LUALIB_SUBDIRECTORY "libs" #endif /// Name of the binary file containing some configuration settings. #if defined (__MINT__) #define CONFIG_FILENAME "GFX2.CFG" #else #define CONFIG_FILENAME "gfx2.cfg" #endif /// Name of the text file containing some settings in INI format. #if defined (__MINT__) #define INI_FILENAME "GFX2.INI" #else #define INI_FILENAME "gfx2.ini" #endif /// Name of the backup of the INI file. #if defined (__MINT__) #define INISAVE_FILENAME "GFX2.$$$" #else #define INISAVE_FILENAME "gfx2.$$$" #endif /// Name of the default .INI file (read-only: gives .INI format and defaults) #if defined (__MINT__) #define INIDEF_FILENAME "GFX2DEF.INI" #else #define INIDEF_FILENAME "gfx2def.ini" #endif /// Prefix for filenames of safety backups (main) #if defined (__MINT__) #define SAFETYBACKUP_PREFIX_A "A" #else #define SAFETYBACKUP_PREFIX_A "a" #endif /// Prefix for filenames of safety backups (spare) #if defined (__MINT__) #define SAFETYBACKUP_PREFIX_B "B" #else #define SAFETYBACKUP_PREFIX_B "b" #endif /// Name of the image file that serves as an application icon. #if defined (__MINT__) #define GFX2_ICON_FILENAME "GFX2.GIF" #else #define GFX2_ICON_FILENAME "gfx2.gif" #endif /// Name of the image file for the default (and fallback) GUI skin. #if defined (__MINT__) #define DEFAULT_SKIN_FILENAME "SDPAINT.PNG" #else #define DEFAULT_SKIN_FILENAME "skin_DPaint.png" #endif /// Name of the image file for the default (and fallback) 8x8 font. #if defined (__MINT__) #define DEFAULT_FONT_FILENAME "FDPAINT.PNG" #else #define DEFAULT_FONT_FILENAME "font_DPaint.png" #endif /// File extension for safety backups #if defined (__MINT__) #define BACKUP_FILE_EXTENSION ".BKP" #else #define BACKUP_FILE_EXTENSION ".bkp" #endif /// File prefix for fonts #if defined (__MINT__) #define FONT_PREFIX "F" #else #define FONT_PREFIX "font_" #endif /// File prefix for skins #if defined (__MINT__) #define SKIN_PREFIX "S" #else #define SKIN_PREFIX "skin_" #endif grafx2_2.4+git20180105/src/pxtall3.h0000664000000000000000000000631113223665306015270 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file pxtall3.h /// Renderer for 3/4 tall pixels (3x4). ////////////////////////////////////////////////////////////////////////////// #include "struct.h" void Pixel_tall3 (word x,word y,byte color); byte Read_pixel_tall3 (word x,word y); void Block_tall3 (word start_x,word start_y,word width,word height,byte color); void Pixel_preview_normal_tall3 (word x,word y,byte color); void Pixel_preview_magnifier_tall3 (word x,word y,byte color); void Horizontal_XOR_line_tall3 (word x_pos,word y_pos,word width); void Vertical_XOR_line_tall3 (word x_pos,word y_pos,word height); void Display_brush_color_tall3 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_brush_mono_tall3 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); void Clear_brush_tall3 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); void Remap_screen_tall3 (word x_pos,word y_pos,word width,word height,byte * conversion_table); void Display_part_of_screen_tall3 (word width,word height,word image_width); void Display_line_on_screen_tall3 (word x_pos,word y_pos,word width,byte * line); void Read_line_screen_tall3 (word x_pos,word y_pos,word width,byte * line); void Display_part_of_screen_scaled_tall3(word width,word height,word image_width,byte * buffer); void Display_brush_color_zoom_tall3 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); void Display_brush_mono_zoom_tall3 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); void Clear_brush_scaled_tall3 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); void Display_brush_tall3 (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_line_on_screen_fast_tall3 (word x_pos,word y_pos,word width,byte * line); grafx2_2.4+git20180105/src/init.c0000664000000000000000000030505713223665306014650 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2009 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ // Signal handler: I activate it for the two platforms who certainly // support them. Feel free to check with others. #if defined(__WIN32__) || defined(__linux__) #define GRAFX2_CATCHES_SIGNALS #endif #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include #include #endif #include //#include #include #ifndef __VBCC__ #include #endif #include #include #include #include #if defined(__WIN32__) #include // GetLogicalDrives(), GetDriveType(), DRIVE_* #endif #ifndef __GP2X__ #include #endif #if defined (__MINT__) #include #endif #ifdef GRAFX2_CATCHES_SIGNALS #include #endif #include "buttons.h" #include "const.h" #include "errors.h" #include "global.h" #include "graph.h" #include "init.h" #include "io.h" #include "factory.h" #include "help.h" #include "hotkeys.h" #include "keyboard.h" #include "loadsave.h" // Image_emergency_backup #include "misc.h" #include "mountlist.h" // read_file_system_list #include "operatio.h" #include "palette.h" #include "sdlscreen.h" #include "setup.h" #include "struct.h" #include "transform.h" #include "windows.h" #include "layers.h" #include "special.h" char Gui_loading_error_message[512]; // Rechercher la liste et le type des lecteurs de la machine #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) void bstrtostr( BSTR in, STRPTR out, TEXT max ); #endif // Fonctions de lecture dans la skin de l'interface graphique byte GUI_seek_down(SDL_Surface *gui, int *start_x, int *start_y, byte neutral_color,char * section) { byte color; int y; y=*start_y; *start_x=0; do { color=Get_SDL_pixel_8(gui,*start_x,y); if (color!=neutral_color) { *start_y=y; return 0; } y++; } while (yh); sprintf(Gui_loading_error_message, "Error in skin file: Was looking down from %d,%d for a '%s', and reached the end of the image\n", *start_x, *start_y, section); return 1; } byte GUI_seek_right(SDL_Surface *gui, int *start_x, int start_y, byte neutral_color, char * section) { byte color; int x; x=*start_x; do { color=Get_SDL_pixel_8(gui,x,start_y); if (color!=neutral_color) { *start_x=x; return 0; } x++; } while (xw); sprintf(Gui_loading_error_message, "Error in skin file: Was looking right from %d,%d for a '%s', and reached the edege of the image\n", *start_x, start_y, section); return 1; } byte Read_GUI_block(T_Gui_skin *gfx, SDL_Surface *gui, int start_x, int start_y, void *dest, int width, int height, char * section, int type) { // type: 0 = normal GUI element, only 4 colors allowed // type: 1 = mouse cursor, 4 colors allowed + transparent // type: 2 = brush icon or sieve pattern (only gui->Color[3] and gui->Color_trans) // type: 3 = raw bitmap (splash screen) byte * dest_ptr=dest; int x,y; byte color; // Verification taille if (start_y+height>=gui->h || start_x+width>=gui->w) { sprintf(Gui_loading_error_message, "Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but it doesn't fit the image.\n", start_x, start_y, height, width, section); return 1; } for (y=start_y; yColor[0] && color != gfx->Color[1] && color != gfx->Color[2] && color != gfx->Color[3])) { sprintf(Gui_loading_error_message, "Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but at %d,%d a pixel was found with color %d which isn't one of the GUI colors (which were detected as %d,%d,%d,%d.\n", start_x, start_y, height, width, section, x, y, color, gfx->Color[0], gfx->Color[1], gfx->Color[2], gfx->Color[3]); return 1; } if (type==1 && (color != gfx->Color[0] && color != gfx->Color[1] && color != gfx->Color[2] && color != gfx->Color[3] && color != gfx->Color_trans)) { sprintf(Gui_loading_error_message, "Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but at %d,%d a pixel was found with color %d which isn't one of the mouse colors (which were detected as %d,%d,%d,%d,%d.\n", start_x, start_y, height, width, section, x, y, color, gfx->Color[0], gfx->Color[1], gfx->Color[2], gfx->Color[3], gfx->Color_trans); return 1; } if (type==2) { if (color != gfx->Color[3] && color != gfx->Color_trans) { sprintf(Gui_loading_error_message, "Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but at %d,%d a pixel was found with color %d which isn't one of the brush colors (which were detected as %d on %d.\n", start_x, start_y, height, width, section, x, y, color, gfx->Color[3], gfx->Color_trans); return 1; } // Conversion en 0/1 pour les brosses monochromes internes color = (color != gfx->Color_trans); } *dest_ptr=color; dest_ptr++; } } return 0; } byte Read_GUI_pattern(T_Gui_skin *gfx, SDL_Surface *gui, int start_x, int start_y, word *dest, char * section) { byte buffer[256]; int x,y; if (Read_GUI_block(gfx, gui, start_x, start_y, buffer, 16, 16, section, 2)) return 1; for (y=0; y<16; y++) { *dest=0; for (x=0; x<16; x++) { *dest=*dest | buffer[y*16+x]<Color_trans) { found=1; break; } } if (found) break; } // Locate first non-empty line found=0; for (start_y=0;start_y<14;start_y++) { for (x=0;x<29;x++) { if (cursor_buffer[start_y*29+x]!=gfx->Color_trans) { found=1; break; } } if (found) break; } gfx->Cursor_offset_X[cursor_number]=14-start_x; gfx->Cursor_offset_Y[cursor_number]=14-start_y; for (y=0;yCursor_sprite[cursor_number][y][x]=cursor_buffer[(start_y+y)*29+start_x+x]; } byte Parse_skin(SDL_Surface * gui, T_Gui_skin *gfx) { int i,j; int cursor_x=0,cursor_y=0; byte color; byte neutral_color; // color neutre utilise pour dlimiter les lments GUI int char_1=0; // Indices utiliss pour les 4 "fontes" qui composent les int char_2=0; // grands titres de l'aide. Chaque indice avance dans int char_3=0; // l'une des fontes dans l'ordre : 1 2 int char_4=0; // 3 4 byte mouse_cursor_area[31][29]; SDL_Palette * SDLPal; // Default palette if (!gui->format || gui->format->BitsPerPixel != 8) { sprintf(Gui_loading_error_message, "Not a 8-bit image"); return 1; } SDLPal=gui->format->palette; if (!SDLPal || SDLPal->ncolors!=256) { sprintf(Gui_loading_error_message, "Not a 256-color palette"); return 1; } // Read the default palette Get_SDL_Palette(SDLPal, gfx->Default_palette); // Carr "noir" gfx->Color[0] = Get_SDL_pixel_8(gui,cursor_x,cursor_y); do { if (++cursor_x>=gui->w) { sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==gfx->Color[0]); // Carr "fonc" gfx->Color[1] = color; do { if (++cursor_x>=gui->w) { sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==gfx->Color[1]); // Carr "clair" gfx->Color[2] = color; do { if (++cursor_x>gui->w) { sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==gfx->Color[2]); // Carr "blanc" gfx->Color[3] = color; do { if (++cursor_x>=gui->w) { sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==gfx->Color[3]); // Carr "transparent" gfx->Color_trans=color; do { if (++cursor_x>=gui->w) { sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==gfx->Color_trans); // Reste : couleur neutre neutral_color=color; cursor_x=0; cursor_y=1; while ((color=Get_SDL_pixel_8(gui,cursor_x,cursor_y))==gfx->Color[0]) { cursor_y++; if (cursor_y>=gui->h) { sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); return 1; } } // Menu if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "menu")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_block[0], Menu_bars[MENUBAR_TOOLS].Skin_width, Menu_bars[MENUBAR_TOOLS].Height,"menu",0)) return 1; // Preview cursor_x += Menu_bars[MENUBAR_TOOLS].Skin_width; if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "preview")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Preview, 173, 16, "preview", 0)) return 1; cursor_y+= Menu_bars[MENUBAR_TOOLS].Height; // Layerbar if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "layer bar")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Layerbar_block[0], 144, 10,"layer bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_LAYERS].Height; // Animbar if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "anim bar")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Animbar_block[0], 236, 14,"anim bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_ANIMATION].Height; // Status bar if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "status bar")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Statusbar_block[0], Menu_bars[MENUBAR_STATUS].Skin_width, Menu_bars[MENUBAR_STATUS].Height,"status bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_STATUS].Height; // Menu (selected) if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "selected menu")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_block[1], Menu_bars[MENUBAR_TOOLS].Skin_width, Menu_bars[MENUBAR_TOOLS].Height,"selected menu",0)) return 1; cursor_y+= Menu_bars[MENUBAR_TOOLS].Height; // Layerbar (selected) if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "selected layer bar")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Layerbar_block[1], 144, 10,"selected layer bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_LAYERS].Height; // Animbar (selected) if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "selected anim bar")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Animbar_block[1], 236, 14,"selected anim bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_ANIMATION].Height; // Status bar (selected) if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "selected status bar")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Statusbar_block[1], Menu_bars[MENUBAR_STATUS].Skin_width, Menu_bars[MENUBAR_STATUS].Height,"selected status bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_STATUS].Height; // Effects for (i=0; iEffect_sprite[i], EFFECT_SPRITE_WIDTH, EFFECT_SPRITE_HEIGHT, "effect sprite",0)) return 1; cursor_x+=EFFECT_SPRITE_WIDTH; } cursor_y+=EFFECT_SPRITE_HEIGHT; // Layer sprite for (j=0; j<3; j++) { for (i=0; i<16; i++) { if (i==0) { if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "layer sprite")) return 1; } else { if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "layer sprite")) return 1; } if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Layer_sprite[j][i], LAYER_SPRITE_WIDTH, LAYER_SPRITE_HEIGHT, "layer sprite",1)) return 1; cursor_x+=LAYER_SPRITE_WIDTH; } cursor_y+=LAYER_SPRITE_HEIGHT; } // Mouse cursors for (i=0; iMenu_sprite[0][i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "menu sprite",1)) return 1; cursor_x+=MENU_SPRITE_WIDTH; } cursor_y+=MENU_SPRITE_HEIGHT; // Menu sprites (selected) for (i=0; iMenu_sprite[1][i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "selected menu sprite",1)) return 1; cursor_x+=MENU_SPRITE_WIDTH; } cursor_y+=MENU_SPRITE_HEIGHT; // Drive sprites for (i=0; iIcon_sprite[i], ICON_SPRITE_WIDTH, ICON_SPRITE_HEIGHT, "sprite drive",1)) return 1; cursor_x+=ICON_SPRITE_WIDTH; } cursor_y+=ICON_SPRITE_HEIGHT; // Logo splash screen if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "logo menu")) return 1; if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Logo_grafx2, 231, 56, "logo menu",3)) return 1; cursor_y+=56; // Trames for (i=0; iSieve_pattern[i],"sieve pattern")) return 1; cursor_x+=16; } cursor_y+=16; // Help font: Normal for (i=0; i<256; i++) { // Each line holds 32 symbols if ((i%32)==0) { if (i!=0) cursor_y+=8; if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (norm)")) return 1; } else { if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (norm)")) return 1; } if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, &(gfx->Help_font_norm[i][0][0]), 6, 8, "help font (norm)",0)) return 1; cursor_x+=6; } cursor_y+=8; // Help font: Bold for (i=0; i<256; i++) { // Each line holds 32 symbols if ((i%32)==0) { if (i!=0) cursor_y+=8; if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (bold)")) return 1; } else { if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (bold)")) return 1; } if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, &(gfx->Bold_font[i][0][0]), 6, 8, "help font (bold)",0)) return 1; cursor_x+=6; } cursor_y+=8; // Help font: Title for (i=0; i<256; i++) { byte * dest; // Each line holds 64 symbols if ((i%64)==0) { if (i!=0) cursor_y+=8; if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (title)")) return 1; } else { if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (title)")) return 1; } if (i&1) if (i&64) dest=&(gfx->Help_font_t4[char_4++][0][0]); else dest=&(gfx->Help_font_t2[char_2++][0][0]); else if (i&64) dest=&(gfx->Help_font_t3[char_3++][0][0]); else dest=&(gfx->Help_font_t1[char_1++][0][0]); if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, dest, 6, 8, "help font (title)",0)) return 1; cursor_x+=6; } cursor_y+=8; // Copy unselected bitmaps to current ones memcpy(gfx->Menu_block[2], gfx->Menu_block[0], Menu_bars[MENUBAR_TOOLS].Skin_width*Menu_bars[MENUBAR_TOOLS].Height); memcpy(gfx->Layerbar_block[2], gfx->Layerbar_block[0], sizeof(gfx->Layerbar_block[0])); memcpy(gfx->Animbar_block[2], gfx->Animbar_block[0], sizeof(gfx->Animbar_block[0])); memcpy(gfx->Statusbar_block[2], gfx->Statusbar_block[0], Menu_bars[MENUBAR_STATUS].Skin_width*Menu_bars[MENUBAR_STATUS].Height); return 0; } T_Gui_skin * Load_graphics(const char * skin_file, T_Gradient_array *gradients) { T_Gui_skin * gfx; char filename[MAX_PATH_CHARACTERS]; SDL_Surface * gui; if (skin_file[0] == '\0') { sprintf(Gui_loading_error_message, "Wrong skin file name \"\"\n"); return NULL; } gfx = (T_Gui_skin *)malloc(sizeof(T_Gui_skin)); if (gfx == NULL) { sprintf(Gui_loading_error_message, "Not enough memory to read skin file\n"); return NULL; } // Read the "skin" file strcpy(filename,Data_directory); strcat(filename,SKINS_SUBDIRECTORY PATH_SEPARATOR); strcat(filename,skin_file); gui=Load_surface(filename, gradients); if (!gui) { sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n"); free(gfx); gfx = NULL; return NULL; } if (Parse_skin(gui, gfx)) { SDL_FreeSurface(gui); free(gfx); gfx = NULL; return NULL; } SDL_FreeSurface(gui); return gfx; } // ---- font loading ----- byte Parse_font(SDL_Surface * image, byte * font) { int character; byte color; int x, y; int chars_per_line; // Check image size if (image->w % 8) { sprintf(Gui_loading_error_message, "Error in font file: Image width is not a multiple of 8.\n"); return 1; } if (image->w * image->h < 8*8*256) { sprintf(Gui_loading_error_message, "Error in font file: Image is too small to be a 256-character 8x8 font.\n"); return 1; } chars_per_line = image->w/8; for (character=0; character < 256; character++) { for (y=0; y<8; y++) { for (x=0;x<8; x++) { // Pick pixel color = Get_SDL_pixel_8(image, (character % chars_per_line)*8+x, (character / chars_per_line)*8+y); if (color > 1) { sprintf(Gui_loading_error_message, "Error in font file: Only colors 0 and 1 can be used for the font.\n"); return 1; } // Put it in font. 0 = BG, 1 = FG. font[character*64 + y*8 + x]=color; } } } return 0; } byte * Load_font(const char * font_name) { byte * font; char filename[MAX_PATH_CHARACTERS]; SDL_Surface * image; if (font_name[0] == '\0') { sprintf(Gui_loading_error_message, "Wrong font name \"\"\n"); return NULL; } font = (byte *)malloc(8*8*256); if (font == NULL) { sprintf(Gui_loading_error_message, "Not enough memory to read font file\n"); return NULL; } // Read the file containing the image sprintf(filename,"%s" SKINS_SUBDIRECTORY "%s%s", Data_directory, PATH_SEPARATOR, font_name); image=Load_surface(filename, NULL); if (!image) { sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n"); free(font); return NULL; } if (Parse_font(image, font)) { SDL_FreeSurface(image); free(font); return NULL; } SDL_FreeSurface(image); return font; } // Initialisation des boutons: // Action factice: void Do_nothing(void) {} // Initialiseur d'un bouton: void Init_button(byte btn_number, const char* tooltip, word x_offset, word y_offset, word width, word height, byte shape, Func_action left_action, Func_action right_action, byte left_instant, byte right_instant, Func_action unselect_action, byte family) { Buttons_Pool[btn_number].X_offset =x_offset; Buttons_Pool[btn_number].Y_offset =y_offset; Buttons_Pool[btn_number].Width =width-1; Buttons_Pool[btn_number].Height =height-1; Buttons_Pool[btn_number].Pressed =0; Buttons_Pool[btn_number].Icon =-1; Buttons_Pool[btn_number].Shape =shape; Buttons_Pool[btn_number].Tooltip =tooltip; Buttons_Pool[btn_number].Left_action =left_action; Buttons_Pool[btn_number].Right_action =right_action; Buttons_Pool[btn_number].Left_instant =left_instant; Buttons_Pool[btn_number].Right_instant =right_instant; Buttons_Pool[btn_number].Unselect_action =unselect_action; Buttons_Pool[btn_number].Family =family; } // Initiliseur de tous les boutons: void Init_buttons(void) { byte button_index; for (button_index=0;button_index= MAX_VIDEO_MODES-1) { DEBUG("Error! Attempt to create too many videomodes. Maximum is:", MAX_VIDEO_MODES); return; } if (!fullscreen) supported = 128; // Prefere, non modifiable else if (SDL_VideoModeOK(width, height, 8, SDL_FULLSCREEN)) supported = 1; // supported else { // Non supporte : on ne le prend pas return; } Video_mode[Nb_video_modes].Width = width; Video_mode[Nb_video_modes].Height = height; Video_mode[Nb_video_modes].Mode = mode; Video_mode[Nb_video_modes].Fullscreen = fullscreen; Video_mode[Nb_video_modes].State = supported; Nb_video_modes ++; } // Utilis pour trier les modes retourns par SDL int Compare_video_modes(const void *p1, const void *p2) { const T_Video_mode *mode1 = (const T_Video_mode *)p1; const T_Video_mode *mode2 = (const T_Video_mode *)p2; // Tris par largeur if(mode1->Width - mode2->Width) return mode1->Width - mode2->Width; // Tri par hauteur return mode1->Height - mode2->Height; } // Initializes the list of available video modes void Set_all_video_modes(void) { SDL_Rect** Modes; Nb_video_modes=0; // The first mode will have index number 0. // It will be the default mode if an unsupported one // is requested in gfx2.ini #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(GCWZERO) // Native GP2X resolution Set_video_mode( 320,240,0, 1); #else // Window mode, with default size of 640x480 Set_video_mode( 640,480,0, 0); #endif Set_video_mode( 320,200,0, 1); Set_video_mode( 320,224,0, 1); #if !defined(__GP2X__) && !defined(__WIZ__) && !defined(__CAANOO__) && !defined(GCWZERO) // For the GP2X, this one is already declared above. Set_video_mode( 320,240,0, 1); #endif Set_video_mode( 320,256,0, 1); Set_video_mode( 320,270,0, 1); Set_video_mode( 320,282,0, 1); Set_video_mode( 320,300,0, 1); Set_video_mode( 320,360,0, 1); Set_video_mode( 320,400,0, 1); Set_video_mode( 320,448,0, 1); Set_video_mode( 320,480,0, 1); Set_video_mode( 320,512,0, 1); Set_video_mode( 320,540,0, 1); Set_video_mode( 320,564,0, 1); Set_video_mode( 320,600,0, 1); Set_video_mode( 360,200,0, 1); Set_video_mode( 360,224,0, 1); Set_video_mode( 360,240,0, 1); Set_video_mode( 360,256,0, 1); Set_video_mode( 360,270,0, 1); Set_video_mode( 360,282,0, 1); Set_video_mode( 360,300,0, 1); Set_video_mode( 360,360,0, 1); Set_video_mode( 360,400,0, 1); Set_video_mode( 360,448,0, 1); Set_video_mode( 360,480,0, 1); Set_video_mode( 360,512,0, 1); Set_video_mode( 360,540,0, 1); Set_video_mode( 360,564,0, 1); Set_video_mode( 360,600,0, 1); Set_video_mode( 400,200,0, 1); Set_video_mode( 400,224,0, 1); Set_video_mode( 400,240,0, 1); Set_video_mode( 400,256,0, 1); Set_video_mode( 400,270,0, 1); Set_video_mode( 400,282,0, 1); Set_video_mode( 400,300,0, 1); Set_video_mode( 400,360,0, 1); Set_video_mode( 400,400,0, 1); Set_video_mode( 400,448,0, 1); Set_video_mode( 400,480,0, 1); Set_video_mode( 400,512,0, 1); Set_video_mode( 400,540,0, 1); Set_video_mode( 400,564,0, 1); Set_video_mode( 400,600,0, 1); Set_video_mode( 640,224,0, 1); Set_video_mode( 640,240,0, 1); Set_video_mode( 640,256,0, 1); Set_video_mode( 640,270,0, 1); Set_video_mode( 640,300,0, 1); Set_video_mode( 640,350,0, 1); Set_video_mode( 640,400,0, 1); Set_video_mode( 640,448,0, 1); Set_video_mode( 640,480,0, 1); Set_video_mode( 640,512,0, 1); Set_video_mode( 640,540,0, 1); Set_video_mode( 640,564,0, 1); Set_video_mode( 640,600,0, 1); Set_video_mode( 800,600,0, 1); Set_video_mode(1024,768,0, 1); Modes = SDL_ListModes(NULL, SDL_FULLSCREEN); if ((Modes != (SDL_Rect**)0) && (Modes!=(SDL_Rect**)-1)) { int index; for (index=0; Modes[index]; index++) { int index2; #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(GCWZERO) // On the GP2X the first mode is not windowed, so include it in the search. index2=0; #else index2=1; #endif for (/**/; index2 < Nb_video_modes; index2++) if (Modes[index]->w == Video_mode[index2].Width && Modes[index]->h == Video_mode[index2].Height) { // Was already in the hard-coded list: ok, don't add. break; } if (index2 >= Nb_video_modes && Modes[index]->w>=320 && Modes[index]->h>=200) { // New mode to add to the list Set_video_mode(Modes[index]->w,Modes[index]->h,0, 1); } } // Sort the modes : those found by SDL were listed at the end. // Note that we voluntarily omit the first entry: the default mode. qsort(&Video_mode[1], Nb_video_modes - 1, sizeof(T_Video_mode), Compare_video_modes); } } //--------------------------------------------------------------------------- int Load_CFG(int reload_all) { FILE* Handle; char filename[MAX_PATH_CHARACTERS]; long file_size; int index,index2; T_Config_header cfg_header; T_Config_chunk Chunk; T_Config_shortcut_info cfg_shortcut_info; T_Config_video_mode cfg_video_mode; int key_conversion = 0; strcpy(filename,Config_directory); strcat(filename,"gfx2.cfg"); file_size=File_length(filename); if ((Handle=fopen(filename,"rb"))==NULL) return ERROR_CFG_MISSING; if ( (file_size<7) || (!Read_bytes(Handle, &cfg_header.Signature, 3)) || memcmp(cfg_header.Signature,"CFG",3) || (!Read_byte(Handle, &cfg_header.Version1)) || (!Read_byte(Handle, &cfg_header.Version2)) || (!Read_byte(Handle, &cfg_header.Beta1)) || (!Read_byte(Handle, &cfg_header.Beta2)) ) goto Erreur_lecture_config; // Version DOS de Robinson et X-Man if ( (cfg_header.Version1== 2) && (cfg_header.Version2== 0) && (cfg_header.Beta1== 96)) { // Les touches (scancodes) sont convertir) key_conversion = 1; } // Version SDL jusqu'a 98% else if ( (cfg_header.Version1== 2) && (cfg_header.Version2== 0) && (cfg_header.Beta1== 97)) { // Les touches 00FF (pas de touche) sont a comprendre comme 0x0000 key_conversion = 2; } // Version SDL else if ( (cfg_header.Version1!=VERSION1) || (cfg_header.Version2!=VERSION2) || (cfg_header.Beta1!=BETA1) || (cfg_header.Beta2!=BETA2) ) goto Erreur_config_ancienne; // - Lecture des infos contenues dans le fichier de config - while (Read_byte(Handle, &Chunk.Number)) { Read_word_le(Handle, &Chunk.Size); switch (Chunk.Number) { case CHUNK_KEYS: // Touches if (reload_all) { for (index=0; index<(long)(Chunk.Size/6); index++) { if (!Read_word_le(Handle, &cfg_shortcut_info.Number) || !Read_word_le(Handle, &cfg_shortcut_info.Key) || !Read_word_le(Handle, &cfg_shortcut_info.Key2) ) goto Erreur_lecture_config; else { if (key_conversion==1) { cfg_shortcut_info.Key = Key_for_scancode(cfg_shortcut_info.Key); } else if (key_conversion==2) { if (cfg_shortcut_info.Key == 0x00FF) cfg_shortcut_info.Key = 0x0000; if (cfg_shortcut_info.Key2 == 0x00FF) cfg_shortcut_info.Key2 = 0x0000; } for (index2=0; ((index2>8) { case 0 : Config_Key[Ordering[index2]&0xFF][0]=cfg_shortcut_info.Key; Config_Key[Ordering[index2]&0xFF][1]=cfg_shortcut_info.Key2; break; case 1 : Buttons_Pool[Ordering[index2]&0xFF].Left_shortcut[0] = cfg_shortcut_info.Key; Buttons_Pool[Ordering[index2]&0xFF].Left_shortcut[1] = cfg_shortcut_info.Key2; break; case 2 : Buttons_Pool[Ordering[index2]&0xFF].Right_shortcut[0] = cfg_shortcut_info.Key; Buttons_Pool[Ordering[index2]&0xFF].Right_shortcut[1] = cfg_shortcut_info.Key2; break; } } else goto Erreur_lecture_config; } } } else { if (fseek(Handle,Chunk.Size,SEEK_CUR)==-1) goto Erreur_lecture_config; } break; case CHUNK_VIDEO_MODES: // Modes vido for (index=0; index<(long)(Chunk.Size/5); index++) { if (!Read_byte(Handle, &cfg_video_mode.State) || !Read_word_le(Handle, &cfg_video_mode.Width) || !Read_word_le(Handle, &cfg_video_mode.Height) ) goto Erreur_lecture_config; #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) index2=0; #else index2=1; #endif for (/**/; index2> (i&7))) != 0); } } } else { if (fseek(Handle,Chunk.Size,SEEK_CUR)==-1) goto Erreur_lecture_config; } break; case CHUNK_SCRIPTS: if (reload_all) { int current_size=0; int current_script=0; while(current_size=10) break; } } break; default: // Chunk inconnu goto Erreur_lecture_config; } } if (fclose(Handle)) return ERROR_CFG_CORRUPTED; return 0; Erreur_lecture_config: fclose(Handle); return ERROR_CFG_CORRUPTED; Erreur_config_ancienne: fclose(Handle); return ERROR_CFG_OLD; } int Save_CFG(void) { FILE* Handle; int index; int index2; int modes_to_save; char filename[MAX_PATH_CHARACTERS]; T_Config_header cfg_header; T_Config_chunk Chunk; T_Config_shortcut_info cfg_shortcut_info={0,0,0}; T_Config_video_mode cfg_video_mode={0,0,0}; strcpy(filename,Config_directory); strcat(filename,CONFIG_FILENAME); if ((Handle=fopen(filename,"wb"))==NULL) return ERROR_SAVING_CFG; // Ecriture du header memcpy(cfg_header.Signature,"CFG",3); cfg_header.Version1=VERSION1; cfg_header.Version2=VERSION2; cfg_header.Beta1 =BETA1; cfg_header.Beta2 =BETA2; if (!Write_bytes(Handle, &cfg_header.Signature,3) || !Write_byte(Handle, cfg_header.Version1) || !Write_byte(Handle, cfg_header.Version2) || !Write_byte(Handle, cfg_header.Beta1) || !Write_byte(Handle, cfg_header.Beta2) ) goto Erreur_sauvegarde_config; // Enregistrement des touches Chunk.Number=CHUNK_KEYS; Chunk.Size=NB_SHORTCUTS*6; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; for (index=0; index>8) { case 0 : cfg_shortcut_info.Key =Config_Key[Ordering[index]&0xFF][0]; cfg_shortcut_info.Key2=Config_Key[Ordering[index]&0xFF][1]; break; case 1 : cfg_shortcut_info.Key =Buttons_Pool[Ordering[index]&0xFF].Left_shortcut[0]; cfg_shortcut_info.Key2=Buttons_Pool[Ordering[index]&0xFF].Left_shortcut[1]; break; case 2 : cfg_shortcut_info.Key =Buttons_Pool[Ordering[index]&0xFF].Right_shortcut[0]; cfg_shortcut_info.Key2=Buttons_Pool[Ordering[index]&0xFF].Right_shortcut[1]; break; } if (!Write_word_le(Handle, cfg_shortcut_info.Number) || !Write_word_le(Handle, cfg_shortcut_info.Key) || !Write_word_le(Handle, cfg_shortcut_info.Key2) ) goto Erreur_sauvegarde_config; } // D'abord compter les modes pour lesquels l'utilisateur a mis une prfrence modes_to_save=0; #if defined(__GP2X__) || defined (__WIZ__) || defined (__CAANOO__) index = 0; #else index = 1; #endif for (/**/; index> (i&7); if ((i&7) == 7) { // Write one byte if (!Write_byte(Handle, current_byte)) goto Erreur_sauvegarde_config; current_byte=0; } } // Remainder if ((i&7) != 0) { // Write one byte if (!Write_byte(Handle, current_byte)) goto Erreur_sauvegarde_config; } } } // Save script shortcuts { int i; Chunk.Number=CHUNK_SCRIPTS; // Compute size : Data stored as 10 pascal strings Chunk.Size=0; for (i=0; i<10; i++) { if (Bound_script[i]==NULL) Chunk.Size+=1; else Chunk.Size+=strlen(Bound_script[i])+1; } // Header if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; // Strings for (i=0; i<10; i++) { byte size=0; if (Bound_script[i]!=NULL) size=strlen(Bound_script[i]); if (!Write_byte(Handle, size)) goto Erreur_sauvegarde_config; if (size) if (!Write_bytes(Handle, Bound_script[i], size)) goto Erreur_sauvegarde_config; } } if (fclose(Handle)) return ERROR_SAVING_CFG; return 0; Erreur_sauvegarde_config: fclose(Handle); return ERROR_SAVING_CFG; } // (R)assigne toutes les valeurs de configuration par dfaut void Set_config_defaults(void) { int index, index2; // Keyboard shortcuts for (index=0; index>8) { case 0 : Config_Key[Ordering[index]&0xFF][0]=ConfigKey[index].Key; Config_Key[Ordering[index]&0xFF][1]=ConfigKey[index].Key2; break; case 1 : Buttons_Pool[Ordering[index]&0xFF].Left_shortcut[0] = ConfigKey[index].Key; Buttons_Pool[Ordering[index]&0xFF].Left_shortcut[1] = ConfigKey[index].Key2; break; case 2 : Buttons_Pool[Ordering[index]&0xFF].Right_shortcut[0] = ConfigKey[index].Key; Buttons_Pool[Ordering[index]&0xFF].Right_shortcut[1] = ConfigKey[index].Key2; break; } } // Shade Shade_current=0; for (index=0; index<8; index++) { Shade_list[index].Step=1; Shade_list[index].Mode=0; for (index2=0; index2<512; index2++) Shade_list[index].List[index2]=256; } // Shade par dfaut pour la palette standard for (index=0; index<7; index++) for (index2=0; index2<16; index2++) Shade_list[0].List[index*17+index2]=index*16+index2+16; Shade_list_to_lookup_tables(Shade_list[Shade_current].List, Shade_list[Shade_current].Step, Shade_list[Shade_current].Mode, Shade_table_left,Shade_table_right); // Mask for (index=0; index<256; index++) Mask_table[index]=0; // Stencil for (index=0; index<256; index++) Stencil[index]=1; // Smooth Smooth_matrix[0][0]=1; Smooth_matrix[0][1]=2; Smooth_matrix[0][2]=1; Smooth_matrix[1][0]=2; Smooth_matrix[1][1]=4; Smooth_matrix[1][2]=2; Smooth_matrix[2][0]=1; Smooth_matrix[2][1]=2; Smooth_matrix[2][2]=1; // Exclude colors for (index=0; index<256; index++) Exclude_color[index]=0; // Quick shade Quick_shade_step=1; Quick_shade_loop=0; // Grid Snap_width=Snap_height=8; Snap_offset_X=Snap_offset_Y=0; } #ifdef GRAFX2_CATCHES_SIGNALS #if defined(__WIN32__) #define SIGHANDLER_T __p_sig_fn_t #elif defined(__macosx__) typedef void (*sig_t) (int); #define SIGHANDLER_T sig_t #else #define SIGHANDLER_T __sighandler_t #endif // Memorize the signal handlers of SDL SIGHANDLER_T Handler_TERM=SIG_DFL; SIGHANDLER_T Handler_INT=SIG_DFL; SIGHANDLER_T Handler_ABRT=SIG_DFL; SIGHANDLER_T Handler_SEGV=SIG_DFL; SIGHANDLER_T Handler_FPE=SIG_DFL; void Sig_handler(int sig) { // Restore default behaviour signal(SIGTERM, Handler_TERM); signal(SIGINT, Handler_INT); signal(SIGABRT, Handler_ABRT); signal(SIGSEGV, Handler_SEGV); signal(SIGFPE, Handler_FPE); switch(sig) { case SIGTERM: case SIGINT: case SIGABRT: case SIGSEGV: Image_emergency_backup(); default: break; } } #endif void Init_sighandler(void) { #ifdef GRAFX2_CATCHES_SIGNALS Handler_TERM=signal(SIGTERM,Sig_handler); Handler_INT =signal(SIGINT,Sig_handler); Handler_ABRT=signal(SIGABRT,Sig_handler); Handler_SEGV=signal(SIGSEGV,Sig_handler); Handler_FPE =signal(SIGFPE,Sig_handler); #endif } void Init_brush_container(void) { int i; for (i=0; iDefault_palette[gfx->Color[0]]; //Config.Fav_menu_colors[1] = gfx->Default_palette[gfx->Color[1]]; //Config.Fav_menu_colors[2] = gfx->Default_palette[gfx->Color[2]]; //Config.Fav_menu_colors[3] = gfx->Default_palette[gfx->Color[3]]; // Reassign GUI color indices MC_Black = gfx->Color[0]; MC_Dark = gfx->Color[1]; MC_Light = gfx->Color[2]; MC_White = gfx->Color[3]; MC_Trans = gfx->Color_trans; MC_OnBlack=MC_Dark; MC_Window=MC_Light; MC_Lighter=MC_White; MC_Darker=MC_Dark; // Set menubars to point to the new data for (i=0; i<3; i++) { Menu_bars[MENUBAR_TOOLS ].Skin[i] = (byte*)&(gfx->Menu_block[i]); Menu_bars[MENUBAR_LAYERS].Skin[i] = (byte*)&(gfx->Layerbar_block[i]); Menu_bars[MENUBAR_ANIMATION].Skin[i] = (byte*)&(gfx->Animbar_block[i]); Menu_bars[MENUBAR_STATUS].Skin[i] = (byte*)&(gfx->Statusbar_block[i]); } } void Init_paintbrush(int index, int width, int height, byte shape, const char * bitmap) { if (bitmap!=NULL) { int i; Paintbrush[index].Shape=shape; Paintbrush[index].Width=width; Paintbrush[index].Height=height; Paintbrush[index].Offset_X=width>>1; Paintbrush[index].Offset_Y=height>>1; // Decode pixels for (i=0;i> (i&7))) != 0); } } else { Paintbrush_shape=shape; Set_paintbrush_size(width, height); Store_paintbrush(index); } } void Init_paintbrushes(void) { int index; Init_paintbrush( 0, 1, 1,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 1, 2, 2,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 2, 3, 3,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 3, 4, 4,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 4, 5, 5,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 5, 7, 7,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 6, 8, 8,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 7,12,12,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 8,16,16,PAINTBRUSH_SHAPE_SQUARE, NULL); Init_paintbrush( 9,16,16,PAINTBRUSH_SHAPE_SIEVE_SQUARE, NULL); Init_paintbrush(10,15,15,PAINTBRUSH_SHAPE_DIAMOND, NULL); Init_paintbrush(11, 5, 5,PAINTBRUSH_SHAPE_DIAMOND, NULL); Init_paintbrush(12, 3, 3,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(13, 4, 4,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(14, 5, 5,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(15, 6, 6,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(16, 8, 8,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(17,10,10,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(18,12,12,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(19,14,14,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(20,16,16,PAINTBRUSH_SHAPE_ROUND, NULL); Init_paintbrush(21,15,15,PAINTBRUSH_SHAPE_SIEVE_ROUND, NULL); Init_paintbrush(22,11,11,PAINTBRUSH_SHAPE_SIEVE_ROUND, NULL); Init_paintbrush(23, 5, 5,PAINTBRUSH_SHAPE_SIEVE_ROUND, NULL); Init_paintbrush(24, 2, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); Init_paintbrush(25, 3, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); Init_paintbrush(26, 4, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); Init_paintbrush(27, 8, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); Init_paintbrush(28, 1, 2,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); Init_paintbrush(29, 1, 3,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); Init_paintbrush(30, 1, 4,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); Init_paintbrush(31, 1, 8,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); Init_paintbrush(32, 3, 3,PAINTBRUSH_SHAPE_CROSS, NULL); Init_paintbrush(33, 5, 5,PAINTBRUSH_SHAPE_CROSS, NULL); Init_paintbrush(34, 5, 5,PAINTBRUSH_SHAPE_PLUS, NULL); Init_paintbrush(35,15,15,PAINTBRUSH_SHAPE_PLUS, NULL); Init_paintbrush(36, 2, 2,PAINTBRUSH_SHAPE_SLASH, NULL); Init_paintbrush(37, 4, 4,PAINTBRUSH_SHAPE_SLASH, NULL); Init_paintbrush(38, 8, 8,PAINTBRUSH_SHAPE_SLASH, NULL); Init_paintbrush(39, 2, 2,PAINTBRUSH_SHAPE_ANTISLASH, NULL); Init_paintbrush(40, 4, 4,PAINTBRUSH_SHAPE_ANTISLASH, NULL); Init_paintbrush(41, 8, 8,PAINTBRUSH_SHAPE_ANTISLASH, NULL); Init_paintbrush(42, 4, 4,PAINTBRUSH_SHAPE_RANDOM, "\x20\x81"); Init_paintbrush(43, 8, 8,PAINTBRUSH_SHAPE_RANDOM, "\x44\x00\x11\x00\x88\x01\x40\x08"); Init_paintbrush(44,13,13,PAINTBRUSH_SHAPE_RANDOM, "\x08\x00\x08\x90\x00\x10\x42\x10\x02\x06\x02\x02\x04\x02\x08\x42\x10\x44\x00\x00\x44\x00"); Init_paintbrush(45, 3, 3,PAINTBRUSH_SHAPE_MISC, "\x7f\x00"); Init_paintbrush(46, 3, 3,PAINTBRUSH_SHAPE_MISC, "\xdd\x80"); Init_paintbrush(47, 7, 7,PAINTBRUSH_SHAPE_MISC, "\x06\x30\x82\x04\x10\x20\x00"); for (index=0;index>1); Paintbrush[index].Offset_Y=(Paintbrush[index].Height>>1); } } /// Set application icon(s) void Define_icon(void) { #ifdef WIN32 // Specific code for Win32: // Load icon from embedded resource. // This will provide both the 16x16 and 32x32 versions. do { HICON hicon; HRSRC hresource; HINSTANCE hInstance; LPVOID lpResIconDir; LPVOID lpResIcon16; LPVOID lpResIcon32; HGLOBAL hMem; WORD nID; SDL_SysWMinfo info; hInstance = (HINSTANCE)GetModuleHandle(NULL); if (hInstance==NULL) break; // Icon is resource #1 hresource = FindResource(hInstance, MAKEINTRESOURCE(1), RT_GROUP_ICON); if (hresource==NULL) break; // Load and lock the icon directory. hMem = LoadResource(hInstance, hresource); if (hMem==NULL) break; lpResIconDir = LockResource(hMem); if (lpResIconDir==NULL) break; SDL_VERSION(&info.version); SDL_GetWMInfo(&info); // // 16x16 // // Get the identifier of the 16x16 icon nID = LookupIconIdFromDirectoryEx((PBYTE) lpResIconDir, TRUE, 16, 16, LR_DEFAULTCOLOR); if (nID==0) break; // Find the bits for the nID icon. hresource = FindResource(hInstance, MAKEINTRESOURCE(nID), MAKEINTRESOURCE((long)RT_ICON)); if (hresource==NULL) break; // Load and lock the icon. hMem = LoadResource(hInstance, hresource); if (hMem==NULL) break; lpResIcon16 = LockResource(hMem); if (lpResIcon16==NULL) break; // Create a handle to the icon. hicon = CreateIconFromResourceEx((PBYTE) lpResIcon16, SizeofResource(hInstance, hresource), TRUE, 0x00030000, 16, 16, LR_DEFAULTCOLOR); if (hicon==NULL) break; // Set it SetClassLongPtr(info.window, GCL_HICONSM, (LONG_PTR)hicon); // // 32x32 // // Get the identifier of the 32x32 icon nID = LookupIconIdFromDirectoryEx((PBYTE) lpResIconDir, TRUE, 32, 32, LR_DEFAULTCOLOR); if (nID==0) break; // Find the bits for the nID icon. hresource = FindResource(hInstance, MAKEINTRESOURCE(nID), MAKEINTRESOURCE((long)RT_ICON)); if (hresource==NULL) break; // Load and lock the icon. hMem = LoadResource(hInstance, hresource); if (hMem==NULL) break; lpResIcon32 = LockResource(hMem); if (lpResIcon32==NULL) break; // Create a handle to the icon. hicon = CreateIconFromResourceEx((PBYTE) lpResIcon32, SizeofResource(hInstance, hresource), TRUE, 0x00030000, 32, 32, LR_DEFAULTCOLOR); if (hicon==NULL) break; // Set it SetClassLongPtr(info.window, GCL_HICON, (LONG_PTR)hicon); // Success return; } while (0); // Failure: fall back on normal SDL version: #endif // General version: Load icon from the file gfx2.gif { char icon_path[MAX_PATH_CHARACTERS]; SDL_Surface * icon; sprintf(icon_path, "%s%s", Data_directory, "gfx2.gif"); icon = IMG_Load(icon_path); if (icon && icon->w == 32 && icon->h == 32) { Uint32 pink; pink = SDL_MapRGB(icon->format, 255, 0, 255); if (icon->format->BitsPerPixel == 8) { // 8bit image: use color key SDL_SetColorKey(icon, SDL_SRCCOLORKEY, pink); SDL_WM_SetIcon(icon,NULL); } else { // 24bit image: need to build a mask on magic pink byte *icon_mask; int x,y; icon_mask=malloc(128); memset(icon_mask,0,128); for (y=0;y<32;y++) for (x=0;x<32;x++) if (Get_SDL_pixel_hicolor(icon, x, y) != pink) icon_mask[(y*32+x)/8] |=0x80>>(x&7); SDL_WM_SetIcon(icon,icon_mask); free(icon_mask); icon_mask = NULL; } SDL_FreeSurface(icon); } } } grafx2_2.4+git20180105/src/filesel.h0000664000000000000000000000421213223665306015322 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file filesel.h /// Fileselector window, used for loading and saving images and brushes. ////////////////////////////////////////////////////////////////////////////// #ifndef __FILESEL_H__ #define __FILESEL_H__ #include "struct.h" #include "loadsave.h" byte Button_Load_or_Save(T_Selector_settings *settings, byte load, T_IO_Context *context); void Add_element_to_list(T_Fileselector *list, const char * full_name, const char *short_name, int type, byte icon); /// /// Formats a display name for a file, directory, or similar name (drive, volume). /// The returned value is a pointer to a single static buffer of maximum 40 characters /// including the '\\0'. char * Format_filename(const char * fname, word max_length, int type); void Free_fileselector_list(T_Fileselector *list); void Sort_list_of_files(T_Fileselector *list); void Recount_files(T_Fileselector *list); T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index); void Read_list_of_drives(T_Fileselector *list, byte name_length); short Find_file_in_fileselector(T_Fileselector *list, const char * fname); void Locate_list_item(T_List_button * list, short selected_item); int Quicksearch_list(T_List_button * list, T_Fileselector * selector); void Reset_quicksearch(void); extern T_Selector_settings * Selector; #endif grafx2_2.4+git20180105/src/pxdouble.c0000664000000000000000000003466513223665306015533 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxdouble.h" #include "pxwide.h" // for Display_transparent_line_on_screen_wide() #define ZOOMX 2 #define ZOOMY 2 void Pixel_double (word x,word y,byte color) /* Affiche un pixel de la color aux coords x;y l'cran */ { *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1)* VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1)* VIDEO_LINE_WIDTH + 1)=color; } byte Read_pixel_double (word x,word y) /* On retourne la couleur du pixel aux coords donnes */ { return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); } void Block_double (word start_x,word start_y,word width,word height,byte color) /* On affiche un rectangle de la couleur donne */ { SDL_Rect rectangle; rectangle.x=start_x*ZOOMX; rectangle.y=start_y*ZOOMY; rectangle.w=width*ZOOMX; rectangle.h=height*ZOOMY; SDL_FillRect(Screen_SDL,&rectangle,color); } void Display_part_of_screen_double (word width,word height,word image_width) /* Afficher une partie de l'image telle quelle sur l'cran */ { byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'cran (dest) byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de dpart ds la source (src) int y; int dy; for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne for (dy=width;dy>0;dy--) { *(dest+1)=*dest=*src; src++; dest+=ZOOMX; } // On double la ligne qu'on vient de copier memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } //Update_rect(0,0,width,height); } void Pixel_preview_normal_double (word x,word y,byte color) /* Affichage d'un pixel dans l'cran, par rapport au dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure Pixel_Preview_Loupe_SDL. */ { // if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) Pixel_double(x-Main_offset_X,y-Main_offset_Y,color); } void Pixel_preview_magnifier_double (word x,word y,byte color) { // Affiche le pixel dans la partie non zoome Pixel_double(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) { // On est dedans int height; int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_double( Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, y_zoom, Main_magnifier_factor, height, color ); } } void Horizontal_XOR_line_double(word x_pos,word y_pos,word width) { //On calcule la valeur initiale de dest: byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; int x; for (x=0;x0;i--) { *dest=*(dest+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=xor_lut[*dest]; dest+=VIDEO_LINE_WIDTH*ZOOMY; } } void Display_brush_color_double(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = Brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+1) = *dest = *src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } Update_rect(x_pos,y_pos,width,height); } void Display_brush_mono_double(word x_pos, word y_pos, word x_offset, word y_offset, word width, word height, byte transp_color, byte color, word brush_width) /* On affiche la brosse en monochrome */ { byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination // l'cran byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds // la brosse int x,y; for(y=height;y!=0;y--) //Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { if (*src!=transp_color) *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=color; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=brush_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Clear_brush_double(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width) { byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'cran (dest) byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de dpart ds la source (src) int y; int x; (void)x_offset; // unused (void)y_offset; // unused (void)transp_color; // unused for(y=height;y!=0;y--) // Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*src; // On passe au pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante src+=image_width-width; dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } // Affiche une brosse (arbitraire) l'cran void Display_brush_double(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; // src = Position dans la brosse byte* src = brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*src; } // Pixel suivant src++; dest+=ZOOMX; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; src = src + brush_width - width; } } void Remap_screen_double(word x_pos,word y_pos,word width,word height,byte * conversion_table) { // dest = coords a l'cran byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; int x,y; // Pour chaque ligne for(y=height;y>0;y--) { // Pour chaque pixel for(x=width;x>0;x--) { *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest= conversion_table[*dest]; dest +=ZOOMX; } dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; } Update_rect(x_pos,y_pos,width,height); } void Display_line_on_screen_fast_double(word x_pos,word y_pos,word width,byte * line) /* On affiche toute une ligne de pixels telle quelle. */ /* Utilise si le buffer contient dja des pixel doubls. */ { memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); } void Display_line_on_screen_double(word x_pos,word y_pos,word width,byte * line) /* On affiche une ligne de pixels en les doublant. */ { int x; byte *dest; dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; for(x=width;x>0;x--) { *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*line; dest+=ZOOMX; line++; } } void Display_transparent_mono_line_on_screen_double( word x_pos, word y_pos, word width, byte* line, byte transp_color, byte color) // Affiche une ligne l'cran avec une couleur + transparence. // Utilis par les brosses en mode zoom { byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; int x; // Pour chaque pixel for(x=0;x 0); src += image_width; } // ATTENTION on n'arrive jamais ici ! } // Affiche une partie de la brosse couleur zoome void Display_brush_color_zoom_double(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle de la brosse byte * buffer) { byte* src = Brush+y_offset*brush_width + x_offset; word y = y_pos; byte bx; // Pour chaque ligne while(1) { Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche facteur fois la ligne zoome for(bx=Main_magnifier_factor;bx>0;bx--) { Display_transparent_line_on_screen_wide(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); y++; if(y==end_y_pos) { return; } } src += brush_width; } // ATTENTION zone jamais atteinte } void Display_brush_mono_zoom_double(word x_pos, word y_pos, word x_offset, word y_offset, word width, // width non zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle de la brosse byte * buffer ) { byte* src = Brush + y_offset * brush_width + x_offset; int y=y_pos*ZOOMY; //Pour chaque ligne zoomer : while(1) { int bx; // src = Ligne originale // On clate la ligne Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche la ligne Facteur fois l'cran (sur des // lignes conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome Display_transparent_mono_line_on_screen_double( x_pos, y, width * Main_magnifier_factor, buffer, transp_color, color ); // On passe la ligne suivante y++; // On vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); Update_rect( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); return; } bx --; } while (bx > 0); // Passage la ligne suivante dans la brosse aussi src+=brush_width; } } void Clear_brush_scaled_double(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer) { // En fait on va recopier l'image non zoome dans la partie zoome ! byte* src = Main_screen + y_offset * image_width + x_offset; int y = y_pos; int bx; (void)transp_color; // unused // Pour chaque ligne zoomer while(1){ Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); bx=Main_magnifier_factor; // Pour chaque ligne do{ Display_line_on_screen_fast_double(x_pos,y, width * Main_magnifier_factor,buffer); // Ligne suivante y++; if(y==end_y_pos) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); Update_rect(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); return; } bx--; }while(bx!=0); src+= image_width; } } grafx2_2.4+git20180105/src/struct.h0000664000000000000000000006667613223665307015252 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2014 Sergii Pylypenko Copyright 2011 Pawel Gralski Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file struct.h /// Structures that can be used in the whole program. ////////////////////////////////////////////////////////////////////////////// #ifndef _STRUCT_H_ #define _STRUCT_H_ #if defined(__BEOS__) || defined(__TRU64__) #include #else #include #endif #include "const.h" // POSIX calls it strcasecmp, Windows uses stricmp... no ANSI standard. #ifdef WIN32 #define strcasecmp stricmp #endif // Definition of the base data types /// 8bit unsigned integer typedef uint8_t byte; /// 16bit unsigned integer typedef uint16_t word; /// 32bit unsigned integer typedef uint32_t dword; /// 64bit unsigned integer typedef uint64_t qword; // Named function prototypes // GrafX2 use a lot of function pointer to do the drawing depending in the "fake hardware zoom" and the magnifier status. typedef void (* Func_action) (void); ///< An action. Used when you click a menu button or trigger a keyboard shortcut. typedef void (* Func_pixel) (word,word,byte); ///< Set pixel at position (x,y) to color c. Used in load screen to write the data to brush, picture, or preview area. typedef byte (* Func_read) (word,word); ///< Read a pixel at position (x,y) on something. Used for example in save to tell if the data is a brush or a picture typedef void (* Func_clear) (byte); typedef void (* Func_display) (word,word,word); typedef byte (* Func_effect) (word,word,byte); ///< Called by all drawing tools to draw with a special effect (smooth, transparency, shade, ...) typedef void (* Func_block) (word,word,word,word,byte); typedef void (* Func_line_XOR) (word,word,word); ///< Draw an XOR line on the picture view of the screen. Use a different function when in magnify mode. typedef void (* Func_display_brush_color) (word,word,word,word,word,word,byte,word); typedef void (* Func_display_brush_mono) (word,word,word,word,word,word,byte,byte,word); typedef void (* Func_gradient) (long,short,short); typedef void (* Func_remap) (word,word,word,word,byte *); typedef void (* Func_procsline) (word,word,word,byte *); typedef void (* Func_display_zoom) (word,word,word,byte *); typedef void (* Func_display_brush_color_zoom) (word,word,word,word,word,word,byte,word,byte *); typedef void (* Func_display_brush_mono_zoom) (word,word,word,word,word,word,byte,byte,word,byte *); typedef void (* Func_draw_brush) (byte *,word,word,word,word,word,word,byte,word); typedef void (* Func_draw_list_item) (word,word,word,byte); ///< Draw an item inside a list button. This is done with a callback so it is possible to draw anything, as the list itself doesn't handle the content /// A set of RGB values. #ifdef __GNUC__ typedef struct { byte R; ///< Red byte G; ///< Green byte B; ///< Blue } __attribute__((__packed__)) T_Components, T_Palette[256] ; ///< A complete 256-entry RGB palette (768 bytes). #else #pragma pack(1) typedef struct { byte R; ///< Red byte G; ///< Green byte B; ///< Blue } T_Components, T_Palette[256] ; ///< A complete 256-entry RGB palette (768 bytes). #pragma pack() #endif /// A normal rectangular button in windows and menus. typedef struct T_Normal_button { short Number; ///< Unique identifier for all controls word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. word Width; ///< Width before scaling word Height; ///< Height before scaling byte Clickable; ///< Boolean, unused. byte Repeatable; ///< Boolean, true if the button activates repeatedly until you release the mouse button. Used for "+" buttons, for example. word Shortcut; ///< Keyboard shortcut that will emulate a click on this button. struct T_Normal_button * Next;///< Pointer to the next normal button of current window. } T_Normal_button; /// A window control that shows a complete 256-color palette typedef struct T_Palette_button { short Number; ///< Unique identifier for all controls word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. struct T_Palette_button * Next;///< Pointer to the next palette of current window. } T_Palette_button; /// A window control that represents a scrollbar, with a slider, and two arrow buttons. typedef struct T_Scroller_button { short Number; ///< Unique identifier for all controls byte Is_horizontal; ///< Boolean: True if slider is horizontal instead of vertical. word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. word Length; ///< Length before scaling. word Nb_elements; ///< Number of distinct values it can take. word Nb_visibles; ///< If this slider is meant to show several elements of a collection, this is their number (otherwise, it's 1). word Position; ///< Current position of the slider: which item it's pointing. word Cursor_length; ///< Dimension of the slider, in pixels before scaling. struct T_Scroller_button * Next;///< Pointer to the next scroller of current window. } T_Scroller_button; /// Special invisible button /// A window control that only has a rectangular "active" area which catches mouse clicks, // but no visible shape. It's used for custom controls where the drawing is done on // a case by case basis. typedef struct T_Special_button { short Number; ///< Unique identifier for all controls word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. word Width; ///< Width before scaling word Height; ///< Height before scaling struct T_Special_button * Next;///< Pointer to the next special button of current window. } T_Special_button; /// Data for a dropdown item, ie. one proposed choice. typedef struct T_Dropdown_choice { short Number; ///< Value that identifies the choice (for this dropdown only) const char * Label; ///< String to display in the dropdown panel struct T_Dropdown_choice * Next;///< Pointer to the next choice for this dropdown. } T_Dropdown_choice; /// A window control that behaves like a dropdown button. typedef struct T_Dropdown_button { short Number; ///< Unique identifier for all controls word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. word Width; ///< Width before scaling word Height; ///< Height before scaling byte Display_choice; ///< Boolean, true if the engine should print the selected item's label in the dropdown area when the user chooses it. byte Display_centered; ///< Boolean, true to center the labels (otherwise, align left) byte Display_arrow; ///< Boolean, true to display a "down" arrow box in top right byte Bottom_up; ///< Boolean, true to make the dropdown panel go above its button instead of below it byte Active_button; ///< Determines which mouse button(s) cause the dropdown panel to open: LEFT_SIDE || RIGHT_SIDE || (LEFT_SIDE|RIGHT_SIDE) word Dropdown_width; ///< Width of the dropdown panel when it's open. Use 0 for "same as the dropdown button" T_Dropdown_choice * First_item; ///< Linked list with the choices available for this dropdown. struct T_Dropdown_button * Next;///< Pointer to the next dropdown button of current window. } T_Dropdown_button; /// Data for one item (file, directory) in a fileselector. typedef struct T_Fileselector_item { char Full_name[MAX_PATH_CHARACTERS]; ///< Filesystem value. byte Type; ///< Type of item: 0 = File, 1 = Directory, 2 = Drive byte Icon; ///< One of ::ICON_TYPES, ICON_NONE for none. struct T_Fileselector_item * Next; ///< Pointer to next item of the current fileselector. struct T_Fileselector_item * Previous;///< Pointer to previous item of the current fileselector. word Length_short_name; ///< Number of bytes allocated for :Short_name #if __GNUC__ < 3 char Short_name[0]; ///< Name to display. #else char Short_name[]; ///< Name to display. #endif // No field after Short_name[] ! Dynamic allocation according to name length. } T_Fileselector_item; /// Data for a fileselector typedef struct T_Fileselector { /// Number of elements in the current fileselector's ::Filelist short Nb_elements; /// Number of files in the current fileselector's ::Filelist short Nb_files; /// Number of directories in the current fileselector's ::Filelist short Nb_directories; /// Head of the linked list for the fileselector. T_Fileselector_item * First; /// Index for direct access to element number N T_Fileselector_item ** Index; } T_Fileselector; /// "List" button as used in the font selection, skin selection, and brush factory screens. It's like a limited filelist. /// The screenmode selection and load/save screen were written before this existed so they use their own code. It would be nice if they were updated to use this one. typedef struct T_List_button { short Number; ///< Unique identifier for all controls short List_start; ///< Index of the font to appear as first line short Cursor_position; ///< Index of the selected line (0=top) T_Special_button * Entry_button; ///< Pointer to the associated selection control. T_Scroller_button * Scroller; ///< Pointer to the associated scroller Func_draw_list_item Draw_list_item; ///< Function to call for each item to draw its line byte Color_index; ///< Background color: From 0->MC_Black to 3->MC_White struct T_List_button * Next; ///< Pointer to the next list button of current window. } T_List_button; /// A stackable window (editor screen) typedef struct { word Pos_X; word Pos_Y; word Width; word Height; word Nb_buttons; T_Normal_button *Normal_button_list; T_Palette_button *Palette_button_list; T_Scroller_button *Scroller_button_list; T_Special_button *Special_button_list; T_Dropdown_button *Dropdown_button_list; T_List_button *List_button_list; int Attribute1; int Attribute2; byte Draggable; } T_Window; /// Data for one line of the "Help" screens. typedef struct { char Line_type; ///< Kind of line: 'N' for normal line, 'S' for a bold line, 'K' for a line with keyboard shortcut, 'T' and '-' for upper and lower titles. char * Text; ///< Displayed string. int Line_parameter; ///< Generic parameter depending on line type. For 'K' lines: a shortcut identifier. For others: unused. } T_Help_table; /// Data for one section of the "Help" screens, ie a page. typedef struct { const T_Help_table* Help_table; ///< Pointer to the array of ::T_Help_table that contains the lines word Length; ///< Size of the array of lines } T_Help_section; /// Data for one setting of gradients. Warning, this one is saved/loaded as binary. typedef struct { byte Start; ///< First color byte End; ///< Last color dword Inverse; ///< Boolean, true if the gradient goes in descending order dword Mix; ///< Amount of randomness to add to the mix (0-255) dword Technique;///< Gradient technique: 0 (no pattern) 1 (dithering), or 2 (big dithering) byte Speed; ///< Speed of cycling. 0 for disabled, 1-64 otherwise. } T_Gradient_range; /// Data for a full set of gradients. typedef struct { int Used; ///< Reference count T_Gradient_range Range[16]; } T_Gradient_array; /// Data for one setting of shade. Warning, this one is saved/loaded as binary. typedef struct { word List[512]; ///< List of entries, each one is either a color (0-255) or -1 for empty. byte Step; ///< Step to increment/decrement on left-clicks. byte Mode; ///< Shade mode: Normal, Loop, or No-saturation see ::SHADE_MODES } T_Shade; /// Data for one fullscreen video mode in configuration file. Warning, this one is saved/loaded as binary. typedef struct { byte State; ///< How good is the mode supported. 0:Good (white) 1:OK (light) 2:So-so (dark) 4:User-disabled (black); +128 => System doesn't support it at all. word Width; ///< Videomode width in pixels. word Height;///< Videomode height in pixels. } T_Config_video_mode; /// Header for gfx2.cfg typedef struct { char Signature[3]; ///< Signature for the file format. "CFG". byte Version1; ///< Major version number (ex: 2) byte Version2; ///< Minor version number (ex: 0) byte Beta1; ///< Major beta version number (ex: 96) byte Beta2; ///< Major beta version number (ex: 5) } T_Config_header; /// Header for a config chunk in for gfx2.cfg typedef struct { byte Number; ///< Section identfier. Possible values are in enum ::CHUNKS_CFG word Size; ///< Size of the configuration block that follows, in bytes. } T_Config_chunk; /// Configuration for one keyboard shortcut in gfx2.cfg typedef struct { word Number; ///< Indicates the shortcut action. This is a number starting from 0, which matches ::T_Key_config.Number word Key; ///< Keyboard shortcut: SDLK_something, or -1 for none word Key2; ///< Alternate keyboard shortcut: SDLK_something, or -1 for none } T_Config_shortcut_info; /// This structure holds all the settings saved and loaded as gfx2.ini. typedef struct { char *Font_file; ///< Name of the font used in the menus. Matches file skins/font_*.png (Case-sensitive on some filesystems) char *Skin_file; ///< String, name of the file where all the graphic data is stored int Show_hidden_files; ///< Boolean, true to show hidden files in fileselectors. int Show_hidden_directories; ///< Boolean, true to show hidden directories in fileselectors. // int Show_system_directories; ///< (removed when converted from DOS) byte Display_image_limits; ///< Boolean, true to display a dotted line at the borders of the image if it's smaller than screen. byte Cursor; ///< Mouse cursor aspect: 1 Solid, 2 Transparent, 3 Thin byte Maximize_preview; ///< Boolean, true to make previews in fileselector fit the whole rectangle. byte Auto_set_res; ///< Boolean, true to make grafx2 switch to a new resolution whenever you load an image. byte Coords_rel; ///< Boolean, true to display coordinates as relative (instead of absolute) byte Backup; ///< Boolean, true to backup the original file whenever you save an image. byte Adjust_brush_pick; ///< Boolean, true to omit the right and bottom edges when grabbing a brush in Grid mode. byte Auto_save; ///< Boolean, true to save configuration when exiting program. byte Max_undo_pages; ///< Number of steps to memorize for Undo/Redo. byte Mouse_sensitivity_index_x; ///< Mouse sensitivity in X axis byte Mouse_sensitivity_index_y; ///< Mouse sensitivity in Y axis byte Mouse_merge_movement; ///< Number of SDL mouse events that are merged into a single change of mouse coordinates. byte Delay_left_click_on_slider; ///< Delay (in 1/100s) between two activations of a repeatable button when you hold left-click. byte Delay_right_click_on_slider; ///< Delay (in 1/100s) between two activations of a repeatable button when you hold left-click. long Timer_delay; ///< Delay (in 1/55s) before showing a preview in a fileselector. T_Components Fav_menu_colors[4]; ///< Favorite colors to use for the menu. int Nb_max_vertices_per_polygon; ///< Limit for the number of vertices in polygon tools. byte Clear_palette; ///< Boolean, true to reset the palette (to black) before loading an image. byte Set_resolution_according_to; ///< When Auto_set_res is on, this determines if the mode should be chosen according to the "original screen" information in the file (1) or the picture dimensons (2) int8_t Ratio; ///< Determines the scaling of menu and windows: 0 no scaling, 1 scaling, 2 slight scaling, negative= opposite of max scaling byte Fast_zoom; ///< Boolean, true if the magnifier shortcut should automatically view the mouse area. byte Find_file_fast; ///< In fileselectors, this determines which entries should be sought when typing letters: 0 all, 1 files only, 2 directories only. byte Separate_colors; ///< Boolean, true if the menu palette should separate color cells with a black outline. word Palette_cells_X; ///< Number of colors to show in a row of the menu palette. word Palette_cells_Y; ///< Number of colors to show in a column of the menu palette. byte Palette_vertical; ///< Boolean, true if the menu palette should go top to bottom instead of left to right byte FX_Feedback; ///< Boolean, true if drawing effects should read the image being modified (instead of the image before clicking) byte Safety_colors; ///< Boolean, true to make the palette automatically re-create menu colors if needed after a "Zap" or color reduction. byte Opening_message; ///< Boolean, true to display the splash screen on strtup. byte Clear_with_stencil; ///< Boolean, true to take the stencil into effect (if active) when using the Clear function. byte Auto_discontinuous; ///< Boolean, true to automatically switch to the discontinuous freehand draw after grabbing a brush. byte Screen_size_in_GIF; ///< Boolean, true to store current resolution in GIF files. byte Auto_nb_used; ///< Boolean, true to count colors in Palette screen. byte Default_resolution; ///< Default video mode to use on startup. Index in ::Video_mode. char *Bookmark_directory[NB_BOOKMARKS];///< Bookmarked directories in fileselectors: This is the full directory name. char Bookmark_label[NB_BOOKMARKS][8+1];///< Bookmarked directories in fileselectors: This is the displayed name. int Window_pos_x; ///< Last window x position (9999 if unsupportd/irrelevant for the platform) int Window_pos_y; ///< Last window y position (9999 if unsupportd/irrelevant for the platform) word Double_click_speed; ///< Maximum delay for double-click, in ms. word Double_key_speed; ///< Maximum delay for double-keypress, in ms. byte Right_click_colorpick; ///< Boolean, true to enable a "tablet" mode, where RMB acts as instant colorpicker byte Sync_views; ///< Boolean, true when the Main and Spare should share their viewport settings. byte Stylus_mode; ///< Boolean, true to tweak some tools (eg:Curve) for single-button stylus. word Swap_buttons; ///< Sets which key swaps mouse buttons : 0=none, or MOD_CTRL, or MOD_ALT. char Scripts_directory[MAX_PATH_CHARACTERS];///< Full pathname of directory for Lua scripts byte Allow_multi_shortcuts; ///< Boolean, true if the same key combination can trigger multiple shortcuts. byte Tilemap_allow_flipped_x; ///< Boolean, true if the Tilemap tool should detect x-flipped tiles. byte Tilemap_allow_flipped_y; ///< Boolean, true if the Tilemap tool should detect y-flipped tiles. byte Tilemap_show_count; ///< Boolean, true if the Tilemap tool should display tile count after analysis. byte Use_virtual_keyboard; ///< 0: Auto, 1: On, 2: Off byte Default_mode_layers; ///< Indicates if default new image has layers (alternative is animation) } T_Config; // Structures utilises pour les descriptions de pages et de liste de pages. // Lorsqu'on grera les animations, il faudra aussi des listes de listes de // pages. // Ces structures sont manipules travers des fonctions de gestion du // backup dans "graph.c". typedef struct T_Image { byte * Pixels; int Duration; } T_Image; /// This is the data for one step of Undo/Redo, for one image. /// This structure is resized dynamically to hold pointers to all of the layers in the picture. /// The pointed layers are just byte* holding the raw pixel data. But at Image[0]-1 you will find a short that is used as a reference counter for each layer. /// This way we can use the same pixel data in many undo pages when the user edit only one of the layers (which is what they usually do). typedef struct T_Page { int Width; ///< Image width in pixels. int Height; ///< Image height in pixels. T_Palette Palette; ///< Image palette. byte Image_mode; ///< 0= layered image, 1=animation, char Comment[COMMENT_SIZE+1]; ///< Comment to store in the image file. char File_directory[MAX_PATH_CHARACTERS];///< Directory that contains the file. char Filename[MAX_PATH_CHARACTERS]; ///< Filename without directory. byte File_format; ///< File format, in enum ::FILE_FORMATS struct T_Page *Next; ///< Pointer to the next backup struct T_Page *Prev; ///< Pointer to the previous backup T_Gradient_array *Gradients; ///< Pointer to the gradients used by the image. byte Background_transparent; ///< Boolean, true if Layer 0 should have transparent pixels byte Transparent_color; ///< Index of transparent color. 0 to 255. int Nb_layers; ///< Number of layers #if __GNUC__ < 3 // gcc2 doesn't suport [], but supports [0] which does the same thing. T_Image Image[0]; ///< Pixel data for the (first layer of) image. #else T_Image Image[]; ///< Pixel data for the (first layer of) image. #endif // No field after Image[] ! Dynamic layer allocation for Image[1], [2] etc. } T_Page; /// Collection of undo/redo steps. typedef struct { int List_size; ///< Number of ::T_Page in the vector "Pages". T_Page * Pages; ///< Head of a linked list of pages, each one being a undo/redo step. } T_List_of_pages; /// A single image bitmap /// This struct is used to store a flattened view of the current picture. typedef struct { int Width; ///< Image width in pixels. int Height; ///< Image height in pixels. byte * Image; ///< Pixel data for the image. } T_Bitmap; /// A single memorized brush from the Brush Container typedef struct { byte Paintbrush_shape; ///< Kind of brush byte Thumbnail[BRUSH_CONTAINER_PREVIEW_WIDTH][BRUSH_CONTAINER_PREVIEW_HEIGHT]; // Data for color brush word Width; word Height; byte * Brush; /// < Color brush (if any) T_Palette Palette; byte Colormap[256]; byte Transp_color; } T_Brush_template; /// GUI skin data typedef struct { // Mouse /// X coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_WIDTH word Cursor_offset_X[NB_CURSOR_SPRITES]; /// Y coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_HEIGHT word Cursor_offset_Y[NB_CURSOR_SPRITES]; /// Graphic resources for the mouse cursor. byte Cursor_sprite[NB_CURSOR_SPRITES][CURSOR_SPRITE_HEIGHT][CURSOR_SPRITE_WIDTH]; // Sieve patterns /// Preset sieve patterns, stored as binary (one word per line) word Sieve_pattern[12][16]; // Menu and other graphics /// Bitmap data for the menu, a single rectangle. byte Menu_block[3][35][MENU_WIDTH]; byte Layerbar_block[3][10][144]; byte Animbar_block[3][14][236]; byte Statusbar_block[3][9][20]; /// Bitmap data for the icons that are displayed over the menu. byte Menu_sprite[2][NB_MENU_SPRITES][MENU_SPRITE_HEIGHT][MENU_SPRITE_WIDTH]; /// Bitmap data for the different "effects" icons. byte Effect_sprite[NB_EFFECTS_SPRITES][EFFECT_SPRITE_HEIGHT][EFFECT_SPRITE_WIDTH]; /// Bitmap data for the different Layer icons. byte Layer_sprite[3][16][LAYER_SPRITE_HEIGHT][LAYER_SPRITE_WIDTH]; /// Bitmap data for the Grafx2 logo that appears on splash screen. All 256 colors allowed. byte Logo_grafx2[231*56]; /// Bitmap data for the 6x8 font used in help screens. byte Help_font_norm [256][6][8]; /// Bitmap data for the 6x8 font used in help screens ("bold" verstion). byte Bold_font [256][6][8]; // 12 // 34 /// Bitmap data for the title font used in help screens. Top-left quarter. byte Help_font_t1 [64][6][8]; /// Bitmap data for the title font used in help screens. Top-right quarter. byte Help_font_t2 [64][6][8]; /// Bitmap data for the title font used in help screens. Bottom-left quarter. byte Help_font_t3 [64][6][8]; /// Bitmap data for the title font used in help screens. Bottom-right quarter. byte Help_font_t4 [64][6][8]; /// Bitmap data for the small 8x8 icons. byte Icon_sprite[NB_ICON_SPRITES][ICON_SPRITE_HEIGHT][ICON_SPRITE_WIDTH]; /// A default 256-color palette. T_Palette Default_palette; /// Preview for displaying in the skin dialog byte Preview[16][173]; /// GUI color indices in skin palette: black, dark, light, white. byte Color[4]; /// Transparent GUI color index in skin file byte Color_trans; } T_Gui_skin; typedef struct { // Preset paintbrushes /// Graphic resources for the preset paintbrushes. byte Sprite[PAINTBRUSH_HEIGHT][PAINTBRUSH_WIDTH]; /// Width of the preset paintbrushes. word Width; /// Height of the preset paintbrushes. word Height; /// Type of the preset paintbrush: index in enum PAINTBRUSH_SHAPES byte Shape; /// Brush handle for the preset brushes. Generally ::T_Paintbrush::Width[]/2 word Offset_X; /// Brush handle for the preset brushes. Generally ::T_Paintbrush::Height[]/2 word Offset_Y; } T_Paintbrush; typedef struct { int Previous; int Next; byte Flipped; ///< 0:no, 1:horizontally, 2:vertically, 3:both } T_Tile; /// Settings for an entire file selector screen typedef struct T_Selector_settings { byte Format_filter; ///< 0 for "*.*", or a value of enum ::FILE_FORMATS short Position; ///< Index of the first file/entry to display in list short Offset; ///< Position of the "highlight" bar in the file list char Directory[MAX_PATH_CHARACTERS]; ///< Directory currently browsed } T_Selector_settings; #endif grafx2_2.4+git20180105/src/windows.h0000664000000000000000000001550013223665307015374 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007-2008 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file windows.h /// Graphical interface management functions (windows, menu, cursor) ////////////////////////////////////////////////////////////////////////////// #ifndef __WINDOWS_H_ #define __WINDOWS_H_ #include "struct.h" #define ToWinX(x) (((x)*Menu_factor_X)+Window_pos_X) #define ToWinY(y) (((y)*Menu_factor_Y)+Window_pos_Y) #define ToWinL(l) ((l)*Menu_factor_X) #define ToWinH(h) ((h)*Menu_factor_Y) #define Update_window_area(x,y,w,h) Update_rect(Window_pos_X+(x)*Menu_factor_X,Window_pos_Y+(y)*Menu_factor_Y,(w)*Menu_factor_X,(h)*Menu_factor_Y); void Display_cursor(void); void Hide_cursor(void); void Remap_screen_after_menu_colors_change(void); void Compute_optimal_menu_colors(T_Components * palette); void Remap_menu_sprites(); void Position_screen_according_to_zoom(void); void Compute_separator_data(void); void Compute_magnifier_data(void); void Clip_magnifier_offsets(short *x_offset, short *y_offset); void Compute_limits(void); void Compute_paintbrush_coordinates(void); void Pixel_in_menu(word bar, word x, word y, byte color); void Pixel_in_menu_and_skin(word bar, word x, word y, byte color); void Pixel_in_window(word x,word y,byte color); void Set_fore_color(byte color); void Set_back_color(byte color); void Frame_menu_color(byte id); void Display_menu_palette(void); void Display_menu(void); void Display_layerbar(void); void Reposition_palette(void); void Change_palette_cells(void); int Pick_color_in_palette(void); word Palette_cells_X(void); word Palette_cells_Y(void); void Print_general(short x,short y,const char * str,byte text_color,byte background_color); void Print_in_window(short x,short y,const char * str,byte text_color,byte background_color); void Print_in_window_limited(short x,short y,const char * str,byte size,byte text_color,byte background_color); void Print_char_in_window(short x_pos,short y_pos,const unsigned char c,byte text_color,byte background_color); void Print_in_menu(const char * str, short position); void Print_coordinates(void); void Print_filename(void); void Print_counter(short x,short y,const char * str,byte text_color,byte background_color); byte Confirmation_box(char * message); void Warning_message(char * message); void Verbose_message(const char * caption, const char * message); int Requester_window(char* message, int initial_value); void Display_image_limits(void); void Display_all_screen(void); void Window_rectangle(word x_pos,word y_pos,word width,word height,byte color); void Window_display_frame_generic(word x_pos,word y_pos,word width,word height, byte color_tl,byte color_br,byte color_s,byte color_tlc,byte color_brc); void Window_display_frame_mono(word x_pos,word y_pos,word width,word height,byte color); void Window_display_frame_in(word x_pos,word y_pos,word width,word height); void Window_display_frame_out(word x_pos,word y_pos,word width,word height); void Window_display_frame(word x_pos,word y_pos,word width,word height); void Display_sprite_in_menu(int btn_number,char sprite_number); void Display_paintbrush_in_menu(void); void Display_paintbrush_in_window(word x,word y,int number); void Draw_thingumajig(word x,word y, byte color, short direction); void Display_grad_block_in_window(word x_pos,word y_pos,word width,word height,word block_start,word block_end); void Window_display_icon_sprite(word x_pos,word y_pos,byte type); byte Best_color(byte red,byte green,byte blue); byte Best_color_nonexcluded(byte red,byte green,byte blue); byte Best_color_range(byte red,byte green,byte blue,byte max); byte Best_color_perceptual(byte r,byte g,byte b); byte Best_color_perceptual_except(byte r,byte g,byte b, byte except); void Horizontal_XOR_line_zoom(short x_pos, short y_pos, short width); void Vertical_XOR_line_zoom(short x_pos, short y_pos, short height); void Change_magnifier_factor(byte factor_index, byte point_at_mouse); /// Width of one layer button, in pixels before scaling extern word Layer_button_width; /// Copy viewport settings and offsets from the Main to the Spare. void Copy_view_to_spare(void); /// Definition of a toolbar button typedef struct { // Button aspect word X_offset; ///< Position relative to menu's left word Y_offset; ///< Position relative to menu's top word Width; ///< Button's active width word Height; ///< Button's active heigth byte Pressed; ///< Button is currently pressed byte Shape; ///< Shape, listed in enum ::BUTTON_SHAPES signed char Icon; ///< Which icon to display: Either the one from the toolbar (-1) or one of ::MENU_SPRITE // Triggers on mouse/keyboard Func_action Left_action; ///< Action triggered by a left mouseclick on the button Func_action Right_action; ///< Action triggered by a right mouseclick on the button word Left_shortcut[2]; ///< Keyboard shortcut for a left mouseclick word Right_shortcut[2];///< Keyboard shortcut for a right mouseclick byte Left_instant; ///< Will not wait for mouse release before triggering action byte Right_instant; ///< Will not wait for mouse release before triggering action const char * Tooltip; ///< Text in status bar when button is hovered // Data used when the button is unselected Func_action Unselect_action; ///< Action triggered by unselecting the button byte Family; ///< enum ::FAMILY_OF_BUTTONS. } T_Toolbar_button; extern T_Toolbar_button Buttons_Pool[NB_BUTTONS]; // A menubar. typedef struct { word Width; word Height; byte Visible; word Top; ///< Relative to the top line of the menu, hidden bars don't count. byte* Skin[3]; ///< [0] has normal buttons, [1] has selected buttons, [2] is current. word Skin_width; byte Last_button_index; } T_Menu_Bar; enum { MENUBAR_STATUS = 0, // MUST be 0 MENUBAR_ANIMATION, MENUBAR_LAYERS, MENUBAR_TOOLS, MENUBAR_COUNT }; extern T_Menu_Bar Menu_bars[MENUBAR_COUNT]; #endif grafx2_2.4+git20180105/src/special.c0000664000000000000000000003131013223665307015312 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include "const.h" #include "struct.h" #include "global.h" #include "graph.h" #include "engine.h" #include "windows.h" #include "special.h" #include "pages.h" #include "misc.h" #include "buttons.h" //---------------------- Modifier le pinceau spcial ------------------------- void Set_paintbrush_size(int width, int height) { int x_pos,y_pos; int x,y; int radius2; if (width<1) width=1; if (height<1) height=1; if (width>MAX_PAINTBRUSH_SIZE) width=MAX_PAINTBRUSH_SIZE; if (height>MAX_PAINTBRUSH_SIZE) height=MAX_PAINTBRUSH_SIZE; Paintbrush_width=width; Paintbrush_height=height; Paintbrush_offset_X=Paintbrush_width>>1; Paintbrush_offset_Y=Paintbrush_height>>1; switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_ROUND : radius2=Circle_squared_diameter(Paintbrush_width); for (y_pos=0, y=1-Paintbrush_height; y_pos>1; for (y_pos=0; y_pos>1; for (y_pos=0; y_pos>1; for (y_pos=0; y_pos>1; for (y_pos=0; y_pos>1; for (y_pos=0; y_pos0) Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos-1]=0; if (y_pos>0) Paintbrush_sprite[((y_pos-1)*MAX_PAINTBRUSH_SIZE)+x_pos]=0; } } } } void Smaller_paintbrush(void) { if ( (Paintbrush_shape1) || (Paintbrush_height>1) ) ) { Hide_cursor(); switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_CROSS: case PAINTBRUSH_SHAPE_PLUS: case PAINTBRUSH_SHAPE_DIAMOND: if (Paintbrush_width&1) Set_paintbrush_size(Paintbrush_width-2,Paintbrush_height-2); else Set_paintbrush_size(Paintbrush_width-1,Paintbrush_height-1); break; case PAINTBRUSH_SHAPE_SQUARE: case PAINTBRUSH_SHAPE_SLASH: case PAINTBRUSH_SHAPE_ANTISLASH: case PAINTBRUSH_SHAPE_SIEVE_SQUARE: case PAINTBRUSH_SHAPE_ROUND: case PAINTBRUSH_SHAPE_SIEVE_ROUND: case PAINTBRUSH_SHAPE_RANDOM: Set_paintbrush_size(Paintbrush_width-1,Paintbrush_height-1); break; case PAINTBRUSH_SHAPE_HORIZONTAL_BAR: Set_paintbrush_size(Paintbrush_width-1,1); break; case PAINTBRUSH_SHAPE_VERTICAL_BAR: Set_paintbrush_size(1,Paintbrush_height-1); } Display_paintbrush_in_menu(); Display_cursor(); } } void Bigger_paintbrush(void) { if ( (Paintbrush_shapeMain_image_width) temp_x_offset=Main_image_width-Screen_width; if (temp_y_offset+Menu_Y>Main_image_height) temp_y_offset=Main_image_height-Menu_Y; if (temp_x_offset<0) temp_x_offset=0; if (temp_y_offset<0) temp_y_offset=0; if ( (Main_offset_X!=temp_x_offset) || (Main_offset_Y!=temp_y_offset) ) { Hide_cursor(); Main_offset_X=temp_x_offset; Main_offset_Y=temp_y_offset; Compute_limits(); Compute_paintbrush_coordinates(); Display_all_screen(); // <=> Display_screen + Display_image_limits Display_cursor(); } } // ---------------------- Scroller la fentre de la loupe -------------------- void Scroll_magnifier(short delta_x,short delta_y) { short temp_x_offset; short temp_y_offset; temp_x_offset=Main_magnifier_offset_X+delta_x; temp_y_offset=Main_magnifier_offset_Y+delta_y; Clip_magnifier_offsets(&temp_x_offset, &temp_y_offset); if ( (Main_magnifier_offset_X!=temp_x_offset) || (Main_magnifier_offset_Y!=temp_y_offset) ) { Hide_cursor(); Main_magnifier_offset_X=temp_x_offset; Main_magnifier_offset_Y=temp_y_offset; Position_screen_according_to_zoom(); Compute_limits(); Compute_paintbrush_coordinates(); Display_all_screen(); Display_cursor(); } } // -------------- Changer le Zoom (grce aux touches [+] et [-]) ------------- void Zoom(short delta) { short index; for (index=0; ZOOM_FACTOR[index]!=Main_magnifier_factor; index++); index+=delta; if ( (index>=0) && (index */ ////////////////////////////////////////////////////////////////////////////// ///@file help.h /// Functions related to the help browser. The help data is in helpfile.h ////////////////////////////////////////////////////////////////////////////// #ifndef __HELP_H_ #define __HELP_H_ /*! Called to open the help window with the keyboard shortcut. If the mouse is over a button, its contextual help will be displayed. Else, the default helpscreen will be shown. */ void Button_Help(void); /*! Displays and runs the "Statistics" window */ void Button_Stats(void); /*! Displays and runs the "Help / About..." window @param section Number of the help section page to display (equals the button number the mouse was hovering for the contextual help), -1 for the main help page. @param sub_section Help sub-section title (the page will be scrolled so this title is at the top). */ void Window_help(int section, const char * sub_section); /// Opens a window where you can change a shortcut key(s). void Window_set_shortcut(int action_id); /// /// Print a line with the 'help' (6x8) font. short Print_help(short x_pos, short y_pos, const char *line, char line_type, short link_position, short link_size); // Nom de la touche actuallement assignée à un raccourci d'après son numéro // de type 0x100+BOUTON_* ou SPECIAL_* const char * Keyboard_shortcut_value(word shortcut_number); /// /// Browse the complete list of shortcuts and ensure that a key only triggers /// one of them. void Remove_duplicate_shortcuts(void); #endif grafx2_2.4+git20180105/src/Grafx2.icns0000775000000000000000000003672013223665306015551 0ustar rootrooticns=ih32 8 8@@@82@@@@@@@83@8@@@@98R'|@@@@@98R|=@@@@9N|@@@@@9N||@@@@@@N|@@@@@@@N@@@@@4|||||@@@@||@@@@@@||@@@|||8@@@@||T@ @@@@@|||\8@@@@|||\8@@@@||\89@@@@|\89@|||\89@||\9||\9|\9||\@|||\+ ||\8 |||||\8|R;||\R>||||\R?@||||\\R@|||||\R@|\\\\R@||||\ \\ @|\\ \\@|||\|\@|||||\\|\\@||||||\|\\\\|\||\\\|\|\\\|\\\\||\\\\\|\R\\\\\@||\R\\\\\\\\@||\R\\@@||R\\@2@R\  8 8|||8`|||||||8c|l||||n8K3|||||n83v||||nw|||||nw||||||w|||||||w|||||\|||||||||||||8||||T| |||||8||||8||||8n||||8n|8n|nnn|S g gnwz||| ||||||||||`| 8 8888؉8+++ 58T 888888888+8+8+8ԙ88r8rrrr r+ 88 888r8r8r8r8r  il32,@@3@@ @@@@@@3@@@3@@@@@3@@@@@3@@@@@@@@@@@@@@@@@@ @@@@ 93 @3@3@3@3 @\\\I\\II\\\ \II\\II\\\\\\I I\\\\\\RI\ǃ||b|| ||||||b|||b|||||b|||||b|||||||||||||||||| |||| nǃb |b|b|b|b | ǃ ee ee eeeeeee +ǃ  eeeeeeee ereis32@@@@@@@@@@@@ @\@\\\\\\\\\\\\|||||||||||||| ich8 ңҝyyNҩz띣yry룞yyNҤңyNryңr룝ҝ룝*yyyyNrrTrNzNr룝ңrNңzNrrzңyxN띣ҀrNNңrrxҌҞyxNҍyxrNNҍyxrҍNNҌrҌNxҍrrrrNNrrxrҍTҍrrҍҍNNNrҍҍrxxNҌ댍NNNNr밍rҌҌNTrrҌrҌҍNNrҍrxrrNNrҌNrrNrrxҍҍNTrҍҍҌrrҍ쌍ҍrҍҌrTҌұҍxҌҌҌNrҍ󱍌ҍ댍ұҍrrҍ󍌱ҍrN󍍌ҍicl8+y띣yzyyҤໝңҝyҝӀ՝yգգҤҤҤໝҤҤ+Ҥ댍ҍҍҍҍҍҌҌҍҍҌҍұҍҍҍҌics8zҍҌ댍ҍҍұich4y gfgg`ffngy fffffxvgy~fflffffyyyfyy ffff fffovfiyvfgn~flff fffovfgnvfffgo ffffffofffvfyvf`fffo gfnfffl fovfgfffff` ffffg~ygnffffffffflofgfgfffff` ffffffoy~fgffffffffffffowfffvfffl fffff`ff_ vgfgfffffff` ff_~i~vffffff` lff`fdyvyfffffffffff`ff_vfffffflf` fffffdyfffffffffff_ffffflf`f` fffevffff`fff ff_ffff`ffffdvffflf` ff_fffffflffe ff f ffffffOvf``fffffffefff ffffffffVOvf` fff` ffl feEe vfff ffffFeOnf` ffl fff` ffEE ffff`fffeVUOf` ff`ff`ffVffd_ffffffff`ffVdfeOvl fff` fffff`fff\N_`ffffffffl fl TeOvff f` ffffffl \Vd_fff`ffffffffe`UE_fffffefVfTP UE_fffflfff_eEfdVef_ffflffdFffdVfe_f` ff`ff_UVf`eTfeOvlffeEdVTTeVT_f ffZTUTTVfEE_ff fffSUUeT_fffffoTTUENT_icl4pw|ww|owxfffowi~wm ff_xwvvm ffo|ignxfm ff_xvvfv onifgfgm_vvvfffff oynfffffm fm ff_Yvvvfffm fffffffm m f_^ffffmfffvffmm ffoVfflffffm ffffvffm ffffivfffffxm fmffffnf ffm m ff ffiffff`fffom fm ffff`mf_`fffff`eZ`f ff_ff` ff_lfeeVV`fVOm m VOfffff_fdVVfVFZffVF_eded_UEETTUEE_ics4` o``of`f`ff`f`f`f`ofm`ffo `f_f`ffef ffd_ff`ffT_f fVeF_`oVT_TTich#H *?Y:ZWw{[|ojw^~~x?ß?|1<珏c8ێ>8y|??;[k=qկۏ[????ICN#???W0/??cS,.jߦ??}?????ics#H랸;͇߹??h8mk 5555l8mk55555555555555555555555555555555555555555555s8mkgrafx2_2.4+git20180105/src/palette.h0000664000000000000000000000463313223665306015344 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file palette.h /// Palette screen, and some palette-related high-level functions. ////////////////////////////////////////////////////////////////////////////// /// Open the palette menu and handles everything inside it. void Button_Palette(void); /// Open the secondary palette menu and handles it. void Button_Secondary_palette(void); /// Choose the number of graduations for RGB components, from 2 to 256. void Set_palette_RGB_scale(int); int Get_palette_RGB_scale(void); /// Configure Gamma correction void Set_palette_Gamma(int); /// /// Scale a component (R, G or B) according to the current RGB graduations. /// Returns the resulting value, in the [0-255] range. byte Round_palette_component(byte comp); /*! Adds 4 menu colors in the current palette. @param color_usage An up-to-date color usage table (byte[256]) (read only) @param not_picture 0 if the caller is the palette screen, 1 if it's a preview in the file selector. */ void Set_nice_menu_colors(dword * color_usage,int not_picture); /// Put some colors in the clipboard. /// @param nb_colors Number of colors to push /// @param colors First color of the input array void Set_clipboard_colors(int nb_colors, T_Components *colors); /// Get some RGB colors from clipboard. /// @param palette Target palette /// @param start_color Index of first color to replace /// @return Number of colors retrieved (0-256) int Get_clipboard_colors(T_Palette palette, byte start_color); /// Get the favorite color to use for GUI's black,dark,light or white. const T_Components * Favorite_GUI_color(byte color_index); grafx2_2.4+git20180105/src/layers.c0000664000000000000000000004452413223665306015203 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2009 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include "const.h" #include "struct.h" #include "global.h" #include "windows.h" #include "engine.h" #include "pages.h" #include "sdlscreen.h" #include "input.h" #include "help.h" #include "misc.h" #include "readline.h" #include "graph.h" void Layer_activate(int layer, short side) { word old_layers; if (layer >= Main_backups->Pages->Nb_layers) return; // Keep a copy of which layers were visible old_layers = Main_layers_visible; if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { if (side == RIGHT_SIDE) { // Right-click on current layer if (Main_current_layer == layer) { if (Main_layers_visible == (dword)(1<Pages); //Update_FX_feedback(Config.FX_Feedback); Update_pixel_renderer(); Display_all_screen(); Display_layerbar(); Display_cursor(); } void Button_Layer_add(void) { int max[] = {MAX_NB_LAYERS, MAX_NB_FRAMES, 5}; Hide_cursor(); if (Main_backups->Pages->Nb_layers < max[Main_backups->Pages->Image_mode]) { // Backup with unchanged layers Backup_layers(LAYER_NONE); if (!Add_layer(Main_backups,Main_current_layer+1)) { Update_depth_buffer(); // I just noticed this might be unneeded, since the new layer // is transparent, it shouldn't have any visible effect. Display_all_screen(); Display_layerbar(); End_of_modification(); } } Unselect_button(BUTTON_LAYER_ADD); Unselect_button(BUTTON_ANIM_ADD_FRAME); Display_cursor(); } void Button_Layer_duplicate(void) { int max[] = {MAX_NB_LAYERS, MAX_NB_FRAMES, 5}; Hide_cursor(); if (Main_backups->Pages->Nb_layers < max[Main_backups->Pages->Image_mode]) { // Backup with unchanged layers Backup_layers(LAYER_NONE); if (!Add_layer(Main_backups,Main_current_layer+1)) { // Make a copy of current image memcpy( Main_backups->Pages->Image[Main_current_layer].Pixels, Main_backups->Pages->Image[Main_current_layer-1].Pixels, Main_backups->Pages->Width*Main_backups->Pages->Height); if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { Update_depth_buffer(); // I just noticed this might be unneeded, since the new layer // is transparent, it shouldn't have any visible effect. Display_all_screen(); } Display_layerbar(); End_of_modification(); } } Unselect_button(BUTTON_LAYER_ADD); Unselect_button(BUTTON_ANIM_ADD_FRAME); Display_cursor(); } void Button_Layer_remove(void) { Hide_cursor(); if (Main_backups->Pages->Nb_layers > 1) { // Backup with unchanged layers Backup_layers(LAYER_NONE); if (!Delete_layer(Main_backups,Main_current_layer)) { Update_screen_targets(); Redraw_layered_image(); Display_all_screen(); Display_layerbar(); End_of_modification(); } } Unselect_button(BUTTON_LAYER_REMOVE); Unselect_button(BUTTON_ANIM_REMOVE_FRAME); Display_cursor(); } short Layer_under_mouse(void) { short layer; // Determine which button is clicked according to mouse position layer = (Mouse_X/Menu_factor_X - Menu_bars[MENUBAR_LAYERS].Skin_width) / Layer_button_width; // Safety required because the mouse cursor can have slided outside button. if (layer < 0) layer=0; else if (layer > Main_backups->Pages->Nb_layers-1) layer=Main_backups->Pages->Nb_layers-1; return layer; } void Button_Layer_select(void) { short layer = Layer_under_mouse(); Layer_activate(layer, LEFT_SIDE); Mouse_K=0; } void Button_Layer_toggle(void) { int layer; // Determine which button is clicked according to mouse position layer = (Mouse_X/Menu_factor_X - Menu_bars[MENUBAR_LAYERS].Skin_width) / Layer_button_width; // Safety required because the mouse cursor can have slided outside button. if (layer < 0) layer=0; else if (layer > Main_backups->Pages->Nb_layers-1) layer=Main_backups->Pages->Nb_layers-1; Layer_activate(layer, RIGHT_SIDE); Mouse_K=0; } static void Draw_transparent_color(byte color) { char buf[4]; Num2str(color, buf, 3); Print_in_window(63,39,buf,MC_Black,MC_Light); Window_rectangle(90,39,13,7,color); } static void Draw_transparent_background(byte background) { Print_in_window(99,57,background?"X":" ",MC_Black,MC_Light); } void Button_Layer_menu(void) { byte transparent_color = Main_backups->Pages->Transparent_color; byte transparent_background = Main_backups->Pages->Background_transparent; short clicked_button; byte color; byte click; Open_window(122,100,"Layers"); Window_display_frame_in( 6, 21,110, 52); Print_in_window(14,18,"Transparency",MC_Dark,MC_Light); Print_in_window(11,38,"Color",MC_Black,MC_Light); Window_set_normal_button(54, 36, 56,13,"" , 0,1,KEY_NONE); // 1 Draw_transparent_color(transparent_color); Print_in_window(11,57,"Background",MC_Black,MC_Light); Window_set_normal_button(95, 54, 15,13,"" , 0,1,KEY_NONE); // 2 Draw_transparent_background(transparent_background); Window_set_normal_button( 7, 78, 51,14,"OK" , 0,1,SDLK_RETURN); // 3 Window_set_normal_button(63, 78, 51,14,"Cancel", 0,1,KEY_ESC); // 4 Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_LAYER_MENU, NULL); switch(clicked_button) { case 1: // color Get_color_behind_window(&color,&click); if (click && transparent_color!=color) { transparent_color=color; Hide_cursor(); Draw_transparent_color(transparent_color); Display_cursor(); Wait_end_of_click(); } break; case 2: // background transparent_background = !transparent_background; Hide_cursor(); Draw_transparent_background(transparent_background); Display_cursor(); break; } } while (clicked_button<3); // On exit Hide_cursor(); Close_window(); if (clicked_button==3) { // Accept changes if (Main_backups->Pages->Transparent_color != transparent_color || Main_backups->Pages->Background_transparent != transparent_background) { Backup_layers(LAYER_NONE); Main_backups->Pages->Transparent_color = transparent_color; Main_backups->Pages->Background_transparent = transparent_background; Redraw_layered_image(); Display_all_screen(); End_of_modification(); } } Unselect_button(BUTTON_LAYER_MENU); Unselect_button(BUTTON_LAYER_MENU2); Display_cursor(); } void Button_Layer_set_transparent(void) { Hide_cursor(); if (Main_backups->Pages->Transparent_color != Back_color) { Backup_layers(LAYER_ALL); Main_backups->Pages->Transparent_color = Back_color; Redraw_layered_image(); Display_all_screen(); End_of_modification(); } Unselect_button(BUTTON_LAYER_COLOR); Display_cursor(); } void Button_Layer_get_transparent(void) { Hide_cursor(); if (Main_backups->Pages->Transparent_color != Back_color) { Set_back_color(Main_backups->Pages->Transparent_color); } Unselect_button(BUTTON_LAYER_COLOR); Display_cursor(); } void Button_Layer_merge(void) { Hide_cursor(); if (Main_current_layer>0) { // Backup layer below the current Backup_layers(Main_current_layer-1); Merge_layer(); Update_screen_targets(); Redraw_layered_image(); Display_all_screen(); Display_layerbar(); End_of_modification(); } Unselect_button(BUTTON_LAYER_MERGE); Display_cursor(); } void Button_Layer_up(void) { Hide_cursor(); if (Main_current_layer < (Main_backups->Pages->Nb_layers-1)) { T_Image tmp; dword layer_flags; // Backup with unchanged layers Backup_layers(LAYER_NONE); // swap tmp = Main_backups->Pages->Image[Main_current_layer]; Main_backups->Pages->Image[Main_current_layer] = Main_backups->Pages->Image[Main_current_layer+1]; Main_backups->Pages->Image[Main_current_layer+1] = tmp; // Swap visibility indicators layer_flags = (Main_layers_visible >> Main_current_layer) & 3; // Only needed if they are different. if (layer_flags == 1 || layer_flags == 2) { // One is on, the other is off. Negating them will // perform the swap. Main_layers_visible ^= (3 << Main_current_layer); } Main_current_layer++; Update_screen_targets(); Redraw_layered_image(); Display_all_screen(); Display_layerbar(); End_of_modification(); } Unselect_button(BUTTON_LAYER_UP); Unselect_button(BUTTON_ANIM_UP_FRAME); Display_cursor(); } void Button_Layer_down(void) { Hide_cursor(); if (Main_current_layer > 0) { T_Image tmp; dword layer_flags; // Backup with unchanged layers Backup_layers(LAYER_NONE); // swap tmp = Main_backups->Pages->Image[Main_current_layer]; Main_backups->Pages->Image[Main_current_layer] = Main_backups->Pages->Image[Main_current_layer-1]; Main_backups->Pages->Image[Main_current_layer-1] = tmp; // Swap visibility indicators layer_flags = (Main_layers_visible >> (Main_current_layer-1)) & 3; // Only needed if they are different. if (layer_flags == 1 || layer_flags == 2) { // Only needed if they are different. // One is on, the other is off. Negating them will // perform the swap. Main_layers_visible ^= (3 << (Main_current_layer-1)); } Main_current_layer--; Update_screen_targets(); Redraw_layered_image(); Display_layerbar(); Display_all_screen(); End_of_modification(); } Unselect_button(BUTTON_LAYER_DOWN); Unselect_button(BUTTON_ANIM_DOWN_FRAME); Display_cursor(); } int Interpret_delay(int delay) { // Firefox behavior if (delay>30) return delay; if (delay==0) return 100; return 30; } void Button_Anim_time(void) { short clicked_button; int mode=0; int frame; char buffer[6+1]; T_Special_button * input_duration_button; int duration=Main_backups->Pages->Image[Main_current_layer].Duration; Open_window(166,110,"Animation speed"); Print_in_window(88,20,"ms",MC_Black,MC_Light); input_duration_button = Window_set_input_button(33,18,6); // 1 Num2str(duration,buffer,6); Print_in_window_limited(input_duration_button->Pos_X+2,input_duration_button->Pos_Y+2,buffer,input_duration_button->Width/8,MC_Black,MC_Light); Print_in_window(24,37,"Set this frame",MC_Black,MC_Light); Window_set_normal_button(7, 34, 13,13,"X" , 0,1,KEY_NONE); // 2 Print_in_window(24,55,"Set all frames",MC_Black,MC_Light); Window_set_normal_button(7, 52, 13,13,"" , 0,1,KEY_NONE); // 3 Print_in_window(24,73,"Add to all frames",MC_Black,MC_Light); Window_set_normal_button(7, 70, 13,13,"" , 0,1,KEY_NONE); // 4 Window_set_normal_button( 7, 92, 51,14,"OK" , 0,1,SDLK_RETURN); // 5 Window_set_normal_button(63, 92, 51,14,"Cancel", 0,1,KEY_ESC); // 6 Update_window_area(0,0,Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_ANIM_TIME, NULL); switch(clicked_button) { case 1: // duration // safety if (duration <= -10000) sprintf(buffer,"-99999"); else if (duration >= 1000000) sprintf(buffer,"999999"); else sprintf(buffer,"%d", duration); Hide_cursor(); if (Readline(input_duration_button->Pos_X+2, input_duration_button->Pos_Y+2, buffer, 6, INPUT_TYPE_DECIMAL)) { duration=atoi(buffer); } Print_in_window_limited(input_duration_button->Pos_X+2,input_duration_button->Pos_Y+2,buffer,input_duration_button->Width/8,MC_Black,MC_Light); Display_cursor(); break; case 2: // Radio: set 1 case 3: // Radio: set all case 4: // Radio: add mode=clicked_button-2; Hide_cursor(); Print_in_window(10,37,mode==0?"X":" ",MC_Black,MC_Light); Print_in_window(10,55,mode==1?"X":" ",MC_Black,MC_Light); Print_in_window(10,73,mode==2?"X":" ",MC_Black,MC_Light); Display_cursor(); break; } } while (clicked_button<5); // On exit Hide_cursor(); Close_window(); if (clicked_button==5) { // Accept changes Backup_layers(LAYER_NONE); switch(mode) { case 0: if (duration<0) duration=0; else if (duration>655350) duration=655350; Main_backups->Pages->Image[Main_current_layer].Duration = duration; break; case 1: if (duration<0) duration=0; else if (duration>655350) duration=655350; for (frame=0; framePages->Nb_layers; frame++) { Main_backups->Pages->Image[frame].Duration = duration; } break; case 2: for (frame=0; framePages->Nb_layers; frame++) { int cur_duration = Main_backups->Pages->Image[frame].Duration+duration; if (cur_duration<0) cur_duration=0; else if (cur_duration>655350) cur_duration=655350; Main_backups->Pages->Image[frame].Duration = cur_duration; } break; break; } End_of_modification(); } Unselect_button(BUTTON_ANIM_TIME); Display_cursor(); } void Button_Anim_first_frame(void) { if (Main_current_layer>0) Layer_activate(0,LEFT_SIDE); Hide_cursor(); Unselect_button(BUTTON_ANIM_FIRST_FRAME); Display_cursor(); } void Button_Anim_prev_frame(void) { if (Main_backups->Pages->Nb_layers>1) { if (Main_current_layer==0) Layer_activate(Main_backups->Pages->Nb_layers-1,LEFT_SIDE); else Layer_activate(Main_current_layer-1,LEFT_SIDE); } Hide_cursor(); Unselect_button(BUTTON_ANIM_PREV_FRAME); Display_cursor(); } void Button_Anim_next_frame(void) { if (Main_backups->Pages->Nb_layers>1) { if (Main_current_layer==Main_backups->Pages->Nb_layers-1) Layer_activate(0,LEFT_SIDE); else Layer_activate(Main_current_layer+1,LEFT_SIDE); } Hide_cursor(); Unselect_button(BUTTON_ANIM_NEXT_FRAME); Display_cursor(); } void Button_Anim_last_frame(void) { if (Main_current_layer < (Main_backups->Pages->Nb_layers-1)) Layer_activate((Main_backups->Pages->Nb_layers-1),LEFT_SIDE); Hide_cursor(); Unselect_button(BUTTON_ANIM_LAST_FRAME); Display_cursor(); } void Button_Anim_continuous_next(void) { Uint32 time_start; int time_in_current_frame=0; time_start = SDL_GetTicks(); do { int target_frame; Uint32 time_now; Get_input(20); time_now=SDL_GetTicks(); time_in_current_frame += time_now-time_start; time_start=time_now; target_frame = Main_current_layer; while (time_in_current_frame > Main_backups->Pages->Image[target_frame].Duration) { time_in_current_frame -= Interpret_delay(Main_backups->Pages->Image[target_frame].Duration); target_frame = (target_frame+1) % Main_backups->Pages->Nb_layers; } if (target_frame != Main_current_layer) { Layer_activate(target_frame,LEFT_SIDE); } } while (Mouse_K); Hide_cursor(); Unselect_button(BUTTON_ANIM_NEXT_FRAME); Display_cursor(); } void Button_Anim_continuous_prev(void) { Uint32 time_start; int time_in_current_frame=0; time_start = SDL_GetTicks(); do { int target_frame; Uint32 time_now; Get_input(20); time_now=SDL_GetTicks(); time_in_current_frame += time_now-time_start; time_start=time_now; target_frame = Main_current_layer; while (time_in_current_frame > Main_backups->Pages->Image[target_frame].Duration) { time_in_current_frame -= Interpret_delay(Main_backups->Pages->Image[target_frame].Duration); target_frame = (target_frame+Main_backups->Pages->Nb_layers-1) % Main_backups->Pages->Nb_layers; } if (target_frame != Main_current_layer) { Layer_activate(target_frame,LEFT_SIDE); } } while (Mouse_K); Hide_cursor(); Unselect_button(BUTTON_ANIM_PREV_FRAME); Display_cursor(); } grafx2_2.4+git20180105/src/pxtall.c0000664000000000000000000003126013223665306015201 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include "global.h" #include "sdlscreen.h" #include "misc.h" #include "graph.h" #include "pxtall.h" #include "pxsimple.h" #define ZOOMX 1 #define ZOOMY 2 void Pixel_tall (word x,word y,byte color) /* Affiche un pixel de la color aux coords x;y l'cran */ { *(Screen_pixels + x + y*ZOOMY*VIDEO_LINE_WIDTH)=color; *(Screen_pixels + x + (y*ZOOMY+1)*VIDEO_LINE_WIDTH)=color; } byte Read_pixel_tall (word x,word y) /* On retourne la couleur du pixel aux coords donnes */ { return *( Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x ); } void Block_tall (word start_x,word start_y,word width,word height,byte color) /* On affiche un rectangle de la couleur donne */ { SDL_Rect rectangle; rectangle.x=start_x; rectangle.y=start_y*ZOOMY; rectangle.w=width; rectangle.h=height*ZOOMY; SDL_FillRect(Screen_SDL,&rectangle,color); } void Display_part_of_screen_tall (word width,word height,word image_width) /* Afficher une partie de l'image telle quelle sur l'cran */ { byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'cran (dest) byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de dpart ds la source (src) int y; for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne memcpy(dest,src,width); dest+=VIDEO_LINE_WIDTH; memcpy(dest,src,width); // On passe la ligne suivante src+=image_width; dest+=VIDEO_LINE_WIDTH; } //Update_rect(0,0,width,height); } void Pixel_preview_normal_tall (word x,word y,byte color) /* Affichage d'un pixel dans l'cran, par rapport au dcalage de l'image * dans l'cran, en mode normal (pas en mode loupe) * Note: si on modifie cette procdure, il faudra penser faire galement * la modif dans la procdure Pixel_Preview_Loupe_SDL. */ { // if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) Pixel_tall(x-Main_offset_X,y-Main_offset_Y,color); } void Pixel_preview_magnifier_tall (word x,word y,byte color) { // Affiche le pixel dans la partie non zoome Pixel_tall(x-Main_offset_X,y-Main_offset_Y,color); // Regarde si on doit aussi l'afficher dans la partie zoome if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) { // On est dedans int height; int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); if (Menu_Y - y_zoom < Main_magnifier_factor) // On ne doit dessiner qu'un morceau du pixel // sinon on dpasse sur le menu height = Menu_Y - y_zoom; else height = Main_magnifier_factor; Block_tall( Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, y_zoom, Main_magnifier_factor, height, color ); } } void Horizontal_XOR_line_tall(word x_pos,word y_pos,word width) { //On calcule la valeur initiale de dest: byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; int x; for (x=0;x 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *dest = *src; *(dest+VIDEO_LINE_WIDTH) = *src; } // Pixel suivant src++; dest++; } // On passe la ligne suivante dest = dest + ZOOMY*VIDEO_LINE_WIDTH - width; src = src + brush_width - width; } Update_rect(x_pos,y_pos,width,height); } void Display_brush_mono_tall(word x_pos, word y_pos, word x_offset, word y_offset, word width, word height, byte transp_color, byte color, word brush_width) /* On affiche la brosse en monochrome */ { byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; // dest = adr Destination // l'cran byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds // la brosse int x,y; for(y=height;y!=0;y--) //Pour chaque ligne { for(x=width;x!=0;x--) //Pour chaque pixel { if (*src!=transp_color) { *dest=color; *(dest+VIDEO_LINE_WIDTH)=color; } // On passe au pixel suivant src++; dest++; } // On passe la ligne suivante src+=brush_width-width; dest+=ZOOMY*VIDEO_LINE_WIDTH-width; } Update_rect(x_pos,y_pos,width,height); } void Clear_brush_tall(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width) { byte* dest=Screen_pixels+x_pos+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'cran (dest) byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de dpart ds la source (src) int y; (void)x_offset; // unused (void)y_offset; // unused (void)transp_color; // unused for(y=height;y!=0;y--) // Pour chaque ligne { // On fait une copie de la ligne memcpy(dest,src,width); dest+=VIDEO_LINE_WIDTH; memcpy(dest,src,width); // On passe la ligne suivante src+=image_width; dest+=VIDEO_LINE_WIDTH; } Update_rect(x_pos,y_pos,width,height); } // Affiche une brosse (arbitraire) l'cran void Display_brush_tall(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) { // dest = Position l'cran byte* dest = Screen_pixels + y_pos*ZOOMY*VIDEO_LINE_WIDTH + x_pos; // src = Position dans la brosse byte* src = brush + y_offset * brush_width + x_offset; word x,y; // Pour chaque ligne for(y = height;y > 0; y--) { // Pour chaque pixel for(x = width;x > 0; x--) { // On vrifie que ce n'est pas la transparence if(*src != transp_color) { *dest = *src; *(dest+VIDEO_LINE_WIDTH) = *src; } // Pixel suivant src++; dest++; } // On passe la ligne suivante dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width; src = src + brush_width - width; } } void Remap_screen_tall(word x_pos,word y_pos,word width,word height,byte * conversion_table) { // dest = coords a l'cran byte* dest = Screen_pixels + y_pos*ZOOMY*VIDEO_LINE_WIDTH + x_pos; int x,y; // Pour chaque ligne for(y=height*ZOOMY;y>0;y--) { // Pour chaque pixel for(x=width;x>0;x--) { *dest = conversion_table[*dest]; dest ++; } dest = dest + VIDEO_LINE_WIDTH - width; } Update_rect(x_pos,y_pos,width,height); } void Display_line_on_screen_tall(word x_pos,word y_pos,word width,byte * line) /* On affiche toute une ligne de pixels. Utilis pour les textes. */ { memcpy(Screen_pixels+x_pos+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width); memcpy(Screen_pixels+x_pos+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width); } void Read_line_screen_tall(word x_pos,word y_pos,word width,byte * line) { memcpy(line,VIDEO_LINE_WIDTH*ZOOMY*y_pos + x_pos + Screen_pixels,width); } void Display_part_of_screen_scaled_tall( word width, // width non zoome word height, // height zoome word image_width,byte * buffer) { byte* src = Main_screen + Main_magnifier_offset_Y * image_width + Main_magnifier_offset_X; int y = 0; // Ligne en cours de traitement // Pour chaque ligne zoomer while(1) { int x; // On clate la ligne Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On l'affiche Facteur fois, sur des lignes conscutives x = Main_magnifier_factor*ZOOMY; // Pour chaque ligne do{ // On affiche la ligne zoome Display_line_on_screen_simple( Main_X_zoom, y, width*Main_magnifier_factor, buffer ); // On passe la suivante y++; if(y==height*ZOOMY) { Redraw_grid(Main_X_zoom,0, width*Main_magnifier_factor,height); Update_rect(Main_X_zoom,0, width*Main_magnifier_factor,height); return; } x--; }while (x > 0); src += image_width; } // ATTENTION on n'arrive jamais ici ! } // Affiche une partie de la brosse couleur zoome void Display_brush_color_zoom_tall(word x_pos,word y_pos, word x_offset,word y_offset, word width, // width non zoome word end_y_pos,byte transp_color, word brush_width, // width relle de la brosse byte * buffer) { byte* src = Brush+y_offset*brush_width + x_offset; word y = y_pos; byte bx; // Pour chaque ligne while(1) { Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche facteur fois la ligne zoome for(bx=Main_magnifier_factor;bx>0;bx--) { Display_transparent_line_on_screen_simple(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); memcpy(Screen_pixels + (y*ZOOMY +1) * VIDEO_LINE_WIDTH + x_pos, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos, width*Main_magnifier_factor); y++; if(y==end_y_pos) { return; } } src += brush_width; } // ATTENTION zone jamais atteinte } void Display_brush_mono_zoom_tall(word x_pos, word y_pos, word x_offset, word y_offset, word width, // width non zoome word end_y_pos, byte transp_color, byte color, word brush_width, // width relle de la brosse byte * buffer ) { byte* src = Brush + y_offset * brush_width + x_offset; int y=y_pos*ZOOMY; //Pour chaque ligne zoomer : while(1) { int bx; // src = Ligne originale // On clate la ligne Zoom_a_line(src,buffer,Main_magnifier_factor,width); // On affiche la ligne Facteur fois l'cran (sur des // lignes conscutives) bx = Main_magnifier_factor*ZOOMY; // Pour chaque ligne cran do { // On affiche la ligne zoome Display_transparent_mono_line_on_screen_simple( x_pos, y, width * Main_magnifier_factor, buffer, transp_color, color ); // On passe la ligne suivante y++; // On vrifie qu'on est pas la ligne finale if(y == end_y_pos*ZOOMY) { Redraw_grid( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); Update_rect( x_pos, y_pos, width * Main_magnifier_factor, end_y_pos - y_pos ); return; } bx --; } while (bx > 0); // Passage la ligne suivante dans la brosse aussi src+=brush_width; } } void Clear_brush_scaled_tall(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer) { // En fait on va recopier l'image non zoome dans la partie zoome ! byte* src = Main_screen + y_offset * image_width + x_offset; int y = y_pos; int bx; (void)transp_color; // unused // Pour chaque ligne zoomer while(1){ Zoom_a_line(src,buffer,Main_magnifier_factor,width); bx=Main_magnifier_factor; // Pour chaque ligne do{ Display_line_on_screen_tall(x_pos,y, width * Main_magnifier_factor,buffer); // Ligne suivante y++; if(y==end_y_pos) { Redraw_grid(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); Update_rect(x_pos,y_pos, width*Main_magnifier_factor,end_y_pos-y_pos); return; } bx--; }while(bx!=0); src+= image_width; } } grafx2_2.4+git20180105/src/libraw2crtc.c0000664000000000000000000001055013223665306016112 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* GFX2CRTC - libraw2crtc.c * CloudStrife - 20080921 * Diffus sous licence libre CeCILL v2 * Voire LICENCE */ #include #include #include #include "const.h" #include "global.h" #include "struct.h" #include "loadsave.h" unsigned short addrCalc(unsigned char vcc, unsigned char rcc, unsigned char hcc, unsigned char cclk, unsigned char r1, unsigned char r12, unsigned char r13) { unsigned short MA; unsigned short addr; //MA = vcc*r1 + hcc + (0x0C)*256; MA = vcc*r1 + hcc + r12*256 + r13; addr = cclk | ((MA & 0x03FF) << 1); addr = addr | ((rcc & 0x07) << 11); addr = addr | ((MA & 0x3000) << 2); return addr; } unsigned char mode0interlace(T_IO_Context * context, unsigned char x, unsigned char y) { unsigned char mode0pixel[] = {0, 64, 4, 68, 16, 80, 20, 84, 1, 65, 5, 69, 17, 81, 21, 85}; return mode0pixel[Get_pixel(context,x,y)] << 1 | mode0pixel[Get_pixel(context,x+1,y)]; } unsigned char mode1interlace(T_IO_Context * context, unsigned char x, unsigned char y) { unsigned char mode1pixel[] = {0, 16, 1, 17}; return mode1pixel[Get_pixel(context,x,y)] << 3 | mode1pixel[Get_pixel(context,x+1,y)] << 2 | mode1pixel[Get_pixel(context,x+2,y)] << 1 | mode1pixel[Get_pixel(context,x+3,y)]; } unsigned char mode2interlace(T_IO_Context * context, unsigned char x, unsigned char y) { unsigned char out = 0; int i; for(i = 0; i < 8; i++) out += ((Get_pixel(context,x+7-i,y)&1) << i); return out; } unsigned char mode3interlace(T_IO_Context * context, unsigned char x, unsigned char y) { unsigned char mode3pixel[] = {0, 16, 1, 17}; return mode3pixel[Get_pixel(context, x,y)] << 3 | mode3pixel[Get_pixel(context,x+1,y)] << 2; } unsigned char (*ptrMode)(T_IO_Context * context, unsigned char x, unsigned char y); unsigned char *raw2crtc(T_IO_Context *context, unsigned char mode, unsigned char r9, unsigned long *outSize, unsigned char *r1, unsigned char r12, unsigned char r13) { unsigned char *outBuffer; unsigned char *tmpBuffer; unsigned char *allocationBuffer; unsigned short minAddr = 0; unsigned char minAddrIsDefined = 0; unsigned short maxAddr = 0; int y,x; unsigned char r6; unsigned short i; unsigned char *ptrTmp; unsigned char *ptrOut; unsigned char vcc; unsigned char rcc; unsigned char hcc; unsigned char cclk; int width = context->Width; int height = context->Height; switch(mode) { case 0: { *r1 = (width+3)/4; ptrMode = mode0interlace; break; } case 1: { *r1 = (width+7)/8; ptrMode = mode1interlace; break; } case 2: { *r1 = (width+15)/16; ptrMode = mode2interlace; break; } case 3: { *r1 = (width+3)/4; ptrMode = mode3interlace; break; } default: { exit(4); } } tmpBuffer = (unsigned char*)malloc(0xFFFF); if (tmpBuffer == NULL) { printf("Allocation tmpBuffer rat\n"); exit(4); } allocationBuffer = (unsigned char*)malloc(0xFFFF); if(allocationBuffer == NULL) { printf("Allocation allocationBuffer rat\n"); exit(4); } memset(allocationBuffer, 0, 0xFFFF); r6 = height/(r9+1); for(vcc = 0; vcc < r6; vcc++) { for(rcc = 0; rcc < (r9+1); rcc++) { for(hcc = 0; hcc < *r1; hcc++) { for(cclk = 0; cclk < 2; cclk++) { x = (hcc << 1 | cclk); y = vcc*(r9+1) + rcc; *(tmpBuffer + addrCalc(vcc, rcc, hcc, cclk, *r1, r12, r13)) = (*ptrMode)(context,x,y); *(allocationBuffer + addrCalc(vcc, rcc, hcc, cclk, *r1, r12, r13)) += 1; } } } } for(i = 0; i < 0xFFFF; i++) { if(*(allocationBuffer + i) > 1) { printf("Attention : Ecriture multiple a l'adresse mmoire %d\n",i); } if(*(allocationBuffer + i) > 0) { maxAddr = i; } if((*(allocationBuffer + i) == 1) && (minAddrIsDefined == 0)) { minAddr = i; minAddrIsDefined = 1; } } *outSize = (maxAddr + 1) - minAddr; outBuffer = (unsigned char*)malloc((*outSize)); if (outBuffer == NULL) { printf("Allocation outBuffer rat\n"); exit(4); } ptrTmp = tmpBuffer + minAddr; ptrOut = outBuffer; for(i = minAddr; i <= maxAddr; i++) { *(ptrOut++) = *(ptrTmp++); } free(tmpBuffer); tmpBuffer = NULL; free(allocationBuffer); allocationBuffer = NULL; return outBuffer; } grafx2_2.4+git20180105/src/saveini.c0000664000000000000000000005412513223665306015340 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include "const.h" #include "global.h" #include "readini.h" #include "io.h" #include "errors.h" #include "misc.h" #include "saveini.h" #include "setup.h" #include "windows.h" int Save_INI_reach_group(FILE * old_file,FILE * new_file,char * buffer,char * group) { int stop_seek; char * group_upper; char * upper_buffer; // On alloue les zones de mmoire: group_upper =(char *)malloc(1024); upper_buffer=(char *)malloc(1024); // On commence par se faire une version majuscule du groupe rechercher: strcpy(group_upper,group); Load_INI_clear_string(group_upper, 0); stop_seek=0; do { // On lit une ligne dans le fichier: if (fgets(buffer,1024,old_file)==0) { free(upper_buffer); free(group_upper); return ERROR_INI_CORRUPTED; } // On s'en fait une version en majuscule: strcpy(upper_buffer,buffer); Load_INI_clear_string(upper_buffer, 0); // On compare la chane avec le groupe recherch: stop_seek=Load_INI_seek_pattern(upper_buffer,group_upper); if (fprintf(new_file,"%s",buffer)<0) { free(upper_buffer); free(group_upper); return ERROR_SAVING_INI; } } while (stop_seek==0); free(upper_buffer); free(group_upper); return 0; } int Save_INI_char_in_value_alphabet(char c) { if ( ( // Digit (c>='0') && (c<='9') ) || ( // Uppercase letter (c>='A') && (c<='Z') ) || ( // Lowerchase letter (c>='a') && (c<='z') ) || (c == '$') || // Hexa prefix (c == '-') || // Minus sign (c== '.') // Dot (in filenames) ) return 1; else return 0; } void Save_INI_set_value(char * dest,char * source,int nb_values_to_set,int * values,int litteral) { int dest_index; int source_index; int value_index; // On commence par recopier tout jusqu'au symbole '=': for (source_index=0;source[source_index]!='=';source_index++) dest[source_index]=source[source_index]; // Puis on recopie le symbole '=': dest[source_index]=source[source_index]; source_index++; // Puis on recopie tous les espaces qui suivent: for (;source[source_index]==' ';source_index++) dest[source_index]=source[source_index]; // Pour l'instant, la source et la destination en sont au mme point: dest_index=source_index; // Puis pour chaque valeur recopier: for (value_index=0;value_index Yes memcpy(dest+dest_index,"yes",3); dest_index+=3; } else { // La valeur <=> No memcpy(dest+dest_index,"no",2); dest_index+=2; } } else { // La valeur doit tre crite sous forme numrique if (source[source_index]=='$') { // On va crire la valeur sous forme hexadcimale: // On commence par inscrire le symbole '$': dest[dest_index]='$'; // Puis on y concatne la valeur: sprintf(dest+dest_index+1,"%x",values[value_index]); dest_index+=strlen(dest+dest_index); } else { // On va crire la valeur sous forme dcimale: sprintf(dest+dest_index,"%d",values[value_index]); dest_index+=strlen(dest+dest_index); } } // Dans la source, on saute la valeur: for (;Save_INI_char_in_value_alphabet(source[source_index]) && (source[source_index]!='\0');source_index++); if (value_index!=(nb_values_to_set-1)) { // Il reste d'autres valeurs crire // On recopie tous les caractres de la source jusqu'au suivant qui // dsigne une valeur: for (;(!Save_INI_char_in_value_alphabet(source[source_index])) && (source[source_index]!='\0');source_index++,dest_index++) dest[dest_index]=source[source_index]; } else { // C'est la dernire valeur initialiser // On recopie toute la fin de la ligne: for (;source[source_index]!='\0';source_index++,dest_index++) dest[dest_index]=source[source_index]; // Et on n'oublie pas d'y mettre l''\0': dest[dest_index]='\0'; } } } void Save_INI_set_string(char * dest,char * source,char * value) { int dest_index; int source_index; // On commence par recopier tout jusqu'au symbole '=': for (source_index=0;source[source_index]!='=';source_index++) dest[source_index]=source[source_index]; // Puis on recopie le symbole '=': dest[source_index]=source[source_index]; source_index++; // Puis on recopie tous les espaces qui suivent: for (;source[source_index]==' ';source_index++) dest[source_index]=source[source_index]; // Pour l'instant, la source et la destination en sont au mme point: dest_index=source_index; // Dans la destination, on crit la valeur: strcpy(dest+dest_index,value); dest_index+=strlen(value); // Dans la source, on saute la valeur: for (;Save_INI_char_in_value_alphabet(source[source_index]) && (source[source_index]!='\0');source_index++); // On recopie toute la fin de la ligne: for (;source[source_index]!='\0';source_index++,dest_index++) dest[dest_index]=source[source_index]; // Et on n'oublie pas d'y mettre l''\0': dest[dest_index]='\0'; } int Save_INI_set_strings(FILE * old_file,FILE * new_file,char * buffer,char * option_name,char * value) { int stop_seek; char * option_upper; char * upper_buffer; char * result_buffer; //int buffer_index; // On alloue les zones de mmoire: option_upper=(char *)malloc(1024); upper_buffer=(char *)malloc(1024); result_buffer=(char *)malloc(1024); // On convertit un eventuel argument NULL en chaine vide. if (value == NULL) value=""; // On commence par se faire une version majuscule de l'option rechercher: strcpy(option_upper,option_name); Load_INI_clear_string(option_upper, 0); stop_seek=0; do { // On lit une ligne dans le fichier: if (fgets(buffer,1024,old_file)==0) { free(result_buffer); free(upper_buffer); free(option_upper); return ERROR_INI_CORRUPTED; } // On s'en fait une version en majuscule: strcpy(upper_buffer,buffer); Load_INI_clear_string(upper_buffer, 0); // On compare la chane avec l'option recherche: stop_seek=Load_INI_seek_pattern(upper_buffer,option_upper); if (stop_seek) { // On l'a trouve: Save_INI_set_string(result_buffer,buffer,value); if (fprintf(new_file,"%s",result_buffer)<0) { free(result_buffer); free(upper_buffer); free(option_upper); return ERROR_SAVING_INI; } } else { // On l'a pas trouve: if (fprintf(new_file,"%s",buffer)<0) { free(result_buffer); free(upper_buffer); free(option_upper); return ERROR_SAVING_INI; } } } while (stop_seek==0); free(result_buffer); free(upper_buffer); free(option_upper); return 0; } int Save_INI_set_values(FILE * old_file,FILE * new_file,char * buffer,char * option_name,int nb_values_to_set,int * values,int litteral) { int stop_seek; char * option_upper; char * upper_buffer; char * result_buffer; //int buffer_index; // On alloue les zones de mmoire: option_upper=(char *)malloc(1024); upper_buffer=(char *)malloc(1024); result_buffer=(char *)malloc(1024); // On commence par se faire une version majuscule de l'option rechercher: strcpy(option_upper,option_name); Load_INI_clear_string(option_upper, 0); stop_seek=0; do { // On lit une ligne dans le fichier: if (fgets(buffer,1024,old_file)==0) { free(result_buffer); free(upper_buffer); free(option_upper); DEBUG("END OF FILE",0); return ERROR_INI_CORRUPTED; } // On s'en fait une version en majuscule: strcpy(upper_buffer,buffer); Load_INI_clear_string(upper_buffer, 0); // On compare la chane avec l'option recherche: stop_seek=Load_INI_seek_pattern(upper_buffer,option_upper); if (stop_seek) { // On l'a trouve: Save_INI_set_value(result_buffer,buffer,nb_values_to_set,values,litteral); if (fprintf(new_file,"%s",result_buffer)<0) { free(result_buffer); free(upper_buffer); free(option_upper); return ERROR_SAVING_INI; } } else { // On l'a pas trouve: if (fprintf(new_file,"%s",buffer)<0) { free(result_buffer); free(upper_buffer); free(option_upper); return ERROR_SAVING_INI; } } } while (stop_seek==0); free(result_buffer); free(upper_buffer); free(option_upper); return 0; } void Save_INI_flush(FILE * old_file,FILE * new_file,char * buffer) { while (fgets(buffer,1024,old_file)!=0) fprintf(new_file,"%s",buffer); } int Save_INI(T_Config * conf) { FILE * old_file; FILE * new_file; char * buffer; int values[3]; char filename[MAX_PATH_CHARACTERS]; char temp_filename[MAX_PATH_CHARACTERS]; int return_code; char ref_ini_file[MAX_PATH_CHARACTERS]; int ini_file_exists; int index; // On alloue les zones de mmoire: buffer=(char *)malloc(1024); // On calcule les noms des fichiers qu'on manipule: strcpy(filename,Config_directory); strcat(filename,INI_FILENAME); // On vrifie si le fichier INI existe if ((ini_file_exists = File_exists(filename))) { strcpy(temp_filename,Config_directory); strcat(temp_filename,INISAVE_FILENAME); // Delete gfx2.$$$ remove(temp_filename); // Rename current config file as gfx2.$$$ if (rename(filename,temp_filename)!=0) { goto Erreur_ERREUR_SAUVEGARDE_INI; } } // On rcupre un fichier INI "propre" partir de gfx2def.ini strcpy(ref_ini_file,Data_directory); strcat(ref_ini_file,INIDEF_FILENAME); old_file=fopen(ref_ini_file,"rb"); if (old_file==0) { fclose(old_file); free(buffer); return ERROR_INI_MISSING; } new_file=fopen(filename,"wb"); if (new_file==0) { free(buffer); return ERROR_SAVING_INI; } if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[MOUSE]"))) goto Erreur_Retour; values[0]=conf->Mouse_sensitivity_index_x; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"X_sensitivity",1,values,0))) goto Erreur_Retour; values[0]=conf->Mouse_sensitivity_index_y; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Y_sensitivity",1,values,0))) goto Erreur_Retour; values[0]=0; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"X_correction_factor",1,values,0))) goto Erreur_Retour; values[0]=0; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Y_correction_factor",1,values,0))) goto Erreur_Retour; values[0]=(conf->Cursor)+1; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Cursor_aspect",1,values,0))) goto Erreur_Retour; if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[MENU]"))) goto Erreur_Retour; values[0]=conf->Fav_menu_colors[2].R>>2; values[1]=conf->Fav_menu_colors[2].G>>2; values[2]=conf->Fav_menu_colors[2].B>>2; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Light_color",3,values,0))) goto Erreur_Retour; values[0]=conf->Fav_menu_colors[1].R>>2; values[1]=conf->Fav_menu_colors[1].G>>2; values[2]=conf->Fav_menu_colors[1].B>>2; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Dark_color",3,values,0))) goto Erreur_Retour; values[0]=conf->Ratio; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Menu_ratio",1,values,0))) goto Erreur_Retour; if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[FILE_SELECTOR]"))) goto Erreur_Retour; values[0]=conf->Show_hidden_files?1:0; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Show_hidden_files",1,values,1))) goto Erreur_Retour; values[0]=conf->Show_hidden_directories?1:0; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Show_hidden_directories",1,values,1))) goto Erreur_Retour; /* values[0]=conf->Show_system_directories?1:0; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Show_system_directories",1,values,1))) goto Erreur_Retour; */ values[0]=conf->Timer_delay; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Preview_delay",1,values,0))) goto Erreur_Retour; values[0]=conf->Maximize_preview; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Maximize_preview",1,values,1))) goto Erreur_Retour; values[0]=conf->Find_file_fast; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Find_file_fast",1,values,0))) goto Erreur_Retour; if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[LOADING]"))) goto Erreur_Retour; values[0]=conf->Auto_set_res; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_set_resolution",1,values,1))) goto Erreur_Retour; values[0]=conf->Set_resolution_according_to; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Set_resolution_according_to",1,values,0))) goto Erreur_Retour; values[0]=conf->Clear_palette; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Clear_palette",1,values,1))) goto Erreur_Retour; if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[MISCELLANEOUS]"))) goto Erreur_Retour; values[0]=conf->Display_image_limits; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Draw_limits",1,values,1))) goto Erreur_Retour; values[0]=conf->Adjust_brush_pick; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Adjust_brush_pick",1,values,1))) goto Erreur_Retour; values[0]=2-conf->Coords_rel; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Coordinates",1,values,0))) goto Erreur_Retour; values[0]=conf->Backup; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Backup",1,values,1))) goto Erreur_Retour; values[0]=conf->Max_undo_pages; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Undo_pages",1,values,0))) goto Erreur_Retour; values[0]=conf->Delay_left_click_on_slider; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Gauges_scrolling_speed_Left",1,values,0))) goto Erreur_Retour; values[0]=conf->Delay_right_click_on_slider; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Gauges_scrolling_speed_Right",1,values,0))) goto Erreur_Retour; values[0]=conf->Auto_save; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_save",1,values,1))) goto Erreur_Retour; values[0]=conf->Nb_max_vertices_per_polygon; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Vertices_per_polygon",1,values,0))) goto Erreur_Retour; values[0]=conf->Fast_zoom; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Fast_zoom",1,values,1))) goto Erreur_Retour; values[0]=conf->Separate_colors; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Separate_colors",1,values,1))) goto Erreur_Retour; values[0]=conf->FX_Feedback; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"FX_feedback",1,values,1))) goto Erreur_Retour; values[0]=conf->Safety_colors; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Safety_colors",1,values,1))) goto Erreur_Retour; values[0]=conf->Opening_message; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Opening_message",1,values,1))) goto Erreur_Retour; values[0]=conf->Clear_with_stencil; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Clear_with_stencil",1,values,1))) goto Erreur_Retour; values[0]=conf->Auto_discontinuous; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_discontinuous",1,values,1))) goto Erreur_Retour; values[0]=conf->Screen_size_in_GIF; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Save_screen_size_in_GIF",1,values,1))) goto Erreur_Retour; values[0]=conf->Auto_nb_used; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_nb_colors_used",1,values,1))) goto Erreur_Retour; if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Default_video_mode",Mode_label(conf->Default_resolution)))) goto Erreur_Retour; values[0]=Video_mode[0].Width; values[1]=Video_mode[0].Height; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Default_window_size",2,values,0))) goto Erreur_Retour; values[0]=(conf->Mouse_merge_movement); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Merge_movement",1,values,0))) goto Erreur_Retour; values[0]=(conf->Palette_cells_X); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Palette_cells_X",1,values,0))) goto Erreur_Retour; values[0]=(conf->Palette_cells_Y); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Palette_cells_Y",1,values,0))) goto Erreur_Retour; for (index=0;indexBookmark_label[index]))) goto Erreur_Retour; if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Bookmark_directory",conf->Bookmark_directory[index]))) goto Erreur_Retour; } values[0]=(conf->Palette_vertical); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Palette_vertical",1,values,1))) goto Erreur_Retour; values[0]=conf->Window_pos_x; values[1]=conf->Window_pos_y; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Window_position",2,values,0))) goto Erreur_Retour; values[0]=(conf->Double_click_speed); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Double_click_speed",1,values,0))) goto Erreur_Retour; values[0]=(conf->Double_key_speed); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Double_key_speed",1,values,0))) goto Erreur_Retour; if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Skin_file",conf->Skin_file))) goto Erreur_Retour; if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Font_file",conf->Font_file))) goto Erreur_Retour; values[0]=(Pixel_ratio); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Pixel_ratio",1,values,0))) { DEBUG("saving pixel ratio",return_code); goto Erreur_Retour; } values[0]=0; if (!Menu_bars[MENUBAR_LAYERS].Visible && !Menu_bars[MENUBAR_ANIMATION].Visible) values[0]|=2; if (!Menu_bars[MENUBAR_TOOLS].Visible) values[0]|=4; values[0]=255 ^ values[0]; // Remaining bits are filled so that when new toolbars get implemented, they will // be visible by default. if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Menubars_visible",1,values,0))) goto Erreur_Retour; values[0]=(conf->Right_click_colorpick); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Right_click_colorpick",1,values,1))) goto Erreur_Retour; values[0]=(conf->Sync_views); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Sync_views",1,values,1))) goto Erreur_Retour; switch(conf->Swap_buttons) { case MOD_CTRL: values[0]=1; break; case MOD_ALT: values[0]=2; break; default: values[0]=0; } if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Swap_buttons",1,values,0))) goto Erreur_Retour; if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Scripts_directory",conf->Scripts_directory))) goto Erreur_Retour; values[0]=(conf->Allow_multi_shortcuts); if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Allow_multi_shortcuts",1,values,1))) goto Erreur_Retour; values[0]=conf->Tilemap_allow_flipped_x; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Tilemap_detect_mirrored_x",1,values,1))) goto Erreur_Retour; values[0]=conf->Tilemap_allow_flipped_y; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Tilemap_detect_mirrored_y",1,values,1))) goto Erreur_Retour; values[0]=conf->Tilemap_show_count; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Tilemap_count",1,values,1))) goto Erreur_Retour; values[0]=conf->Use_virtual_keyboard; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Use_virtual_keyboard",1,values,0))) goto Erreur_Retour; values[0]=conf->Default_mode_layers; if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Default_mode_layers",1,values,1))) goto Erreur_Retour; // Insert new values here Save_INI_flush(old_file,new_file,buffer); fclose(new_file); fclose(old_file); // On efface le fichier temporaire <=> Ancienne version du .INI if (ini_file_exists) remove(temp_filename); free(buffer); return 0; // Gestion des erreurs: Erreur_Retour: fclose(new_file); fclose(old_file); free(buffer); return return_code; Erreur_ERREUR_SAUVEGARDE_INI: free(buffer); return ERROR_SAVING_INI; } grafx2_2.4+git20180105/src/pxtall.h0000664000000000000000000000617113223665306015211 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file pxtall.h /// Renderer for tall pixels (1x2). ////////////////////////////////////////////////////////////////////////////// #include "struct.h" void Pixel_tall (word x,word y,byte color); byte Read_pixel_tall (word x,word y); void Block_tall (word start_x,word start_y,word width,word height,byte color); void Pixel_preview_normal_tall (word x,word y,byte color); void Pixel_preview_magnifier_tall (word x,word y,byte color); void Horizontal_XOR_line_tall (word x_pos,word y_pos,word width); void Vertical_XOR_line_tall (word x_pos,word y_pos,word height); void Display_brush_color_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_brush_mono_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); void Clear_brush_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); void Remap_screen_tall (word x_pos,word y_pos,word width,word height,byte * conversion_table); void Display_part_of_screen_tall (word width,word height,word image_width); void Display_line_on_screen_tall (word x_pos,word y_pos,word width,byte * line); void Read_line_screen_tall (word x_pos,word y_pos,word width,byte * line); void Display_part_of_screen_scaled_tall(word width,word height,word image_width,byte * buffer); void Display_brush_color_zoom_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); void Display_brush_mono_zoom_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); void Clear_brush_scaled_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); void Display_brush_tall (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); grafx2_2.4+git20180105/src/windows.c0000664000000000000000000030700513223665307015373 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Franck Charlet Copyright 2007-2008 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see ******************************************************************************** Graphical interface management functions (windows, menu, cursor) */ #include #include // atoi() #include // strncpy() strlen() #include "windows.h" #include "engine.h" #include "errors.h" #include "global.h" #include "graph.h" #include "input.h" #include "misc.h" #include "op_c.h" #include "readline.h" #include "sdlscreen.h" #include "palette.h" T_Toolbar_button Buttons_Pool[NB_BUTTONS]; T_Menu_Bar Menu_bars[MENUBAR_COUNT] = {{MENU_WIDTH, 9, 1, 45, {NULL,NULL,NULL}, 20, BUTTON_HIDE }, // Status {MENU_WIDTH, 14, 1, 35, {NULL,NULL,NULL}, 236, BUTTON_ANIM_PLAY }, // Animation {MENU_WIDTH, 10, 1, 35, {NULL,NULL,NULL}, 144, BUTTON_LAYER_SELECT }, // Layers {MENU_WIDTH, 35, 1, 0, {NULL,NULL,NULL}, 254, BUTTON_CHOOSE_COL }} // Main ; /// Width of one layer button, in pixels before scaling word Layer_button_width = 1; // L'encapsulation tente une perce...ou un dernier combat. // Nombre de cellules rel dans la palette du menu word Menu_cells_X; word Palette_cells_X() { return Menu_cells_X; } word Menu_cells_Y; word Palette_cells_Y() { return Menu_cells_Y; } // Affichage d'un pixel dans le menu (si visible) void Pixel_in_menu(word bar, word x, word y, byte color) { if (Menu_is_visible && Menu_bars[bar].Visible) Block(x*Menu_factor_X,(y+Menu_bars[bar].Top)*Menu_factor_Y+Menu_Y,Menu_factor_X,Menu_factor_Y,color); } // Affichage d'un pixel dans le menu et met a jour la bitmap de skin void Pixel_in_menu_and_skin(word bar, word x, word y, byte color) { Pixel_in_menu(bar, x, y, color); Menu_bars[bar].Skin[2][y*Menu_bars[bar].Skin_width + x] = color; } // Affichage d'un pixel dans la fentre (la fentre doit tre visible) void Pixel_in_window(word x,word y,byte color) { Block((x*Menu_factor_X)+Window_pos_X,(y*Menu_factor_Y)+Window_pos_Y,Menu_factor_X,Menu_factor_Y,color); } // Affichage d'un rectangle dans la fentre (la fentre doit tre visible) void Window_rectangle(word x_pos,word y_pos,word width,word height,byte color) { Block((x_pos*Menu_factor_X)+Window_pos_X,(y_pos*Menu_factor_Y)+Window_pos_Y,width*Menu_factor_X,height*Menu_factor_Y,color); } // -- Affichages de diffrents cadres dans une fentre ----------------------- // -- Frame gnral avec couleurs paramtrables -- void Window_display_frame_generic(word x_pos,word y_pos,word width,word height, byte color_tl,byte color_br,byte color_s,byte color_tlc,byte color_brc) // Paramtres de couleurs: // color_tl =Bords Haut et Gauche // color_br =Bords Bas et Droite // color_s =Coins Haut-Droite et Bas-Gauche // color_tlc=Coin Haut-Gauche // color_brc=Coin Bas-Droite { // Bord haut (sans les extrmits) Window_rectangle(x_pos+1,y_pos,width-2,1,color_tl); // Bord bas (sans les extrmits) Window_rectangle(x_pos+1,y_pos+height-1,width-2,1,color_br); // Bord gauche (sans les extrmits) Window_rectangle(x_pos, y_pos+1,1,height-2,color_tl); // Bord droite (sans les extrmits) Window_rectangle(x_pos+width-1,y_pos+1,1,height-2,color_br); // Coin haut gauche Pixel_in_window(x_pos,y_pos,color_tlc); // Coin haut droite Pixel_in_window(x_pos+width-1,y_pos,color_s); // Coin bas droite Pixel_in_window(x_pos+width-1,y_pos+height-1,color_brc); // Coin bas gauche Pixel_in_window(x_pos,y_pos+height-1,color_s); } // -- Frame dont tout le contour est d'une seule couleur -- void Window_display_frame_mono(word x_pos,word y_pos,word width,word height,byte color) { Window_display_frame_generic(x_pos,y_pos,width,height,color,color,color,color,color); } // -- Frame creux: fonc en haut-gauche et clair en bas-droite -- void Window_display_frame_in(word x_pos,word y_pos,word width,word height) { Window_display_frame_generic(x_pos,y_pos,width,height,MC_Dark,MC_White,MC_Light,MC_Dark,MC_White); } // -- Frame bomb: clair en haut-gauche et fonc en bas-droite -- void Window_display_frame_out(word x_pos,word y_pos,word width,word height) { Window_display_frame_generic(x_pos,y_pos,width,height,MC_White,MC_Dark,MC_Light,MC_White,MC_Dark); } // -- Frame de sparation: un cadre bomb dans un cadre creux (3D!!!) -- void Window_display_frame(word x_pos,word y_pos,word width,word height) { Window_display_frame_in(x_pos,y_pos,width,height); Window_display_frame_out(x_pos+1,y_pos+1,width-2,height-2); } //-- Affichages relatifs la palette dans le menu --------------------------- // -- Affichage des couleurs courante (fore/back) de pinceau dans le menu -- void Display_foreback(void) { if (Menu_is_visible && Menu_bars[MENUBAR_TOOLS].Visible) { Block((MENU_WIDTH-17)*Menu_factor_X,Menu_Y+Menu_factor_Y,Menu_factor_X<<4,Menu_factor_Y*7,Back_color); Block((MENU_WIDTH-13)*Menu_factor_X,Menu_Y+(Menu_factor_Y<<1),Menu_factor_X<<3,Menu_factor_Y*5,Fore_color); Update_rect((MENU_WIDTH-17)*Menu_factor_X,Menu_Y+Menu_factor_Y,Menu_factor_X<<4,Menu_factor_Y*7); } } /*! Get the top left corner for the palette cell of a color @param index Index of the color, starting at 0 for the top left one. Limited to Menu_cells_X/Menu_cells_Y. */ word Palette_cell_X(byte index) { if (Config.Palette_vertical) { return (MENU_WIDTH+1+((index-First_color_in_palette)%Menu_cells_X)*Menu_palette_cell_width)*Menu_factor_X; } else { return (MENU_WIDTH+1+((index-First_color_in_palette)/Menu_cells_Y)*Menu_palette_cell_width)*Menu_factor_X; } } /*! Get the top left corner for the palette cell of a color @param index Index of the color, starting at 0 for the top left one. Limited to Menu_cells_X/Menu_cells_Y. */ word Palette_cell_Y(byte index) { if (Config.Palette_vertical) { return Menu_Y+((1+(((index-First_color_in_palette)/Menu_cells_X)*(Menu_bars[MENUBAR_TOOLS].Height/Menu_cells_Y)))*Menu_factor_Y); } else { return Menu_Y+((1+(((index-First_color_in_palette)%Menu_cells_Y)*(Menu_bars[MENUBAR_TOOLS].Height/Menu_cells_Y)))*Menu_factor_Y); } } void Set_fore_color(byte color) { byte old_fore_color = Fore_color; Fore_color=color; Reposition_palette(); Display_foreback(); Frame_menu_color(old_fore_color); Frame_menu_color(Fore_color); } void Set_back_color(byte color) { byte old_back_color = Back_color; Back_color=color; Display_foreback(); Frame_menu_color(old_back_color); Frame_menu_color(Back_color); } /// /// Redraw the cell in the menu palette for ::Fore_color. /// This function checks bounds, it won't draw anything if Fore_color is not visible. /// @param id: Color number to frame void Frame_menu_color(byte id) { word start_x,start_y,end_x,end_y; word index; word cell_height=Menu_bars[MENUBAR_TOOLS].Height/Menu_cells_Y; byte color; if (! Menu_bars[MENUBAR_TOOLS].Visible) return; if (id==Fore_color) color = MC_White; else if (id==Back_color) color = MC_Dark; else color = MC_Black; if ((id>=First_color_in_palette) && (idPages->Image_mode == 0 && Main_backups->Pages->Nb_layers > 1) transparent = Main_backups->Pages->Transparent_color; // Color is not selected, no dotted lines Block(start_x,start_y,Menu_palette_cell_width*Menu_factor_X, cell_height*Menu_factor_Y,id); if (id == transparent) { Block(start_x, start_y, cw / 2, ch / 2, MC_Light); Block(start_x + cw / 2, start_y + ch / 2, (cw+1) / 2, (ch+1) / 2, MC_Dark); } Update_rect(start_x,start_y,Menu_palette_cell_width*Menu_factor_X,cell_height*Menu_factor_Y); } else { end_x=Menu_palette_cell_width-1; end_y=cell_height-1; // Draw dotted lines // Top line for (index=0; index<=end_x; index++) Block(start_x+index*Menu_factor_X,start_y, Menu_factor_X,Menu_factor_Y, ((index)&1)?color:MC_Black); // Left line for (index=1; indexPages->Image_mode == 0 && Main_backups->Pages->Nb_layers > 1) transparent = Main_backups->Pages->Transparent_color; // Compute the size of the color cells (they are smaller by 1px when using // 'separate colors" if (Config.Separate_colors) { cw = Menu_palette_cell_width * Menu_factor_X - 1; ch = cell_height * Menu_factor_Y - 1; } else { cw = (Menu_palette_cell_width)*Menu_factor_X; ch = (cell_height)*Menu_factor_Y; } for (color=First_color_in_palette;color<256&&(color-First_color_in_palette)=First_color_in_palette+Menu_cells_X*Menu_cells_Y) First_color_in_palette+=cells; } if (old_color!=First_color_in_palette) Display_menu_palette(); } void Change_palette_cells() { // On initialise avec la configuration de l'utilisateur Menu_cells_X=Config.Palette_cells_X; Menu_cells_Y=Config.Palette_cells_Y; // Mais on sait jamais if (Menu_cells_X<1) Menu_cells_X=1; if (Menu_cells_Y<1) Menu_cells_Y=1; while (1) { Menu_palette_cell_width = ((Screen_width/Menu_factor_X)-(MENU_WIDTH+2)) / Menu_cells_X; // Si a tient, c'est bon. Sinon, on retente avec une colonne de moins if (Menu_palette_cell_width>2) break; Menu_cells_X--; } // Cale First_color_in_palette sur un multiple du nombre de cellules (arrondi infrieur) if (Config.Palette_vertical) First_color_in_palette=First_color_in_palette/Menu_cells_X*Menu_cells_X; else First_color_in_palette=First_color_in_palette/Menu_cells_Y*Menu_cells_Y; // Si le nombre de cellules a beaucoup augment et qu'on tait prs de // la fin, il faut reculer First_color_in_palette pour montrer plein // de couleurs. if ((int)First_color_in_palette+(Menu_cells_Y)*Menu_cells_X*2>=256) { if (Config.Palette_vertical) First_color_in_palette=255/Menu_cells_X*Menu_cells_X-(Menu_cells_Y-1)*Menu_cells_X; else First_color_in_palette=255/Menu_cells_Y*Menu_cells_Y-(Menu_cells_X-1)*Menu_cells_Y; } // Mise jour de la taille du bouton dans le menu. C'est pour pas que // la bordure noire soit active. Buttons_Pool[BUTTON_CHOOSE_COL].Width=(Menu_palette_cell_width*Menu_cells_X)-1; Buttons_Pool[BUTTON_CHOOSE_COL].Height=(MENU_HEIGHT-9)/Menu_cells_Y*Menu_cells_Y-1; } // Retrouve la couleur sur laquelle pointe le curseur souris. // Cette fonction suppose qu'on a dja vrifi que le curseur est dans // la zone rectangulaire du BUTTON_CHOOSE_COL // La fonction renvoie -1 si on est "trop gauche" (pas possible) // ou aprs la couleur 255 (Ce qui peut arriver si la palette est affiche // avec un nombre de lignes qui n'est pas une puissance de deux.) int Pick_color_in_palette() { int color; int line; int column; line=(((Mouse_Y-Menu_Y)/Menu_factor_Y)-1)/((Menu_bars[MENUBAR_TOOLS].Height)/Menu_cells_Y); column=(((Mouse_X/Menu_factor_X)-(MENU_WIDTH+1))/Menu_palette_cell_width); if (Config.Palette_vertical) { color=First_color_in_palette+line*Menu_cells_X+column; } else { color=First_color_in_palette+line+column*Menu_cells_Y; } if (color<0 || color>255) return -1; return color; } /// Draws a solid textured area, to the right of a toolbar. void Draw_bar_remainder(word current_menu, word x_off) { word y_pos; word x_pos; for (y_pos=0;y_posPages->Nb_layers; word horiz_space; word current_button; word repeats=1; // Available space in pixels horiz_space = Screen_width / Menu_factor_X - Menu_bars[MENUBAR_LAYERS].Skin_width; // Don't display all buttons if not enough room if (horiz_space/button_width < button_number) button_number = horiz_space/button_width; // Only 16 icons at the moment if (button_number > 16) // can be different from MAX_NB_LAYERS button_number = 16; // Enlarge the buttons themselves if there's enough room while (button_number*(button_width+2) < horiz_space && repeats < 20) { repeats+=1; button_width+=2; } x_off=Menu_bars[MENUBAR_LAYERS].Skin_width; for (current_button=0; current_button0; i--) { Pixel_in_menu(MENUBAR_LAYERS, x_pos + x_off, y_pos, Gfx->Layer_sprite[sprite_index][current_button][y_pos][source_x]); x_pos++; } } // Next line x_pos=0; } // Next button x_off+=button_width; } // Texture any remaining space to the right. // This overwrites any junk like deleted buttons. Draw_bar_remainder(MENUBAR_LAYERS, x_off); // Update the active area of the layers pseudo-button Buttons_Pool[BUTTON_LAYER_SELECT].Width = button_number * button_width; // Required to determine which layer button is clicked Layer_button_width = button_width; // A screen refresh required by some callers Update_rect( Menu_bars[MENUBAR_LAYERS].Skin_width, Menu_Y+Menu_bars[MENUBAR_LAYERS].Top*Menu_factor_Y, horiz_space*Menu_factor_X, Menu_bars[MENUBAR_LAYERS].Height*Menu_factor_Y); } if (Menu_bars[MENUBAR_ANIMATION].Visible) { char str[9]; // Rest of horizontal line Draw_bar_remainder(MENUBAR_ANIMATION, Menu_bars[MENUBAR_ANIMATION].Skin_width); // Frame# background rectangle // Block((Menu_bars[MENUBAR_ANIMATION].Skin_width)*Menu_factor_X,(0+Menu_bars[MENUBAR_ANIMATION].Top)*Menu_factor_Y+Menu_Y,8*8*Menu_factor_X,8*Menu_factor_Y,MC_Light); // Frame #/# snprintf(str, 8, "%3d/%3d", Main_current_layer+1, Main_backups->Pages->Nb_layers); Print_general((59)*Menu_factor_X,(Menu_bars[MENUBAR_ANIMATION].Top+3)*Menu_factor_Y+Menu_Y,str,MC_Black,MC_Light); Update_rect( (59)*Menu_factor_X, (Menu_bars[MENUBAR_ANIMATION].Top+3)*Menu_factor_Y+Menu_Y, 7*8*Menu_factor_X, 8*Menu_factor_Y); } } /// Display the whole menu void Display_menu(void) { word x_pos; word y_pos; int8_t current_menu; char str[4]; if (Menu_is_visible) { // display menu sprite for (current_menu = MENUBAR_COUNT - 1; current_menu >= 0; current_menu --) { if(Menu_bars[current_menu].Visible) { // Skinned area for (y_pos=0;y_pos=Main_X_zoom) )) { // Prepare display of XY coordinates even if in some cases they will be // erased with some other text if ( (Current_operation!=OPERATION_COLORPICK) && (Current_operation!=OPERATION_REPLACE) ) Print_in_menu("X: Y: ",0); else { // The colorpicker display the color id between the parentheses Print_in_menu("X: Y: ( )",0); Num2str(Colorpicker_color,str,3); Print_in_menu(str,20); Print_general(170*Menu_factor_X,Menu_status_Y," ",0,Colorpicker_color); } Print_coordinates(); } Print_filename(); } // Now update the area: menu height and whole screen width (including palette) Update_rect(0,Menu_Y,Screen_width,Menu_height*Menu_factor_Y); } } // -- Affichage de texte ----------------------------------------------------- // -- Afficher une chane n'importe o l'cran -- void Print_general(short x,short y,const char * str,byte text_color,byte background_color) { word index; int x_pos; int y_pos; byte *font_pixel; short real_x; short real_y; byte repeat_menu_x_factor; byte repeat_menu_y_factor; real_y=y; for (y_pos=0;y_pos<8<<3;y_pos+=1<<3) { real_x=0; // Position dans le buffer for (index=0;str[index]!='\0';index++) { // Pointeur sur le premier pixel du caractre font_pixel=Menu_font+(((unsigned char)str[index])<<6); for (x_pos=0;x_pos<8;x_pos+=1) for (repeat_menu_x_factor=0;repeat_menu_x_factor size) { display_string[size-1]=ELLIPSIS_CHARACTER; } Print_in_window(x, y, display_string, text_color, background_color); } /// Draws a string in a window void Print_in_window(short x,short y,const char * str,byte text_color,byte background_color) { short x_pos = x; int index; for (index=0;str[index]!='\0';index++) { Print_char_in_window(x,y,str[index],text_color,background_color); x+=8; } Update_window_area(x_pos,y,8*strlen(str),8); } // Draws a string in the menu's status bar void Print_in_menu(const char * str, short position) { Print_general((18+(position<<3))*Menu_factor_X,Menu_status_Y,str,MC_Black,MC_Light); Update_status_line(position, strlen(str)); } /// Draws the mouse coordinates on the menu /// Only update the digits and doesn't refresh the "X: Y:" labels. This function needs to be fast as it is called each time the mouse moves. void Print_coordinates(void) { char temp[5]; if (Menu_is_visible && !Cursor_in_menu) { if ( (Current_operation==OPERATION_COLORPICK) || (Current_operation==OPERATION_RMB_COLORPICK) || (Current_operation==OPERATION_REPLACE) ) { if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0) && (Paintbrush_XPages->Filename; size_t inbytesleft = strlen(input); char * output = display_string; size_t outbytesleft = sizeof(display_string)-1; if(cd != (iconv_t)-1 && (ssize_t)iconv(cd, &input, &inbytesleft, &output, &outbytesleft) >= 0) *output = '\0'; else #endif /* ENABLE_FILENAMES_ICONV */ { strncpy(display_string, Main_backups->Pages->Filename, sizeof(display_string)-1); display_string[sizeof(display_string)-1] = '\0'; } } string_size = strlen(display_string); display_string[max_size]='\0'; if (string_size > max_size) { string_size = max_size; display_string[string_size-1]=ELLIPSIS_CHARACTER; } // Erase whole area Block(Screen_width-max_size*8*Menu_factor_X, Menu_status_Y,Menu_factor_X*max_size*8,Menu_factor_Y<<3,MC_Light); // Print Print_general(Screen_width-(string_size<<3)*Menu_factor_X,Menu_status_Y,display_string,MC_Black,MC_Light); } // Fonction d'affichage d'une chaine numrique avec une fonte trs fine // Spcialise pour les compteurs RGB void Print_counter(short x,short y,const char * str,byte text_color,byte background_color) { // Macros pour crire des litteraux binaires. // Ex: Ob(11110000) == 0xF0 #define Ob(x) ((unsigned)Ob_(0 ## x ## uL)) #define Ob_(x) ((x & 1) | (x >> 2 & 2) | (x >> 4 & 4) | (x >> 6 & 8) | \ (x >> 8 & 16) | (x >> 10 & 32) | (x >> 12 & 64) | (x >> 14 & 128)) byte thin_font[14][8] = { { // 0 Ob(00011100), Ob(00110110), Ob(00110110), Ob(00110110), Ob(00110110), Ob(00110110), Ob(00110110), Ob(00011100) }, { // 1 Ob(00001100), Ob(00011100), Ob(00111100), Ob(00001100), Ob(00001100), Ob(00001100), Ob(00001100), Ob(00001100) }, { // 2 Ob(00011100), Ob(00110110), Ob(00000110), Ob(00000110), Ob(00000110), Ob(00001100), Ob(00011000), Ob(00111110) }, { // 3 Ob(00011100), Ob(00110110), Ob(00000110), Ob(00001100), Ob(00000110), Ob(00000110), Ob(00110110), Ob(00011100) }, { // 4 Ob(00001100), Ob(00001100), Ob(00011000), Ob(00011000), Ob(00110000), Ob(00110100), Ob(00111110), Ob(00000100) }, { // 5 Ob(00111110), Ob(00110000), Ob(00110000), Ob(00111100), Ob(00000110), Ob(00000110), Ob(00110110), Ob(00011100) }, { // 6 Ob(00011100), Ob(00110110), Ob(00110000), Ob(00111100), Ob(00110110), Ob(00110110), Ob(00110110), Ob(00011100) }, { // 7 Ob(00111110), Ob(00000110), Ob(00000110), Ob(00001100), Ob(00011000), Ob(00011000), Ob(00011000), Ob(00011000) }, { // 8 Ob(00011100), Ob(00110110), Ob(00110110), Ob(00011100), Ob(00110110), Ob(00110110), Ob(00110110), Ob(00011100) }, { // 9 Ob(00011100), Ob(00110110), Ob(00110110), Ob(00011110), Ob(00000110), Ob(00000110), Ob(00110110), Ob(00011100) }, { // (espace) Ob(00000000), Ob(00000000), Ob(00000000), Ob(00000000), Ob(00000000), Ob(00000000), Ob(00000000), Ob(00000000) }, { // + Ob(00000000), Ob(00001000), Ob(00001000), Ob(00111110), Ob(00001000), Ob(00001000), Ob(00000000), Ob(00000000) }, { // - Ob(00000000), Ob(00000000), Ob(00000000), Ob(00111110), Ob(00000000), Ob(00000000), Ob(00000000), Ob(00000000) }, { // +- Ob(00001000), Ob(00001000), Ob(00111110), Ob(00001000), Ob(00001000), Ob(00000000), Ob(00111110), Ob(00000000) } }; word index; short x_pos; short y_pos; for (index=0;str[index]!='\0';index++) { int char_number; switch(str[index]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': char_number=str[index]-'0'; break; case ' ': default: char_number=10; break; case '+': char_number=11; break; case '-': char_number=12; break; case '': char_number=13; break; } for (y_pos=0;y_pos<8;y_pos++) { for (x_pos=0;x_pos<6;x_pos++) { byte color = (thin_font[char_number][y_pos] & (1 << (6-x_pos))) ? text_color:background_color; Pixel_in_window(x+(index*6+x_pos),y+y_pos,color); } } } Update_window_area(x,y,strlen(str)*6,8); } /// /// Window asking for confirmation before an action is performed. /// This function is able to display multi-line messages and /// center the lines, but the carriage returns have to be explicit. /// The function will clip the message in case of problem. /// @return 1 if user pressed OK, 0 if CANCEL byte Confirmation_box(char * message) { short clicked_button; word window_width = 120; word nb_lines = 1; const char *c = message; short current_length=0; short current_line; // Count lines, and measure max line length for (c=message; *c != '\0'; c++) { if (*c == '\n') { current_length=0; nb_lines++; } else { current_length++; window_width=Max(window_width, (current_length<<3)+20); } } // Safety if (window_width>310) window_width=310; Open_window(window_width,52+(nb_lines<<3),"Confirmation"); c=message; for (current_line=0; current_line < nb_lines; current_line++) { char * next_eol; char display_string[36+1]; next_eol = strchr(c, '\n'); if (next_eol==NULL) // last line current_length = strlen(c); else current_length = next_eol-c; // Safeguard if (current_length>36) current_length=36; // Copy part of string in null-terminated buffer strncpy(display_string, c, current_length); display_string[current_length]='\0'; Print_in_window((window_width>>1)-(current_length<<2), 20+(current_line<<3), display_string, MC_Black, MC_Light); c += current_length; if (*c == '\n') c++; } Window_set_normal_button((window_width/3)-20 ,29+(nb_lines<<3),40,14,"Yes",1,1,SDLK_y); // 1 Window_set_normal_button(((window_width<<1)/3)-20,29+(nb_lines<<3),40,14,"No" ,1,1,SDLK_n); // 2 Update_window_area(0, 0, Window_width, Window_height); Display_cursor(); do { clicked_button=Window_clicked_button(); if (Key==SDLK_RETURN) clicked_button=1; if (Key==KEY_ESC) clicked_button=2; } while (clicked_button<=0); Key=0; Close_window(); Display_cursor(); return (clicked_button==1)? 1 : 0; } /// Window that allows you to enter a single value int Requester_window(char* message, int initial_value) { short clicked_button = 0; word window_width; char str[10]; window_width=(strlen(message)<<3)+20; if (window_width<120) window_width = 120; Open_window(window_width, 60, "Request"); Print_in_window((window_width>>1)-(strlen(message)<<2), 20, message, MC_Black, MC_Light); sprintf(str, "%d", initial_value); Window_set_input_button(10, 37, 4); // 1 Print_in_window(11, 39, str, MC_Black, MC_Light); Window_set_normal_button(60 ,37,40,14,"OK",1,1,SDLK_y); // 2 Window_set_normal_button(130,37,60,14,"Cancel" ,1,1,SDLK_n); // 3 Update_window_area(0, 0, window_width, 60); Display_cursor(); do { clicked_button = Window_clicked_button(); if (clicked_button == 1) Readline(11, 39, str, 4, INPUT_TYPE_INTEGER); if (Key == SDLK_ESCAPE) clicked_button = 2; } while (clicked_button <= 0); Key = 0; Close_window(); Display_cursor(); return clicked_button==2?-1:atoi(str); } /// Window that show a warning message and wait for a click on the OK button void Warning_message(char * message) { short clicked_button; word window_width; window_width=(strlen(message)<<3)+20; if (window_width<120) window_width=120; Open_window(window_width,60,"Warning!"); Print_in_window((window_width>>1)-(strlen(message)<<2),20,message,MC_Black,MC_Light); Window_set_normal_button((window_width>>1)-20 ,37,40,14,"OK",1,1,SDLK_RETURN); // 1 Update_window_area(0,0,window_width,60); Display_cursor(); do clicked_button=Window_clicked_button(); while ((clicked_button<=0) && (Key!=KEY_ESC) && (Key!=SDLK_o)); Key=0; Close_window(); Display_cursor(); } /// Window that shows a big message (up to 35x13), and waits for a click on OK. /// On call: Cursor must be displayed /// On exit: Cursor is displayed void Verbose_message(const char *caption, const char * message ) { short clicked_button; int line; int last_space; int nb_char; char buffer[36]; byte original_cursor_shape = Cursor_shape; Open_window(300,160,caption); // Word-wrap the message for (line=0; line < 13 && *message!='\0'; line++) { last_space = -1; for (nb_char=0; nb_char<35 && message[nb_char]!='\0'; nb_char++) { buffer[nb_char]=message[nb_char]; if (message[nb_char] == ' ') { last_space = nb_char; } else if (message[nb_char] == '\n') { last_space = nb_char; break; } } // Close line buffer if (message[nb_char]=='\0' || last_space == -1) last_space = nb_char; buffer[last_space]='\0'; // Print Print_in_window(10,20+line*8,buffer,MC_Black,MC_Light); // Next line message=message+last_space; // Strip at most one carriage return and any leading spaces if (*message == '\n') message++; while (*message == ' ') message++; } Window_set_normal_button(300/2-20,160-23,40,14,"OK",1,1,SDLK_RETURN); // 1 Update_window_area(0,0,Window_width,Window_height); Cursor_shape=CURSOR_SHAPE_ARROW; Display_cursor(); do clicked_button=Window_clicked_button(); while ((clicked_button<=0) && (Key!=KEY_ESC) && (Key!=SDLK_o)); Key=0; Close_window(); Cursor_shape=original_cursor_shape; Display_cursor(); } // -- Redessiner le sprite d'un bouton dans le menu -- void Display_sprite_in_menu(int btn_number,char sprite_number) { Buttons_Pool[btn_number].Icon=sprite_number; if (Buttons_Pool[btn_number].Shape == BUTTON_SHAPE_TRIANGLE_TOP_LEFT) Buttons_Pool[btn_number+1].Icon=sprite_number; else if (Buttons_Pool[btn_number].Shape == BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT) Buttons_Pool[btn_number-1].Icon=sprite_number; } // -- Redessiner la forme du pinceau dans le menu -- void Display_paintbrush_in_menu(void) { switch(Paintbrush_shape) { case PAINTBRUSH_SHAPE_COLOR_BRUSH: Display_sprite_in_menu(BUTTON_PAINTBRUSHES, MENU_SPRITE_COLOR_BRUSH); break; case PAINTBRUSH_SHAPE_MONO_BRUSH: Display_sprite_in_menu(BUTTON_PAINTBRUSHES, MENU_SPRITE_MONO_BRUSH); break; default: Display_sprite_in_menu(BUTTON_PAINTBRUSHES, -1); break; } Draw_menu_button(BUTTON_PAINTBRUSHES,BUTTON_RELEASED); } // -- Dessiner un pinceau prdfini dans la fentre -- void Display_paintbrush_in_window(word x,word y,int number) // Pinceau = 0..NB_PAINTBRUSH_SPRITES-1 : Pinceau prdfini { word x_pos; word y_pos; word window_x_pos; word window_y_pos; int x_size; int y_size; word origin_x; word origin_y; word width; word height; x_size=Menu_factor_X/Pixel_height; if (x_size<1) x_size=1; y_size=Menu_factor_Y/Pixel_width; if (y_size<1) y_size=1; width=Min(Paintbrush[number].Width,PAINTBRUSH_WIDTH); height=Min(Paintbrush[number].Height,PAINTBRUSH_WIDTH); origin_x = (x + 8)*Menu_factor_X - (width/2)*x_size+Window_pos_X; origin_y = (y + 8)*Menu_factor_Y - (height/2)*y_size+Window_pos_Y; for (window_y_pos=0,y_pos=0; y_posblock_end) { index=block_start; block_start=block_end; block_end=index; } for (index=start_y;indexIcon_sprite[type][j][i]); Update_rect(ToWinX(x_pos),ToWinY(y_pos),ToWinL(ICON_SPRITE_WIDTH),ToWinH(ICON_SPRITE_HEIGHT)); } void Display_menu_palette_avoiding_window(byte * table) { // On part du principe qu'il n'y a que le bas d'une fentre qui puisse // empiter sur la palette... Et c'est dj pas mal! word color,real_color; word start_x,start_y; word end_x,end_y; word width; word height; word corner_x=Window_pos_X+Window_width*Menu_factor_X; // |_ Coin bas-droit word corner_y=Window_pos_Y+Window_height*Menu_factor_Y; // | de la fentre +1 if (Config.Separate_colors) { width=(Menu_palette_cell_width-1)*Menu_factor_X; height=Menu_factor_Y*((Menu_height-11)/Menu_cells_Y-1); } else { width=Menu_palette_cell_width*Menu_factor_X; height=Menu_factor_Y*((Menu_height-11)/Menu_cells_Y); } for (color=0,real_color=First_color_in_palette;color=corner_y) || (end_x<=Window_pos_X) || (start_x>=corner_x) ) Block(start_x,start_y,width,height,real_color); else { if (start_x>=Window_pos_X) { if ( (end_x>corner_x) || (end_y>corner_y) ) { if ( (end_x>corner_x) && (end_y>corner_y) ) { Block(corner_x,start_y,end_x-corner_x,corner_y-start_y,real_color); Block(start_x,corner_y,width,end_y-corner_y,real_color); } else { if (end_y>corner_y) Block(start_x,corner_y,width,end_y-corner_y,real_color); else Block(corner_x,start_y,end_x-corner_x,height,real_color); } } } else { if (end_xcorner_y) { Block(start_x,start_y,Window_pos_X-start_x,corner_y-start_y,real_color); Block(start_x,corner_y,width,end_y-corner_y,real_color); } else Block(start_x,start_y,Window_pos_X-start_x,height,real_color); } else { if (end_y>corner_y) { Block(start_x,start_y,Window_pos_X-start_x,corner_y-start_y,real_color); Block(corner_x,start_y,end_x-corner_x,corner_y-start_y,real_color); Block(start_x,corner_y,width,end_y-corner_y,real_color); } else { Block(start_x,start_y,Window_pos_X-start_x,height,real_color); Block(corner_x,start_y,end_x-corner_x,height,real_color); } } } } { // Affichage du bloc directement dans le "buffer de fond" de la fenetre. // Cela permet au bloc de couleur d'apparaitre si on dplace la fenetre. short x_pos; short y_pos; short relative_x; // besoin d'une variable signe short relative_y; // besoin d'une variable signe // Attention aux units relative_x = ((short)start_x - (short)Window_pos_X); relative_y = ((short)start_y - (short)Window_pos_Y); for (y_pos=relative_y;y_pos<(relative_y+height)&&y_pos=0&&y_pos>=0) Pixel_background(x_pos,y_pos,real_color); } } } Update_rect(MENU_WIDTH*Menu_factor_X,Menu_Y_before_window,Screen_width-(MENU_WIDTH*Menu_factor_X),(Menu_height-11)*Menu_factor_Y); } // -------- Calcul des bornes de la partie d'image visible l'cran --------- void Compute_limits(void) /* Avant l'appel cette fonction, les donnes de la loupe doivent tre jour. */ { if (Main_magnifier_mode) { // -- Calcul des limites de la partie non zoome de l'image -- Limit_top =Main_offset_Y; Limit_left=Main_offset_X; Limit_visible_bottom =Limit_top+Menu_Y-1; Limit_visible_right=Limit_left+Main_separator_position-1; if (Limit_visible_bottom>=Main_image_height) Limit_bottom=Main_image_height-1; else Limit_bottom=Limit_visible_bottom; if (Limit_visible_right>=Main_image_width) Limit_right=Main_image_width-1; else Limit_right=Limit_visible_right; // -- Calcul des limites de la partie zoome de l'image -- Limit_top_zoom =Main_magnifier_offset_Y; Limit_left_zoom=Main_magnifier_offset_X; Limit_visible_bottom_zoom =Limit_top_zoom+Main_magnifier_height-1; Limit_visible_right_zoom=Limit_left_zoom+Main_magnifier_width-1; if (Limit_visible_bottom_zoom>=Main_image_height) Limit_bottom_zoom=Main_image_height-1; else Limit_bottom_zoom=Limit_visible_bottom_zoom; if (Limit_visible_right_zoom>=Main_image_width) Limit_right_zoom=Main_image_width-1; else Limit_right_zoom=Limit_visible_right_zoom; } else { // -- Calcul des limites de la partie visible de l'image -- Limit_top =Main_offset_Y; Limit_left=Main_offset_X; Limit_visible_bottom =Limit_top+(Menu_is_visible?Menu_Y:Screen_height)-1; // A REVOIR POUR SIMPLIFICATION Limit_visible_right=Limit_left+Screen_width-1; if (Limit_visible_bottom>=Main_image_height) Limit_bottom=Main_image_height-1; else Limit_bottom=Limit_visible_bottom; if (Limit_visible_right>=Main_image_width) Limit_right=Main_image_width-1; else Limit_right=Limit_visible_right; } } // -- Calculer les coordonnes du pinceau en fonction du snap et de la loupe - void Compute_paintbrush_coordinates(void) { if ((Main_magnifier_mode) && (Mouse_X>=Main_X_zoom)) { Paintbrush_X=((Mouse_X-Main_X_zoom)/Main_magnifier_factor)+Main_magnifier_offset_X; Paintbrush_Y=(Mouse_Y/Main_magnifier_factor)+Main_magnifier_offset_Y; } else { Paintbrush_X=Mouse_X+Main_offset_X; Paintbrush_Y=Mouse_Y+Main_offset_Y; } if (Snap_mode) { Paintbrush_X=(((Paintbrush_X+(Snap_width>>1)-Snap_offset_X)/Snap_width)*Snap_width)+Snap_offset_X; Paintbrush_Y=(((Paintbrush_Y+(Snap_height>>1)-Snap_offset_Y)/Snap_height)*Snap_height)+Snap_offset_Y; } // Handling the snap axis mode, when shift is pressed. switch (Current_operation) { // Operations that don't implement it case OPERATION_LINE: case OPERATION_ROTATE_BRUSH: Snap_axis=0; break; // Operations that implement it default: if (Snap_axis==0 && (SDL_GetModState() & KMOD_SHIFT)) { // Start "Snap axis" mode Snap_axis=1; Snap_axis_origin_X=Paintbrush_X; Snap_axis_origin_Y=Paintbrush_Y; } } if (Snap_axis==1) { // Cursor moved if (Paintbrush_X != Snap_axis_origin_X || Paintbrush_Y != Snap_axis_origin_Y) { if ((Paintbrush_X-Snap_axis_origin_X)*(Paintbrush_X-Snap_axis_origin_X) > (Paintbrush_Y-Snap_axis_origin_Y)*(Paintbrush_Y-Snap_axis_origin_Y)) // Displacement was bigger on X axis: lock Y Snap_axis=2; else Snap_axis=3; } } if (Snap_axis==2) { Paintbrush_Y = Snap_axis_origin_Y; } else if (Snap_axis==3) { Paintbrush_X = Snap_axis_origin_X; } } // -- Affichage de la limite de l'image ------------------------------------- void Display_image_limits(void) { short start; short pos; short end; byte right_is_visible; byte bottom_is_visible; short old_zoom_limit; right_is_visible=Main_image_width<((Main_magnifier_mode)?Main_separator_position:Screen_width); bottom_is_visible =Main_image_heightMain_separator_position) { Main_offset_X=Main_magnifier_offset_X+(Main_magnifier_width>>1) -(Main_separator_position>>1); if (Main_offset_X<0) Main_offset_X=0; else if (Main_image_widthMenu_Y) { Main_offset_Y=Main_magnifier_offset_Y+(Main_magnifier_height>>1) -(Menu_Y>>1); if (Main_offset_Y<0) Main_offset_Y=0; else if (Main_image_heightMain_separator_position) { Main_offset_X=target_x-Mouse_X; // Do not allow the zoomed part to show something that the // non-zoomed part doesn't see. All clipping is computed according // to the non-zoomed part. if (Main_magnifier_offset_X Main_offset_X+Main_separator_position) Main_offset_X = Main_magnifier_offset_X+Main_magnifier_width-Main_separator_position; if (Main_offset_X<0) Main_offset_X=0; else if (Main_image_widthMenu_Y) { Main_offset_Y=target_y-Mouse_Y; // Do not allow the zoomed part to show something that the // non-zoomed part doesn't see. All clipping is computed according // to the non-zoomed part. if (Main_magnifier_offset_Y Main_offset_Y) Main_offset_Y = Main_magnifier_offset_Y+Main_magnifier_height; if (Main_offset_Y<0) Main_offset_Y=0; else if (Main_image_height>1)-theoric_X)/Main_magnifier_factor)*Main_magnifier_factor); Main_separator_position=Main_X_zoom-(Menu_factor_X*SEPARATOR_WIDTH); // Correction en cas de dbordement sur la gauche while (Main_separator_position*(Main_magnifier_factor+1)=theoric_X) { Main_separator_position-=Main_magnifier_factor; Main_X_zoom-=Main_magnifier_factor; } } // -------------------- Calcul des information de la loupe ------------------- void Compute_magnifier_data(void) /* Aprs modification des donnes de la loupe, il faut recalculer les limites. */ { Compute_separator_data(); Main_magnifier_width=(Screen_width-Main_X_zoom)/Main_magnifier_factor; Main_magnifier_height=Menu_Y/Main_magnifier_factor; if (Menu_Y%Main_magnifier_factor) Main_magnifier_height++; Clip_magnifier_offsets(&Main_magnifier_offset_X, &Main_magnifier_offset_Y); } void Clip_magnifier_offsets(short *x_offset, short *y_offset) { if (Main_magnifier_mode) { if (*x_offset) { if (Main_image_width<*x_offset+Main_magnifier_width) *x_offset=Main_image_width-Main_magnifier_width; if (*x_offset<0) *x_offset=0; } if (*y_offset) { if (Main_image_height<*y_offset+Main_magnifier_height) *y_offset=Main_image_height-Main_magnifier_height+(Main_magnifier_height*Main_magnifier_factor-Menu_Y>=Main_magnifier_factor/2); if (*y_offset<0) *y_offset=0; } } } /// Changes magnifier factor and updates everything needed void Change_magnifier_factor(byte factor_index, byte point_at_mouse) { int target_x,target_y; // These coordinates are in image space byte magnified_view_leads=1; // Values that need to be computed before switching to the new zoom factor if (!point_at_mouse || Cursor_in_menu || !Main_magnifier_mode) { // Locate the pixel in center of the magnified area target_x = Main_magnifier_offset_X + (Main_magnifier_width >> 1); target_y = Main_magnifier_offset_Y + (Main_magnifier_height >> 1); point_at_mouse=0; } else if (Mouse_X>=Main_X_zoom) { // Locate the pixel under the cursor, in magnified area target_x=((Mouse_X-Main_X_zoom)/Main_magnifier_factor)+Main_magnifier_offset_X; target_y=(Mouse_Y/Main_magnifier_factor)+Main_magnifier_offset_Y; point_at_mouse=1; } else { // Locate the pixel under the cursor, in normal area target_x=Mouse_X+Main_offset_X; target_y=Mouse_Y+Main_offset_Y; magnified_view_leads=0; point_at_mouse=0; } Main_magnifier_factor=ZOOM_FACTOR[factor_index]; Compute_magnifier_data(); if (Main_magnifier_mode) { // Recompute the magnifier offset (center its view) if (point_at_mouse) { // Target pixel must be located under the mouse position. Main_magnifier_offset_X = target_x-((Mouse_X-Main_X_zoom)/Main_magnifier_factor); Main_magnifier_offset_Y = target_y-((Mouse_Y)/Main_magnifier_factor); } else { // Target pixel must be positioned at new center Main_magnifier_offset_X = target_x-(Main_magnifier_width>>1); Main_magnifier_offset_Y = target_y-(Main_magnifier_height>>1); } // Fix cases where the image would overflow on edges Clip_magnifier_offsets(&Main_magnifier_offset_X, &Main_magnifier_offset_Y); if (magnified_view_leads) Position_screen_according_to_zoom(); else Position_screen_according_to_position(target_x, target_y); Pixel_preview=Pixel_preview_magnifier; } else Pixel_preview=Pixel_preview_normal; Compute_limits(); Compute_paintbrush_coordinates(); } void Copy_view_to_spare(void) { // Don't do anything if the pictures have different dimensions if (Main_image_width!=Spare_image_width || Main_image_height!=Spare_image_height) return; // Copie des dcalages de la fentre principale (non zoome) de l'image Spare_offset_X=Main_offset_X; Spare_offset_Y=Main_offset_Y; // Copie du boolen "Mode loupe" de l'image Spare_magnifier_mode=Main_magnifier_mode; // Copie du facteur de zoom du brouillon Spare_magnifier_factor=Main_magnifier_factor; // Copie des dimensions de la fentre de zoom Spare_magnifier_width=Main_magnifier_width; Spare_magnifier_height=Main_magnifier_height; // Copie des dcalages de la fentre de zoom Spare_magnifier_offset_X=Main_magnifier_offset_X; Spare_magnifier_offset_Y=Main_magnifier_offset_Y; // Copie des donnes du split du zoom Spare_separator_position=Main_separator_position; Spare_X_zoom=Main_X_zoom; Spare_separator_proportion=Main_separator_proportion; } // -- Afficher la barre de sparation entre les parties zoomes ou non en // mode Loupe -- void Display_separator(void) { // Partie grise du milieu Block(Main_separator_position+(Menu_factor_X<<1),Menu_factor_Y, (SEPARATOR_WIDTH-4)*Menu_factor_X, Menu_Y-(Menu_factor_Y<<1),MC_Light); // Barre noire de gauche Block(Main_separator_position,0,Menu_factor_X,Menu_Y,MC_Black); // Barre noire de droite Block(Main_X_zoom-Menu_factor_X,0,Menu_factor_X,Menu_Y,MC_Black); // Bord haut (blanc) Block(Main_separator_position+Menu_factor_X,0, (SEPARATOR_WIDTH-3)*Menu_factor_X,Menu_factor_Y,MC_White); // Bord gauche (blanc) Block(Main_separator_position+Menu_factor_X,Menu_factor_Y, Menu_factor_X,(Menu_Y-(Menu_factor_Y<<1)),MC_White); // Bord droite (gris fonc) Block(Main_X_zoom-(Menu_factor_X<<1),Menu_factor_Y, Menu_factor_X,(Menu_Y-(Menu_factor_Y<<1)),MC_Dark); // Bord bas (gris fonc) Block(Main_separator_position+(Menu_factor_X<<1),Menu_Y-Menu_factor_Y, (SEPARATOR_WIDTH-3)*Menu_factor_X,Menu_factor_Y,MC_Dark); // Coin bas gauche Block(Main_separator_position+Menu_factor_X,Menu_Y-Menu_factor_Y, Menu_factor_X,Menu_factor_Y,MC_Light); // Coin haut droite Block(Main_X_zoom-(Menu_factor_X<<1),0, Menu_factor_X,Menu_factor_Y,MC_Light); Update_rect(Main_separator_position,0,SEPARATOR_WIDTH*Menu_factor_X,Menu_Y); // On raffiche toute la partie gauche du split, ce qui permet d'effacer son ancienne position } // -- Fonctions de manipulation du curseur ----------------------------------- // -- Afficher une barre horizontale XOR zoome void Horizontal_XOR_line_zoom(short x_pos, short y_pos, short width) { short real_x_pos=Main_X_zoom+(x_pos-Main_magnifier_offset_X)*Main_magnifier_factor; short real_y_pos=(y_pos-Main_magnifier_offset_Y)*Main_magnifier_factor; short real_width=width*Main_magnifier_factor; short end_y_pos=(real_y_pos+Main_magnifier_factor=Main_X_zoom) ) ) || (Windows_open) || (Cursor_shape==CURSOR_SHAPE_HOURGLASS) ) shape=Cursor_shape; else shape=CURSOR_SHAPE_ARROW; switch(shape) { case CURSOR_SHAPE_TARGET : if (!Paintbrush_hidden) Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color); if (!Cursor_hidden) { if (Config.Cursor==1) { start_y=(Mouse_Y<6)?6-Mouse_Y:0; if (start_y<4) Vertical_XOR_line (Mouse_X,Mouse_Y+start_y-6,4-start_y); start_x=(Mouse_X<6)?(short)6-Mouse_X:0; if (start_x<4) Horizontal_XOR_line(Mouse_X+start_x-6,Mouse_Y,4-start_x); end_x=(Mouse_X+7>Screen_width)?Mouse_X+7-Screen_width:0; if (end_x<4) Horizontal_XOR_line(Mouse_X+3,Mouse_Y,4-end_x); end_y=(Mouse_Y+7>Screen_height)?Mouse_Y+7-Screen_height:0; if (end_y<4) Vertical_XOR_line (Mouse_X,Mouse_Y+3,4-end_y); Update_rect(Mouse_X+start_x-6,Mouse_Y+start_y-6,13-end_x,13-end_y); } else { temp=(Config.Cursor)?CURSOR_SHAPE_THIN_TARGET:CURSOR_SHAPE_TARGET; start_x=Mouse_X-Gfx->Cursor_offset_X[temp]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; for (y_pos=start_y,counter_y=0; counter_y<15 && y_pos < Screen_height; y_pos++,counter_y++) { if( y_pos < 0 ) continue; for (x_pos=start_x,counter_x=0; counter_x<15 && x_pos < Screen_width; x_pos++,counter_x++) { if( x_pos < 0 ) continue; color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; Cursor_background[counter_y][counter_x]=Read_pixel(x_pos,y_pos); if (color!=MC_Trans) Pixel(x_pos,y_pos,color); } } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); } } break; case CURSOR_SHAPE_COLORPICKER: if (!Paintbrush_hidden) Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color); if (Config.Cursor==1) { // Barres formant la croix principale start_y=(Mouse_Y<5)?5-Mouse_Y:0; if (start_y<3) Vertical_XOR_line (Mouse_X,Mouse_Y+start_y-5,3-start_y); start_x=(Mouse_X<5)?(short)5-Mouse_X:0; if (start_x<3) Horizontal_XOR_line(Mouse_X+start_x-5,Mouse_Y,3-start_x); end_x=(Mouse_X+6>Screen_width)?Mouse_X+6-Screen_width:0; if (end_x<3) Horizontal_XOR_line(Mouse_X+3,Mouse_Y,3-end_x); end_y=(Mouse_Y+6>Menu_Y/*Screen_height*/)?Mouse_Y+6-Menu_Y/*Screen_height*/:0; if (end_y<3) Vertical_XOR_line (Mouse_X,Mouse_Y+3,3-end_y); // Petites barres aux extrmits start_x=(!Mouse_X); start_y=(!Mouse_Y); end_x=(Mouse_X>=Screen_width-1); end_y=(Mouse_Y>=Menu_Y-1); if (Mouse_Y>5) Horizontal_XOR_line(start_x+Mouse_X-1,Mouse_Y-6,3-(start_x+end_x)); if (Mouse_X>5) Vertical_XOR_line (Mouse_X-6,start_y+Mouse_Y-1,3-(start_y+end_y)); if (Mouse_XCursor_offset_X[temp]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { if(y_pos<0) continue; if(y_pos>=Screen_height) break; for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) { if(x_pos<0) continue; if(x_pos>=Screen_width) break; color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; // On sauvegarde dans Cursor_background pour restaurer plus tard Cursor_background[counter_y][counter_x]=Read_pixel(x_pos,y_pos); if (color!=MC_Trans) Pixel(x_pos,y_pos,color); } } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); } break; case CURSOR_SHAPE_MULTIDIRECTIONAL : case CURSOR_SHAPE_HORIZONTAL : case CURSOR_SHAPE_BUCKET : if (Cursor_hidden) break; case CURSOR_SHAPE_ARROW : case CURSOR_SHAPE_HOURGLASS : start_x=Mouse_X-Gfx->Cursor_offset_X[shape]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[shape]; for (y_pos=start_y,counter_y=0;counter_y=Screen_height) break; for (x_pos=start_x,counter_x=0;counter_x=Screen_width) break; color=Gfx->Cursor_sprite[shape][counter_y][counter_x]; // On sauvegarde dans Cursor_background pour restaurer plus tard Cursor_background[counter_y][counter_x]=Read_pixel(x_pos,y_pos); if (color!=MC_Trans) Pixel(x_pos,y_pos,color); } } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); break; case CURSOR_SHAPE_XOR_TARGET : x_pos=Paintbrush_X-Main_offset_X; y_pos=Paintbrush_Y-Main_offset_Y; counter_x=(Main_magnifier_mode)?Main_separator_position:Screen_width; // width de la barre XOR if ((y_pos=Limit_top)) { Horizontal_XOR_line(0,Paintbrush_Y-Main_offset_Y,counter_x); Update_rect(0,Paintbrush_Y-Main_offset_Y,counter_x,1); } if ((x_pos=Limit_left)) { Vertical_XOR_line(Paintbrush_X-Main_offset_X,0,Menu_Y); Update_rect(Paintbrush_X-Main_offset_X,0,1,Menu_Y); } if (Main_magnifier_mode) { // UPDATERECT if ((Paintbrush_Y>=Limit_top_zoom) && (Paintbrush_Y<=Limit_visible_bottom_zoom)) Horizontal_XOR_line_zoom(Limit_left_zoom,Paintbrush_Y,Main_magnifier_width); if ((Paintbrush_X>=Limit_left_zoom) && (Paintbrush_X<=Limit_visible_right_zoom)) Vertical_XOR_line_zoom(Paintbrush_X,Limit_top_zoom,Main_magnifier_height); } break; case CURSOR_SHAPE_XOR_RECTANGLE : // !!! Cette forme ne peut pas tre utilise en mode Loupe !!! // Petite croix au centre start_x=(Mouse_X-3); start_y=(Mouse_Y-3); end_x =(Mouse_X+4); end_y =(Mouse_Y+4); if (start_x<0) start_x=0; if (start_y<0) start_y=0; if (end_x>Screen_width) end_x=Screen_width; if (end_y>Menu_Y) end_y=Menu_Y; Horizontal_XOR_line(start_x,Mouse_Y,end_x-start_x); Vertical_XOR_line (Mouse_X,start_y,end_y-start_y); // Grand rectangle autour start_x=Mouse_X-(Main_magnifier_width>>1); start_y=Mouse_Y-(Main_magnifier_height>>1); if (start_x+Main_magnifier_width>=Limit_right-Main_offset_X) start_x=Limit_right-Main_magnifier_width-Main_offset_X+1; if (start_y+Main_magnifier_height>=Limit_bottom-Main_offset_Y) start_y=Limit_bottom-Main_magnifier_height-Main_offset_Y+1; if (start_x<0) start_x=0; if (start_y<0) start_y=0; end_x=start_x+Main_magnifier_width-1; end_y=start_y+Main_magnifier_height-1; Horizontal_XOR_line(start_x,start_y,Main_magnifier_width); Vertical_XOR_line(start_x,start_y+1,Main_magnifier_height-2); Vertical_XOR_line( end_x,start_y+1,Main_magnifier_height-2); Horizontal_XOR_line(start_x, end_y,Main_magnifier_width); Update_rect(start_x,start_y,end_x+1-start_x,end_y+1-start_y); break; default: //case CURSOR_SHAPE_XOR_ROTATION : start_x=1-(Brush_width>>1); start_y=1-(Brush_height>>1); end_x=start_x+Brush_width-1; end_y=start_y+Brush_height-1; if (Brush_rotation_center_is_defined) { if ( (Brush_rotation_center_X==Paintbrush_X) && (Brush_rotation_center_Y==Paintbrush_Y) ) { cos_a=1.0; sin_a=0.0; } else { x_pos=Paintbrush_X-Brush_rotation_center_X; y_pos=Paintbrush_Y-Brush_rotation_center_Y; cos_a=(float)x_pos/sqrt((x_pos*x_pos)+(y_pos*y_pos)); sin_a=sin(acos(cos_a)); if (y_pos>0) sin_a=-sin_a; } Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3); Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4); x1+=Brush_rotation_center_X; y1+=Brush_rotation_center_Y; x2+=Brush_rotation_center_X; y2+=Brush_rotation_center_Y; x3+=Brush_rotation_center_X; y3+=Brush_rotation_center_Y; x4+=Brush_rotation_center_X; y4+=Brush_rotation_center_Y; Pixel_figure_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,0); Draw_line_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,Paintbrush_X,Paintbrush_Y,0); } else { x1=x3=1-Brush_width; y1=y2=start_y; x2=x4=Paintbrush_X; y3=y4=end_y; x1+=Paintbrush_X; y1+=Paintbrush_Y; y2+=Paintbrush_Y; x3+=Paintbrush_X; y3+=Paintbrush_Y; y4+=Paintbrush_Y; Pixel_figure_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,0); Draw_line_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,Paintbrush_X,Paintbrush_Y,0); } Draw_line_preview_xor(x1,y1,x2,y2,0); Draw_line_preview_xor(x2,y2,x4,y4,0); Draw_line_preview_xor(x4,y4,x3,y3,0); Draw_line_preview_xor(x3,y3,x1,y1,0); } } // -- Effacer le curseur -- void Hide_cursor(void) { byte shape; int start_x; // int car sont parfois ngatifs ! (quand on dessine sur un bord) int start_y; short end_x; short end_y; int x_pos = 0; int y_pos; short counter_x = 0; short counter_y; int temp; float cos_a,sin_a; short x1,y1,x2,y2,x3,y3,x4,y4; if ( ( (Mouse_Y=Main_X_zoom) ) ) || (Windows_open) || (Cursor_shape==CURSOR_SHAPE_HOURGLASS) ) shape=Cursor_shape; else shape=CURSOR_SHAPE_ARROW; switch(shape) { case CURSOR_SHAPE_TARGET : if (!Cursor_hidden) { if (Config.Cursor==1) { start_y=(Mouse_Y<6)?6-Mouse_Y:0; if (start_y<4) Vertical_XOR_line (Mouse_X,Mouse_Y+start_y-6,4-start_y); start_x=(Mouse_X<6)?(short)6-Mouse_X:0; if (start_x<4) Horizontal_XOR_line(Mouse_X+start_x-6,Mouse_Y,4-start_x); end_x=(Mouse_X+7>Screen_width)?Mouse_X+7-Screen_width:0; if (end_x<4) Horizontal_XOR_line(Mouse_X+3,Mouse_Y,4-end_x); end_y=(Mouse_Y+7>Screen_height)?Mouse_Y+7-Screen_height:0; if (end_y<4) Vertical_XOR_line (Mouse_X,Mouse_Y+3,4-end_y); Update_rect(Mouse_X+start_x-6,Mouse_Y+start_y-6,13-end_x,13-end_y); } else { temp=(Config.Cursor)?CURSOR_SHAPE_THIN_TARGET:CURSOR_SHAPE_TARGET; start_x=Mouse_X-Gfx->Cursor_offset_X[temp]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { if(y_pos < 0) continue; if(y_pos>=Screen_height) break; for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) { if(x_pos < 0) continue; else if (x_pos>=Screen_width) break; Pixel(x_pos,y_pos,Cursor_background[counter_y][counter_x]); } } Update_rect(Max(start_x,0),Max(start_y,0),x_pos-start_x,y_pos-start_y); } } if (!Paintbrush_hidden) { Hide_paintbrush(Paintbrush_X,Paintbrush_Y); } break; case CURSOR_SHAPE_COLORPICKER: if (Config.Cursor==1) { // Barres formant la croix principale start_y=(Mouse_Y<5)?5-Mouse_Y:0; if (start_y<3) Vertical_XOR_line (Mouse_X,Mouse_Y+start_y-5,3-start_y); start_x=(Mouse_X<5)?(short)5-Mouse_X:0; if (start_x<3) Horizontal_XOR_line(Mouse_X+start_x-5,Mouse_Y,3-start_x); end_x=(Mouse_X+6>Screen_width)?Mouse_X+6-Screen_width:0; if (end_x<3) Horizontal_XOR_line(Mouse_X+3,Mouse_Y,3-end_x); end_y=(Mouse_Y+6>Screen_height)?Mouse_Y+6-Screen_height:0; if (end_y<3) Vertical_XOR_line (Mouse_X,Mouse_Y+3,3-end_y); start_x=(!Mouse_X); start_y=(!Mouse_Y); end_x=(Mouse_X>=Screen_width-1); end_y=(Mouse_Y>=Menu_Y-1); if (Mouse_Y>5) Horizontal_XOR_line(start_x+Mouse_X-1,Mouse_Y-6,3-(start_x+end_x)); if (Mouse_X>5) Vertical_XOR_line (Mouse_X-6,start_y+Mouse_Y-1,3-(start_y+end_y)); if (Mouse_XCursor_offset_X[temp]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { if(y_pos<0) continue; if(y_pos>=Screen_height) break; for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) { if(x_pos<0) continue; if(x_pos>=Screen_width) break; Pixel(x_pos,y_pos,Cursor_background[counter_y][counter_x]); } } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); } if (!Paintbrush_hidden) Hide_paintbrush(Paintbrush_X,Paintbrush_Y); break; case CURSOR_SHAPE_MULTIDIRECTIONAL : case CURSOR_SHAPE_HORIZONTAL : case CURSOR_SHAPE_BUCKET : if (Cursor_hidden) break; case CURSOR_SHAPE_ARROW : case CURSOR_SHAPE_HOURGLASS : start_x=Mouse_X-Gfx->Cursor_offset_X[shape]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[shape]; for (y_pos=start_y,counter_y=0;counter_y=Screen_height) break; for (x_pos=start_x,counter_x=0;counter_x=Screen_width) break; Pixel(x_pos,y_pos,Cursor_background[counter_y][counter_x]); } } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); break; case CURSOR_SHAPE_XOR_TARGET : x_pos=Paintbrush_X-Main_offset_X; y_pos=Paintbrush_Y-Main_offset_Y; counter_x=(Main_magnifier_mode)?Main_separator_position:Screen_width; // width de la barre XOR if ((y_pos=Limit_top)) { Horizontal_XOR_line(0,Paintbrush_Y-Main_offset_Y,counter_x); Update_rect(0,Paintbrush_Y-Main_offset_Y,counter_x,1); } if ((x_pos=Limit_left)) { Vertical_XOR_line(Paintbrush_X-Main_offset_X,0,Menu_Y); Update_rect(Paintbrush_X-Main_offset_X,0,1,Menu_Y); } if (Main_magnifier_mode) { // UPDATERECT if ((Paintbrush_Y>=Limit_top_zoom) && (Paintbrush_Y<=Limit_visible_bottom_zoom)) Horizontal_XOR_line_zoom(Limit_left_zoom,Paintbrush_Y,Main_magnifier_width); if ((Paintbrush_X>=Limit_left_zoom) && (Paintbrush_X<=Limit_visible_right_zoom)) Vertical_XOR_line_zoom(Paintbrush_X,Limit_top_zoom,Main_magnifier_height); } break; case CURSOR_SHAPE_XOR_RECTANGLE : // !!! Cette forme ne peut pas tre utilise en mode Loupe !!! // Petite croix au centre start_x=(Mouse_X-3); start_y=(Mouse_Y-3); end_x =(Mouse_X+4); end_y =(Mouse_Y+4); if (start_x<0) start_x=0; if (start_y<0) start_y=0; if (end_x>Screen_width) end_x=Screen_width; if (end_y>Menu_Y) end_y=Menu_Y; Horizontal_XOR_line(start_x,Mouse_Y,end_x-start_x); Vertical_XOR_line (Mouse_X,start_y,end_y-start_y); // Grand rectangle autour start_x=Mouse_X-(Main_magnifier_width>>1); start_y=Mouse_Y-(Main_magnifier_height>>1); if (start_x+Main_magnifier_width>=Limit_right-Main_offset_X) start_x=Limit_right-Main_magnifier_width-Main_offset_X+1; if (start_y+Main_magnifier_height>=Limit_bottom-Main_offset_Y) start_y=Limit_bottom-Main_magnifier_height-Main_offset_Y+1; if (start_x<0) start_x=0; if (start_y<0) start_y=0; end_x=start_x+Main_magnifier_width-1; end_y=start_y+Main_magnifier_height-1; Horizontal_XOR_line(start_x,start_y,Main_magnifier_width); Vertical_XOR_line(start_x,start_y+1,Main_magnifier_height-2); Vertical_XOR_line( end_x,start_y+1,Main_magnifier_height-2); Horizontal_XOR_line(start_x, end_y,Main_magnifier_width); Update_rect(start_x,start_y,end_x+1-start_x,end_y+1-start_y); break; default: //case CURSOR_SHAPE_XOR_ROTATION : start_x=1-(Brush_width>>1); start_y=1-(Brush_height>>1); end_x=start_x+Brush_width-1; end_y=start_y+Brush_height-1; if (Brush_rotation_center_is_defined) { if ( (Brush_rotation_center_X==Paintbrush_X) && (Brush_rotation_center_Y==Paintbrush_Y) ) { cos_a=1.0; sin_a=0.0; } else { x_pos=Paintbrush_X-Brush_rotation_center_X; y_pos=Paintbrush_Y-Brush_rotation_center_Y; cos_a=(float)x_pos/sqrt((x_pos*x_pos)+(y_pos*y_pos)); sin_a=sin(acos(cos_a)); if (y_pos>0) sin_a=-sin_a; } Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3); Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4); x1+=Brush_rotation_center_X; y1+=Brush_rotation_center_Y; x2+=Brush_rotation_center_X; y2+=Brush_rotation_center_Y; x3+=Brush_rotation_center_X; y3+=Brush_rotation_center_Y; x4+=Brush_rotation_center_X; y4+=Brush_rotation_center_Y; Pixel_figure_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,0); Draw_line_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,Paintbrush_X,Paintbrush_Y,0); } else { x1=x3=1-Brush_width; y1=y2=start_y; x2=x4=Paintbrush_X; y3=y4=end_y; x1+=Paintbrush_X; y1+=Paintbrush_Y; y2+=Paintbrush_Y; x3+=Paintbrush_X; y3+=Paintbrush_Y; y4+=Paintbrush_Y; Pixel_figure_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,0); Draw_line_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,Paintbrush_X,Paintbrush_Y,0); } Draw_line_preview_xor(x1,y1,x2,y2,0); Draw_line_preview_xor(x2,y2,x4,y4,0); Draw_line_preview_xor(x4,y4,x3,y3,0); Draw_line_preview_xor(x3,y3,x1,y1,0); } } // -- Fonction diverses d'affichage ------------------------------------------ // -- Reafficher toute l'image (en prenant en compte le facteur de zoom) -- void Display_all_screen(void) { word width; word height; // ---/\/\/\ Partie non zoome: /\/\/\--- if (Main_magnifier_mode) { if (Main_image_widthPages->Transparent_color); } else { if (Main_image_widthPages->Transparent_color); } if (Main_image_heightPages->Transparent_color); // ---/\/\/\ Partie zoome: /\/\/\--- if (Main_magnifier_mode) { // Affichage de la barre de split Display_separator(); // Calcul de la largeur visible if (Main_image_widthPages->Transparent_color); if (heightPages->Transparent_color); } // ---/\/\/\ Affichage des limites /\/\/\--- if (Config.Display_image_limits) Display_image_limits(); Update_rect(0,0,Screen_width,Menu_Y); // TODO On peut faire plus fin, en vitant de mettre jour la partie droite du split quand on est en mode loupe. Mais c'est pas vraiment intressant ? } byte Best_color(byte r,byte g,byte b) { int col; int delta_r,delta_g,delta_b; int dist; int best_dist=0x7FFFFFFF; int rmean; byte best_color=0; for (col=0; col<256; col++) { if (!Exclude_color[col]) { delta_r=(int)Main_palette[col].R-r; delta_g=(int)Main_palette[col].G-g; delta_b=(int)Main_palette[col].B-b; rmean = ( Main_palette[col].R + r ) / 2; if (!(dist= ( ( (512+rmean) *delta_r*delta_r) >>8) + 4*delta_g*delta_g + (((767-rmean)*delta_b*delta_b)>>8))) //if (!(dist=(delta_r*delta_r*30)+(delta_g*delta_g*59)+(delta_b*delta_b*11))) return col; if (dist>8) + 4*delta_g*delta_g + (((767-rmean)*delta_b*delta_b)>>8); //dist=(delta_r*delta_r*30)+(delta_g*delta_g*59)+(delta_b*delta_b*11) if (dist improvement) { improvement = after - before; betterpair = i; } } if (improvement > 0) { // Swapping these colors get us something "more different". Do it ! byte idx2 = xor_lut[betterpair]; byte i2 = xor_lut[idx]; xor_lut[betterpair] = i2; xor_lut[i2] = betterpair; xor_lut[idx] = idx2; xor_lut[idx2] = idx; found = 1; } } } while(found); } int Same_color(T_Components * palette, byte c1, byte c2) { if (palette[c1].R==palette[c2].R && palette[c1].G==palette[c2].G && palette[c1].B==palette[c2].B) return 1; return 0; } void Compute_optimal_menu_colors(T_Components * palette) { int i; byte l[256]; byte s[256]; byte h; int max_l = -1, min_l = 256; int low_l, hi_l; int delta_low = 999999; int delta_high = 999999; const int tolerence=16; const T_Components cpc_colors[4] = { { 0, 0, 0}, { 0, 0,128}, // Dark blue {128,128,128}, // Grey {255,255,255} }; Old_black =MC_Black; Old_dark = MC_Dark; Old_light = MC_Light; Old_white = MC_White; Old_trans = MC_Trans; // First method: // If all close matches for the ideal colors exist, pick them. for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[3]].R/tolerence && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[3]].G/tolerence && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[3]].B/tolerence) { MC_White=i; for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[2]].R/tolerence && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[2]].G/tolerence && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[2]].B/tolerence) { MC_Light=i; for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[1]].R/tolerence && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[1]].G/tolerence && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[1]].B/tolerence) { MC_Dark=i; for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[0]].R/tolerence && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[0]].G/tolerence && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[0]].B/tolerence) { MC_Black=i; // On cherche une couleur de transparence diffrente des 4 autres. for (MC_Trans=0; ((MC_Trans==MC_Black) || (MC_Trans==MC_Dark) || (MC_Trans==MC_Light) || (MC_Trans==MC_White)); MC_Trans++); // Easy case MC_OnBlack=MC_Dark; MC_Window=MC_Light; MC_Lighter=MC_White; MC_Darker=MC_Dark; Remap_menu_sprites(); return; } } } } } } } } // Second method: For CPC 27-color modes only // Try to find colors that just work if (Get_palette_RGB_scale()==3) for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[3].R/tolerence && Round_palette_component(palette[i].G)/tolerence==cpc_colors[3].G/tolerence && Round_palette_component(palette[i].B)/tolerence==cpc_colors[3].B/tolerence) { MC_White=i; for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[2].R/tolerence && Round_palette_component(palette[i].G)/tolerence==cpc_colors[2].G/tolerence && Round_palette_component(palette[i].B)/tolerence==cpc_colors[2].B/tolerence) { MC_Light=i; for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[1].R/tolerence && Round_palette_component(palette[i].G)/tolerence==cpc_colors[1].G/tolerence && Round_palette_component(palette[i].B)/tolerence==cpc_colors[1].B/tolerence) { MC_Dark=i; for (i=255; i>=0; i--) { if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[0].R/tolerence && Round_palette_component(palette[i].G)/tolerence==cpc_colors[0].G/tolerence && Round_palette_component(palette[i].B)/tolerence==cpc_colors[0].B/tolerence) { MC_Black=i; // On cherche une couleur de transparence diffrente des 4 autres. for (MC_Trans=0; ((MC_Trans==MC_Black) || (MC_Trans==MC_Dark) || (MC_Trans==MC_Light) || (MC_Trans==MC_White)); MC_Trans++); // Easy case MC_OnBlack=MC_Dark; MC_Window=MC_Light; MC_Lighter=MC_White; MC_Darker=MC_Dark; Remap_menu_sprites(); return; } } } } } } } } // Third method: // Compute luminance for whole palette // Take the darkest as black, the brightest white for(i = 0; i < 256; i++) { RGB_to_HSL(palette[i].R, palette[i].G, palette[i].B, &h, &s[i], &l[i]); // Another formula for lightness, in 0-255 range //l[i]=Perceptual_lightness(&palette[i])/4062/255; if (l[i] > max_l) { max_l = l[i]; MC_White = i; } } for(i = 0; i < 256; i++) { if (l[i] < min_l && i!=MC_White) { min_l = l[i]; MC_Black = i; } } // Alter the S values according to the L range - this is for the future // comparisons, so that highly variable saturation doesn't weigh // too heavily when the the lightness is in a narrow range. for(i = 0; i < 256; i++) { s[i]=s[i]*(max_l-min_l)/255; } for(i = 0; i < 256; i++) { // Adjust (reduce) perceived saturation at both ends of L spectrum if (l[i]>192) s[i]=s[i]*(255-l[i])/64; else if (l[i]<64) s[i]=s[i]*l[i]/64; } // Find color nearest to min+2(max-min)/3 // but at the same time we try to minimize the saturation so that the menu // still looks grey hi_l = min_l + 2*(max_l - min_l)/3; for (i = 0; i < 256; i++) { if ( abs(l[i] - hi_l) + s[i]/2 < delta_high && i!=MC_White && i!=MC_Black) { delta_high = abs(l[i] - hi_l) + s[i]/2; MC_Light = i; } } // Target "Dark color" is 2/3 between Light and Black low_l = ((int)l[MC_Light]*2+l[MC_Black])/3; for (i = 0; i < 256; i++) { if ( abs((int)l[i] - low_l) + s[i]/6 < delta_low && i!=MC_White && i!=MC_Black && i!=MC_Light) { delta_low = abs((int)l[i] - low_l)+ s[i]/6; MC_Dark = i; } } //if (l[MC_Light]Cursor_sprite[k][j][i]); // Main menu bar for (k=0; k<3; k++) for (j=0; jMenu_block[k][j][i]); // Menu sprites for (l=0; l<2; l++) for (k=0; kMenu_sprite[l][k][j][i]); // Effects sprites for (k=0; kEffect_sprite[k][j][i]); // Layers buttons for (l=0; l<3; l++) for (k=0; k<16; k++) for (j=0; jLayer_sprite[l][k][j][i]); // Status bar for (k=0; k<3; k++) for (j=0; jStatusbar_block[k][j][i]); // Layer bar for (k=0; k<3; k++) for (j=0; j<10; j++) for (i=0; i<144; i++) Remap_pixel(&Gfx->Layerbar_block[k][j][i]); // Anim bar for (k=0; k<3; k++) for (j=0; j<14; j++) for (i=0; i<236; i++) Remap_pixel(&Gfx->Animbar_block[k][j][i]); // Help fonts for (k=0; k<256; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) Remap_pixel(&Gfx->Help_font_norm[k][i][j]); for (k=0; k<256; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) Remap_pixel(&Gfx->Bold_font[k][i][j]); for (k=0; k<64; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) Remap_pixel(&Gfx->Help_font_t1[k][i][j]); for (k=0; k<64; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) Remap_pixel(&Gfx->Help_font_t2[k][i][j]); for (k=0; k<64; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) Remap_pixel(&Gfx->Help_font_t3[k][i][j]); for (k=0; k<64; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) Remap_pixel(&Gfx->Help_font_t4[k][i][j]); // Drives and other misc. 8x8 icons for (k=0; kIcon_sprite[k][j][i]); // Skin preview for (j = 0; j < 173; j++) for (i = 0; i < 16; i++) Remap_pixel(&Gfx->Preview[i][j]); } Clear_border(MC_Black); } grafx2_2.4+git20180105/src/saveini.h0000664000000000000000000000200513223665306015333 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file saveini.h /// Saving settings in gfx2.ini ////////////////////////////////////////////////////////////////////////////// int Save_INI(T_Config * conf); grafx2_2.4+git20180105/src/SFont.c0000664000000000000000000001423713223665306014733 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* SFont: a simple font-library that uses special .pngs as fonts Copyright (C) 2003 Karl Bartel License: GPL or LGPL (at your choice) WWW: http://www.linux-games.com/sfont/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . Karl Bartel Cecilienstr. 14 12307 Berlin GERMANY karlb@gmx.net */ #include #include #include #include #include "SFont.h" static Uint32 GetPixel(SDL_Surface *Surface, Sint32 X, Sint32 Y) { Uint8 *bits; Uint32 Bpp; assert(X>=0); assert(Xw); Bpp = Surface->format->BytesPerPixel; bits = ((Uint8 *)Surface->pixels)+Y*Surface->pitch+X*Bpp; // Get the pixel switch(Bpp) { case 1: return *((Uint8 *)Surface->pixels + Y * Surface->pitch + X); break; case 2: return *((Uint16 *)Surface->pixels + Y * Surface->pitch/2 + X); break; case 3: { // Format/endian independent Uint8 r, g, b; r = *((bits)+Surface->format->Rshift/8); g = *((bits)+Surface->format->Gshift/8); b = *((bits)+Surface->format->Bshift/8); return SDL_MapRGB(Surface->format, r, g, b); } break; case 4: return *((Uint32 *)Surface->pixels + Y * Surface->pitch/4 + X); break; } return -1; } SFont_Font* SFont_InitFont(SDL_Surface* Surface) { int x = 0, i = 33; Uint32 pixel; SFont_Font* Font; Uint32 pink; if (Surface == NULL) return NULL; Font = (SFont_Font *) malloc(sizeof(SFont_Font)); memset(Font, 0, sizeof(SFont_Font)); Font->Surface = Surface; SDL_LockSurface(Surface); pink = GetPixel(Surface, 0, 0); while (x < Surface->w) { if (GetPixel(Surface, x, 0) != pink) { Font->CharBegin[i]=x; while((x < Surface->w) && (GetPixel(Surface, x, 0)!= pink)) x++; Font->CharWidth[i]=x-Font->CharBegin[i]; i++; } x++; } // Create lowercase characters, if not present for (i=0; i <26; i++) { if (Font->CharWidth['a'+i]==0) { Font->CharBegin['a'+i]=Font->CharBegin['A'+i]; Font->CharWidth['a'+i]=Font->CharWidth['A'+i]; } } // Determine space width. // This strange format doesn't allow font designer to write explicit // space as a character. // Rule: A space should be as large as the character " if available, // or 'a' if it's not. Font->Space = Font->CharWidth[(int)'"']; if (Font->Space<2) Font->Space = Font->CharWidth[(int)'a']; pixel = GetPixel(Surface, 0, Surface->h-1); SDL_UnlockSurface(Surface); // No longer use SDL color keying //SDL_SetColorKey(Surface, SDL_SRCCOLORKEY, pixel); Font->Transparent=pixel; return Font; } void SFont_FreeFont(SFont_Font* FontInfo) { SDL_FreeSurface(FontInfo->Surface); free(FontInfo); } void SFont_Write(SDL_Surface *Surface, const SFont_Font *Font, int x, int y, const char *text) { const char* c; SDL_Rect srcrect, dstrect; if(text == NULL) return; // these values won't change in the loop srcrect.y = 1; dstrect.y = y; srcrect.h = dstrect.h = Font->Surface->h - 1; for(c = text; *c != '\0' && x <= Surface->w ; c++) { if (*c == '\n') { dstrect.y += Font->Surface->h-1; x=0; continue; } // skip spaces and nonprintable characters else if (*c == ' ' || Font->CharWidth[(int)*c]==0) { x += Font->Space; continue; } srcrect.w = Font->CharWidth[(int)*c]; dstrect.w = srcrect.w; srcrect.x = Font->CharBegin[(int)*c]; dstrect.x = x; SDL_BlitSurface(Font->Surface, &srcrect, Surface, &dstrect); x += Font->CharWidth[(int)*c]; } } int SFont_TextWidth(const SFont_Font *Font, const char *text) { const char* c; int width = 0; int previous_width = 0; if(text == NULL) return 0; for(c = text; *c != '\0'; c++) { if (*c == '\n') { if (previous_widthCharWidth[(int)*c]==0) { width += Font->Space; continue; } width += Font->CharWidth[(int)*c]; } return previous_widthSurface->h - 1) * (nb_cr+1); } /* // Do not use: Doesn't implement carriage returns void SFont_WriteCenter(SDL_Surface *Surface, const SFont_Font *Font, int y, const char *text) { SFont_Write(Surface, Font, Surface->w/2 - SFont_TextWidth(Font, text)/2, y, text); } */ grafx2_2.4+git20180105/src/brush.h0000664000000000000000000001070313223665306015024 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007-2008 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file brush.h /// Actions on the brush. ////////////////////////////////////////////////////////////////////////////// #ifndef __BRUSH_H_ #define __BRUSH_H_ #include "struct.h" /*! Gets the brush from the picture. @param start_x left edge coordinate in the picture @param start_y upper edge coordinate in the picture @param end_x right edge coordinate in the picture @param end_y bottom edge coordinate in the picture @param clear If 1, the area is also cleared from the picture. */ void Capture_brush(short start_x,short start_y,short end_x,short end_y,short clear); /*! Rotates the brush to the right. */ void Rotate_90_deg(void); /*! Stretch the brush to fit the given rectangle. */ void Stretch_brush(short x1, short y1, short x2, short y2); /*! Stretch the brush to fit the given rectangle. Uses fast approximation for the preview while drawing the rectangle on screen. */ void Stretch_brush_preview(short x1, short y1, short x2, short y2); /*! Rotates the brush to the right from the given angle. */ void Rotate_brush(float angle); /*! Stretch the brush to fit the given rectangle. Uses fast approximation for the preview while changing the angle. */ void Rotate_brush_preview(float angle); /*! Remap the brush palette to the nearest color in the picture one. Used when switching to the spare page. */ /*! Distort the brush on the screen. */ void Distort_brush_preview(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4); /*! Replace the brush by a distorted version of itself. */ void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4); void Remap_brush(void); /*! Get color indexes used by the brush. */ void Get_colors_from_brush(void); /*! Outline the brush, add 1 foreground-colored pixel on the edges. Edges are detected considering the backcolor as transparent. */ void Outline_brush(void); /*! Nibble the brush, remove 1 pixel on the edges and make it transparent (ie filled with back color). Edges are detected considering the backcolor as transparent. */ void Nibble_brush(void); /*! Get brush from picture according to a freehand form. @param vertices number of points in the freehand form @param points array of points coordinates @param clear If set to 1, the captured area is also cleared from the picture. */ void Capture_brush_with_lasso(int vertices, short * points,short clear); /*! \brief Allocates memory for a brush size change. This function can return the old brush pixels which can then be used by the caller to fill the new brush. Data is not automatically copied or converted from the old brush to the new one here. @param new_brush_width: new width of the brush @param new_brush_height: new height of the brush @param new_brush: Optionally, you can provide an already allocated new brush - otherwise, this function performs the allocation. @param old_brush: If the caller passes NULL, this function will free the old pixel data. If the caller provides the address of a (free) byte pointer, the function will make it point to the original pixel data, in this case it will be the caller's responsibility to free() it (after transferring pixels to Brush, usually). @return 0 on success, non-zero when running out of memory. */ byte Realloc_brush(word new_brush_width, word new_brush_height, byte *new_brush, byte **old_brush); /// Sets brush's original palette and color mapping. void Brush_set_palette(T_Palette *palette); void Begin_brush_rotation(void); void End_brush_rotation(void); #endif grafx2_2.4+git20180105/src/shade.h0000664000000000000000000000220713223665307014766 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file shade.h /// Screens for Shade and Quick-shade settings. ////////////////////////////////////////////////////////////////////////////// #ifndef SHADE_H_INCLUDED #define SHADE_H_INCLUDED void Button_Quick_shade_menu(void); int Shade_settings_menu(void); #endif // SHADE_H_INCLUDED grafx2_2.4+git20180105/src/pages.c0000664000000000000000000012715513223665306015005 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Franck Charlet Copyright 2007-2017 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////// /////////////////////////// GESTION DU BACKUP //////////////////////////// ////////////////////////////////////////////////////////////////////////// #include #include #include #include "global.h" #include "pages.h" #include "errors.h" #include "loadsave.h" #include "misc.h" #include "windows.h" #include "tiles.h" #include "graph.h" // -- Layers data /// Array of two images, that contains the "flattened" version of the visible layers. T_Bitmap Main_visible_image; T_Bitmap Main_visible_image_backup; T_Bitmap Main_visible_image_depth_buffer; T_Bitmap Spare_visible_image; /// /// GESTION DES PAGES /// /// Bitfield which records which layers are backed up in Page 0. static dword Last_backed_up_layers=0; /// Total number of unique bitmaps (layers, animation frames, backups) long Stats_pages_number=0; /// Total memory used by bitmaps (layers, animation frames, backups) long long Stats_pages_memory=0; /// Allocate and initialize a new page. T_Page * New_page(int nb_layers) { T_Page * page; page = (T_Page *)malloc(sizeof(T_Page)+nb_layers*sizeof(T_Image)); if (page!=NULL) { int i; for (i=0; iImage[i].Pixels=NULL; page->Image[i].Duration=100; } page->Width=0; page->Height=0; page->Image_mode = IMAGE_MODE_LAYERED; memset(page->Palette,0,sizeof(T_Palette)); page->Comment[0]='\0'; page->File_directory[0]='\0'; page->Filename[0]='\0'; page->File_format=DEFAULT_FILEFORMAT; page->Nb_layers=nb_layers; page->Gradients=NULL; page->Transparent_color=0; // Default transparent color page->Background_transparent=0; page->Next = page->Prev = NULL; } return page; } // ============================================================== // Layers allocation functions. // // Layers are made of a "number of users" (short), followed by // the actual pixel data (a large number of bytes). // Every time a layer is 'duplicated' as a reference, the number // of users is incremented. // Every time a layer is freed, the number of users is decreased, // and only when it reaches zero the pixel data is freed. // ============================================================== /// Allocate a new layer byte * New_layer(long pixel_size) { short * ptr = malloc(sizeof(short)+pixel_size); if (ptr==NULL) return NULL; // Stats Stats_pages_number++; Stats_pages_memory+=pixel_size; *ptr = 1; return (byte *)(ptr+1); } /// Free a layer void Free_layer(T_Page * page, int layer) { short * ptr; if (page->Image[layer].Pixels==NULL) return; ptr = (short *)(page->Image[layer].Pixels); if (-- (*(ptr-1))) // Users-- return; else { free(ptr-1); } // Stats Stats_pages_number--; Stats_pages_memory-=page->Width * page->Height; } /// Duplicate a layer (new reference) byte * Dup_layer(byte * layer) { short * ptr = (short *)(layer); if (layer==NULL) return NULL; (*(ptr-1)) ++; // Users ++ return layer; } // ============================================================== /// Adds a shared reference to the gradient data of another page. Pass NULL for new. T_Gradient_array *Dup_gradient(T_Page * page) { // new if (page==NULL || page->Gradients==NULL) { T_Gradient_array *array; array=(T_Gradient_array *)calloc(1, sizeof(T_Gradient_array)); if (!array) return NULL; array->Used=1; return array; } // shared page->Gradients->Used++; return page->Gradients; } void Download_infos_page_main(T_Page * page) // Affiche la page l'cran { //int factor_index; int size_is_modified; if (page!=NULL) { size_is_modified=(Main_image_width!=page->Width) || (Main_image_height!=page->Height); Main_image_width=page->Width; Main_image_height=page->Height; memcpy(Main_palette,page->Palette,sizeof(T_Palette)); Main_fileformat=page->File_format; if (size_is_modified) { Main_magnifier_mode=0; Main_offset_X=0; Main_offset_Y=0; Pixel_preview=Pixel_preview_normal; Compute_limits(); Compute_paintbrush_coordinates(); } } //Update_buffers( page->Width, page->Height); //memcpy(Main_screen, page->Image[Main_current_layer].Pixels, page->Width*page->Height); } void Redraw_layered_image(void) { if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { // Re-construct the image with the visible layers byte layer=0; // First layer if (Main_backups->Pages->Image_mode == IMAGE_MODE_MODE5 && Main_layers_visible & (1<<4)) { // The raster result layer is visible: start there // Copy it in Main_visible_image int i; for (i=0; i< Main_image_width*Main_image_height; i++) { layer = *(Main_backups->Pages->Image[4].Pixels+i); if (Main_layers_visible & (1 << layer)) Main_visible_image.Image[i]=*(Main_backups->Pages->Image[layer].Pixels+i); else Main_visible_image.Image[i] = layer; } // Copy it to the depth buffer memcpy(Main_visible_image_depth_buffer.Image, Main_backups->Pages->Image[4].Pixels, Main_image_width*Main_image_height); // Next layer= (1<<4)+1; } else { for (layer=0; layerPages->Nb_layers; layer++) { if ((1<Pages->Image[layer].Pixels, Main_image_width*Main_image_height); // Initialize the depth buffer memset(Main_visible_image_depth_buffer.Image, layer, Main_image_width*Main_image_height); // skip all other layers layer++; break; } } } // subsequent layer(s) for (; layerPages->Nb_layers; layer++) { if ((1<Pages->Image[layer].Pixels+i); if (color != Main_backups->Pages->Transparent_color) // transparent color { *(Main_visible_image.Image+i) = color; if (layer != Main_current_layer) *(Main_visible_image_depth_buffer.Image+i) = layer; } } } } } else { Update_screen_targets(); } Update_FX_feedback(Config.FX_Feedback); } void Update_depth_buffer(void) { if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { // Re-construct the depth buffer with the visible layers. // This function doesn't touch the visible buffer, it assumes // that it was already up-to-date. (Ex. user only changed active layer) int layer; // First layer for (layer=0; layerPages->Nb_layers; layer++) { if ((1<Pages->Nb_layers; layer++) { // skip the current layer, whenever we reach it if (layer == Main_current_layer) continue; if ((1<Pages->Image[layer].Pixels+i); if (color != Main_backups->Pages->Transparent_color) // transparent color { *(Main_visible_image_depth_buffer.Image+i) = layer; } } } } } Update_FX_feedback(Config.FX_Feedback); } void Redraw_spare_image(void) { if (Spare_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { // Re-construct the image with the visible layers byte layer; // First layer for (layer=0; layerPages->Nb_layers; layer++) { if ((1<Pages->Image[layer].Pixels, Spare_image_width*Spare_image_height); // No depth buffer in the spare //memset(Spare_visible_image_depth_buffer.Image, // layer, // Spare_image_width*Spare_image_height); // skip all other layers layer++; break; } } // subsequent layer(s) for (; layerPages->Nb_layers; layer++) { if ((1<Pages->Image[layer].Pixels+i); if (color != Spare_backups->Pages->Transparent_color) // transparent color { *(Spare_visible_image.Image+i) = color; //if (layer != Spare_current_layer) // *(Spare_visible_image_depth_buffer.Image+i) = layer; } } } } } } void Redraw_current_layer(void) { if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { int i; for (i=0; iPages->Image[Main_current_layer].Pixels+i); if (color != Main_backups->Pages->Transparent_color) // transparent color { *(Main_visible_image.Image+i) = color; } else { *(Main_visible_image.Image+i) = *(Main_backups->Pages->Image[depth].Pixels+i); } } } } } void Upload_infos_page_main(T_Page * page) // Sauve l'cran courant dans la page { if (page!=NULL) { //page->Image[Main_current_layer].Pixels=Main_screen; page->Width=Main_image_width; page->Height=Main_image_height; memcpy(page->Palette,Main_palette,sizeof(T_Palette)); page->File_format=Main_fileformat; } } void Download_infos_page_spare(T_Page * page) { if (page!=NULL) { Spare_image_width=page->Width; Spare_image_height=page->Height; memcpy(Spare_palette,page->Palette,sizeof(T_Palette)); Spare_fileformat=page->File_format; } } void Upload_infos_page_spare(T_Page * page) { if (page!=NULL) { //page->Image[Spare_current_layer].Pixels=Spare_screen; page->Width=Spare_image_width; page->Height=Spare_image_height; memcpy(page->Palette,Spare_palette,sizeof(T_Palette)); page->File_format=Spare_fileformat; } } byte * FX_feedback_screen; void Update_FX_feedback(byte with_feedback) { if (with_feedback) FX_feedback_screen=Main_backups->Pages->Image[Main_current_layer].Pixels; else FX_feedback_screen=Main_backups->Pages->Next->Image[Main_current_layer].Pixels; } void Clear_page(T_Page * page) { // On peut appeler cette fonction sur une page non alloue. int i; for (i=0; iNb_layers; i++) { Free_layer(page, i); page->Image[i].Pixels=NULL; page->Image[i].Duration=0; } // Free_gradient() : This data is reference-counted if (page->Gradients) { page->Gradients->Used--; if (page->Gradients->Used==0) free(page->Gradients); page->Gradients=NULL; } page->Width=0; page->Height=0; // On ne se proccupe pas de ce que deviens le reste des infos de l'image. } void Copy_S_page(T_Page * dest,T_Page * source) { *dest=*source; dest->Gradients=NULL; } /// /// GESTION DES LISTES DE PAGES /// void Init_list_of_pages(T_List_of_pages * list) { // Important: appeler cette fonction sur toute nouvelle structure // T_List_of_pages! list->List_size=0; list->Pages=NULL; } int Allocate_list_of_pages(T_List_of_pages * list) { // Important: la T_List_of_pages ne doit pas dj dsigner une liste de // pages alloue auquel cas celle-ci serait perdue. T_Page * page; // On initialise chacune des nouvelles pages page=New_page(1); if (!page) return 0; // Set as first page of the list page->Next = page; page->Prev = page; list->Pages = page; list->List_size=1; page->Gradients=Dup_gradient(NULL); if (!page->Gradients) return 0; return 1; // Succs } void Backward_in_list_of_pages(T_List_of_pages * list) { // Cette fonction fait l'quivalent d'un "Undo" dans la liste de pages. // Elle effectue une sorte de ROL (Rotation Left) sur la liste: // +---+-+-+-+-+-+-+-+-+-+ | // 0123456789A | // +---+-+-+-+-+-+-+-+-+-+ | 0=page courante // |_ A=page la plus ancienne // v v v v v v v v v v v | 1=Dernire page (1er backup) // +---+-+-+-+-+-+-+-+-+-+ | // 123456789A0 | // +---+-+-+-+-+-+-+-+-+-+ | // Pour simuler un vritable Undo, l'appelant doit mettre la structure // de page courante jour avant l'appel, puis en rextraire les infos en // sortie, ainsi que celles relatives la plus rcente page d'undo (1re // page de la liste). if (Last_backed_up_layers) { // First page contains a ready-made backup of its ->Next. // We have swap the first two pages, so the original page 0 // will end up in position 0 again, and then overwrite it with a backup // of the 'new' page1. T_Page * page0; T_Page * page1; page0 = list->Pages; page1 = list->Pages->Next; page0->Next = page1->Next; page1->Prev = page0->Prev; page0->Prev = page1; page1->Next = page0; list->Pages = page0; return; } list->Pages = list->Pages->Next; } void Advance_in_list_of_pages(T_List_of_pages * list) { // Cette fonction fait l'quivalent d'un "Redo" dans la liste de pages. // Elle effectue une sorte de ROR (Rotation Right) sur la liste: // +-+-+-+-+-+-+-+-+-+-+-+ | // |0|1|2|3|4|5|6|7|8|9|A| | // +-+-+-+-+-+-+-+-+-+-+-+ | 0=page courante // | | | | | | | | | | | |_ A=page la plus ancienne // v v v v v v v v v v v | 1=Dernire page (1er backup) // +-+-+-+-+-+-+-+-+-+-+-+ | // |A|0|1|2|3|4|5|6|7|8|9| | // +-+-+-+-+-+-+-+-+-+-+-+ | // Pour simuler un vritable Redo, l'appelant doit mettre la structure // de page courante jour avant l'appel, puis en rextraire les infos en // sortie, ainsi que celles relatives la plus rcente page d'undo (1re // page de la liste). if (Last_backed_up_layers) { // First page contains a ready-made backup of its ->Next. // We have swap the first two pages, so the original page 0 // will end up in position -1 again, and then overwrite it with a backup // of the 'new' page1. T_Page * page0; T_Page * page1; page0 = list->Pages; page1 = list->Pages->Prev; page0->Prev = page1->Prev; page1->Next = page0->Next; page0->Next = page1; page1->Prev = page0; list->Pages = page1; return; } list->Pages = list->Pages->Prev; } void Free_last_page_of_list(T_List_of_pages * list) { if (list!=NULL) { if (list->List_size>0) { T_Page * page; // The last page is the one before first page = list->Pages->Prev; page->Next->Prev = page->Prev; page->Prev->Next = page->Next; Clear_page(page); free(page); page = NULL; list->List_size--; } } } // layer tells which layers have to be fresh copies instead of references : // it's a layer number (>=0) or LAYER_NONE or LAYER_ALL int Create_new_page(T_Page * new_page, T_List_of_pages * list, int layer) { // This function fills the "Image" field of a new Page, // based on the pages's attributes (width,height,...) // then pushes it on front of a Page list. if (list->List_size >= (Config.Max_undo_pages+1)) { // List is full. // If some other memory-limit was to be implemented, here would // be the right place to do it. // For example, we could rely on Stats_pages_memory, // because it's the sum of all bitmaps in use (in bytes). // Destroy the latest page Free_last_page_of_list(list); } { int i; for (i=0; iNb_layers; i++) { if (layer == LAYER_ALL || i == layer) new_page->Image[i].Pixels=New_layer(new_page->Height*new_page->Width); else new_page->Image[i].Pixels=Dup_layer(list->Pages->Image[i].Pixels); new_page->Image[i].Duration=list->Pages->Image[i].Duration; } } // Insert as first new_page->Next = list->Pages; new_page->Prev = list->Pages->Prev; list->Pages->Prev->Next = new_page; list->Pages->Prev = new_page; list->Pages = new_page; list->List_size++; return 1; } void Change_page_number_of_list(T_List_of_pages * list,int number) { // Truncate the list if larger than requested while(list->List_size > number) { Free_last_page_of_list(list); } } void Free_page_of_a_list(T_List_of_pages * list) { // On ne peut pas dtruire la page courante de la liste si aprs // destruction il ne reste pas encore au moins une page. if (list->List_size>1) { // On fait faire un undo la liste, comme a, la nouvelle page courante // est la page prcdente Backward_in_list_of_pages(Main_backups); // Puis on dtruit la dernire page, qui est l'ancienne page courante Free_last_page_of_list(list); } } void Update_screen_targets(void) { if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { Main_screen=Main_visible_image.Image; Screen_backup=Main_visible_image_backup.Image; } else { Main_screen=Main_backups->Pages->Image[Main_current_layer].Pixels; // Sometimes this function will be called in situations where the // current history step and previous one don't have as many layers. // I don't like the idea of letting Screen_backup NULL or dangling, // so in case Screen_backup was queried, it will point to a valid // readable bitmap of correct size : current image. if (Main_backups->Pages->Nb_layers != Main_backups->Pages->Next->Nb_layers || Main_backups->Pages->Width != Main_backups->Pages->Next->Width || Main_backups->Pages->Height != Main_backups->Pages->Next->Height) Screen_backup=Main_screen; else Screen_backup=Main_backups->Pages->Next->Image[Main_current_layer].Pixels; } Update_pixel_renderer(); } /// Update all the special image buffers, if necessary. int Update_buffers(int width, int height) { if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { // At least one dimension is different if (Main_visible_image.Width*Main_visible_image.Height != width*height) { // Current image free(Main_visible_image.Image); Main_visible_image.Image = (byte *)malloc(width * height); if (Main_visible_image.Image == NULL) return 0; } Main_visible_image.Width = width; Main_visible_image.Height = height; if (Main_visible_image_backup.Width*Main_visible_image_backup.Height != width*height) { // Previous image free(Main_visible_image_backup.Image); Main_visible_image_backup.Image = (byte *)malloc(width * height); if (Main_visible_image_backup.Image == NULL) return 0; } Main_visible_image_backup.Width = width; Main_visible_image_backup.Height = height; if (Main_visible_image_depth_buffer.Width*Main_visible_image_depth_buffer.Height != width*height) { // Depth buffer free(Main_visible_image_depth_buffer.Image); Main_visible_image_depth_buffer.Image = (byte *)malloc(width * height); if (Main_visible_image_depth_buffer.Image == NULL) return 0; } Main_visible_image_depth_buffer.Width = width; Main_visible_image_depth_buffer.Height = height; } Update_screen_targets(); return 1; } /// Update all the special image buffers of the spare page, if necessary. int Update_spare_buffers(int width, int height) { if (Spare_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { // At least one dimension is different if (Spare_visible_image.Width*Spare_visible_image.Height != width*height) { // Current image free(Spare_visible_image.Image); Spare_visible_image.Image = (byte *)malloc(width * height); if (Spare_visible_image.Image == NULL) return 0; } Spare_visible_image.Width = width; Spare_visible_image.Height = height; } return 1; } /// /// GESTION DES BACKUPS /// int Init_all_backup_lists(enum IMAGE_MODES image_mode, int width, int height) { // width et height correspondent la dimension des images de dpart. int i; if (! Allocate_list_of_pages(Main_backups) || ! Allocate_list_of_pages(Spare_backups)) return 0; // On a russi allouer deux listes de pages dont la taille correspond // celle demande par l'utilisateur. // On cre un descripteur de page correspondant la page principale Upload_infos_page_main(Main_backups->Pages); // On y met les infos sur la dimension de dmarrage Main_backups->Pages->Width=width; Main_backups->Pages->Height=height; strcpy(Main_backups->Pages->File_directory,Main_selector.Directory); strcpy(Main_backups->Pages->Filename,"NO_NAME.GIF"); for (i=0; iPages->Nb_layers; i++) { Main_backups->Pages->Image[i].Pixels=New_layer(width*height); if (! Main_backups->Pages->Image[i].Pixels) return 0; memset(Main_backups->Pages->Image[i].Pixels, 0, width*height); } Main_visible_image.Width = 0; Main_visible_image.Height = 0; Main_visible_image.Image = NULL; Main_visible_image_backup.Image = NULL; Main_visible_image_depth_buffer.Image = NULL; Main_backups->Pages->Image_mode = image_mode; Spare_visible_image.Width = 0; Spare_visible_image.Height = 0; Spare_visible_image.Image = NULL; Spare_backups->Pages->Image_mode = image_mode; if (!Update_buffers(width, height)) return 0; if (!Update_spare_buffers(width, height)) return 0; // For speed, instead of Redraw_layered_image() we'll directly set the buffers. if (Main_visible_image.Image != NULL) { memset(Main_visible_image.Image, 0, width*height); memset(Main_visible_image_backup.Image, 0, width*height); memset(Main_visible_image_depth_buffer.Image, 0, width*height); } if (Spare_visible_image.Image != NULL) memset(Spare_visible_image.Image, 0, width*height); Download_infos_page_main(Main_backups->Pages); Update_FX_feedback(Config.FX_Feedback); // Default values for spare page Spare_backups->Pages->Width = width; Spare_backups->Pages->Height = height; memcpy(Spare_backups->Pages->Palette,Main_palette,sizeof(T_Palette)); strcpy(Spare_backups->Pages->Comment,""); strcpy(Spare_backups->Pages->File_directory,Main_selector.Directory); strcpy(Spare_backups->Pages->Filename,"NO_NAME2.GIF"); Spare_backups->Pages->File_format=DEFAULT_FILEFORMAT; // Copy this informations in the global Spare_ variables Download_infos_page_spare(Spare_backups->Pages); // Clear the initial Visible buffer //memset(Main_screen,0,Main_image_width*Main_image_height); // Spare for (i=0; iPages->Image[i].Pixels=New_layer(width*height); if (! Spare_backups->Pages->Image[i].Pixels) return 0; memset(Spare_backups->Pages->Image[i].Pixels, 0, width*height); } //memset(Spare_screen,0,Spare_image_width*Spare_image_height); End_of_modification(); return 1; } void Set_number_of_backups(int nb_backups) { Change_page_number_of_list(Main_backups,nb_backups+1); Change_page_number_of_list(Spare_backups,nb_backups+1); // Le +1 vient du fait que dans chaque liste, en 1re position on retrouve // les infos de la page courante sur le brouillon et la page principale. // (nb_backups = Nombre de backups, sans compter les pages courantes) } int Backup_new_image(int layers,int width,int height) { // Retourne 1 si une nouvelle page est disponible et 0 sinon T_Page * new_page; // On cre un descripteur pour la nouvelle page courante new_page=New_page(layers); if (!new_page) { Error(0); return 0; } new_page->Width=width; new_page->Height=height; new_page->Transparent_color=0; new_page->Gradients=Dup_gradient(NULL); if (!Create_new_page(new_page,Main_backups,LAYER_ALL)) { Error(0); return 0; } Update_buffers(width, height); memset(Main_visible_image_depth_buffer.Image, 0, width*height); Download_infos_page_main(Main_backups->Pages); return 1; } int Backup_with_new_dimensions(int width,int height) { // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et // 0 sinon. T_Page * new_page; int i; // On cre un descripteur pour la nouvelle page courante new_page=New_page(Main_backups->Pages->Nb_layers); if (!new_page) { Error(0); return 0; } new_page->Width=width; new_page->Height=height; new_page->Transparent_color=0; if (!Create_new_page(new_page,Main_backups,LAYER_ALL)) { Error(0); return 0; } // Copy data from previous history step memcpy(Main_backups->Pages->Palette,Main_backups->Pages->Next->Palette,sizeof(T_Palette)); strcpy(Main_backups->Pages->Comment,Main_backups->Pages->Next->Comment); Main_backups->Pages->File_format=Main_backups->Pages->Next->File_format; strcpy(Main_backups->Pages->Filename, Main_backups->Pages->Next->Filename); strcpy(Main_backups->Pages->File_directory, Main_backups->Pages->Next->File_directory); Main_backups->Pages->Gradients=Dup_gradient(Main_backups->Pages->Next); Main_backups->Pages->Background_transparent=Main_backups->Pages->Next->Background_transparent; Main_backups->Pages->Transparent_color=Main_backups->Pages->Next->Transparent_color; Main_backups->Pages->Image_mode=Main_backups->Pages->Next->Image_mode; // Fill with transparent color for (i=0; iPages->Nb_layers;i++) { memset(Main_backups->Pages->Image[i].Pixels, Main_backups->Pages->Transparent_color, width*height); } Update_buffers(width, height); Download_infos_page_main(Main_backups->Pages); // Same code as in End_of_modification(), // Without saving a safety backup: if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { memcpy(Main_visible_image_backup.Image, Main_visible_image.Image, Main_image_width*Main_image_height); } else { Update_screen_targets(); } Update_FX_feedback(Config.FX_Feedback); // -- return 1; } /// /// Resizes a backup step in-place (doesn't add a Undo/Redo step). /// Should only be called after an actual backup, because it loses the current. /// pixels. This function is meant to be used from within Lua scripts. int Backup_in_place(int width,int height) { // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et // 0 sinon. int i; byte ** new_layer; // Perform all allocations first new_layer=calloc(Main_backups->Pages->Nb_layers,sizeof(byte *)); if (!new_layer) return 0; for (i=0; iPages->Nb_layers; i++) { new_layer[i]=New_layer(height*width); if (!new_layer[i]) { // Allocation error for (; i>0; i--) free(new_layer[i]); free(new_layer); return 0; } } // Now ok to proceed for (i=0; iPages->Nb_layers; i++) { // Replace layers Free_layer(Main_backups->Pages,i); Main_backups->Pages->Image[i].Pixels=new_layer[i]; // Fill with transparency memset(Main_backups->Pages->Image[i].Pixels, Main_backups->Pages->Transparent_color, width*height); } Main_backups->Pages->Width=width; Main_backups->Pages->Height=height; Download_infos_page_main(Main_backups->Pages); // The following is part of Update_buffers() // (without changing the backup buffer) if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { // At least one dimension is different if (Main_visible_image.Width*Main_visible_image.Height != width*height) { // Current image free(Main_visible_image.Image); Main_visible_image.Image = (byte *)malloc(width * height); if (Main_visible_image.Image == NULL) return 0; } Main_visible_image.Width = width; Main_visible_image.Height = height; if (Main_visible_image_depth_buffer.Width*Main_visible_image_depth_buffer.Height != width*height) { // Depth buffer free(Main_visible_image_depth_buffer.Image); Main_visible_image_depth_buffer.Image = (byte *)malloc(width * height); if (Main_visible_image_depth_buffer.Image == NULL) return 0; } Main_visible_image_depth_buffer.Width = width; Main_visible_image_depth_buffer.Height = height; } Update_screen_targets(); return 1; } int Backup_and_resize_the_spare(int width,int height) { // Retourne 1 si la page de dimension souhaitee est disponible en brouillon // et 0 sinon. T_Page * new_page; int return_code=0; int nb_layers; nb_layers=Spare_backups->Pages->Nb_layers; // On cre un descripteur pour la nouvelle page de brouillon new_page=New_page(nb_layers); if (!new_page) { Error(0); return 0; } // Fill it with a copy of the latest history Copy_S_page(new_page,Spare_backups->Pages); new_page->Gradients=Dup_gradient(Spare_backups->Pages); new_page->Width=width; new_page->Height=height; if (Create_new_page(new_page,Spare_backups,LAYER_ALL)) { byte i; for (i=0; iPages->Image[i].Pixels, Spare_backups->Pages->Transparent_color, width*height); } // Update_buffers(width, height); // Not for spare Download_infos_page_spare(Spare_backups->Pages); // Light up the 'has unsaved changes' indicator Spare_image_is_modified=1; return_code=1; } return return_code; } void Backup(void) // Sauve la page courante comme premire page de backup et cre une nouvelle page // pur continuer dessiner. Utilis par exemple pour le fill { Backup_layers(Main_current_layer); } void Backup_layers(int layer) { int i; T_Page *new_page; /* if (Last_backed_up_layers == (1<Pages); // Create a fresh Page descriptor new_page=New_page(Main_backups->Pages->Nb_layers); if (!new_page) { Error(0); return; } // Fill it with a copy of the latest history Copy_S_page(new_page,Main_backups->Pages); new_page->Gradients=Dup_gradient(Main_backups->Pages); Create_new_page(new_page,Main_backups,layer); Download_infos_page_main(new_page); Update_FX_feedback(Config.FX_Feedback); // Copy the actual pixels from the backup to the latest page if (layer != LAYER_NONE) { for (i=0; iPages->Nb_layers;i++) { if (layer == LAYER_ALL || i == layer) memcpy(Main_backups->Pages->Image[i].Pixels, Main_backups->Pages->Next->Image[i].Pixels, Main_image_width*Main_image_height); } } // Light up the 'has unsaved changes' indicator Main_image_is_modified=1; /* Last_backed_up_layers = 1<Image[layer].Pixels == page->Next->Image[layer].Pixels) { Free_layer(page, layer); page->Image[layer].Pixels=New_layer(page->Height*page->Width); memcpy( page->Image[layer].Pixels, page->Next->Image[layer].Pixels, page->Width*page->Height); return 1; } return 0; } void Backup_the_spare(int layer) { int i; T_Page *new_page; // Create a fresh Page descriptor new_page=New_page(Spare_backups->Pages->Nb_layers); if (!new_page) { Error(0); return; } // Fill it with a copy of the latest history Copy_S_page(new_page,Spare_backups->Pages); new_page->Gradients=Dup_gradient(Spare_backups->Pages); Create_new_page(new_page,Spare_backups,layer); // Copy the actual pixels from the backup to the latest page if (layer != LAYER_NONE) { for (i=0; iPages->Nb_layers;i++) { if (layer == LAYER_ALL || i == layer) memcpy(Spare_backups->Pages->Image[i].Pixels, Spare_backups->Pages->Next->Image[i].Pixels, Spare_image_width*Spare_image_height); } } // Light up the 'has unsaved changes' indicator Spare_image_is_modified=1; } void Check_layers_limits() { if (Main_current_layer > Main_backups->Pages->Nb_layers-1) { Main_current_layer = Main_backups->Pages->Nb_layers-1; Main_layers_visible |= 1<Pages); // On fait faire un undo la liste des backups de la page principale Backward_in_list_of_pages(Main_backups); Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); // On extrait ensuite les infos sur la nouvelle page courante Download_infos_page_main(Main_backups->Pages); // Note: le backup n'a pas obligatoirement les mmes dimensions ni la mme // palette que la page courante. Mais en temps normal, le backup // n'est pas utilis la suite d'un Undo. Donc a ne devrait pas // poser de problmes. Check_layers_limits(); Redraw_layered_image(); End_of_modification(); if (width != Main_image_width || height != Main_image_height) Tilemap_update(); } void Redo(void) { int width = Main_image_width; int height = Main_image_height; if (Last_backed_up_layers) { Free_page_of_a_list(Main_backups); Last_backed_up_layers=0; } // On remet jour l'tat des infos de la page courante (pour pouvoir les // retrouver plus tard) Upload_infos_page_main(Main_backups->Pages); // On fait faire un redo la liste des backups de la page principale Advance_in_list_of_pages(Main_backups); Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); // On extrait ensuite les infos sur la nouvelle page courante Download_infos_page_main(Main_backups->Pages); // Note: le backup n'a pas obligatoirement les mmes dimensions ni la mme // palette que la page courante. Mais en temps normal, le backup // n'est pas utilis la suite d'un Redo. Donc a ne devrait pas // poser de problmes. Check_layers_limits(); Redraw_layered_image(); End_of_modification(); if (width != Main_image_width || height != Main_image_height) Tilemap_update(); } void Free_current_page(void) { // On dtruit la page courante de la liste principale Free_page_of_a_list(Main_backups); // On extrait ensuite les infos sur la nouvelle page courante Download_infos_page_main(Main_backups->Pages); // Note: le backup n'a pas obligatoirement les mmes dimensions ni la mme // palette que la page courante. Mais en temps normal, le backup // n'est pas utilis la suite d'une destruction de page. Donc a ne // devrait pas poser de problmes. Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); Check_layers_limits(); Redraw_layered_image(); End_of_modification(); } void Exchange_main_and_spare(void) { T_List_of_pages * temp_list; // On commence par mettre jour dans les descripteurs les infos sur les // pages qu'on s'apprte changer, pour qu'on se retrouve pas avec de // vieilles valeurs qui datent de mathuzalem. Upload_infos_page_main(Main_backups->Pages); Upload_infos_page_spare(Spare_backups->Pages); // On inverse les listes de pages temp_list=Main_backups; Main_backups=Spare_backups; Spare_backups=temp_list; // On extrait ensuite les infos sur les nouvelles pages courante, brouillon // et backup. /* SECTION GROS CACA PROUT PROUT */ // Auparavant on ruse en mettant dj jour les dimensions de la // nouvelle page courante. Si on ne le fait pas, le "Download" va dtecter // un changement de dimensions et va btement sortir du mode loupe, alors // que lors d'un changement de page, on veut bien conserver l'tat du mode // loupe du brouillon. Main_image_width=Main_backups->Pages->Width; Main_image_height=Main_backups->Pages->Height; Download_infos_page_main(Main_backups->Pages); Download_infos_page_spare(Spare_backups->Pages); } void End_of_modification(void) { //Update_buffers(Main_image_width, Main_image_height); if (Main_backups->Pages->Image_mode != IMAGE_MODE_ANIMATION) { // Backup buffer can have "wrong" size if a Lua script // performs a resize. Update_buffers(Main_image_width, Main_image_height); // memcpy(Main_visible_image_backup.Image, Main_visible_image.Image, Main_image_width*Main_image_height); } else { Update_screen_targets(); } Update_FX_feedback(Config.FX_Feedback); /* Last_backed_up_layers = 0; Backup(); */ // // Processing safety backups // Main_edits_since_safety_backup++; Rotate_safety_backups(); } /// Add a new layer to latest page of a list. Returns 0 on success. byte Add_layer(T_List_of_pages *list, int layer) { int max[] = {MAX_NB_LAYERS, MAX_NB_FRAMES, 5}; T_Page * source_page; T_Page * new_page; byte * new_image; int i; int duration; source_page = list->Pages; if (list->Pages->Nb_layers >= max[list->Pages->Image_mode]) // MAX_NB_LAYERS return 1; // Keep the position reasonable if (layer > list->Pages->Nb_layers) layer = list->Pages->Nb_layers; // Allocate the pixel data new_image = New_layer(list->Pages->Height*list->Pages->Width); if (! new_image) { Error(0); return 1; } // Re-allocate the page itself, with room for one more pointer new_page = realloc(source_page, sizeof(T_Page)+(list->Pages->Nb_layers+1)*sizeof(T_Image)); if (!new_page) { Error(0); return 1; } if (new_page != source_page) { // Need some housekeeping because the page moved in memory. // Update all pointers that pointed to it: new_page->Prev->Next = new_page; new_page->Next->Prev = new_page; list->Pages = new_page; } list->Pages->Nb_layers++; // Move around the pointers. This part is going to be tricky when we // have 'animations x layers' in this vector. for (i=list->Pages->Nb_layers-1; i>layer ; i--) { new_page->Image[i]=new_page->Image[i-1]; } new_page->Image[layer].Pixels=new_image; if (list->Pages->Nb_layers==0) duration=100; else if (layer>0) duration=new_page->Image[layer-1].Duration; else duration=new_page->Image[1].Duration; new_page->Image[layer].Duration=duration; // Fill with transparency, initially memset(new_image, Main_backups->Pages->Transparent_color, list->Pages->Height*list->Pages->Width); // transparent color // Done. Note that the visible buffer is already ok since we // only inserted a transparent "slide" somewhere. // The depth buffer is all wrong though. // Update the flags of visible layers. { dword layers_before; dword layers_after; dword *visible_layers_flag; // Determine if we're modifying the spare or the main page. if (list == Main_backups) { visible_layers_flag = &Main_layers_visible; Main_current_layer = layer; } else { visible_layers_flag = &Spare_layers_visible; Spare_current_layer = layer; } // Fun with binary! layers_before = ((1<= list->Pages->Nb_layers) layer = list->Pages->Nb_layers - 1; if (list->Pages->Nb_layers == 1) return 1; // For simplicity, we won't actually shrink the page in terms of allocation. // It would only save the size of a pointer, and anyway, as the user draws, // this page is going to fall off the end of the Undo-list // and so it will be cleared anyway. // Smart freeing of the pixel data Free_layer(list->Pages, layer); list->Pages->Nb_layers--; // Move around the pointers. This part is going to be tricky when we // have 'animations x layers' in this vector. for (i=layer; i < list->Pages->Nb_layers; i++) { list->Pages->Image[i]=list->Pages->Image[i+1]; } // Done. At this point the visible buffer and the depth buffer are // all wrong. // Update the flags of visible layers. { dword layers_before; dword layers_after; dword *visible_layers_flag; byte new_current_layer; // Determine if we're modifying the spare or the main page. if (list == Main_backups) { visible_layers_flag = &Main_layers_visible; if (Main_current_layer>=layer && Main_current_layer>0) Main_current_layer--; new_current_layer = Main_current_layer; } else { visible_layers_flag = &Spare_layers_visible; if (Spare_current_layer>=layer && Spare_current_layer>0) Spare_current_layer--; new_current_layer = Spare_current_layer; } // Fun with binary! layers_before = ((1<>1; *visible_layers_flag = layers_before | layers_after; // Ensure the current layer is part what is shown. *visible_layers_flag |= 1<Pages->Image[Main_current_layer].Pixels+i); if (color != Main_backups->Pages->Transparent_color) // transparent color *(Main_backups->Pages->Image[Main_current_layer-1].Pixels+i) = color; } return Delete_layer(Main_backups,Main_current_layer); } void Switch_layer_mode(enum IMAGE_MODES new_mode) { if (new_mode == Main_backups->Pages->Image_mode) return; Main_backups->Pages->Image_mode = new_mode; switch (new_mode) { case IMAGE_MODE_MODE5: case IMAGE_MODE_LAYERED: default: Update_buffers(Main_image_width, Main_image_height); Redraw_layered_image(); break; case IMAGE_MODE_ANIMATION: // nothing to do. // Eventually, we may clear the buffers to save a bit of memory... break; } Update_pixel_renderer(); } grafx2_2.4+git20180105/src/io.h0000664000000000000000000001305313223665306014311 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Pawel Gralski Copyright 2008 Yves Rizoud Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file io.h /// Low-level endian-neutral file operations, and also some filesystem operations. /// Many of these may seem trivial, but the wrappers eliminate the need for a /// forest of preprocessor defines in each file. /// You MUST use the functions in this file instead of: /// - fread() and fwrite() /// - stat() /// - fstat() /// - opendir() /// - readdir() /// - Also, don't assume "/" or "\\", use PATH_SEPARATOR /// If you don't, you break another platform. ////////////////////////////////////////////////////////////////////////////// /// Reads a single byte from an open file. Returns true if OK, false if a file i/o error occurred. int Read_byte(FILE *file, byte *dest); /// Writes a single byte to an open file. Returns true if OK, false if a file i/o error occurred. int Write_byte(FILE *file, byte b); /// Reads several bytes from an open file. Returns true if OK, false if a file i/o error occurred. int Read_bytes(FILE *file, void *dest, size_t size); /// Writes several bytes to an open file. Returns true if OK, false if a file i/o error occurred. int Write_bytes(FILE *file, void *dest, size_t size); /// Reads a 16-bit Low-Endian word from an open file. Returns true if OK, false if a file i/o error occurred. int Read_word_le(FILE *file, word *dest); /// Writes a 16-bit Low-Endian word to an open file. Returns true if OK, false if a file i/o error occurred. int Write_word_le(FILE *file, word w); /// Reads a 32-bit Low-Endian dword from an open file. Returns true if OK, false if a file i/o error occurred. int Read_dword_le(FILE *file, dword *dest); /// Writes a 32-bit Low-Endian dword to an open file. Returns true if OK, false if a file i/o error occurred. int Write_dword_le(FILE *file, dword dw); /// Reads a 16-bit Big-Endian word from an open file. Returns true if OK, false if a file i/o error occurred. int Read_word_be(FILE *file, word *dest); /// Writes a 16-bit Big-Endian word to an open file. Returns true if OK, false if a file i/o error occurred. int Write_word_be(FILE *file, word w); /// Reads a 32-bit Big-Endian dword from an open file. Returns true if OK, false if a file i/o error occurred. int Read_dword_be(FILE *file, dword *dest); /// Writes a 32-bit Big-Endian dword to an open file. Returns true if OK, false if a file i/o error occurred. int Write_dword_be(FILE *file, dword dw); /// Extracts the filename part from a full file name. void Extract_filename(char *dest, const char *source); /// Extracts the directory from a full file name. void Extract_path(char *dest, const char *source); /// Finds the rightmost path separator in a full filename. Used to separate directory from file. char * Find_last_separator(const char * str); #if defined(__WIN32__) #define PATH_SEPARATOR "\\" #elif defined(__MINT__) #define PATH_SEPARATOR "\\" #else #define PATH_SEPARATOR "/" #endif /// Size of a file, in bytes. Returns 0 in case of error. int File_length(const char *fname); /// Size of a file, in bytes. Takes an open file as argument, returns 0 in case of error. int File_length_file(FILE * file); /// Returns true if a file passed as a parameter exists in the current directory. int File_exists(char * fname); /// Returns true if a directory passed as a parameter exists in the current directory. int Directory_exists(char * directory); /// Check if a file or directory is hidden. Full name (with directories) is optional. int File_is_hidden(const char *fname, const char *full_name); /// Scans a directory, calls Callback for each file in it, void For_each_file(const char * directory_name, void Callback(const char *)); /// Scans a directory, calls Callback for each file or directory in it, void For_each_directory_entry(const char * directory_name, void Callback(const char *, byte is_file, byte is_directory, byte is_hidden)); /// /// Creates a fully qualified name from a directory and filename. /// The point is simply to insert a PATH_SEPARATOR when needed. void Get_full_filename(char * output_name, char * file_name, char * directory_name); /// /// Appends a file or directory name to an existing directory name. /// As a special case, when the new item is equal to PARENT_DIR, this /// will remove the rightmost directory name. /// reverse_path is optional, if it's non-null, the function will /// write there : /// - if filename is ".." : The name of eliminated directory/file /// - else: ".." void Append_path(char *path, const char *filename, char *reverse_path); /// /// Creates a lock file, to check if an other instance of Grafx2 is running. /// @return 0 on success (first instance), -1 on failure (others are running) byte Create_lock_file(const char *file_directory); /// /// Release a lock file created by ::Create_lock_file void Release_lock_file(const char *file_directory); grafx2_2.4+git20180105/src/.DS_Store0000664000000000000000000006000413223665306015212 0ustar rootrootBud1@@  0 lpfile helpfile.hinfoblob0h<op_c.hIlocblobn4hotkeys.hIlocblob& hotkeys.hinfoblob0h<  @ @ @ @@op_c.hinfoblob0h< operatio.cIlocblobJ4 operatio.cinfoblob0h< operatio.hIlocblob&4 operatio.hinfoblob0h<pages.cIlocblobn^pages.cinfoblob0ɞpages.hIlocblobJ^pages.hinfoblob0h< palette.cIlocblob&^ palette.cinfoblob0ɞ palette.hIlocblobn palette.hinfoblob0ɞ pversion.cIlocblob pversion.cinfoblob0ɞ pxdouble.cIlocblob4 pxdouble.cinfoblob0ɞ pxdouble.hIlocblob^ pxdouble.hinfoblob0ɞpxquad.cIlocblobpxquad.hIlocblobpxquad.hinfoblob0ɞ pxsimple.cIlocblob pxsimple.hIlocblobpxtall.cIlocblob0pxtall.hIlocblobZ pxtall2.cIlocblobn pxtall2.hIlocblobJ pxtriple.cIlocblob& pxtriple.hIlocblobpxwide.cIlocblobnpxwide.hIlocblobJ pxwide2.cIlocblob& pxwide2.hIlocblob readini.cIlocblobJ readini.hIlocblob& readline.cIlocblobn readline.hIlocblobJ realpath.cIlocblobn realpath.hIlocblobJ saveini.cIlocblob& saveini.hIlocblobn SDLMain.hIlocblobJ SDLMain.mIlocblob& sdlscreen.cIlocblobn sdlscreen.hIlocblobJsetup.cIlocblobsetup.hIlocblobnSFont.cIlocblob&SFont.hIlocblobn0shade.cIlocblobJ0shade.hIlocblob&0 special.cIlocblobnZ special.hIlocblobJZstruct.hIlocblob&Ztext.cIlocblobtext.hIlocblobn,tiles.cIlocblobJ, transform.cIlocblob&, transform.hIlocblob, version.cIlocblob version.cinfoblob0ɟ windows.cIlocblobnV windows.hIlocblobJV=brush.cIlocblobnbrush.cinfoblob0h<brush.hIlocblobJbrush.hinfoblob0h< brush_ops.cIlocblob& brush_ops.cinfoblob0ɞ buttons.cIlocblobn< buttons.cinfoblob0h< buttons.hIlocblobJ< buttons.hinfoblob0h<buttons_effects.cIlocblob&<buttons_effects.cinfoblob0ɞ colorred.hinfoblob0h<const.hIlocblobJfconst.hinfoblob0h<engine.cIlocblob<engine.cinfoblob0ɞengine.hIlocblobnfengine.hinfoblob0K English.lprojIlocblobJ English.lprojicgoblob English.lprojinfoblob0ɞerrors.hIlocblob&ferrors.hinfoblob0ɞ factory.cIlocblobf factory.cinfoblob0ɞ factory.hIlocblobn factory.hinfoblob0ɞ fileformats.cIlocblob& fileformats.cinfoblob0ɞ filesel.cIlocblob filesel.cinfoblob0ɞ filesel.hIlocblobn filesel.hinfoblob0K gfx2.icnsIlocblobgfx2.icoIlocblob&global.hIlocblobnglobal.hinfoblob0h<grafx2-2.2.1753-macosx.zipIlocblobRgrafx2-2.3wip.1755-macosx.zipIlocblobR Grafx2.appIlocblobJ Grafx2.appinfoblob0hUGrafx2.app.zipIlocblob_ Grafx2.icnsIlocblob&VGrafx2.xcodeprojIlocblobGrafx2.xcodeprojdilcblob  WfnGrafx2_Prefix.pchIlocblob/Grafx2_Prefix.pchinfoblob0ɞgraph.cIlocblobngraph.cinfoblob0h<graph.hIlocblobJgraph.hinfoblob0h< haiku.cppIlocblob& haiku.cppinfoblob0ɞhaiku.hIlocblobhaiku.hinfoblob0ɞhelp.cIlocblobhelp.cinfoblob0ɞhelp.hIlocblobhelp.hinfoblob0K helpfile.hIlocblobn82 hotkeys.cIlocblob8 hotkeys.cinfoblob0ɞ hotkeys.hIlocblob& hotkeys.hinfoblob0h<init.cIlocblobJ8init.cinfoblob0h<init.hIlocblob&8init.hinfoblob0ɞinput.cIlocblob&binput.cinfoblob0Kinput.hIlocblobbinput.hinfoblob0h<io.cIlocblobnbio.cinfoblob0Kio.hIlocblobJbio.hinfoblob0K keyboard.cIlocblobn keyboard.cinfoblob0ɞ keyboard.hIlocblob keyboard.hinfoblob0ɞlayers.cIlocblobJlayers.cinfoblob0h<layers.hIlocblob&layers.hinfoblob0h< libraw2crtc.cIlocblob libraw2crtc.cinfoblob0ɞ libraw2crtc.hIlocblobn libraw2crtc.hinfoblob0ɞ loadsave.cIlocblobJ loadsave.cinfoblob0h< loadsave.hIlocblob& loadsave.hinfoblob0h<main.cIlocblobnmain.cinfoblob0h<MakefileIlocblobJ Makefile.depIlocblob&makefile.macosxIlocblobmisc.cIlocblobJmisc.cinfoblob0h<misc.hIlocblob&misc.hinfoblob0h<miscfileformats.cIlocblobmiscfileformats.cinfoblob0ɞ mountlist.cIlocblobn mountlist.cinfoblob0h< mountlist.hIlocblobJ mountlist.hinfoblob0ɞoldies.hinfoblob0h<op_c.cIlocblob& op_c.cinfoblob0ɞgraph.cIlocblobngraph.cinfoblob0h<graph.hIlocblobJgraph.hinfoblob0h< haiku.cppIlocblob& haiku.cppinfoblob0ɞhaiku.hIlocblobhaiku.hinfoblob0ɞhelp.cIlocblobhelp.cinfoblob0ɞhelp.hIlocblobhelp.hinfoblob0K helpfile.hIlocblobn8@ E  0 DSDB `HP` @ @.cIlocblobJlayers.cinfoblob0h<layers.hIlocblob&layers.hinfoblob0h< libraw2crtc.cIlocblob libraw2crtc.cinfoblob0ɞ libraw2crtc.hIlocblobn libraw2crtc.hinfoblob0ɞ loadsave.cIlocblobJ loadsave.cinfoblob0h< loadsave.hIlocblob& loadsave.hinfoblob0h<grafx2_2.4+git20180105/src/hotkeys.h0000664000000000000000000000503013223665306015364 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2008 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file hotkeys.h /// Definition of the tables used by the keyboard shortcuts. /// The actual data is in hotkeys.c ////////////////////////////////////////////////////////////////////////////// #if !defined(__VBCC__) #include #else #define bool char #endif #include #define NB_SHORTCUTS 210 ///< Number of actions that can have a key combination associated to it. /*** Types definitions and structs ***/ typedef struct { word Number; ///< Identifier for shortcut. This is a number starting from 0, which matches ::T_Config_shortcut_info.Number char Label[36]; ///< Text to show in the screen where you can edit the shortcut. char Explanation1[37]; ///< Explanation text (1/3) to show in the screen where you can edit the shortcut. char Explanation2[37]; ///< Explanation text (2/3) to show in the screen where you can edit the shortcut. char Explanation3[37]; ///< Explanation text (3/3) to show in the screen where you can edit the shortcut. bool Suppr; ///< Boolean, true if the shortcut can be removed. word Key; ///< Primary shortcut. Value is a keycode, see keyboard.h word Key2; ///< Secondary shortcut. Value is a keycode, see keyboard.h } T_Key_config; /// Table with all the configurable shortcuts, whether they are for a menu button or a special action. extern T_Key_config ConfigKey[NB_SHORTCUTS]; /// /// Translation table from a shortcut index to a shortcut identifier. /// The value is either: /// - 0x000 + special shortcut number /// - 0x100 + button number (left click) /// - 0x200 + button number (right click) extern word Ordering[NB_SHORTCUTS]; grafx2_2.4+git20180105/src/operatio.h0000664000000000000000000001556713223665306015540 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file operatio.h /// Code for the drawing tools operations. ////////////////////////////////////////////////////////////////////////////// #include "struct.h" // General operation handling functions. These may be moved to ops_handler.h when operatio.c grows over 5000 lines again... /// Do some housekeeping before starting work on a operation. void Start_operation_stack(word new_operation); /// Put a value on ::Operation_stack void Operation_push(short value); /// Take a value off ::Operation_stack void Operation_pop(short * value); void Init_start_operation(void); short Distance(short x1, short y1, short x2, short y2); //////////////////////////////////////////////////// OPERATION_CONTINUOUS_DRAW void Freehand_mode1_1_0(void); void Freehand_mode1_1_2(void); void Freehand_mode12_0_2(void); void Freehand_mode1_2_0(void); void Freehand_mode1_2_2(void); ///////////////////////////////////////////////// OPERATION_DISCONTINUOUS_DRAW void Freehand_mode2_1_0(void); void Freehand_mode2_1_2(void); void Freehand_mode2_2_0(void); void Freehand_mode2_2_2(void); ////////////////////////////////////////////////////// OPERATION_POINT_DRAW void Freehand_mode3_1_0(void); void Freehand_Mode3_2_0(void); void Freehand_mode3_0_1(void); ///////////////////////////////////////////////////////////// OPERATION_LINE void Line_12_0(void); void Line_12_5(void); void Line_0_5(void); ///////////////////////////////////////////////////////////// OPERATION_MAGNIFY void Magnifier_12_0(void); /////////////////////////////////////////////////// OPERATION_RECTANGLE_????? void Rectangle_12_0(void); void Rectangle_12_5(void); void Empty_rectangle_0_5(void); void Filled_rectangle_0_5(void); ////////////////////////////////////////////////////// OPERATION_CERCLE_????? void Circle_12_0(void); void Circle_12_5(void); void Empty_circle_0_5(void); void Filled_circle_0_5(void); ///////////////////////////////////////////////////// OPERATION_ELLIPSE_????? void Ellipse_12_0(void); void Ellipse_12_5(void); void Empty_ellipse_0_5(void); void Filled_ellipse_0_5(void); ////////////////////////////////////////////////////// OPERATION_GRAB_BRUSH void Brush_12_0(void); void Brush_12_5(void); void Brush_0_5(void); ///////////////////////////////////////////////////// OPERATION_STRETCH_BRUSH void Stretch_brush_12_0(void); void Stretch_brush_1_7(void); void Stretch_brush_0_7(void); void Stretch_brush_2_7(void); //////////////////////////////////////////////////// OPERATION_ROTATE_BRUSH void Rotate_brush_12_0(void); void Rotate_brush_1_5(void); void Rotate_brush_0_5(void); void Rotate_brush_2_5(void); ///////////////////////////////////////////////////// OPERATION_DISTORT_BRUSH void Distort_brush_0_0(void); void Distort_brush_1_0(void); void Distort_brush_2_0(void); void Distort_brush_1_8(void); void Distort_brush_2_8(void); void Distort_brush_1_9(void); void Distort_brush_0_9(void); //////////////////////////////////////////////////////// OPERATION_POLYBRUSH void Polybrush_12_8(void); ////////////////////////////////////////////////////////////// OPERATION_FILL void Fill_1_0(void); void Fill_2_0(void); ///////////////////////////////////////////////////////// OPERATION_REPLACE void Replace_1_0(void); void Replace_2_0(void); /////////////////////////////////////////////////////////// OPERATION_COLORPICK void Pipette_0_0(void); void Colorpicker_12_0(void); void Colorpicker_1_1(void); void Colorpicker_2_1(void); void Colorpicker_0_1(void); /////////////////////////////////////////////////////////// OPERATION_K_LINE void K_line_12_0(void); void K_line_12_6(void); void K_line_0_6(void); void K_line_12_7(void); /////////////////////////////////////////////////// OPERATION_COURBE_?_POINTS void Curve_34_points_1_0(void); void Curve_34_points_2_0(void); void Curve_34_points_1_5(void); void Curve_34_points_2_5(void); void Curve_4_points_0_5(void); void Curve_4_points_1_9(void); void Curve_4_points_2_9(void); void Curve_3_points_0_5(void); void Curve_3_points_0_11(void); void Curve_3_points_12_11(void); ///////////////////////////////////////////////////////////// OPERATION_AIRBRUSH void Airbrush_1_0(void); void Airbrush_2_0(void); void Airbrush_12_2(void); void Airbrush_0_2(void); //////////////////////////////////////////////////////////// OPERATION_*POLY* void Polygon_12_0(void); void Polygon_12_9(void); void Polyfill_12_0(void); void Polyfill_0_8(void); void Polyfill_12_8(void); void Polyfill_12_9(void); void Polyform_12_0(void); void Polyform_12_8(void); void Polyform_0_8(void); void Filled_polyform_12_0(void); void Filled_polyform_12_8(void); void Filled_polyform_0_8(void); void Filled_contour_0_8(void); //////////////////////////////////////////////////////////// OPERATION_SCROLL void Scroll_12_0(void); void Scroll_12_5(void); void Scroll_0_5(void); //////////////////////////////////////////////////// OPERATION_GRAD_CIRCLE void Grad_circle_12_0(void); void Grad_circle_12_6(void); void Grad_circle_0_6(void); void Grad_circle_12_8(void); void Grad_circle_or_ellipse_0_8(void); ////////////////////////////////////////////////// OPERATION_GRAD_ELLIPSE void Grad_ellipse_12_0(void); void Grad_ellipse_12_6(void); void Grad_ellipse_0_6(void); void Grad_ellipse_12_8(void); ///////////////////////////////////////////////// OPERATION_GRAD_RECTANGLE void Grad_rectangle_12_0(void); void Grad_rectangle_12_5(void); void Grad_rectangle_0_5(void); void Grad_rectangle_0_7(void); void Grad_rectangle_12_7(void); void Grad_rectangle_12_9(void); void Grad_rectangle_0_9(void); /////////////////////////////////////////////////// OPERATION_CENTERED_LINES void Centered_lines_12_0(void); void Centered_lines_12_3(void); void Centered_lines_0_3(void); void Centered_lines_12_7(void); void Centered_lines_0_7(void); /////////////////////////////////////////////////// OPERATION_RMB_COLORPICK byte Rightclick_colorpick(byte cursor_visible); void Rightclick_colorpick_2_1(void); void Rightclick_colorpick_0_1(void); /////////////////////////////////////////////////// OPERATION_PAN_VIEW void Pan_view_0_0(void); void Pan_view_12_0(void); void Pan_view_12_2(void); void Pan_view_0_2(void); grafx2_2.4+git20180105/src/brush.c0000664000000000000000000020276213223665306015027 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Franck Charlet Copyright 2007-2008 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see ******************************************************************************** Brush manipulation functions */ #include #include #include // memset() #include "global.h" #include "graph.h" #include "misc.h" #include "errors.h" #include "windows.h" #include "sdlscreen.h" #include "brush.h" #include "tiles.h" // Data used during brush rotation operation static byte * Brush_rotate_buffer; static int Brush_rotate_width; static int Brush_rotate_height; // Calcul de redimensionnement du pinceau pour viter les dbordements de // l'cran et de l'image void Compute_clipped_dimensions(short * x,short * y,short * width,short * height) { if ((*x)(Limit_right+1)) { (*width)=(Limit_right-(*x))+1; } if ((*y)(Limit_bottom+1)) { (*height)=(Limit_bottom-(*y))+1; } } // -- Calcul de redimensionnement du pinceau pour viter les dbordements // de l'cran zoom et de l'image -- void Compute_clipped_dimensions_zoom(short * x,short * y,short * width,short * height) { if ((*x)(Limit_right_zoom+1)) { (*width)=(Limit_right_zoom-(*x))+1; } if ((*y)(Limit_bottom_zoom+1)) { (*height)=(Limit_bottom_zoom-(*y))+1; } } /// Display the paintbrush (preview : on screen only) void Display_paintbrush(short x,short y,byte color) // x,y: position du centre du pinceau // color: couleur appliquer au pinceau { short start_x; // Position X (dans l'image) partir de laquelle on // affiche la brosse/pinceau short start_y; // Position Y (dans l'image) partir de laquelle on // affiche la brosse/pinceau short width; // width dans l'cran selon laquelle on affiche la // brosse/pinceau short height; // height dans l'cran selon laquelle on affiche la // brosse/pinceau short start_x_counter; // Position X (dans la brosse/pinceau) partir // de laquelle on affiche la brosse/pinceau short start_y_counter; // Position Y (dans la brosse/pinceau) partir // de laquelle on affiche la brosse/pinceau byte * temp; if (Mouse_K) // pas de curseur si on est en preview et return; // en train de cliquer if (Main_backups->Pages->Image_mode == IMAGE_MODE_MODE5 && Main_current_layer < 4) { goto single_pixel; } switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_NONE : // No paintbrush. for colorpicker for example break; case PAINTBRUSH_SHAPE_POINT : // A single point single_pixel: if ( (Paintbrush_X>=Limit_left) && (Paintbrush_X<=Limit_right) && (Paintbrush_Y>=Limit_top) && (Paintbrush_Y<=Limit_bottom) ) { Pixel_preview(Paintbrush_X,Paintbrush_Y,color); Update_part_of_screen(x,y,1,1); } break; case PAINTBRUSH_SHAPE_COLOR_BRUSH : // The color brush, displayed in color case PAINTBRUSH_SHAPE_MONO_BRUSH : // or in monochrome with FG color start_x=x-Brush_offset_X; start_y=y-Brush_offset_Y; width=Brush_width; height=Brush_height; Compute_clipped_dimensions(&start_x,&start_y,&width,&height); if (width<=0 || height<=0) break; start_x_counter=start_x-(x-Brush_offset_X); start_y_counter=start_y-(y-Brush_offset_Y); if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH) Display_brush_color( start_x-Main_offset_X, start_y-Main_offset_Y, start_x_counter, start_y_counter, width, height, Back_color, Brush_width); else // mono preview Display_brush_mono(start_x-Main_offset_X, start_y-Main_offset_Y, start_x_counter, start_y_counter, width, height, Back_color, Fore_color, Brush_width); Update_part_of_screen(x-Brush_offset_X,y-Brush_offset_Y,Brush_width,Brush_height); if (Main_magnifier_mode != 0) { Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); start_x_counter=start_x-(x-Brush_offset_X); start_y_counter=start_y-(y-Brush_offset_Y); if ( (width>0) && (height>0) ) { // Corrections dues au Zoom: start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; height=start_y+(height*Main_magnifier_factor); if (height>Menu_Y) height=Menu_Y; if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH) Display_brush_color_zoom(Main_X_zoom+start_x,start_y, start_x_counter,start_y_counter, width,height,Back_color, Brush_width, Horizontal_line_buffer); else // mono preview Display_brush_mono_zoom(Main_X_zoom+start_x,start_y, start_x_counter,start_y_counter, width,height, Back_color,Fore_color, Brush_width, Horizontal_line_buffer); } } break; default : // a paintbrush start_x=x-Paintbrush_offset_X; start_y=y-Paintbrush_offset_Y; width=Paintbrush_width; height=Paintbrush_height; Compute_clipped_dimensions(&start_x,&start_y,&width,&height); start_x_counter=start_x-(x-Paintbrush_offset_X); start_y_counter=start_y-(y-Paintbrush_offset_Y); temp=Brush; Brush=Paintbrush_sprite; if ( (width>0) && (height>0) ) Display_brush_mono(start_x-Main_offset_X, start_y-Main_offset_Y, start_x_counter,start_y_counter, width,height, 0,Fore_color, MAX_PAINTBRUSH_SIZE); if (Main_magnifier_mode != 0) { Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); start_x_counter=start_x-(x-Paintbrush_offset_X); start_y_counter=start_y-(y-Paintbrush_offset_Y); if ( (width>0) && (height>0) ) { // Corrections dues au Zoom: start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; height=start_y+(height*Main_magnifier_factor); if (height>Menu_Y) height=Menu_Y; Display_brush_mono_zoom(Main_X_zoom+start_x,start_y, start_x_counter,start_y_counter, width,height, 0,Fore_color, MAX_PAINTBRUSH_SIZE, Horizontal_line_buffer); } } Brush=temp; } } /// Draw the paintbrush in the image buffer void Draw_paintbrush(short x,short y,byte color) // x,y: position du centre du pinceau // color: couleur appliquer au pinceau { short start_x; // Position X (dans l'image) partir de laquelle on // affiche la brosse/pinceau short start_y; // Position Y (dans l'image) partir de laquelle on // affiche la brosse/pinceau short width; // width dans l'cran selon laquelle on affiche la // brosse/pinceau short height; // height dans l'cran selon laquelle on affiche la // brosse/pinceau short start_x_counter; // Position X (dans la brosse/pinceau) partir // de laquelle on affiche la brosse/pinceau short start_y_counter; // Position Y (dans la brosse/pinceau) partir // de laquelle on affiche la brosse/pinceau short x_pos; // Position X (dans l'image) en cours d'affichage short y_pos; // Position Y (dans l'image) en cours d'affichage short counter_x; // Position X (dans la brosse/pinceau) en cours // d'affichage short counter_y; // Position Y (dans la brosse/pinceau) en cours // d'affichage short end_counter_x; // Position X ou s'arrte l'affichade de la // brosse/pinceau short end_counter_y; // Position Y ou s'arrte l'affichade de la // brosse/pinceau byte temp_color; // color de la brosse en cours d'affichage int position; byte old_color; if (Main_backups->Pages->Image_mode == IMAGE_MODE_MODE5 && Main_current_layer < 4) { // Flood-fill the enclosing area if (x= 0 && y >= 0 && (color=Effect_function(x,y,color)) != (old_color=Read_pixel_from_current_layer(x,y)) && (!((Stencil_mode) && (Stencil[old_color]))) && (!((Mask_mode) && (Mask_table[Read_pixel_from_spare_screen(x,y)]))) ) { short min_x,width,min_y,height; short xx,yy; // determine area switch(Main_current_layer) { case 0: default: // Full layer min_x=0; min_y=0; width=Main_image_width; height=Main_image_height; break; case 1: case 2: // Line min_x=0; min_y=y; width=Main_image_width; height=1; break; case 3: // Segment min_x=x / 48 * 48; min_y=y; width=48; height=1; break; //case 4: // // 8x8 // min_x=x / 8 * 8; // min_y=y / 8 * 8; // width=8; // height=8; // break; } // Clip the bottom edge. // (Necessary if image height is not a multiple) if (min_y+height>=Main_image_height) height=Main_image_height-min_y; // Clip the right edge. // (Necessary if image width is not a multiple) if (min_x+width>=Main_image_width) width=Main_image_width-min_x; for (yy=min_y; yy0) && (height>0) ) Clear_brush(min_x-Main_offset_X, min_y-Main_offset_Y, 0,0, width,height,0, Main_image_width); if (Main_magnifier_mode != 0) { Compute_clipped_dimensions_zoom(&min_x,&min_y,&width,&height); xx=min_x; yy=min_y; if ( (width>0) && (height>0) ) { // Corrections dues au Zoom: min_x=(min_x-Main_magnifier_offset_X)*Main_magnifier_factor; min_y=(min_y-Main_magnifier_offset_Y)*Main_magnifier_factor; height=min_y+(height*Main_magnifier_factor); if (height>Menu_Y) height=Menu_Y; Clear_brush_scaled(Main_X_zoom+min_x,min_y, xx,yy, width,height,0, Main_image_width, Horizontal_line_buffer); } } // End of graphic feedback } return; } switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_NONE : // No paintbrush. for colorpicker for example case PAINTBRUSH_SHAPE_POINT : // !!! TOUJOURS EN PREVIEW !!! break; case PAINTBRUSH_SHAPE_COLOR_BRUSH : // Brush en couleur start_x=x-Brush_offset_X; start_y=y-Brush_offset_Y; width=Brush_width; height=Brush_height; Compute_clipped_dimensions(&start_x,&start_y,&width,&height); if (width<=0 || height<=0) break; start_x_counter=start_x-(x-Brush_offset_X); start_y_counter=start_y-(y-Brush_offset_Y); end_counter_x=start_x_counter+width; end_counter_y=start_y_counter+height; if ((Smear_mode != 0) && (Shade_table==Shade_table_left)) { if (Smear_start != 0) { if ((width>0) && (height>0)) { Copy_part_of_image_to_another( Main_screen, start_x, start_y, width, height, Main_image_width, Smear_brush, start_x_counter, start_y_counter, Smear_brush_width ); Update_part_of_screen(start_x,start_y,width,height); } Smear_start=0; } else { for (y_pos = start_y, counter_y = start_y_counter; counter_y < end_counter_y; y_pos++, counter_y++ ) { for (x_pos = start_x, counter_x = start_x_counter; counter_x < end_counter_x; x_pos++, counter_x++ ) { temp_color = Read_pixel_from_current_screen( x_pos,y_pos ); position = (counter_y * Smear_brush_width)+ counter_x; if ( (Read_pixel_from_brush(counter_x,counter_y) != Back_color) && (counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) ) Display_pixel(x_pos,y_pos,Smear_brush[position]); Smear_brush[position]=temp_color; } } Update_part_of_screen(start_x,start_y,width,height); } Smear_min_X=start_x_counter; Smear_min_Y=start_y_counter; Smear_max_X=end_counter_x; Smear_max_Y=end_counter_y; } else { if (Shade_table==Shade_table_left) for (y_pos=start_y,counter_y=start_y_counter;counter_y0) && (height>0)) { Copy_part_of_image_to_another(Main_screen, start_x,start_y, width,height, Main_image_width, Smear_brush, start_x_counter, start_y_counter, Smear_brush_width); Update_part_of_screen(start_x,start_y,width,height); } Smear_start=0; } else { for (y_pos=start_y,counter_y=start_y_counter;counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) ) Display_pixel(x_pos,y_pos,Smear_brush[position]); Smear_brush[position]=temp_color; } Update_part_of_screen(start_x,start_y,width,height); } Smear_min_X=start_x_counter; Smear_min_Y=start_y_counter; Smear_max_X=end_counter_x; Smear_max_Y=end_counter_y; } else { for (y_pos=start_y,counter_y=start_y_counter;counter_y0) && (height>0)) { Copy_part_of_image_to_another(Main_screen, start_x,start_y, width,height, Main_image_width, Smear_brush, start_x_counter, start_y_counter, Smear_brush_width); Update_part_of_screen(start_x,start_y,width,height); } Smear_start=0; } else { for (y_pos=start_y,counter_y=start_y_counter;counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) // On clippe l'effet smear entre Smear_Min et Smear_Max ) Display_pixel(x_pos,y_pos,Smear_brush[position]); Smear_brush[position]=temp_color; } Update_part_of_screen(start_x, start_y, width, height); } Smear_min_X=start_x_counter; Smear_min_Y=start_y_counter; Smear_max_X=end_counter_x; Smear_max_Y=end_counter_y; } else { for (y_pos=start_y,counter_y=start_y_counter;counter_yMAX_PAINTBRUSH_SIZE)?new_brush_width:MAX_PAINTBRUSH_SIZE; new_smear_brush_height=(new_brush_height>MAX_PAINTBRUSH_SIZE)?new_brush_height:MAX_PAINTBRUSH_SIZE; new_smear_brush=NULL; if ( (((long)Smear_brush_height)*Smear_brush_width) != (((long)new_smear_brush_width)*new_smear_brush_height) ) { new_smear_brush=(byte *)malloc(((long)new_smear_brush_height)*new_smear_brush_width); if (new_smear_brush == NULL) { Error(0); if (old_brush) *old_brush=NULL; if (!new_brush_is_provided) free(new_brush); return 2; } } new_brush_remapped=NULL; if ( (((long)Brush_height)*Brush_width) != (((long)new_brush_height)*new_brush_width) ) { new_brush_remapped=(byte *)malloc(((long)new_brush_height)*new_brush_width); if (new_brush_remapped == NULL) { Error(0); free(new_smear_brush); if (old_brush) *old_brush=NULL; if (!new_brush_is_provided) free(new_brush); return 3; } } // All allocations successful: can replace globals Brush_width=new_brush_width; Brush_height=new_brush_height; Brush_original_back_color=Back_color; if (new_smear_brush) { free(Smear_brush); Smear_brush=new_smear_brush; } Smear_brush_width=new_smear_brush_width; Smear_brush_height=new_smear_brush_height; // Save or free the old brush pixels if (old_brush) *old_brush=Brush_original_pixels; else free(old_brush); Brush_original_pixels=new_brush; // Assign new brush if (new_brush_remapped) { free(Brush); Brush=new_brush_remapped; } return 0; } // -- Effacer le pinceau -- // // void Hide_paintbrush(short x,short y) // x,y: position du centre du pinceau { short start_x; // Position X (dans l'image) partir de laquelle on // affiche la brosse/pinceau short start_y; // Position Y (dans l'image) partir de laquelle on // affiche la brosse/pinceau short width; // width dans l'cran selon laquelle on affiche la // brosse/pinceau short height; // height dans l'cran selon laquelle on affiche la // brosse/pinceau short start_x_counter; // Position X (dans la brosse/pinceau) partir // de laquelle on affiche la brosse/pinceau short start_y_counter; // Position Y (dans la brosse/pinceau) partir // de laquelle on affiche la brosse/pinceau //short x_pos; // Position X (dans l'image) en cours d'affichage //short y_pos; // Position Y (dans l'image) en cours d'affichage //short counter_x; // Position X (dans la brosse/pinceau) en cours //d'affichage //short counter_y; // Position Y (dans la brosse/pinceau) en cours d'affichage byte * temp; if (Mouse_K == 0) switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_POINT : if ( (Paintbrush_X>=Limit_left) && (Paintbrush_X<=Limit_right) && (Paintbrush_Y>=Limit_top) && (Paintbrush_Y<=Limit_bottom) ) { Pixel_preview(Paintbrush_X,Paintbrush_Y,Read_pixel_from_current_screen(Paintbrush_X,Paintbrush_Y)); Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); } break; case PAINTBRUSH_SHAPE_COLOR_BRUSH : // Brush en couleur case PAINTBRUSH_SHAPE_MONO_BRUSH : // Brush monochrome start_x=x-Brush_offset_X; start_y=y-Brush_offset_Y; width=Brush_width; height=Brush_height; Compute_clipped_dimensions(&start_x,&start_y,&width,&height); start_x_counter=start_x-(x-Brush_offset_X); start_y_counter=start_y-(y-Brush_offset_Y); if ( (width>0) && (height>0) ) Clear_brush(start_x-Main_offset_X, start_y-Main_offset_Y, start_x_counter,start_y_counter, width,height,Back_color, Main_image_width); if (Main_magnifier_mode != 0) { Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); start_x_counter=start_x; start_y_counter=start_y; if ( (width>0) && (height>0) ) { // Corrections dues au Zoom: start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; height=start_y+(height*Main_magnifier_factor); if (height>Menu_Y) height=Menu_Y; Clear_brush_scaled(Main_X_zoom+start_x,start_y, start_x_counter,start_y_counter, width,height,Back_color, Main_image_width, Horizontal_line_buffer); } } break; default: // Pinceau start_x=x-Paintbrush_offset_X; start_y=y-Paintbrush_offset_Y; width=Paintbrush_width; height=Paintbrush_height; Compute_clipped_dimensions(&start_x,&start_y,&width,&height); start_x_counter=start_x-(x-Paintbrush_offset_X); start_y_counter=start_y-(y-Paintbrush_offset_Y); temp=Brush; Brush=Paintbrush_sprite; if ( (width>0) && (height>0) ) { Clear_brush(start_x-Main_offset_X, start_y-Main_offset_Y, start_x_counter,start_y_counter, width,height,0, Main_image_width); } if (Main_magnifier_mode != 0) { Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); start_x_counter=start_x; start_y_counter=start_y; if ( (width>0) && (height>0) ) { // Corrections dues au Zoom: start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; height=start_y+(height*Main_magnifier_factor); if (height>Menu_Y) height=Menu_Y; Clear_brush_scaled(Main_X_zoom+start_x,start_y, start_x_counter,start_y_counter, width,height,0, Main_image_width, Horizontal_line_buffer); } } Brush=temp; break; } } void Capture_brush(short start_x,short start_y,short end_x,short end_y,short clear) { short temp; short x_pos; short y_pos; word new_brush_width; word new_brush_height; // On commence par "redresser" les bornes: if (start_x>end_x) { temp=start_x; start_x =end_x; end_x =temp; } if (start_y>end_y) { temp=start_y; start_y =end_y; end_y =temp; } // On ne capture la nouvelle brosse que si elle est au moins partiellement // dans l'image: if ((start_xMain_image_width) new_brush_width=Main_image_width-start_x; if (start_y+new_brush_height>Main_image_height) new_brush_height=Main_image_height-start_y; if (Realloc_brush(new_brush_width, new_brush_height, NULL, NULL)) return; // Unable to allocate the new brush, keep the old one. Copy_image_to_brush(start_x,start_y,Brush_width,Brush_height,Main_image_width); // On regarde s'il faut effacer quelque chose: if (clear) { if (Main_tilemap_mode) { for (y_pos=start_y;y_pos>1); Brush_offset_Y=(Brush_height>>1); } } void Rotate_90_deg(void) { byte * old_brush; if (Realloc_brush(Brush_height, Brush_width, NULL, &old_brush)) { Error(0); return; } Rotate_90_deg_lowlevel(old_brush,Brush_original_pixels,Brush_height,Brush_width); free(old_brush); // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); // On centre la prise sur la brosse Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); } void Remap_brush(void) { short x_pos; // Variable de balayage de la brosse short y_pos; // Variable de balayage de la brosse int color; // On commence par initialiser le tableau de boolens faux for (color=0;color<=255;color++) Brush_colormap[color]=0; // On calcule la table d'utilisation des couleurs for (y_pos=0;y_pos>1); Brush_offset_Y=(Brush_height>>1); free(old_brush); // Libration de l'ancienne brosse } void Nibble_brush(void) { long x_pos,y_pos; byte state; byte * old_brush; word old_width; word old_height; int i; if ( (Brush_width>2) && (Brush_height>2) ) { old_width=Brush_width; old_height=Brush_height; SWAP_PBYTES(Brush, Brush_original_pixels); if (Realloc_brush(Brush_width-2, Brush_height-2, NULL, &old_brush)) { Error(0); SWAP_PBYTES(Brush, Brush_original_pixels); return; } // On copie l'ancienne brosse dans la nouvelle Copy_part_of_image_to_another(old_brush, // source 1, 1, old_width-2, old_height-2, old_width, Brush, // Destination 0, 0, Brush_width); // 1er balayage (horizontal) for (y_pos=0; y_pos0) Pixel_in_brush(x_pos-1,y_pos,Back_color); state=0; } } else { if (state == 0) { Pixel_in_brush(x_pos,y_pos,Back_color); state=1; } } } // Cas du dernier pixel droite de la ligne if (old_brush[((y_pos+1)*old_width)+x_pos+1]==Back_color) Pixel_in_brush(x_pos-1,y_pos,Back_color); } // 2me balayage (vertical) for (x_pos=0; x_pos0) Pixel_in_brush(x_pos,y_pos-1,Back_color); state=0; } } else { if (state == 0) { Pixel_in_brush(x_pos,y_pos,Back_color); state=1; } } } // Cas du dernier pixel en bas de la colonne if (old_brush[((y_pos+1)*old_width)+x_pos+1]==Back_color) Pixel_in_brush(x_pos,y_pos-1,Back_color); } free(old_brush); // Adopt the current palette. memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); memcpy(Brush_original_pixels, Brush, (long)Brush_width*Brush_height); for (i=0; i<256; i++) Brush_colormap[i]=i; //-- // On recentre la prise sur la brosse Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); } } void Capture_brush_with_lasso(int vertices, short * points,short clear) { short start_x=Limit_right+1; short start_y=Limit_bottom+1; short end_x=Limit_left-1; short end_y=Limit_top-1; unsigned short temp; short x_pos; short y_pos; word new_brush_width; word new_brush_height; // On recherche les bornes de la brosse: for (temp=0; temp<2*vertices; temp+=2) { x_pos=points[temp]; y_pos=points[temp+1]; if (x_posend_x) end_x=x_pos; if (y_posend_y) end_y=y_pos; } // On clippe ces bornes l'cran: if (start_xLimit_right) end_x=Limit_right; if (start_yLimit_bottom) end_y=Limit_bottom; // On ne capture la nouvelle brosse que si elle est au moins partiellement // dans l'image: if ((start_x>1); Brush_offset_Y=(Brush_height>>1); } } //------------------------- Etirement de la brosse --------------------------- void Stretch_brush(short x1, short y1, short x2, short y2) { byte * new_brush; int new_brush_width; // Width de la nouvelle brosse int new_brush_height; // Height de la nouvelle brosse // Compute new brush dimensions if ((new_brush_width=x1-x2)<0) { new_brush_width=-new_brush_width; } new_brush_width++; if ((new_brush_height=y1-y2)<0) { new_brush_height=-new_brush_height; } new_brush_height++; new_brush=((byte *)malloc(new_brush_width*new_brush_height)); if (!new_brush) { Error(0); return; } Rescale(Brush_original_pixels, Brush_width, Brush_height, new_brush, new_brush_width, new_brush_height, x2>1); Brush_offset_Y=(Brush_height>>1); } void Stretch_brush_preview(short x1, short y1, short x2, short y2) { int src_x_pos,src_y_pos; int initial_src_x_pos,initial_src_y_pos; int delta_x,delta_y; int dest_x_pos,dest_y_pos; int initial_dest_x_pos,initial_dest_y_pos; int final_dest_x_pos,final_dest_y_pos; int dest_width,dest_height; byte color; // 1er calcul des positions destination extremes: initial_dest_x_pos=Min(x1,x2); initial_dest_y_pos=Min(y1,y2); final_dest_x_pos =Max(x1,x2); final_dest_y_pos =Max(y1,y2); // Calcul des dimensions de la destination: dest_width=final_dest_x_pos-initial_dest_x_pos+1; dest_height=final_dest_y_pos-initial_dest_y_pos+1; // Calcul des vecteurs d'incrmentation : delta_x=(Brush_width<<16)/dest_width; delta_y=(Brush_height<<16)/dest_height; // 1er calcul de la position X initiale dans la source: initial_src_x_pos=(Brush_width<<16)* (Max(initial_dest_x_pos,Limit_left)- initial_dest_x_pos)/dest_width; // Calcul du clip de la destination: initial_dest_x_pos=Max(initial_dest_x_pos,Limit_left); final_dest_x_pos =Min(final_dest_x_pos ,Limit_visible_right); // On discute selon l'inversion en X if (x1>x2) { // Inversion -> Inversion du signe de delta_x delta_x=-delta_x; initial_src_x_pos=(Brush_width<<16)-1-initial_src_x_pos; } // 1er calcul de la position Y initiale dans la source: initial_src_y_pos=(Brush_height<<16)* (Max(initial_dest_y_pos,Limit_top)- initial_dest_y_pos)/dest_height; // Calcul du clip de la destination: initial_dest_y_pos=Max(initial_dest_y_pos,Limit_top); final_dest_y_pos =Min(final_dest_y_pos ,Limit_visible_bottom); // On discute selon l'inversion en Y if (y1>y2) { // Inversion -> Inversion du signe de delta_y delta_y=-delta_y; initial_src_y_pos=(Brush_height<<16)-1-initial_src_y_pos; } // Pour chaque ligne : src_y_pos=initial_src_y_pos; for (dest_y_pos=initial_dest_y_pos;dest_y_pos<=final_dest_y_pos;dest_y_pos++) { // Pour chaque colonne: src_x_pos=initial_src_x_pos; for (dest_x_pos=initial_dest_x_pos;dest_x_pos<=final_dest_x_pos;dest_x_pos++) { color=Read_pixel_from_brush(src_x_pos>>16,src_y_pos>>16); if (color!=Back_color) Pixel_preview(dest_x_pos,dest_y_pos,color); src_x_pos+=delta_x; } src_y_pos+=delta_y; } Update_part_of_screen(initial_dest_x_pos,initial_dest_y_pos,dest_width,dest_height); } /// Returns the minimum of 4 integers. int Min4(long int a, long int b, long int c, long int d) { if (ab) if (c>d) return a>c?a:c; else return a>d?a:d; else if (c>d) return b>c?b:c; else return b>d?b:d; } // Recursive function for linear distortion. void Draw_brush_linear_distort(unsigned long int tex_min_x, unsigned long int tex_min_y, unsigned long int tex_max_x, unsigned long int tex_max_y, long int x1, long int y1, long int x2, long int y2, long int x3, long int y3, long int x4, long int y4) { static byte color; // bounding rectangle static long int min_x, max_x, min_y, max_y; min_x=Min4(x1,x2,x3,x4); max_x=Max4(x1,x2,x3,x4); min_y=Min4(y1,y2,y3,y4); max_y=Max4(y1,y2,y3,y4); if ((max_x>>16) - (min_x>>16) <= 1 && (max_y>>16) - (min_y>>16) <= 1) //if (max_x - min_x <= 1<<16 && max_y - min_y <= 1<<16) { if ((min_x<(max_x&0x7FFF0000)) && (min_y<(max_y&0x7FFF0000))) { color=*(Distort_source + (tex_min_y>>16)*Brush_width + (tex_min_x>>16)); if (color!=Back_color) Pixel_for_distort(min_x>>16,min_y>>16,color); } return; } // Cut in 4 quarters and repeat // "top left" Draw_brush_linear_distort(tex_min_x, tex_min_y, (tex_min_x+tex_max_x)>>1, (tex_min_y+tex_max_y)>>1, x1, y1, (x1+x2)>>1, (y1+y2)>>1, (x1+x2+x3+x4)>>2, (y1+y2+y3+y4)>>2, (x1+x4)>>1, (y1+y4)>>1); // "top right" Draw_brush_linear_distort((tex_min_x+tex_max_x)>>1, tex_min_y, tex_max_x, (tex_min_y+tex_max_y)>>1, (x1+x2)>>1, (y1+y2)>>1, x2, y2, (x2+x3)>>1, (y2+y3)>>1, (x1+x2+x3+x4)>>2, (y1+y2+y3+y4)>>2); // "bottom right" Draw_brush_linear_distort((tex_min_x+tex_max_x)>>1, (tex_min_y+tex_max_y)>>1, tex_max_x, tex_max_y, (x1+x2+x3+x4)>>2, (y1+y2+y3+y4)>>2, (x2+x3)>>1, (y2+y3)>>1, x3, y3, (x3+x4)>>1, (y3+y4)>>1); // "bottom left" Draw_brush_linear_distort(tex_min_x, (tex_min_y+tex_max_y)>>1, (tex_min_x+tex_max_x)>>1, tex_max_y, (x1+x4)>>1, (y1+y4)>>1, (x1+x2+x3+x4)>>2, (y1+y2+y3+y4)>>2, (x3+x4)>>1, (y3+y4)>>1, x4, y4); return; } /// Draws a distorted version of the brush, mapped over the given quad (picture coordinates). void Distort_brush_preview(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4) { Pixel_for_distort=Pixel_figure_preview; Distort_source=Brush; // show pixels from currently-remapped brush Draw_brush_linear_distort(0, 0, (Brush_width<<16), (Brush_height<<16), (x1<<16), (y1<<16), (x2<<16), (y2<<16), (x3<<16), (y3<<16), (x4<<16), (y4<<16)); } /// Modifies the current brush, mapping it over the given quad. void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4) { short min_x, max_x, min_y, max_y; short width, height; byte * new_brush; // Move all coordinates to start on (0,0) min_x=Min4(x1,x2,x3,x4); max_x=Max4(x1,x2,x3,x4); min_y=Min4(y1,y2,y3,y4); max_y=Max4(y1,y2,y3,y4); x1-=min_x; x2-=min_x; x3-=min_x; x4-=min_x; y1-=min_y; y2-=min_y; y3-=min_y; y4-=min_y; width=Max(max_x-min_x, 1); height=Max(max_y-min_y, 1); new_brush=((byte *)malloc((long)width*height)); if (!new_brush) { // Out of memory while allocating new brush Error(0); return; } // Fill the new brush with backcolor, originally. memset(new_brush,Back_color,((long)width)*height); // Call distort routine Pixel_for_distort=Pixel_in_distort_buffer; Distort_source=Brush_original_pixels; // alter pixels before remapping Distort_buffer=new_brush; Distort_buffer_width=width; Draw_brush_linear_distort(0, 0, (Brush_width<<16), (Brush_height<<16), (x1<<16), (y1<<16), (x2<<16), (y2<<16), (x3<<16), (y3<<16), (x4<<16), (y4<<16)); if (Realloc_brush(width, height, new_brush, NULL)) { free(new_brush); Error(0); return; } // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); // Re-center brush handle Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); } //------------------------- Rotation de la brosse --------------------------- #ifndef NAN #define NAN (-1.0e20F) #define isnan(x) ((x)==NAN) #endif float * ScanY_Xt[2]; float * ScanY_Yt[2]; float * ScanY_X[2]; void Interpolate_texture(int start_x,int start_y,int xt1,int yt1, int end_x ,int end_y ,int xt2,int yt2,int height) { int x_pos,y_pos; int incr_x,incr_y; int i,cumul; int delta_x,delta_y; int delta_xt=xt2-xt1; int delta_yt=yt2-yt1; int delta_x2=end_x-start_x; int delta_y2=end_y-start_y; float xt,yt; x_pos=start_x; y_pos=start_y; if (start_xdelta_y) { cumul=delta_x>>1; for (i=0; i<=delta_x; i++) { if (cumul>=delta_x) { cumul-=delta_x; y_pos+=incr_y; } if ((y_pos>=0) && (y_pos=ScanY_X[0][y_pos]) { if (isnan(ScanY_X[1][y_pos]) // Droit non dfini || (x_pos>ScanY_X[1][y_pos])) { ScanY_X[1][y_pos]=(float)x_pos; ScanY_Xt[1][y_pos]=xt; ScanY_Yt[1][y_pos]=yt; } } else { if (isnan(ScanY_X[1][y_pos])) // Droit non dfini { ScanY_X[1][y_pos]=ScanY_X[0][y_pos]; ScanY_Xt[1][y_pos]=ScanY_Xt[0][y_pos]; ScanY_Yt[1][y_pos]=ScanY_Yt[0][y_pos]; ScanY_X[0][y_pos]=(float)x_pos; ScanY_Xt[0][y_pos]=xt; ScanY_Yt[0][y_pos]=yt; } else { ScanY_X[0][y_pos]=(float)x_pos; ScanY_Xt[0][y_pos]=xt; ScanY_Yt[0][y_pos]=yt; } } } } x_pos+=incr_x; cumul+=delta_y; } } else { cumul=delta_y>>1; for (i=0; i<=delta_y; i++) { if (cumul>=delta_y) { cumul-=delta_y; x_pos+=incr_x; } if ((y_pos>=0) && (y_pos=ScanY_X[0][y_pos]) { if (isnan(ScanY_X[1][y_pos]) // Droit non dfini || (x_pos>ScanY_X[1][y_pos])) { ScanY_X[1][y_pos]=(float)x_pos; ScanY_Xt[1][y_pos]=xt; ScanY_Yt[1][y_pos]=yt; } } else { if (isnan(ScanY_X[1][y_pos])) // Droit non dfini { ScanY_X[1][y_pos]=ScanY_X[0][y_pos]; ScanY_Xt[1][y_pos]=ScanY_Xt[0][y_pos]; ScanY_Yt[1][y_pos]=ScanY_Yt[0][y_pos]; ScanY_X[0][y_pos]=(float)x_pos; ScanY_Xt[0][y_pos]=xt; ScanY_Yt[0][y_pos]=yt; } else { ScanY_X[0][y_pos]=(float)x_pos; ScanY_Xt[0][y_pos]=xt; ScanY_Yt[0][y_pos]=yt; } } } } y_pos+=incr_y; cumul+=delta_x; } } } void Compute_quad_texture( byte *texture, int texture_width, int x1,int y1,int xt1,int yt1, int x2,int y2,int xt2,int yt2, int x3,int y3,int xt3,int yt3, int x4,int y4,int xt4,int yt4, byte * buffer, int width, int height) { int x_min,/*x_max,*/y_min/*,y_max*/; int x,y,xt,yt; int start_x,end_x,line_width; float temp; //byte color; x_min=Min(Min(x1,x2),Min(x3,x4)); y_min=Min(Min(y1,y2),Min(y3,y4)); ScanY_Xt[0]=(float *)malloc(height*sizeof(float)); ScanY_Xt[1]=(float *)malloc(height*sizeof(float)); ScanY_Yt[0]=(float *)malloc(height*sizeof(float)); ScanY_Yt[1]=(float *)malloc(height*sizeof(float)); ScanY_X[0] =(float *)malloc(height*sizeof(float)); ScanY_X[1] =(float *)malloc(height*sizeof(float)); // Fill_general avec des valeurs gales NAN. for (y=0; y=0 && yt>=0) buffer[x+(y*width)]=*(texture + yt * texture_width + xt); } for (; x>1); start_y=1-(Brush_height>>1); end_x=start_x+Brush_width-1; end_y=start_y+Brush_height-1; //offset = Brush_rotate_width/Brush_width-1; Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3); Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4); // Calcul des nouvelles dimensions de la brosse: x_min=Min(Min((int)x1,(int)x2),Min((int)x3,(int)x4)); x_max=Max(Max((int)x1,(int)x2),Max((int)x3,(int)x4)); y_min=Min(Min((int)y1,(int)y2),Min((int)y3,(int)y4)); y_max=Max(Max((int)y1,(int)y2),Max((int)y3,(int)y4)); new_brush_width=x_max+1-x_min; new_brush_height=y_max+1-y_min; new_brush=(byte *)malloc(new_brush_width*new_brush_height); if (!new_brush) { Error(0); return; } // Et maintenant on calcule la nouvelle brosse tourne. Compute_quad_texture( Brush_rotate_buffer, Brush_rotate_width, x1,y1, offset, offset, x2,y2,Brush_rotate_width-offset-1, offset, x3,y3, offset,Brush_rotate_height-offset-1, x4,y4,Brush_rotate_width-offset-1,Brush_rotate_height-offset-1, new_brush,new_brush_width,new_brush_height); if (Realloc_brush(new_brush_width, new_brush_height, new_brush, NULL)) { free(new_brush); return; } // Remap according to the last used remap table Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); // Center offsets Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); } void Draw_quad_texture_preview(byte *texture, int texture_width, int x1,int y1,int xt1,int yt1, int x2,int y2,int xt2,int yt2, int x3,int y3,int xt3,int yt3, int x4,int y4,int xt4,int yt4) { int y_min,y_max; int x,y,xt,yt; int y_,y_min_; int start_x,end_x,width,height; float temp; byte color; y_min=Min(Min(y1,y2),Min(y3,y4)); y_max=Max(Max(y1,y2),Max(y3,y4)); height=1+y_max-y_min; ScanY_Xt[0]=(float *)malloc(height*sizeof(float)); ScanY_Xt[1]=(float *)malloc(height*sizeof(float)); ScanY_Yt[0]=(float *)malloc(height*sizeof(float)); ScanY_Yt[1]=(float *)malloc(height*sizeof(float)); ScanY_X[0] =(float *)malloc(height*sizeof(float)); ScanY_X[1] =(float *)malloc(height*sizeof(float)); // Fill_general avec des valeurs gales NAN. for (y=0; yLimit_bottom) y_max=Limit_bottom; for (y_=y_min; y_<=y_max; y_++) { y=y_-y_min_; start_x=Round(ScanY_X[0][y]); end_x =Round(ScanY_X[1][y]); width=1+end_x-start_x; if (start_xLimit_right) end_x=Limit_right; for (x=start_x; x<=end_x; x++) { temp=(float)(0.5+(float)x-ScanY_X[0][y])/(float)width; xt=Round((float)(ScanY_Xt[0][y])+(temp*(ScanY_Xt[1][y]-ScanY_Xt[0][y]))); yt=Round((float)(ScanY_Yt[0][y])+(temp*(ScanY_Yt[1][y]-ScanY_Yt[0][y]))); if (xt>=0 && yt>=0) { color=Brush_colormap[*(texture+xt+yt*texture_width)]; if (color!=Back_color) Pixel_preview(x,y_,color); } } } free(ScanY_Xt[0]); free(ScanY_Xt[1]); free(ScanY_Yt[0]); free(ScanY_Yt[1]); free(ScanY_X[0]); free(ScanY_X[1]); ScanY_Xt[0] = ScanY_Xt[1] = ScanY_Yt[0] = ScanY_Yt[1] = ScanY_X[0] = ScanY_X[1] = NULL; } void Rotate_brush_preview(float angle) { short x1,y1,x2,y2,x3,y3,x4,y4; int start_x,end_x,start_y,end_y; float cos_a=cos(angle); float sin_a=sin(angle); int offset=0; // Calcul des coordonnes des 4 coins: // 1 2 // 3 4 start_x=1-(Brush_width>>1); start_y=1-(Brush_height>>1); end_x=start_x+Brush_width-1; end_y=start_y+Brush_height-1; //offset = Brush_rotate_width/Brush_width-1; Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3); Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4); x1+=Brush_rotation_center_X; y1+=Brush_rotation_center_Y; x2+=Brush_rotation_center_X; y2+=Brush_rotation_center_Y; x3+=Brush_rotation_center_X; y3+=Brush_rotation_center_Y; x4+=Brush_rotation_center_X; y4+=Brush_rotation_center_Y; // Et maintenant on dessine la brosse tourne. Draw_quad_texture_preview(Brush_rotate_buffer, Brush_rotate_width, x1, y1, offset, offset, x2, y2, Brush_rotate_width-offset-1, offset, x3, y3, offset, Brush_rotate_height-offset-1, x4, y4, Brush_rotate_width-offset-1, Brush_rotate_height-offset-1); start_x=Min(Min(x1,x2),Min(x3,x4)); end_x=Max(Max(x1,x2),Max(x3,x4)); start_y=Min(Min(y1,y2),Min(y3,y4)); end_y=Max(Max(y1,y2),Max(y3,y4)); Update_part_of_screen(start_x,start_y,end_x-start_x+1,end_y-start_y+1); } /* /// Sets brush's original palette and color mapping. void Brush_set_palette(T_Palette *palette) { int i; byte need_remap; need_remap=0; memcpy(Brush_original_palette,palette,sizeof(T_Palette)); for (i=0;i<256;i++) { if (Brush_original_palette[i].R!=Main_palette[i].R || Brush_original_palette[i].G!=Main_palette[i].G || Brush_original_palette[i].B!=Main_palette[i].B) { need_remap=1; } } } */ grafx2_2.4+git20180105/src/pxtriple.h0000664000000000000000000000633413223665306015555 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ ////////////////////////////////////////////////////////////////////////////// ///@file pxtriple.h /// Renderer for triple pixels (3x3). ////////////////////////////////////////////////////////////////////////////// #include "struct.h" void Pixel_triple (word x,word y,byte color); byte Read_pixel_triple (word x,word y); void Block_triple (word start_x,word start_y,word width,word height,byte color); void Pixel_preview_normal_triple (word x,word y,byte color); void Pixel_preview_magnifier_triple (word x,word y,byte color); void Horizontal_XOR_line_triple (word x_pos,word y_pos,word width); void Vertical_XOR_line_triple (word x_pos,word y_pos,word height); void Display_brush_color_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_brush_mono_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); void Clear_brush_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); void Remap_screen_triple (word x_pos,word y_pos,word width,word height,byte * conversion_table); void Display_part_of_screen_triple (word width,word height,word image_width); void Display_line_on_screen_triple (word x_pos,word y_pos,word width,byte * line); void Read_line_screen_triple (word x_pos,word y_pos,word width,byte * line); void Display_part_of_screen_scaled_triple(word width,word height,word image_width,byte * buffer); void Display_brush_color_zoom_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); void Display_brush_mono_zoom_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); void Clear_brush_scaled_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); void Display_brush_triple (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); void Display_line_on_screen_fast_triple (word x_pos,word y_pos,word width,byte * line); grafx2_2.4+git20180105/src/oldies.h0000664000000000000000000000152413223665306015161 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Adrien Destugues Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ byte C64_FLI(byte *bitmap, byte *screen_ram, byte *color_ram, byte *background); byte C64_FLI_enforcer(void); grafx2_2.4+git20180105/src/colorred.c0000664000000000000000000000710413223665306015506 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2011 Adrien Destugues Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see ******************************************************************************** 24bit RGB to 8bit indexed functions */ #include #include #include #include "colorred.h" /* Octree for mapping RGB to color. A bit slower than a plain conversion table in theory, but : * Faster than running a search in the palette * Takes less memory than the huge conversion table * No loss of precision */ CT_Tree* CT_new() {return calloc(1, sizeof(CT_Tree));} // debug helper /* void CT_Print(CT_Node* node) { printf("R %d %d\tG %d %d\tB %d %d\tc %d/%d\n", node->Rmin, node->Rmax, node->Gmin, node->Gmax, node->Bmin, node->Bmax, node->children[0], node->children[1]); } */ void CT_set(CT_Tree* colorTree, byte Rmin, byte Gmin, byte Bmin, byte Rmax, byte Gmax, byte Bmax, byte index) { CT_Node* parent; // Create and setup node CT_Node* node = &colorTree->nodes[colorTree->nodecount]; node->Rmin = Rmin; node->Gmin = Gmin; node->Bmin = Bmin; node->Rmax = Rmax; node->Gmax = Gmax; node->Bmax = Bmax; node->children[1] = index; // Now insert it in tree (if we're not the root node) parent = &colorTree->nodes[0]; if (colorTree->nodecount != 0) for(;;) { // Find where to insert ourselves // pre-condition: the parent we're looking at is a superset of the node we're inserting // it may have 0, 1, or 2 child // 0 child: insert as child 0 // 1 child: either we're included in the child, and recurse, or we''re not, and insert at child 1 // 2 child: one of them has to be a superset of the node. if (parent->children[0] == 0) { parent->children[0] = colorTree->nodecount; // We KNOW children[1] was set to 0, because the parent was a split cluster. break; } else { CT_Node* child0 = &colorTree->nodes[parent->children[0]]; if (child0->Rmin <= node->Rmin && child0->Gmin <= node->Gmin && child0->Bmin <= node->Bmin && child0->Rmax >= node->Rmax && child0->Gmax >= node->Gmax && child0->Bmax >= node->Bmax ) { parent = child0; } else if(parent->children[1] == 0) { parent->children[1] = colorTree->nodecount; break; } else { parent = &colorTree->nodes[parent->children[1]]; } } } ++colorTree->nodecount; } byte CT_get(CT_Tree* tree, byte r, byte g, byte b) { // pre condition: node contains (rgb) // find the leaf that also contains (rgb) CT_Node* node = &tree->nodes[0]; for(;;) { if(node->children[0] == 0) // return the palette index return node->children[1]; else { // Left or right ? CT_Node* child0 = &tree->nodes[node->children[0]]; if (child0->Rmin <= r && child0->Gmin <= g && child0->Bmin <= b && child0->Rmax >= r && child0->Gmax >= g && child0->Bmax >= b ) { // left node = child0; } else { // right node = &tree->nodes[node->children[1]]; } } } } void CT_delete(CT_Tree* tree) { free(tree); } grafx2_2.4+git20180105/src/Makefile0000664000000000000000000007777713223665306015220 0ustar rootroot# Grafx2 - The Ultimate 256-color bitmap paint program # # Copyright 2012 Franck Charlet # Copyright 2011 Pawel Gralski # Copyright 2009 Per Olofsson # Copyright 2008 Peter Gordon # Copyright 2008-2010 Yves Rizoud # Copyright 2007-2010 Adrien Destugues # Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) # # Grafx2 is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; version 2 # of the License. # # Grafx2 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Grafx2; if not, see # Overridable defaults prefix = /usr/local exec_prefix = $(prefix) bindir = $(exec_prefix)/bin datarootdir = $(prefix)/share datadir = $(datarootdir) pixmapdir = $(datarootdir)/icons # Compile with OPTIM=0 to disable gcc optimizations, to enable debug. STRIP = strip # Detect GIT revision GIT_REVISION = $(shell git rev-list --count 1af8c74f53110e349d8f0d19b14599281913f71f..) ### Specific to build MAC OS X universal binaries on Tiger or Lion ### ### (may need to be changed or removed depending on the OSX version) ### #MACOSX_LION = 1 ifdef MACOSX_LION MACOSX_SYSROOT = /Developer/SDKs/MacOSX10.6.sdk MACOSX_ARCH = -arch x86_64 -arch i386 else MACOSX_SYSROOT = /Developer/SDKs/MacOSX10.4u.sdk MACOSX_ARCH = -arch ppc -arch i386 endif ### PLATFORM DETECTION AND CONFIGURATION ### PLATFORMOBJ = # There is no uname under windows, but we can guess we are there with the COMSPEC env.var # Windows specific ifdef COMSPEC DELCOMMAND = rm -f MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2.exe COPT = -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -g -ggdb `sdl-config --cflags` $(TTFCOPT) $(JOYCOPT) $(LUACOPT) LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng -lz $(LUALOPT) LUALOPT = -llua CC = gcc OBJDIR = ../obj/win32 # Resources (icon) WINDRES = windres.exe PLATFORMOBJ = $(OBJDIR)/winres.o PLATFORM = win32 #some misc files we have to add to the release archive under windows. PLATFORMFILES = bin/SDL.dll bin/SDL_image.dll bin/libpng14-14.dll bin/zlib1.dll $(TTFLIBS) ZIP = zip else #For all other platforms, we can rely on uname PLATFORM = $(shell uname) ifeq ($(PLATFORM),AmigaOS) # 1 #AmigaOS (3 or 4) specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2 COPT = -Wall -c -gstabs $(shell sdl-config --cflags) $(TTFCOPT) LOPT = $(shell sdl-config --libs) -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) -lft2 CC = gcc OBJDIR = ../obj/amiga ZIP = lha ZIPOPT = a NOTTF = 1 else ifeq ($(PLATFORM),Darwin) # 2 #Mac OS X specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty # Force it OPTIM = 3 CP = cp ZIP = zip PLATFORMFILES = gfx2.png # Where the SDL frameworks are located FWDIR = /Library/Frameworks BIN = ../bin/grafx2 SDLCONFIG := $(shell which sdl-config) ifneq ($(SDLCONFIG), ) # these are for use with macports SDLCOPT = $(shell sdl-config --cflags) SDLLOPT = $(shell sdl-config --libs) $(shell pkg-config --libs SDL_image) else # these are for use with Mac OS X native frameworks #-framework SDL_ttf SDLLOPT = -isysroot $(MACOSX_SYSROOT) $(MACOSX_ARCH) -L/usr/lib -framework SDL -framework SDL_image -framework Cocoa -framework Carbon -framework OpenGL SDLCOPT = $(MACOSX_ARCH) -I$(FWDIR)/SDL.framework/Headers -I$(FWDIR)/SDL_image.framework/Headers -I$(FWDIR)/SDL_ttf.framework/Headers -D_THREAD_SAFE endif # these are for use with macports LUAPKG := $(shell for p in lua5.1 lua-5.1 lua51 lua ; do pkg-config --exists $$p && echo $$p && break ; done) ifneq ($(LUAPKG), ) LUACOPT = $(shell pkg-config $(LUAPKG) --cflags) LUALOPT = $(shell pkg-config $(LUAPKG) --libs) else # these are for use with Mac OS X native frameworks LUACOPT = -I$(FWDIR)/Lua.framework/Headers ifdef MACOSX_LION LUALOPT = -framework lua else LUALOPT = -llua endif endif # these are for everyone COPT = -D_DARWIN_C_SOURCE -D__macosx__ -D__linux__ -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -std=c99 -c -g $(LUACOPT) $(SDLCOPT) $(TTFCOPT) -I/usr/include ifdef MACOSX_LION LOPT = $(SDLLOPT) $(LUALOPT) -framework libpng14 -lz else LOPT = $(SDLLOPT) $(LUALOPT) LIBPNGCONFIG := $(shell libpng-config) ifneq ($(LIBPNGCONFIG), ) COPT += $(shell libpng-config --cflags) LOPT += $(shell libpng-config --ldflags) else LOPT += -lpng endif LOPT += -lz endif # Use gcc for compiling. Use ncc to build a callgraph and analyze the code. CC = gcc #CC = nccgen -ncgcc -ncld -ncfabs OBJDIR = ../obj/macosx PLATFORMOBJ = $(OBJDIR)/SDLMain.o FCLOPT = MACAPPEXE = Grafx2.app/Contents/MacOS/Grafx2 NOTTF = 1 else ifeq ($(PLATFORM),AROS) # 3 #AROS specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2 COPT = -Wall -g $(shell sdl-config --cflags) $(TTFCOPT) LOPT = -lSDL_image $(shell sdl-config --libs) -lpng -ljpeg -lz $(TTFLOPT) -lfreetype2shared CC = gcc OBJDIR = ../obj/aros STRIP = strip --strip-unneeded --remove-section .comment ZIP = lha ZIPOPT = a else ifeq ($(PLATFORM),MorphOS) # 4 #MorphOS specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2 COPT = -Wall -gstabs -c $(shell sdl-config --cflags) $(TTFCOPT) LOPT = -lSDL_image $(shell sdl-config --libs) -lpng -ljpeg -lz $(TTFLOPT) CC = gcc OBJDIR = ../obj/morphos ZIP = lha ZIPOPT = a PLATFORMFILES = ../misc/grafx2.info else ifeq ($(PLATFORM),BeOS) # 6 #BeOS specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2 COPT = -W -Wall -c -g $(shell sdl-config --cflags) $(TTFCOPT) -I/boot/home/config/include LOPT = $(shell sdl-config --libs) -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) CC = gcc OBJDIR = ../obj/beos ZIP = zip else ifeq ($(PLATFORM),Haiku) # 7 #Haiku specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2 PLATFORMOBJ = $(OBJDIR)/haiku.o ifeq ($(NOLUA),1) LUACOPT = LUALOPT = else LUAPKG=lua LUACOPT = -D__ENABLE_LUA__ $(shell pkg-config $(LUAPKG) --cflags) LUALOPT = $(shell pkg-config $(LUAPKG) --libs) endif COPT = -W -Wall -Werror -c -g $(shell sdl-config --cflags) $(TTFCOPT) -I/boot/common/include $(LUACOPT) COPT += -DENABLE_FILENAMES_ICONV LOPT = $(shell sdl-config --libs) -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) -lfreetype -lbe $(LUALOPT) -liconv CC = gcc #Append the gcc kind to the objdir (gcc2 or gcc4) to avoid conflicts when switching from one to other. OBJKIND = $(shell gcc -dumpversion) OBJDIR = ../obj/haiku/$(OBJKIND) ZIP = zip else ifeq ($(PLATFORM),skyos) # 8 #SkyOS specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp BIN = ../bin/grafx2 COPT = -W -Wall -Wdeclaration-after-statement -c -g $(shell sdl-config --cflags) $(TTFCOPT) LOPT = $(shell sdl-config --libs) -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) CC = gcc OBJDIR = ../obj/skyos ZIP = zip else ifeq ($(PLATFORM),OSF1) #9 #OSF1 / tru64 alpha DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp ZIP = zip PLATFORMFILES = gfx2.png BIN = ../bin/grafx2 COPT = -W -Wall -std=c99 -c -g -gstabs -D__TRU64__ $(shell sdl-config --cflags) $(TTFCOPT) $(LUACOPT) LOPT = $(shell sdl-config --libs) -lSDL_image $(TTFLOPT) -lpng $(LUALOPT) -lm OBJDIR = ../obj/unix FCLOPT = -lfontconfig COPT += -DUSE_FC CC = gcc else ifeq ($(PLATFORM),FreeMiNT) #10 #Atari FreeMiNT/TOS specific DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir CP = cp ZIP = zip PLATFORMFILES = gfx2.png CC = gcc BIN = ../bin/grafx2.ttp LUALOPT = -llua OBJDIR = ../obj/m68k-atari-mint PLATFORM = m68k-atari-mint STRIP = strip -s STACK = stack FIX_FLAGS = flags FCLOPT = COPT = -W -Wall -m68020-60 -fomit-frame-pointer -std=c99 -Wdeclaration-after-statement -D__MINT__ -DNO_INLINE_MATH -O$(OPTIM) -c -I$(prefix)/include `$(prefix)/bin/libpng12-config --cflags` `$(prefix)/bin/sdl-config --cflags` $(JOYCOPT) $(LUACOPT) LOPT = -static -m68020-60 -lSDL_image `$(prefix)/bin/sdl-config --libs` -L$(prefix)/lib -ltiff -ljpeg `$(prefix)/bin/libpng12-config --libs` -lz -lm $(TTFLOPT) -lfreetype $(LUALOPT) $(LAYERLOPT) else ifeq ($(PLATFORM),syllable) #11 #Syllable DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp ZIP = zip PLATFORMFILES = gfx2.png LUACOPT = -I/resources/indexes/include LUALOPT = -llua BIN = ../bin/grafx2 COPT = -W -Wall -Wdeclaration-after-statement -std=c99 -c -g `sdl-config --cflags` -I/resources/indexes/include/SDL $(TTFCOPT) $(LUACOPT) $(JOYCOPT) -O$(OPTIM) LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng -lz $(LUALOPT) -lm CC = gcc OBJDIR = ../obj/syllable FCLOPT = else # Finally, the default rules that work fine for most unix/gcc systems, linux and freebsd are tested. # Linux and FreeBSD specific (default rules) DELCOMMAND = rm -rf MKDIR = mkdir -p RMDIR = rmdir --ignore-fail-on-non-empty CP = cp ZIP = zip PLATFORMFILES = gfx2.png ifneq ($(ATARICROSS),1) ifeq ($(NOLUA),1) LUACOPT = LUALOPT = else LUAPKG := $(shell for p in lua5.1 lua-5.1 lua51 lua ; do pkg-config --exists $$p && echo $$p && break ; done) LUACOPT = $(shell pkg-config $(LUAPKG) --cflags) LUALOPT = $(shell pkg-config $(LUAPKG) --libs) endif endif # These can only be used under linux and maybe freebsd. They allow to compile for the gp2x or to create a windows binary ifdef WIN32CROSS #cross compile a Win32 executable CC = i686-w64-mingw32-gcc BIN = ../bin/grafx2.exe COPT = -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -g -ggdb -Dmain=SDL_main $(shell /usr/local/cross-tools/i386-mingw32/bin/sdl-config --cflags) $(TTFCOPT) LOPT = -mwindows -lmingw32 -lSDLmain -lSDL -lshlwapi $(shell /usr/local/cross-tools/i386-mingw32/bin/sdl-config --libs) -lSDL_image $(TTFLOPT) COPT += $(shell PKG_CONFIG_PATH=/usr/local/cross-tools/i386-mingw32/lib/pkgconfig i686-w64-mingw32-pkg-config --cflags libpng) LOPT += $(shell PKG_CONFIG_PATH=/usr/local/cross-tools/i386-mingw32/lib/pkgconfig i686-w64-mingw32-pkg-config --libs libpng) OBJDIR = ../obj/win32 PLATFORM = win32 else ifdef GP2XCROSS #cross compile an exec for the gp2x CC = /opt/open2x/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/bin/arm-open2x-linux-gcc BIN = ../bin/grafx2.gpe COPT = -W -Wall -Wdeclaration-after-statement -pedantic -std=c99 -static -g -O$(OPTIM) -I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include `/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin/sdl-config --cflags` $(TTFCOPT) -D__GP2X__ $(TTFCOPT) $(JOYCOPT) $(LUACOPT) LOPT = -static -lSDL_image `/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin/sdl-config --static-libs` -ljpeg -lpng -lz -lm $(TTFLOPT) $(LUALOPT) OBJDIR = ../obj/gp2x NOTTF = 1 PLATFORM = gp2x STRIP = /opt/open2x/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/bin/arm-open2x-linux-strip JOYCOPT = -DUSE_JOYSTICK else ifdef GCWZERO #cross compile an exec for the gcw0 CC = mipsel-linux-gcc BIN = ../bin/grafx2 LUACOPT = LUALOPT = -lluajit-5.1 COPT = -DGCWZERO -W -Wall -Wdeclaration-after-statement -pedantic -std=c99 -g -O$(OPTIM) -I/opt/gcw0-toolchain/usr/mipsel-gcw0-linux-uclibc/sysroot/usr/include -I/opt/gcw0-toolchain/usr/mipsel-gcw0-linux-uclibc/sysroot/usr/include/SDL `/opt/gcw0-toolchain/usr/mipsel-gcw0-linux-uclibc/sysroot/usr/bin/sdl-config --cflags` $(TTFCOPT) $(TTFCOPT) $(JOYCOPT) $(LUACOPT) LOPT = -L/opt/gcw0-toolchain/usr/mipsel-gcw0-linux-uclibc/sysroot/usr/lib -lSDL_image `/opt/gcw0-toolchain/usr/mipsel-gcw0-linux-uclibc/sysroot/usr/bin/sdl-config --libs` -ljpeg -lpng -lz -lm $(TTFLOPT) $(LUALOPT) OBJDIR = ../obj/gp2x NOTTF = 1 PLATFORM = gp2x STRIP = mipsel-linux-strip JOYCOPT = -DUSE_JOYSTICK else ifdef AROS32CROSS #cross compile an AROS 32 bit executable BIN = ../GrafX2 COPT = -Wall -Wno-pointer-sign -Wno-unused-but-set-variable -g `i386-linux-aros-sdl-config --cflags` $(TTFCOPT) $(LUACOPT) LOPT = -lSDL_image `i386-linux-aros-sdl-config --libs` -lpng -ljpeg -lz $(TTFLOPT) -lfreetype2shared $(LUALOPT) LUACOPT = -I/home/mazze/projects/fullaros/aros-linux-i386-dbg/bin/linux-i386/AROS/Development/include/lua LUALOPT = -llua CC = i386-linux-aros-gcc OBJDIR = ../obj/aros STRIP = strip --strip-unneeded --remove-section .comment PLATFORM = AROS ZIP = lha ZIPOPT = a else ifdef ATARICROSS #cross compile an exec for atari TOS/MiNT machine CC = m68k-atari-mint-gcc BIN = ../bin/grafx2.ttp LUALOPT = -llua OBJDIR = ../obj/m68k-atari-mint PLATFORM = m68k-atari-mint STRIP = m68k-atari-mint-strip -s STACK = m68k-atari-mint-stack FIX_FLAGS = m68k-atari-mint-flags FCLOPT = COPT = -W -Wall -m68020-60 -fomit-frame-pointer -std=c99 -Wdeclaration-after-statement -D__MINT__ -ffast-math -O$(OPTIM) -c -I$(prefix)/include `$(prefix)/bin/libpng12-config --cflags` `$(prefix)/bin/sdl-config --cflags` $(JOYCOPT) $(LUACOPT) LOPT = -static -m68020-60 -lSDL_image `$(prefix)/bin/sdl-config --libs` -L$(prefix)/lib -ltiff -ljpeg `$(prefix)/bin/libpng12-config --libs` -lz -lm $(TTFLOPT) -lfreetype $(LUALOPT) -lm $(LAYERLOPT) -Wl,--stack,8k else # Compiles a regular linux executable for the native platform BIN = ../bin/grafx2 COPT = -W -Wall -Wdeclaration-after-statement -std=c99 -c -g $(shell sdl-config --cflags) $(TTFCOPT) $(LUACOPT) $(JOYCOPT) -O$(OPTIM) COPT += $(shell pkg-config --cflags libpng) ifneq ($(PLATFORM), FreeBSD) COPT += -D_XOPEN_SOURCE=700 endif LOPT = $(shell sdl-config --libs) -lSDL_image $(TTFLOPT) LOPT += $(shell pkg-config --libs libpng) LOPT += $(LUALOPT) -lm CC = gcc OBJDIR = ../obj/unix FCLOPT = -lfontconfig COPT += -DUSE_FC # enable UTF8 filename translation # For Linux (GLibc), iconv is built into the C library so no LOPT needed. COPT += -DENABLE_FILENAMES_ICONV ifneq ($(PLATFORM),Linux) LOPT += -liconv endif endif endif endif endif endif endif endif endif endif endif endif endif endif endif endif endif ### BUILD SETTINGS are set according to vars set in the platform selection, ### the "overridable defaults", and environment variables set before launching make #TrueType is optional: make NOTTF=1 to disable support and dependencies. ifndef ($(ATARICROSS,1)) ifeq ($(NOTTF),1) TTFCOPT = -DNOTTF=1 TTFLOPT = TTFLIBS = TTFLABEL = -nottf else TTFCOPT = TTFLOPT = -L$(prefix)/lib -lSDL_ttf $(FCLOPT) TTFLIBS = bin/libfreetype-6.dll bin/SDL_ttf.dll TTFLABEL = endif else ifeq ($(NOTTF),1) TTFCOPT = -DNOTTF=1 TTFLOPT = TTFLIBS = TTFLABEL = -nottf else TTFCOPT = TTFLOPT = -L$(prefix)/lib -lSDL_ttf $(FCLOPT) TTFLIBS = TTFLABEL = endif endif #Lua scripting is optional too ifeq ($(NOLUA),1) LUACOPT = LUALOPT = LUALABEL = -nolua else LUACOPT += -D__ENABLE_LUA__ LUALABEL = endif #To enable Joystick emulation of cursor, make USE_JOYSTICK=1 (for input.o) #This can be necessary to test cursor code on a PC, but by default for all #non-console platforms the joystick is disabled, to avoid reporting #'restless' movements when an analog joystick or a poorly-calibrated joypad #is plugged in. ifeq ($(USE_JOYSTICK),1) JOYCOPT = -DUSE_JOYSTICK endif ### And now for the real build rules ### .PHONY : all debug release clean depend zip version force install uninstall # This is the list of the objects we want to build. Dependancies are built by "make depend" automatically. OBJ = $(OBJDIR)/main.o $(OBJDIR)/init.o $(OBJDIR)/graph.o $(OBJDIR)/sdlscreen.o $(OBJDIR)/misc.o $(OBJDIR)/special.o $(OBJDIR)/buttons.o $(OBJDIR)/palette.o $(OBJDIR)/help.o $(OBJDIR)/operatio.o $(OBJDIR)/pages.o $(OBJDIR)/loadsave.o $(OBJDIR)/readline.o $(OBJDIR)/engine.o $(OBJDIR)/filesel.o $(OBJDIR)/op_c.o $(OBJDIR)/readini.o $(OBJDIR)/saveini.o $(OBJDIR)/shade.o $(OBJDIR)/keyboard.o $(OBJDIR)/io.o $(OBJDIR)/version.o $(OBJDIR)/text.o $(OBJDIR)/SFont.o $(OBJDIR)/setup.o $(OBJDIR)/pxsimple.o $(OBJDIR)/pxtall.o $(OBJDIR)/pxwide.o $(OBJDIR)/pxdouble.o $(OBJDIR)/pxtriple.o $(OBJDIR)/pxtall2.o $(OBJDIR)/pxtall3.o $(OBJDIR)/pxwide2.o $(OBJDIR)/pxquad.o $(OBJDIR)/windows.o $(OBJDIR)/brush.o $(OBJDIR)/realpath.o $(OBJDIR)/mountlist.o $(OBJDIR)/input.o $(OBJDIR)/hotkeys.o $(OBJDIR)/transform.o $(OBJDIR)/pversion.o $(OBJDIR)/factory.o $(PLATFORMOBJ) $(OBJDIR)/fileformats.o $(OBJDIR)/miscfileformats.o $(OBJDIR)/libraw2crtc.o $(OBJDIR)/brush_ops.o $(OBJDIR)/buttons_effects.o $(OBJDIR)/layers.o $(OBJDIR)/oldies.o $(OBJDIR)/tiles.o $(OBJDIR)/colorred.o SKIN_FILES = ../share/grafx2/skins/skin_classic.png ../share/grafx2/skins/skin_modern.png ../share/grafx2/skins/skin_DPaint.png ../share/grafx2/skins/font_Classic.png ../share/grafx2/skins/font_Fun.png ../share/grafx2/skins/font_Fairlight.png ../share/grafx2/skins/font_Melon.png ../share/grafx2/skins/font_DPaint.png ../share/grafx2/skins/skin_scenish.png ../share/grafx2/skins/font_Seen.png ../share/grafx2/skins/skin_Aurora.png SCRIPT_FILES = ../share/grafx2/scripts/samples_2.4/brush/ApplyColor.lua ../share/grafx2/scripts/samples_2.4/brush/Fisheye.lua ../share/grafx2/scripts/samples_2.4/brush/GrayscaleAvg.lua ../share/grafx2/scripts/samples_2.4/brush/GrayscaleDesat.lua ../share/grafx2/scripts/samples_2.4/brush/Halfsmooth.lua ../share/grafx2/scripts/samples_2.4/brush/Waves.lua ../share/grafx2/scripts/samples_2.4/demo/3DPalette.lua ../share/grafx2/scripts/samples_2.4/demo/Ellipse.lua ../share/grafx2/scripts/samples_2.4/demo/FlipPicture.lua \ ../share/grafx2/scripts/samples_2.4/demo/SierpinskyCarpet.lua ../share/grafx2/scripts/samples_2.4/demo/SierpinskyTriangle.lua ../share/grafx2/scripts/samples_2.4/demo/Spritesheet.lua ../share/grafx2/scripts/samples_2.4/demo/brush/Amigaball.lua ../share/grafx2/scripts/samples_2.4/demo/brush/ColorSphere.lua ../share/grafx2/scripts/samples_2.4/demo/brush/FindAA.lua ../share/grafx2/scripts/samples_2.4/demo/brush/Mandelbrot.lua ../share/grafx2/scripts/samples_2.4/libs/dawnbringer_lib.lua ../share/grafx2/scripts/samples_2.4/libs/memory.lua \ ../share/grafx2/scripts/samples_2.4/palette/Desaturate.lua ../share/grafx2/scripts/samples_2.4/palette/ExpandColors.lua ../share/grafx2/scripts/samples_2.4/palette/FillColorCube.lua ../share/grafx2/scripts/samples_2.4/palette/InvertedRGB.lua ../share/grafx2/scripts/samples_2.4/palette/Set3bit.lua ../share/grafx2/scripts/samples_2.4/palette/Set6bit.lua ../share/grafx2/scripts/samples_2.4/palette/SetC64Palette.lua ../share/grafx2/scripts/samples_2.4/palette/ShiftHue.lua ../share/grafx2/scripts/samples_2.4/picture/CellColourReducer.lua \ ../share/grafx2/scripts/samples_2.4/picture/DrawGridIsometric.lua ../share/grafx2/scripts/samples_2.4/picture/DrawgridOrthogonal_Index.lua ../share/grafx2/scripts/samples_2.4/picture/DrawGridOrthogonal_RGB.lua ../share/grafx2/scripts/samples_2.4/picture/GlassGridFilter.lua ../share/grafx2/scripts/samples_2.4/picture/PaletteToPicture.lua ../share/grafx2/scripts/samples_2.4/picture/Pic2isometric.lua ../share/grafx2/scripts/samples_2.4/picture/Rainbow-Dark2Bright.lua ../share/grafx2/scripts/samples_2.4/picture/RemapImage2RGB.lua \ ../share/grafx2/scripts/samples_2.4/picture/RemapImage2RGB_ed.lua ../share/grafx2/scripts/samples_2.4/picture/RemapImageTo3bitPal.lua ../share/grafx2/scripts/samples_2.4/picture/XBitColourXpaceFromPalette.lua ../share/grafx2/scripts/samples_2.4/picture/Tiler.lua FONT_FILES = ../share/grafx2/fonts/8pxfont.png ../share/grafx2/fonts/Tuffy.ttf ../share/grafx2/fonts/PF_Arma_5__.png ../share/grafx2/fonts/PF_Easta_7_.png ../share/grafx2/fonts/PF_Easta_7__.png ../share/grafx2/fonts/PF_Ronda_7__.png ../share/grafx2/fonts/PF_Tempesta_5.png ../share/grafx2/fonts/PF_Tempesta_5_.png ../share/grafx2/fonts/PF_Tempesta_5__.png ../share/grafx2/fonts/PF_Tempesta_5___.png ../share/grafx2/fonts/PF_Tempesta_7.png ../share/grafx2/fonts/PF_Tempesta_7_.png ../share/grafx2/fonts/PF_Tempesta_7__.png ../share/grafx2/fonts/PF_Tempesta_7___.png ../share/grafx2/fonts/PF_Westa_7_.png ../share/grafx2/fonts/PF_Westa_7__.png ifeq ($(PLATFORM),Darwin) all : $(MACAPPEXE) $(MACAPPEXE) : $(BIN) rm -rf Grafx2.app mkdir -p Grafx2.app Grafx2.app/Contents Grafx2.app/Contents/Frameworks Grafx2.app/Contents/MacOS Grafx2.app/Contents/Resources Grafx2.app/Contents/Resources/scripts mkdir -p Grafx2.app/Contents/Resources/scripts/samples_2.4 mkdir -p Grafx2.app/Contents/Resources/scripts/samples_2.4/brush mkdir -p Grafx2.app/Contents/Resources/scripts/samples_2.4/demo mkdir -p Grafx2.app/Contents/Resources/scripts/samples_2.4/libs mkdir -p Grafx2.app/Contents/Resources/scripts/samples_2.4/palette mkdir -p Grafx2.app/Contents/Resources/scripts/samples_2.4/picture echo 'APPL????' > Grafx2.app/Contents/PkgInfo cp ../Info.plist Grafx2.app/Contents cp -r Grafx2.icns Grafx2.app/Contents/Resources cp -r English.lproj Grafx2.app/Contents/Resources cp -r ../share/grafx2/fonts Grafx2.app/Contents/Resources cp -r ../share/grafx2/skins Grafx2.app/Contents/Resources cp -r ../share/grafx2/gfx2def.ini Grafx2.app/Contents/Resources cp -r ../share/grafx2/scripts/samples_2.4/brush Grafx2.app/Contents/Resources/scripts/samples_2.4 cp -r ../share/grafx2/scripts/samples_2.4/demo Grafx2.app/Contents/Resources/scripts/samples_2.4 cp -r ../share/grafx2/scripts/samples_2.4/libs Grafx2.app/Contents/Resources/scripts/samples_2.4 cp -r ../share/grafx2/scripts/samples_2.4/palette Grafx2.app/Contents/Resources/scripts/samples_2.4 cp -r ../share/grafx2/scripts/samples_2.4/picture Grafx2.app/Contents/Resources/scripts/samples_2.4 ifdef MACOSX_LION mkdir -p Grafx2.app/Contents/Frameworks/Lua.framework/Versions cp -Rp $(FWDIR)/Lua.framework/Versions/A Grafx2.app/Contents/Frameworks/Lua.framework/Versions mkdir -p Grafx2.app/Contents/Frameworks/libpng14.framework/Versions cp -Rp $(FWDIR)/libpng14.framework/Versions/1.4.8 Grafx2.app/Contents/Frameworks/libpng14.framework/Versions endif if [ -d $(FWDIR)/SDL.framework/Versions ] ; then \ mkdir -p Grafx2.app/Contents/Frameworks/SDL.framework/Versions ;\ cp -Rp $(FWDIR)/SDL.framework/Versions/A Grafx2.app/Contents/Frameworks/SDL.framework/Versions ;\ fi if [ -d $(FWDIR)/SDL_image.framework/Versions ] ; then \ mkdir -p Grafx2.app/Contents/Frameworks/SDL_image.framework/Versions ;\ cp -Rp $(FWDIR)/SDL_image.framework/Versions/A Grafx2.app/Contents/Frameworks/SDL_image.framework/Versions ;\ fi # mkdir -p Grafx2.app/Contents/Frameworks/SDL_ttf.framework/Versions # cp -Rp $(FWDIR)/SDL_ttf.framework/Versions/A Grafx2.app/Contents/Frameworks/SDL_ttf.framework/Versions # remove those rm -fr Grafx2.app/Contents/Frameworks/SDL.framework/Versions/A/Headers rm -fr Grafx2.app/Contents/Frameworks/SDL.framework/Versions/A/Resources rm -fr Grafx2.app/Contents/Frameworks/SDL_image.framework/Versions/A/Headers rm -fr Grafx2.app/Contents/Frameworks/SDL_image.framework/Versions/A/Resources ifdef MACOSX_LION rm -fr Grafx2.app/Contents/Frameworks/Lua.framework/Versions/A/Resources rm -fr Grafx2.app/Contents/Frameworks/Lua.framework/Versions/A/Headers rm -fr Grafx2.app/Contents/Frameworks/libpng14.framework/Versions/1.4.8/Resources rm -fr Grafx2.app/Contents/Frameworks/libpng14.framework/Versions/1.4.8/Headers rm -fr Grafx2.app/Contents/Frameworks/SDL_ttf.framework/Versions endif cp $(BIN) $(MACAPPEXE) $(STRIP) -x -X -S $(MACAPPEXE) chmod +x $(MACAPPEXE) tar cvzf grafx2-git$(GIT_REVISION)-macosx.tgz --exclude '.git' --exclude '*DS_Store*' Grafx2.app/* else all : $(BIN) ifeq ($(ATARICROSS),1) $(STACK) -S 128k $(BIN) $(FIX_FLAGS) -S $(BIN) else ifeq ($(PLATFORM),FreeMiNT) $(STACK) -S 128k $(BIN) $(FIX_FLAGS) -S $(BIN) endif endif endif debug : $(BIN) ifeq ($(ATARICROSS),1) $(STACK) -S 128k $(BIN) $(FIX_FLAGS) -S $(BIN) else ifeq ($(PLATFORM),FreeMiNT) $(STACK) -S 128k $(BIN) $(FIX_FLAGS) -S $(BIN) endif endif # Make release will strip the executable to make it smaller but non-debugable release : version $(BIN) $(STRIP) $(BIN) # Create a zip archive ready for upload to the website, including binaries and sourcecode ziprelease: version $(BIN) release echo `sed "s/.*=\"\(.*\)\";/\1/" pversion.c`.$(GIT_REVISION) | tr " :" "_-" | sed -e "s/\(wip\)\\./\1/I" > $(OBJDIR)/versiontag tar cvzf "../src-`cat $(OBJDIR)/versiontag`.tgz" --strip=1 ../src/*.c ../src/*.cpp ../src/*.h ../src/Makefile ../src/Makefile.dep ../src/gfx2.ico ../src/Grafx2_Prefix.pch ../src/SDLMain.m cd .. && $(ZIP) $(ZIPOPT) "grafx2-`cat $(OBJDIR:../%=%)/versiontag`$(TTFLABEL)-$(PLATFORM).$(ZIP)" $(BIN:../%=%) share/grafx2/gfx2def.ini $(SCRIPT_FILES:../%=%) $(SKIN_FILES:../%=%) share/grafx2/gfx2.gif share/icons/grafx2.svg doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt doc/PF_fonts.txt $(FONT_FILES:../%=%) doc/README-zlib1.txt doc/README-SDL.txt doc/README-SDL_image.txt doc/README-SDL_ttf.txt doc/README-lua.txt src-`cat $(OBJDIR:../%=%)/versiontag`.tgz $(PLATFORMFILES:../%=%) $(DELCOMMAND) "../src-`cat $(OBJDIR)/versiontag`.tgz" tar cvzf "../grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-src.tgz" --strip=1 --transform 's,^,grafx2/,g' ../src/*.c ../src/*.cpp ../src/*.h ../src/Makefile ../src/Makefile.dep ../share/grafx2/gfx2def.ini $(SCRIPT_FILES) $(SKIN_FILES) ../src/gfx2.ico ../share/grafx2/gfx2.gif ../share/icons/grafx2.svg ../doc/README.txt ../doc/COMPILING.txt ../doc/gpl-2.0.txt ../doc/PF_fonts.txt ../misc/unix/grafx2.1 ../misc/unix/grafx2.xpm ../misc/unix/grafx2.desktop ../misc/morphos/grafx2.info $(FONT_FILES) ../src/Grafx2_Prefix.pch ../src/SDLMain.m $(DELCOMMAND) "$(OBJDIR)/versiontag" $(BIN) : $(OBJ) test -d ../bin || $(MKDIR) ../bin $(CC) $(OBJ) -o $(BIN) $(LOPT) $(LFLAGS) ifeq ($(PLATFORM),Haiku) rc -o $(OBJDIR)/grafx2.rsrc grafx2.rdef xres -o $(BIN) $(OBJDIR)/grafx2.rsrc mimeset -f $(BIN) endif # GIT revision number version.c : echo "char SVN_revision[]=\"$(GIT_REVISION)\";" > version.c ifeq ($(LABEL),) else echo "char Program_version[]=\"$(LABEL)\";" > pversion.c endif version : delversion delpversion version.c pversion.c $(OBJDIR)/version.o $(OBJDIR)/pversion.o all delversion : $(DELCOMMAND) version.c delpversion : ifeq ($(LABEL),) else $(DELCOMMAND) pversion.c endif $(OBJDIR)/%.o : %.c $(if $(wildcard $(OBJDIR)),,$(MKDIR) $(OBJDIR)) $(CC) $(COPT) $(CFLAGS) -c $*.c -o $(OBJDIR)/$*.o $(OBJDIR)/%.o : %.m $(if $(wildcard $(OBJDIR)),,$(MKDIR) $(OBJDIR)) $(CC) $(COPT) -c $*.m -o $(OBJDIR)/$*.o depend : $(CC) -MM *.c | sed 's:^[^ ]:$$(OBJDIR)/&:' > Makefile.dep # Link the icons to the program under windows $(OBJDIR)/winres.o : gfx2.ico echo "1 ICON \"gfx2.ico\"" | $(WINDRES) -o $(OBJDIR)/winres.o # Compile the C++ file needed in Haiku to use the API $(OBJDIR)/haiku.o : haiku.cpp g++ -c haiku.cpp -o $(OBJDIR)/haiku.o $(COPT) -Wno-multichar clean : $(DELCOMMAND) $(OBJ) $(DELCOMMAND) $(BIN) ifneq ($(PLATFORM),amiga-vbcc) # Linux installation of the program install : $(BIN) # Create dirs test -d $(DESTDIR)$(bindir) || $(MKDIR) $(DESTDIR)$(bindir) test -d $(DESTDIR)$(datadir)/grafx2 || $(MKDIR) $(DESTDIR)$(datadir)/grafx2 test -d $(DESTDIR)$(datadir)/grafx2/fonts || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/fonts test -d $(DESTDIR)$(datadir)/grafx2/skins || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/skins test -d $(DESTDIR)$(datadir)/grafx2/scripts || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts test -d $(DESTDIR)$(datadir)/grafx2/scripts/libs || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/libs test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4 || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4 test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/brush || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/brush test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/demo || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/demo test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/demo/brush || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/demo/brush test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/libs || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/libs test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/palette || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/palette test -d $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/picture || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/picture test -d $(DESTDIR)$(datadir)/applications || $(MKDIR) $(DESTDIR)$(datadir)/applications test -d $(DESTDIR)$(pixmapdir) || $(MKDIR) $(DESTDIR)$(pixmapdir) # Copy files $(CP) $(BIN) $(DESTDIR)$(bindir) $(CP) ../share/grafx2/gfx2def.ini $(DESTDIR)$(datadir)/grafx2/ $(CP) ../share/grafx2/gfx2.gif $(DESTDIR)$(datadir)/grafx2/ $(CP) ../share/grafx2/fonts/* $(DESTDIR)$(datadir)/grafx2/fonts/ $(CP) $(SKIN_FILES) $(DESTDIR)$(datadir)/grafx2/skins/ for f in $(SCRIPT_FILES:../share/%=%); do cp "../share/$$f" "$(DESTDIR)$(datadir)/$$f" ; done # Icon and desktop file for debian $(CP) ../misc/unix/grafx2.desktop $(DESTDIR)$(datadir)/applications/ $(CP) ../misc/unix/grafx2.xpm $(DESTDIR)$(pixmapdir) $(CP) ../share/icons/grafx2.svg $(DESTDIR)$(pixmapdir) @echo Install complete # Linux uninstallation of the program uninstall : $(DELCOMMAND) $(DESTDIR)$(bindir)/grafx2 $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/gfx2def.ini $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/gfx2.gif $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/fonts/* $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/fonts),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/fonts,) $(DELCOMMAND) $(SKIN_FILES:../share%=$(DESTDIR)$(datadir)%) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/skins),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/skins,) $(DELCOMMAND) $(SCRIPT_FILES:../share%=$(DESTDIR)$(datadir)%) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/picture),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/picture,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/palette),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/palette,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/libs),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/libs,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/demo/brush),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/demo/brush,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/demo),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/demo,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/brush),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4/brush,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/samples_2.4,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/libs),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/libs,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts),$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts,) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2),$(RMDIR) $(DESTDIR)$(datadir)/grafx2,) # Icon and desktop file for debian $(DELCOMMAND) $(DESTDIR)$(datadir)/applications/grafx2.desktop $(DELCOMMAND) $(DESTDIR)$(pixmapdir)/grafx2.xpm $(DELCOMMAND) $(DESTDIR)$(pixmapdir)/grafx2.svg @echo Uninstall complete endif -include Makefile.dep grafx2_2.4+git20180105/.gitignore0000664000000000000000000000021013223665306014721 0ustar rootroot*.bak .*.sw? # / /gfx2.ini /gfx2.cfg /message.txt /stdout.txt /stderr.txt /obj /bin/grafx2* /src/version.c /src/*.tgz /src/Grafx2.app grafx2_2.4+git20180105/install/0000775000000000000000000000000013223665306014406 5ustar rootrootgrafx2_2.4+git20180105/install/WinInstaller_23.nsi0000664000000000000000000003607013223665306020046 0ustar rootroot;NSIS Modern User Interface ;Based on the Example Script written by Joost Verburg ;-------------------------------- ;Include Modern UI !include "MUI2.nsh" ;-------------------------------- ;General ;Name and file Name "Grafx2" OutFile "grafx2-2.3.1771.win32.exe" ;Default installation folder InstallDir "$PROGRAMFILES\Grafx2" ;Get installation folder from registry if available InstallDirRegKey HKCU "Software\Grafx2" "" ;Request application privileges for Windows Vista RequestExecutionLevel user ;-------------------------------- ;Interface Settings !define MUI_ABORTWARNING ;-------------------------------- ;Pages !define MUI_WELCOMEFINISHPAGE_BITMAP vector.bmp !define MUI_WELCOMEFINISHPAGE_BITMAP_NOSTRETCH !insertmacro MUI_PAGE_WELCOME ;!define MUI_HEADERIMAGE_BITMAP logo_scenish.bmp ;!define MUI_HEADERIMAGE_BITMAP_NOSTRETCH !insertmacro MUI_PAGE_LICENSE "..\doc\gpl-2.0.txt" !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ;-------------------------------- ;Languages !insertmacro MUI_LANGUAGE "English" ;-------------------------------- ;Functions Function .onInstSuccess MessageBox MB_YESNO "Run GrafX2 now ?" IDNO norun Exec $INSTDIR\bin\grafx2.exe norun: FunctionEnd ;-------------------------------- ;Installer Sections Section "Grafx2" SecProgram SectionIn RO SetOutPath "$INSTDIR" ;ADD YOUR OWN FILES HERE... File ..\src-2.3.1771.tgz SetOutPath "$INSTDIR\bin" File ..\bin\grafx2.exe File ..\bin\SDL_image.dll File ..\bin\SDL.dll File ..\bin\libfreetype-6.dll File ..\bin\SDL_ttf.dll File ..\bin\zlib1.dll File ..\bin\libpng14-14.dll SetOutPath "$INSTDIR\share\grafx2" File ..\share\grafx2\gfx2.gif File ..\share\grafx2\gfx2def.ini SetOutPath "$INSTDIR\share\grafx2\skins" File ..\share\grafx2\skins\font_Classic.png File ..\share\grafx2\skins\font_DPaint.png File ..\share\grafx2\skins\font_Fairlight.png File ..\share\grafx2\skins\font_Fun.png File ..\share\grafx2\skins\font_Melon.png File ..\share\grafx2\skins\font_Seen.png File ..\share\grafx2\skins\skin_Aurora.png File ..\share\grafx2\skins\skin_classic.png File ..\share\grafx2\skins\skin_DPaint.png File ..\share\grafx2\skins\skin_modern.png File ..\share\grafx2\skins\skin_scenish.png SetOutPath "$INSTDIR\share\grafx2\scripts\samples_2.3\brush" File ..\share\grafx2\scripts\samples_2.3\brush\ApplyColor.lua File ..\share\grafx2\scripts\samples_2.3\brush\Fisheye.lua File ..\share\grafx2\scripts\samples_2.3\brush\GrayscaleAvg.lua File ..\share\grafx2\scripts\samples_2.3\brush\GrayscaleDesat.lua File ..\share\grafx2\scripts\samples_2.3\brush\Halfsmooth.lua File ..\share\grafx2\scripts\samples_2.3\brush\Waves.lua SetOutPath "$INSTDIR\share\grafx2\scripts\samples_2.3\demo" File ..\share\grafx2\scripts\samples_2.3\demo\3DPalette.lua File ..\share\grafx2\scripts\samples_2.3\demo\Ellipse.lua File ..\share\grafx2\scripts\samples_2.3\demo\FlipPicture.lua File ..\share\grafx2\scripts\samples_2.3\demo\SierpinskyCarpet.lua File ..\share\grafx2\scripts\samples_2.3\demo\SierpinskyTriangle.lua File ..\share\grafx2\scripts\samples_2.3\demo\Spritesheet.lua SetOutPath "$INSTDIR\share\grafx2\scripts\samples_2.3\demo\brush" File ..\share\grafx2\scripts\samples_2.3\demo\brush\Amigaball.lua File ..\share\grafx2\scripts\samples_2.3\demo\brush\ColorSphere.lua File ..\share\grafx2\scripts\samples_2.3\demo\brush\FindAA.lua File ..\share\grafx2\scripts\samples_2.3\demo\brush\Mandelbrot.lua SetOutPath "$INSTDIR\share\grafx2\scripts\samples_2.3\libs" File ..\share\grafx2\scripts\samples_2.3\libs\dawnbringer_lib.lua File ..\share\grafx2\scripts\samples_2.3\libs\memory.lua SetOutPath "$INSTDIR\share\grafx2\scripts\samples_2.3\palette" File ..\share\grafx2\scripts\samples_2.3\palette\Desaturate.lua File ..\share\grafx2\scripts\samples_2.3\palette\ExpandColors.lua File ..\share\grafx2\scripts\samples_2.3\palette\FillColorCube.lua File ..\share\grafx2\scripts\samples_2.3\palette\InvertedRGB.lua File ..\share\grafx2\scripts\samples_2.3\palette\Set3bit.lua File ..\share\grafx2\scripts\samples_2.3\palette\Set6bit.lua File ..\share\grafx2\scripts\samples_2.3\palette\SetC64Palette.lua File ..\share\grafx2\scripts\samples_2.3\palette\ShiftHue.lua SetOutPath "$INSTDIR\share\grafx2\scripts\samples_2.3\picture" File ..\share\grafx2\scripts\samples_2.3\picture\CellColourReducer.lua File ..\share\grafx2\scripts\samples_2.3\picture\DrawGridIsometric.lua File ..\share\grafx2\scripts\samples_2.3\picture\DrawgridOrthogonal_Index.lua File ..\share\grafx2\scripts\samples_2.3\picture\DrawGridOrthogonal_RGB.lua File ..\share\grafx2\scripts\samples_2.3\picture\GlassGridFilter.lua File ..\share\grafx2\scripts\samples_2.3\picture\PaletteToPicture.lua File ..\share\grafx2\scripts\samples_2.3\picture\Pic2isometric.lua File ..\share\grafx2\scripts\samples_2.3\picture\Rainbow-Dark2Bright.lua File ..\share\grafx2\scripts\samples_2.3\picture\RemapImage2RGB.lua File ..\share\grafx2\scripts\samples_2.3\picture\RemapImage2RGB_ed.lua File ..\share\grafx2\scripts\samples_2.3\picture\RemapImageTo3bitPal.lua File ..\share\grafx2\scripts\samples_2.3\picture\XBitColourXpaceFromPalette.lua SetOutPath "$INSTDIR\doc" File ..\doc\README.txt File ..\doc\COMPILING.txt File ..\doc\README-SDL_ttf.txt File ..\doc\README-SDL.txt File ..\doc\README-SDL_image.txt File ..\doc\README-zlib1.txt File ..\doc\README-lua.txt File ..\doc\gpl-2.0.txt SetOutPath "$INSTDIR\share\grafx2\fonts" File ..\share\grafx2\fonts\8pxfont.png File ..\share\grafx2\fonts\Tuffy.ttf File ..\share\grafx2\fonts\PF_Arma_5__.png File ..\share\grafx2\fonts\PF_Easta_7_.png File ..\share\grafx2\fonts\PF_Easta_7__.png File ..\share\grafx2\fonts\PF_Ronda_7__.png File ..\share\grafx2\fonts\PF_Tempesta_5.png File ..\share\grafx2\fonts\PF_Tempesta_5_.png File ..\share\grafx2\fonts\PF_Tempesta_5__.png File ..\share\grafx2\fonts\PF_Tempesta_5___.png File ..\share\grafx2\fonts\PF_Tempesta_7.png File ..\share\grafx2\fonts\PF_Tempesta_7_.png File ..\share\grafx2\fonts\PF_Tempesta_7__.png File ..\share\grafx2\fonts\PF_Tempesta_7___.png File ..\share\grafx2\fonts\PF_Westa_7_.png File ..\share\grafx2\fonts\PF_Westa_7__.png ; Register in Add/Remove programs WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "DisplayName" "GrafX2 (GNU GPL)" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "UninstallString" "$INSTDIR\uninstall.exe" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "InstalledProductName" "GrafX2" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "InstalledLocation" $INSTDIR WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "DisplayIcon" "$INSTDIR\gfx2.ico" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "URLInfoAbout" "http://grafx2.org" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "DisplayVersion" "2.3.1771" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "NoModify" 1 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "NoRepair" 1 ;Store installation folder WriteRegStr HKLM "Software\Grafx2" "" $INSTDIR ;Create uninstaller WriteUninstaller "$INSTDIR\Uninstall.exe" SectionEnd Section "Desktop shortcut" SecShortcut SetOutPath "$INSTDIR" CreateShortCut "$DESKTOP\Grafx2.lnk" "$INSTDIR\bin\grafx2.exe" "" "" "" SW_SHOWNORMAL SectionEnd ;-------------------------------- ;Descriptions ;Language strings LangString DESC_SecProgram ${LANG_ENGLISH} "Grafx2 application and runtime data." LangString DESC_SecShortcut ${LANG_ENGLISH} "Desktop shortcut." ;Assign language strings to sections !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${SecProgram} $(DESC_SecProgram) !insertmacro MUI_DESCRIPTION_TEXT ${SecShortcut} $(DESC_SecShortcut) !insertmacro MUI_FUNCTION_DESCRIPTION_END ;-------------------------------- ;Uninstaller Section Section "un.SecProgram" ;ADD YOUR OWN FILES HERE... Delete "$INSTDIR\bin\grafx2.exe" Delete "$INSTDIR\src-2.3.1771.tgz" Delete "$INSTDIR\share\grafx2\gfx2.gif" Delete "$INSTDIR\share\grafx2\gfx2def.ini" Delete "$INSTDIR\bin\SDL_image.dll" Delete "$INSTDIR\bin\SDL.dll" Delete "$INSTDIR\bin\libfreetype-6.dll" Delete "$INSTDIR\bin\SDL_ttf.dll" Delete "$INSTDIR\bin\zlib1.dll" Delete "$INSTDIR\bin\libpng14-14.dll" Delete "$INSTDIR\bin\stdout.txt" Delete "$INSTDIR\bin\stderr.txt" RMDir "$INSTDIR\bin" Delete "$INSTDIR\doc\README.txt" Delete "$INSTDIR\doc\COMPILING.txt" Delete "$INSTDIR\doc\README-SDL_ttf.txt" Delete "$INSTDIR\doc\README-SDL.txt" Delete "$INSTDIR\doc\README-SDL_image.txt" Delete "$INSTDIR\doc\README-zlib1.txt" Delete "$INSTDIR\doc\README-lua.txt" Delete "$INSTDIR\doc\gpl-2.0.txt" RMDir "$INSTDIR\doc" Delete "$INSTDIR\share\grafx2\fonts\8pxfont.png" Delete "$INSTDIR\share\grafx2\fonts\Tuffy.ttf" Delete "$INSTDIR\share\grafx2\fonts\PF_Arma_5__.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Easta_7_.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Easta_7__.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Ronda_7__.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_5.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_5_.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_5__.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_5___.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_7.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_7_.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_7__.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_7___.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Westa_7_.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Westa_7__.png" RMDir "$INSTDIR\share\grafx2\fonts" Delete "$INSTDIR\share\grafx2\skins\font_Classic.png" Delete "$INSTDIR\share\grafx2\skins\font_Fun.png" Delete "$INSTDIR\share\grafx2\skins\font_Fairlight.png" Delete "$INSTDIR\share\grafx2\skins\font_Melon.png" Delete "$INSTDIR\share\grafx2\skins\font_DPaint.png" Delete "$INSTDIR\share\grafx2\skins\font_Seen.png" Delete "$INSTDIR\share\grafx2\skins\skin_classic.png" Delete "$INSTDIR\share\grafx2\skins\skin_Aurora.png" Delete "$INSTDIR\share\grafx2\skins\skin_modern.png" Delete "$INSTDIR\share\grafx2\skins\skin_DPaint.png" Delete "$INSTDIR\share\grafx2\skins\skin_scenish.png" RMDir "$INSTDIR\share\grafx2\skins" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\brush\ApplyColor.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\brush\Fisheye.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\brush\GrayscaleAvg.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\brush\GrayscaleDesat.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\brush\Halfsmooth.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\brush\Waves.lua" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.3\brush" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\demo\brush\Amigaball.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\demo\brush\ColorSphere.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\demo\brush\FindAA.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\demo\brush\Mandelbrot.lua" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.3\demo\brush" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\demo\3DPalette.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\demo\Ellipse.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\demo\FlipPicture.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\demo\SierpinskyCarpet.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\demo\SierpinskyTriangle.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\demo\Spritesheet.lua" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.3\demo" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\libs\dawnbringer_lib.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\libs\memory.lua" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.3\libs" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\palette\Desaturate.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\palette\ExpandColors.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\palette\FillColorCube.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\palette\InvertedRGB.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\palette\Set3bit.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\palette\Set6bit.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\palette\SetC64Palette.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\palette\ShiftHue.lua" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.3\palette" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\picture\CellColourReducer.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\picture\DrawGridIsometric.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\picture\DrawgridOrthogonal_Index.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\picture\DrawGridOrthogonal_RGB.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\picture\GlassGridFilter.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\picture\PaletteToPicture.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\picture\Pic2isometric.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\picture\Rainbow-Dark2Bright.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\picture\RemapImage2RGB.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\picture\RemapImage2RGB_ed.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\picture\RemapImageTo3bitPal.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.3\picture\XBitColourXpaceFromPalette.lua" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.3\picture" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.3" RMDir "$INSTDIR\share\grafx2\scripts" RMDir "$INSTDIR\share\grafx2" RMDir "$INSTDIR\share" Delete "$INSTDIR\Uninstall.exe" MessageBox MB_YESNO|MB_DEFBUTTON2|MB_ICONQUESTION "Do you wish to keep your configuration settings ?" IDYES keepconfig IDNO deleteconfig deleteconfig: Delete "$INSTDIR\gfx2.cfg" Delete "$INSTDIR\gfx2.ini" Delete "$APPDATA\Grafx2\gfx2.cfg" Delete "$APPDATA\Grafx2\gfx2.ini" RMDir "$APPDATA\Grafx2" keepconfig: RMDir "$INSTDIR" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" DeleteRegKey /ifempty HKLM "Software\Grafx2" SectionEnd Section "un.SecShortcut" Delete "$DESKTOP\Grafx2.lnk" SectionEnd grafx2_2.4+git20180105/install/WinInstaller.nsi0000664000000000000000000003715513223665306017547 0ustar rootroot;NSIS Modern User Interface ;Based on the Example Script written by Joost Verburg ;-------------------------------- ;Include Modern UI !include "MUI2.nsh" ;-------------------------------- ;General ;Name and file Name "Grafx2" OutFile "grafx2-2.4.2023.win32.exe" ;Default installation folder InstallDir "$PROGRAMFILES\Grafx2" !define MULTIUSER_INSTALLMODE_INSTDIR "Grafx2" ;Get installation folder from registry if available InstallDirRegKey HKCU "Software\Grafx2" "" ;Request application privileges for Windows Vista RequestExecutionLevel user ;-------------------------------- ;Interface Settings !define MUI_ABORTWARNING ;-------------------------------- ;Pages !define MUI_WELCOMEFINISHPAGE_BITMAP vector.bmp !define MUI_WELCOMEFINISHPAGE_BITMAP_NOSTRETCH !insertmacro MUI_PAGE_WELCOME !define MULTIUSER_EXECUTIONLEVEL Highest !define MULTIUSER_MUI !define MULTIUSER_INSTALLMODE_COMMANDLINE ;!define MUI_HEADERIMAGE_BITMAP logo_scenish.bmp ;!define MUI_HEADERIMAGE_BITMAP_NOSTRETCH !insertmacro MUI_PAGE_LICENSE "..\doc\gpl-2.0.txt" !include MultiUser.nsh !insertmacro MULTIUSER_PAGE_INSTALLMODE !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ;-------------------------------- ;Languages !insertmacro MUI_LANGUAGE "English" ;-------------------------------- ;Functions Function .onInit !insertmacro MULTIUSER_INIT FunctionEnd Function un.onInit !insertmacro MULTIUSER_UNINIT FunctionEnd Function .onInstSuccess MessageBox MB_YESNO "Run GrafX2 now ?" IDNO norun Exec $INSTDIR\bin\grafx2.exe norun: FunctionEnd ;-------------------------------- ;Installer Sections Section "Grafx2" SecProgram SectionIn RO SetOutPath "$INSTDIR" ;ADD YOUR OWN FILES HERE... File ..\src-2.4wip2023.tgz SetOutPath "$INSTDIR\bin" File ..\bin\grafx2.exe File ..\bin\SDL_image.dll File ..\bin\SDL.dll File ..\bin\libfreetype-6.dll File ..\bin\SDL_ttf.dll File ..\bin\zlib1.dll File ..\bin\libpng14-14.dll SetOutPath "$INSTDIR\share\grafx2" File ..\share\grafx2\gfx2.gif File ..\share\grafx2\gfx2def.ini SetOutPath "$INSTDIR\share\grafx2\skins" File ..\share\grafx2\skins\font_Classic.png File ..\share\grafx2\skins\font_DPaint.png File ..\share\grafx2\skins\font_Fairlight.png File ..\share\grafx2\skins\font_Fun.png File ..\share\grafx2\skins\font_Melon.png File ..\share\grafx2\skins\font_Seen.png File ..\share\grafx2\skins\skin_Aurora.png File ..\share\grafx2\skins\skin_classic.png File ..\share\grafx2\skins\skin_DPaint.png File ..\share\grafx2\skins\skin_modern.png File ..\share\grafx2\skins\skin_scenish.png SetOutPath "$INSTDIR\share\grafx2\scripts\samples_2.4\brush" File ..\share\grafx2\scripts\samples_2.4\brush\ApplyColor.lua File ..\share\grafx2\scripts\samples_2.4\brush\Fisheye.lua File ..\share\grafx2\scripts\samples_2.4\brush\GrayscaleAvg.lua File ..\share\grafx2\scripts\samples_2.4\brush\GrayscaleDesat.lua File ..\share\grafx2\scripts\samples_2.4\brush\Halfsmooth.lua File ..\share\grafx2\scripts\samples_2.4\brush\Waves.lua SetOutPath "$INSTDIR\share\grafx2\scripts\samples_2.4\demo" File ..\share\grafx2\scripts\samples_2.4\demo\3DPalette.lua File ..\share\grafx2\scripts\samples_2.4\demo\Ellipse.lua File ..\share\grafx2\scripts\samples_2.4\demo\FlipPicture.lua File ..\share\grafx2\scripts\samples_2.4\demo\SierpinskyCarpet.lua File ..\share\grafx2\scripts\samples_2.4\demo\SierpinskyTriangle.lua File ..\share\grafx2\scripts\samples_2.4\demo\Spritesheet.lua SetOutPath "$INSTDIR\share\grafx2\scripts\samples_2.4\demo\brush" File ..\share\grafx2\scripts\samples_2.4\demo\brush\Amigaball.lua File ..\share\grafx2\scripts\samples_2.4\demo\brush\ColorSphere.lua File ..\share\grafx2\scripts\samples_2.4\demo\brush\FindAA.lua File ..\share\grafx2\scripts\samples_2.4\demo\brush\Mandelbrot.lua SetOutPath "$INSTDIR\share\grafx2\scripts\samples_2.4\libs" File ..\share\grafx2\scripts\samples_2.4\libs\dawnbringer_lib.lua File ..\share\grafx2\scripts\samples_2.4\libs\memory.lua SetOutPath "$INSTDIR\share\grafx2\scripts\samples_2.4\palette" File ..\share\grafx2\scripts\samples_2.4\palette\Desaturate.lua File ..\share\grafx2\scripts\samples_2.4\palette\ExpandColors.lua File ..\share\grafx2\scripts\samples_2.4\palette\FillColorCube.lua File ..\share\grafx2\scripts\samples_2.4\palette\InvertedRGB.lua File ..\share\grafx2\scripts\samples_2.4\palette\Set3bit.lua File ..\share\grafx2\scripts\samples_2.4\palette\Set6bit.lua File ..\share\grafx2\scripts\samples_2.4\palette\SetC64Palette.lua File ..\share\grafx2\scripts\samples_2.4\palette\ShiftHue.lua SetOutPath "$INSTDIR\share\grafx2\scripts\samples_2.4\picture" File ..\share\grafx2\scripts\samples_2.4\picture\CellColourReducer.lua File ..\share\grafx2\scripts\samples_2.4\picture\DrawGridIsometric.lua File ..\share\grafx2\scripts\samples_2.4\picture\DrawgridOrthogonal_Index.lua File ..\share\grafx2\scripts\samples_2.4\picture\DrawGridOrthogonal_RGB.lua File ..\share\grafx2\scripts\samples_2.4\picture\GlassGridFilter.lua File ..\share\grafx2\scripts\samples_2.4\picture\PaletteToPicture.lua File ..\share\grafx2\scripts\samples_2.4\picture\Pic2isometric.lua File ..\share\grafx2\scripts\samples_2.4\picture\Rainbow-Dark2Bright.lua File ..\share\grafx2\scripts\samples_2.4\picture\RemapImage2RGB.lua File ..\share\grafx2\scripts\samples_2.4\picture\RemapImage2RGB_ed.lua File ..\share\grafx2\scripts\samples_2.4\picture\RemapImageTo3bitPal.lua File ..\share\grafx2\scripts\samples_2.4\Tiler.lua File ..\share\grafx2\scripts\samples_2.4\picture\XBitColourXpaceFromPalette.lua SetOutPath "$INSTDIR\doc" File ..\doc\COMPILING.txt File ..\doc\PF_fonts.txt File ..\doc\README-SDL.txt File ..\doc\README-SDL_image.txt File ..\doc\README-SDL_ttf.txt File ..\doc\README-lua.txt File ..\doc\README-zlib1.txt File ..\doc\README.txt File ..\doc\gpl-2.0.txt SetOutPath "$INSTDIR\share\grafx2\fonts" File ..\share\grafx2\fonts\8pxfont.png File ..\share\grafx2\fonts\Tuffy.ttf File ..\share\grafx2\fonts\PF_Arma_5__.png File ..\share\grafx2\fonts\PF_Easta_7_.png File ..\share\grafx2\fonts\PF_Easta_7__.png File ..\share\grafx2\fonts\PF_Ronda_7__.png File ..\share\grafx2\fonts\PF_Tempesta_5.png File ..\share\grafx2\fonts\PF_Tempesta_5_.png File ..\share\grafx2\fonts\PF_Tempesta_5__.png File ..\share\grafx2\fonts\PF_Tempesta_5___.png File ..\share\grafx2\fonts\PF_Tempesta_7.png File ..\share\grafx2\fonts\PF_Tempesta_7_.png File ..\share\grafx2\fonts\PF_Tempesta_7__.png File ..\share\grafx2\fonts\PF_Tempesta_7___.png File ..\share\grafx2\fonts\PF_Westa_7_.png File ..\share\grafx2\fonts\PF_Westa_7__.png ; Register in Add/Remove programs WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "DisplayName" "GrafX2 (GNU GPL)" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "UninstallString" "$INSTDIR\uninstall.exe" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "InstalledProductName" "GrafX2" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "InstalledLocation" $INSTDIR WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "DisplayIcon" "$INSTDIR\gfx2.ico" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "URLInfoAbout" "http://grafx2.org" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "DisplayVersion" "2.4.wip2023" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "NoModify" 1 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "NoRepair" 1 ;Store installation folder WriteRegStr HKLM "Software\Grafx2" "" $INSTDIR ;Create uninstaller WriteUninstaller "$INSTDIR\Uninstall.exe" SectionEnd Section "Desktop shortcut" SecShortcut SetOutPath "$INSTDIR" CreateShortCut "$DESKTOP\Grafx2.lnk" "$INSTDIR\bin\grafx2.exe" "" "" "" SW_SHOWNORMAL SectionEnd ;-------------------------------- ;Descriptions ;Language strings LangString DESC_SecProgram ${LANG_ENGLISH} "Grafx2 application and runtime data." LangString DESC_SecShortcut ${LANG_ENGLISH} "Desktop shortcut." ;Assign language strings to sections !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${SecProgram} $(DESC_SecProgram) !insertmacro MUI_DESCRIPTION_TEXT ${SecShortcut} $(DESC_SecShortcut) !insertmacro MUI_FUNCTION_DESCRIPTION_END ;-------------------------------- ;Uninstaller Section Section "un.SecProgram" ;ADD YOUR OWN FILES HERE... Delete "$INSTDIR\bin\grafx2.exe" Delete "$INSTDIR\src-2.4.wip2023.tgz" Delete "$INSTDIR\share\grafx2\gfx2.gif" Delete "$INSTDIR\share\grafx2\gfx2def.ini" Delete "$INSTDIR\bin\SDL_image.dll" Delete "$INSTDIR\bin\SDL.dll" Delete "$INSTDIR\bin\libfreetype-6.dll" Delete "$INSTDIR\bin\SDL_ttf.dll" Delete "$INSTDIR\bin\zlib1.dll" Delete "$INSTDIR\bin\libpng14-14.dll" Delete "$INSTDIR\bin\stdout.txt" Delete "$INSTDIR\bin\stderr.txt" RMDir "$INSTDIR\bin" Delete "$INSTDIR\doc\COMPILING.txt" Delete "$INSTDIR\doc\PF_fonts.txt" Delete "$INSTDIR\doc\README-SDL.txt" Delete "$INSTDIR\doc\README-SDL_image.txt" Delete "$INSTDIR\doc\README-SDL_ttf.txt" Delete "$INSTDIR\doc\README-lua.txt" Delete "$INSTDIR\doc\README-zlib1.txt" Delete "$INSTDIR\doc\README.txt" Delete "$INSTDIR\doc\gpl-2.0.txt" RMDir "$INSTDIR\doc" Delete "$INSTDIR\share\grafx2\fonts\8pxfont.png" Delete "$INSTDIR\share\grafx2\fonts\Tuffy.ttf" Delete "$INSTDIR\share\grafx2\fonts\PF_Arma_5__.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Easta_7_.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Easta_7__.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Ronda_7__.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_5.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_5_.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_5__.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_5___.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_7.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_7_.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_7__.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Tempesta_7___.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Westa_7_.png" Delete "$INSTDIR\share\grafx2\fonts\PF_Westa_7__.png" RMDir "$INSTDIR\share\grafx2\fonts" Delete "$INSTDIR\share\grafx2\skins\font_Classic.png" Delete "$INSTDIR\share\grafx2\skins\font_Fun.png" Delete "$INSTDIR\share\grafx2\skins\font_Fairlight.png" Delete "$INSTDIR\share\grafx2\skins\font_Melon.png" Delete "$INSTDIR\share\grafx2\skins\font_DPaint.png" Delete "$INSTDIR\share\grafx2\skins\font_Seen.png" Delete "$INSTDIR\share\grafx2\skins\skin_classic.png" Delete "$INSTDIR\share\grafx2\skins\skin_Aurora.png" Delete "$INSTDIR\share\grafx2\skins\skin_modern.png" Delete "$INSTDIR\share\grafx2\skins\skin_DPaint.png" Delete "$INSTDIR\share\grafx2\skins\skin_scenish.png" RMDir "$INSTDIR\share\grafx2\skins" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\brush\ApplyColor.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\brush\Fisheye.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\brush\GrayscaleAvg.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\brush\GrayscaleDesat.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\brush\Halfsmooth.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\brush\Waves.lua" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.4\brush" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\demo\brush\Amigaball.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\demo\brush\ColorSphere.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\demo\brush\FindAA.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\demo\brush\Mandelbrot.lua" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.4\demo\brush" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\demo\3DPalette.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\demo\Ellipse.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\demo\FlipPicture.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\demo\SierpinskyCarpet.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\demo\SierpinskyTriangle.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\demo\Spritesheet.lua" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.4\demo" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\libs\dawnbringer_lib.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\libs\memory.lua" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.4\libs" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\palette\Desaturate.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\palette\ExpandColors.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\palette\FillColorCube.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\palette\InvertedRGB.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\palette\Set3bit.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\palette\Set6bit.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\palette\SetC64Palette.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\palette\ShiftHue.lua" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.4\palette" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\picture\CellColourReducer.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\picture\DrawGridIsometric.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\picture\DrawgridOrthogonal_Index.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\picture\DrawGridOrthogonal_RGB.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\picture\GlassGridFilter.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\picture\PaletteToPicture.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\picture\Pic2isometric.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\picture\Rainbow-Dark2Bright.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\picture\RemapImage2RGB.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\picture\RemapImage2RGB_ed.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\picture\RemapImageTo3bitPal.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\picture\Tiler.lua" Delete "$INSTDIR\share\grafx2\scripts\samples_2.4\picture\XBitColourXpaceFromPalette.lua" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.4\picture" RMDir "$INSTDIR\share\grafx2\scripts\samples_2.4" RMDir "$INSTDIR\share\grafx2\scripts" RMDir "$INSTDIR\share\grafx2" RMDir "$INSTDIR\share" Delete "$INSTDIR\Uninstall.exe" MessageBox MB_YESNO|MB_DEFBUTTON2|MB_ICONQUESTION "Do you wish to keep your configuration settings ?" IDYES keepconfig IDNO deleteconfig deleteconfig: Delete "$INSTDIR\gfx2.cfg" Delete "$INSTDIR\gfx2.ini" Delete "$APPDATA\Grafx2\gfx2.cfg" Delete "$APPDATA\Grafx2\gfx2.ini" RMDir "$APPDATA\Grafx2" keepconfig: RMDir "$INSTDIR" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" DeleteRegKey /ifempty HKLM "Software\Grafx2" SectionEnd Section "un.SecShortcut" Delete "$DESKTOP\Grafx2.lnk" SectionEnd grafx2_2.4+git20180105/install/vector.bmp0000664000000000000000000045566013223665306016430 0ustar rootrootBM[6(:  QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJRQQRQQJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJQQQJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJQQQQQQJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJQQQJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJQQQQQQJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJQQQJJJJJJJJJJJJfKsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqdbNJNJJJJJJJJJQQQQQQJJJJJJJJJNJNdcsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJcJsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqtpsmd^NJMJJJJJJJJJQQQQQQJJJJJJJJJNJNdcsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJcJsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqspsmtiugg#ZNJMJJJJJJJJJQQQQQQJJJJJJJJJNJNdcsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJcJsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqspsntiugvewdk'XNKMJJJJJJJJJQQQQQQJJJJJJJJJNJNdcsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJcJsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqspsnukugvewdy!bz$^l+TNKLJJJJJJJJJQQQQQQJJJJJJJJJNJNdcsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJcJsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqspsnukuhvewdy!bz$^z#[z#Vk(MNKLJJJJJJJJJQQQQQQJJJJJJJJJNJNdcsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJcJsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqspsnukuhvewdy!bz%^z#[z#Vz#Sy#Oi(FNKLJJJJJJJJJQQQQQQJJJJJJJJJNJNdcsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJmIsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsnukuhwfwdy!bz%^z#[z#Vz#Sz$Qz$Kz$Gk'@NKLJJJJJJJJJQQQQQQJJJJJJJJJNJNdcsqsqsqsqsqsqsqsqsqsqsqsqsqsq/sqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJcbb`__]]][[[[ZXXXWWWUUTT8:z%`z#[z%Wz$Sz$Qz$Lz$G|#D|$Bk():*8*4*2+1,/,*-*s*%OKKJJJJJJJJJQQQQQQJJJJJJJJJRKI2==<;;:999886655x,,+++)))(''%sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJfeeccccbb`__^NȰp;UUT=)*8+5+3,1-/-+/*0(/%v,"QKKJJJJJJJJJQQQQQQJJJJJJJJJRKI3>===<;;:99988665|,,+++)))(''sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJffeeccccbb`z<êd*UT@%+3-1-/-+0*0(0%2$2"x,QKKJJJJJJJJJQQQQQQJJJJJJJJJRKI3@>>===<;;:9999866區,,+++)))('sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJfffeeccccb`wDUTA#//0,0*0(1%3$3"4!6!}/QKKJJJJJJJJJQQQQQQJJJJJJJJJRKI4BA@>>===<;;::99986擅,,+++)))(sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJgfffeeccc~_UTB"1*1(2%3$4"5!5!56~-QLKJJJJJJJJJQQQQQQJJJJJJJJJRKI5CCBA@>>===<;;::9998薉,,+++)))sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJhgfffeec\~Fc][b SxEUTB 2%4$4"5!6!689:1QLJJJJJJJJJJQQQQQQJJJJJJJJJRKI5CCCCBA@>>===<<;::999ꚍ,,+++))sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJhhgfffey4f _^]]][[[h+ι[UTC5"5!6!88::;=1RLJJJJJJJJJJQQQQQQJJJJJJJJJRKI6DCCCCCBA@>>===<<;::99랑,,+++)sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJihhgfffγgb``_^]]][[[[UUTE8!99;;<=>@3RLJJJJJJJJJJJJJJJJJJJJJJJJJRKI8EEDCCCCCBA@>>===<<;::9좗,,+++sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJkihhgf@nccb``_^]]][[[X`$UUTF9<<<@@@@B3RLJJJJJJJJJJJJJJJJJJJRKI9FFEEDCCCCCBA@@>===<<;::줙,,++sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJkkihhg̭Ŧccccb``_^]]][[[[WUUTG=>>AAACCC6RKIJJJJJJJJJJJJRKI9IGGFEEDCCCCCBA@@>===<<;:5﫜,,+sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJlkkihkp(cccccb``_^]]][[[yAWWUUTKAAABDDEEF9RKIJJJJJJRKI:JJIGGFEEDCCCCCBA@@>===<<;55-,sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJmlkkiRȨfecccccb``_^]]][[[e*WW_$UTKBCDEFGIIJ;RKIRKI;KJJJIGGFEEDCCCCCBA@@>===<<655-sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJmmlkkcffecccccb``_^]]][[\d)`UTLEFFJIKLKM<<MLLJJJIGGFEEDCCCCCBA@@>===<6655럐tssqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJmmmlkĠ>fffecccccb``_^]]][f`UTLJKJLMLNNNNNMLLJJJIGGFEKZ0CCCCBA@@>===88655잍EsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJmmmmlҳu*gfffecccccb``_^]]]Z[UTOLLMNNOONNNNMLLJJJIGGI[2CCCCBA@@>==988655뙉q^sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJnmmmm̫|4ggfffecccccb`bKf"]]\WUUTOONQRQOOONNNMLLJJJIG[2CCCCBB@@>=9988655畂n[/sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJonmmmKhggfffecccccb¢n+]z] WWUUTSSSRRQOOONNNMLLJJJu]4CCCCBB@@>99988655nX11sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJoonmmsihggfffecccc¢n+̱_ XWW|JuBUTTTSRRQOOONNNMLLKT#^6CCCCBB@@:99988655zlU221sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJpoonmz,iihggfffecc|<` XXXv`UTTTSRRQOOONNNMLLKCCCCBB@;:99988655ugR4322sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJpoonmXiihggfffecdb [ZXv^UTTTSRRQOOONNNML_DDCCCCBB;;:9998865554432sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJpoon}u(iihggfffeck c![[[vUUUTTSRRQOOONNNe8mFEDDCCCCB<;;:999886555443sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJpoosmiihggfffeek e!]][vcWUUUTTSRRQOOONNʹGFFEDDCCCC=<;;:99988655544sqsqsqsqsqsqsqdcJJJJJJJJJQQQJJJKJJJJJJJJTTJpoovmiihggfffeek f!^]]vhWWWUUUTTSRRQQOONwQIGFFEDDCCC==<;;:9998865555sqsqsqsqsqsqdcNJNJJJJJJKJJQQQRRQJJJJJJJJJTSJżpoqٽmiihggfffeek g!__^vhXXWWWUUUTTSRRQQOO`3GIGFFEDDCC===<;;:999886555sqsqsqsqsqdcNJNJJJJJJJJJRQQQQQJJJJJJJJJTSJŹpov!miihhgfffeeih!b`_vhXXXXWZh1c(UUTTSSRQQOμe8JGIGFFEDDC>===<;;:99988665sqsqsqsqdcNJNJJJJJJJJJQQQQQQJJJJJJJJJTSJĵpp2miihhgfffeegTfcbbvƬvè`UUTTSSRQQ\JJGIGFFEDF>>===<;;:9998866sqsqsqdcNJNJJJJJJJJJQQQQQQJJJJJJJJJTSKıpp2mkihhgfffeeccccw`UUTTSSRQxKJJGIGFFEu@>>===<;;:999986sqsqdcNJNJJJJJJJJJQQQQQQJJJJJJJJJTSKŭpp2mkihhgfffeeccb`UUTTSSRc/KJJGIGFkCA@>>===<;;::9998sqdcNJNJJJJJJJJJQQQQQQJJJJJJJJJTSKŪpp2mkihhgfffeec`UUTTSSRZ(JJGJpb>===<;;::999dcNJNJJJJJJJJJQQQQQQJJJJJJJJJTRKæpp2mkihhgfffeek `UUTTSS}˹CCBA@>>===<<;::9-NJNJJJJJJJJJQQQQQQJJJJJJJJJTRKápp2mkihhgfffeek sTx=c![[[z`UUTTSVvTCCCBA@>>===<<;:/RJIJJJJJJJJJQQQQQQJJJJJJJJJTRKÞpp2mkihhgfffeek __^]]][[[z`UUTTS[ŵCCCCCBA@>>===<<0RJIJJJJJJJJJQQQQQQJJJJJJJJJTRKšpp2mkihhgfffeei`_^]]][[[z`UUTTSN DCCCCCBA@@>===1RKIJJJJJJJJJQQQQQQJJJJJJJJJTRK—pp2mkihhgfffeen%q1`_^]]][[[zp9UUTTSV*EEDCCCCCBA@@>=2RKIJJJJJJJJJQQQQQQJJJJJJJJJTRKpp2mkihhgffffeo``_^]]][[k2WUUTTSMGFEEDCCCCCBA@@2RKIJJJJJJJJJQQQQQQJJJJJJJJJTRK pp2mkihhggfffVb``_^]]]RWWWUUTTSªvNJIGGFEEDCCCCCBA2RKIJJJJJJJJJQQQQQQJJJJJJJJJTRKŽ!pp2mkihhggff[cb``_^]RXXWWWUUTTTtBd0vMLJJJIGGFEEDCCCCC4RKIJJJJJJJJJQQQQQQJJJJJJJJJTRKŠ!}pp2mkiihggfdccb``_QZXXXWWWUUTTTSRRQO\'RNNNMLLJJJIGGFEEDCCC5RKIJJJJJJJJJQQQQQQJJJJJJJJJTRKyqp2mkiihg>n%cccb`Q[XZXXXWWWUUTTTSRRQOONNNNMLLJJJIGGFEEDC5RKIJJJJJJJJJQQQQQQJJJJJJJJJTRK~xqp2|1kiiSԹcccccQ[[[XZXXXWWWUUTTTSRRQOOONNNMLLJJJIGGFEE6RKIJJJJJJJJJQQQQQQJJJJJJJJJTRKy~yvqp2BecccQ]][[[XZXXXWs=s=UUTTTSRRQOOONNNMLLJJJGGGF8RKIJJJJJJJJJQQQQQQJJJJJJJJJSOJtzxtqqp2ffecf_]]][[[XZXX``UUTTTSRRQOOONNNMLLKJJGG9RKIJJJJJJJJJQQQQQQJJJJJJJJJSOJp}xutsqqp1˪ifffn+_]]][[[XZ__UUTTTSRRQOOONNNMLLKJJ9RKIJJJJJJJJJQQQQQQJJJJJJJJJSOJl~zwtttsqqpw"ɢxhggfn+_]]][[[__UUTTTSRRQOOONNNMLLK:RKIJJJJJJJJJQQQQQQJJJJJJJJJSNJf|xvvtttsqqpo3wo iihgn+_]]]]__UUUTTSRRQOOONNNML;RLIJJJJJJJJJQQQQQQJJJJJJJJJSNJcwwvvvtttsqqpoonmmmmllkiipZn+_]]__UUUTTSRRQOOONNN<RKIJJJJJJJJJQQQJJJJJJJJJJJJSNJ^wwvvvtttsqqpoonmmmmllkx,Rek n+_`_UUUTTSRRQQOON<RKIJJJJJJJJJJJJJJJJJJJJJJJJSNJ^wwwvvvtttsqqpoonnmmmllœRffek wzz_UUUTTSRRQQOO=RKIJJJJJJJJJJJJQQQJJJJJJJJJSMJ^xxwwwvvvtttsqqpoonnmmmnZgfffek z[[zVUUUTTSSRQQON<RKIJJJJJJJJJQQQQQQJJJJJJJJJSNJ_zyxxwwwvvvtttsqqpponnmmNΰhhgfffek z]][bWUUUTTSSRQQML9RKIJJJJJJJJJQQQQQQJJJJJJJJJTNJ`|zzyxxwwwvvvtttssqpponnmtpihhgfffei|^]]cf+WWUUUTTSSRNMLI8RLJJJJJJJJJJQQQQQQJJJJJJJJJTNJb~||zzyxxwwwvvvtttssqpponnzekihhgfffekz__^dg+XWWWWUUTTSONLJIF4RLJJJJJJJJJJQQQQQQJJJJJJJJJTNJc~~~||zzyxxwwwvvvtttssqppondkkihhgffbzb`_dh+XXXXWWWUUUQNLKIFDC3RLJJJJJJJJJJQQQQQQJJJJJJJJJTNJe~~~||zzyxxwwwvvvtttssqppo|,p!kkihhgbzcbbfk+[XXXXXh/n5WUTQMLKGEDB@2QLJJJJJJJJJJQQQQQQJJJJJJJJJTNJe~~~||zzyxxwwwvvvtttssqppos#kkihnzcccfl+[[[XZXXfWUQMLJGECA@=1QLKJJJJJJJJJQQQQQQJJJJJJJJJTNJg~~~||zzyxxwwwvvvtttssqpp`p~zecchl+]][[[XZX_WUOKIEEB@@<;/QKKJJJJJJJJJQQQQQQJJJJJJJJJTNJh~~~||zzyxxwwwvvvtttssqppzfeein+^]]][[[XZZWUNGEBAA=<:8}/QKKJJJJJJJJJQQQQQQJJJJJJJJJTNJi~~~||zzyyxwwwvvvtttssqpz(zfffio+_^]]][[[XWWULDBA><;865!y,QKKJJJJJJJJJQQQQQQJJJJJJJJJTNJk~~~|||zyyxwwwvvvtttssqp|)]hgflo+_^]]][[[WWWULA@=<986!5!3"v+!OKKJJJJJJJJJQQQQQQJJJJJJJJJTOJl~~~|||zyyxwwwvvvtttssqpp[s#ihhmo+_^]]][[XWWWUK><:96!5!4"3$0's*%OKKJJJJJJJJJQQQQQQJJJJJJJJJTOJl~~~|||zyyxwwwvvvtttssqppoy)\teBmlkkino+_^]]][XXWWWUI;99!6!4"3$1%0)/+p**OKKJJJJJJJJJQQQQQQJJJJJJJJJTOJn~~~|||zyyxwwwvvvtttssqppoonmmmmlkot+k o+_^]]]XXXWWWUG9!5!5"4$2%1)/+-+,/o)-OKKJJJJJJJJJQQQQQQJJJJJJJJJTOJo~~~|||zyyxwwwvvvtttssqqpoonmmmmpu+ffk γ`_^]]ZXXXWWWUG5"4$3%2)0+0,,/+1*3m)2NKLJJJJJJJJJQQQQQQJJJJJJJJJTOJo~~~|||zyyxwwwvvvttttsqqpoonmmpu+gfffk v``_^]XZXXXWWWUE3%2)1+0,-0,1*3*6)8l(6NKLJJJJJJJJJQQQQQQJJJJJJJJJTTJo~~~|||zyyxwwwvvvttttsqqpoonsw+hggffficb``__[XZXXXWWWUC 1+0,/0,1*3*6)8';~(>i(}%@|$Dk)DNKLJJJJJJJJJQQQwQQQJJJJJJJJJTTJ~~~~||zyyxwwwwvvvtttsqqpk}2lkiihggfffecccccbb`[[[XZXXXWWWUB#,4+5*9(;)>}'A|$Dz%Gz$Kk)JNKLJJJJJJJJJQQQQQQJJJJJJJJJTTJ~~~||zyyxwwwwvvvtttsqq}+nlkiihggfffecccccbb][[[[ZXXXWWWU@%*9*<)>~'A|%D|$Gz%Kz$Oz$Sk*QNKMJJJJJJJJJQQQQQQJJJJJJJJJTTJ~~~||zyyxxwwwvvvtttsqq2nlkiihggfffecccccb]]][[[ZXXXWWWU@)*>~(A|%D|'Gz%Kz$Oz$Sz#Vz#[l+WNJMJJJJJJJJJQQQQQQJJJJJJJJJTTJ~~~||zzyxxwwwvvvtttsqq2nlkiihggfffeecccc]]]][[[ZXXXWWWU=+}'D|'Gz$Kz%Oz$Sz%Wz#[z%^y!bi'ZNJMJJJJJJJJJQQQRRQJJJJJJJJJTTJ~~~||zzyxxwwwvvvtttsqq2nlkiihggfffeeccc_^]]][[[ZXXXWWWU=-|%Kz%Oz%Sz$Wz#[z%^y!bwdvef \NJMJJJJJJJJJRQQJJJKKJJJJJJJTTJ~~~||zzyxxwwwvvvtttsqq2nlkiihggfffeecc__^]]][[[ZXXXWWWU;2z%Sz$Wz%\z%^z"cwdveuhuld`NJNJJJJJJKJJQQQJJJJJJJJJJJJ~~~||zzyxxwwwvvvtttsqq2>88~8~8~8~8~8}8}8z8z8z8z8w8v8v8v8u8t8t8s8s8s8q8q8q8p8p8_"WU:5z%\z%^z"cwdveuhulsnsqdcJJJJJJJJJQQQJJJJJJJJJJJJ~~~||zzyxxwwwvvvtttsqq2`WU99z"cwdwfuhulsnsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJ~~~||zzyxxwwwvvvtttssq2`WU::wfuhulsnsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJ~~~||zzyxxwwwvvvtttssq2_WWuhuksnsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJ~~~||zzyxxwwwvvvtttssq2WWuksnsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJ~~~||zzyxxwwwvvvttuwsq0Ě̫̫̫̫̫̫̫ͫͫͫͫ˪˪˪ʪɪɪȪȪȪȪȪƪƪŪŪŪŪŪŪŪĪdXWsnsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJ~~~||zzyxxwwwvvvvy|xsqpponnmmmmlkkihhgcccccb``_^]]][[[XZXXXsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJ~~~||zzyxxwwwvxz}ysqpponnmmmmlkkihhecccccb``_^]]][[[XZXXsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJ~~~||zzyxxwww|~}sqpponnmmmmlkkiheecccccb``_^]]][[[XZXsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJ~~~||zzy^^y~sqpponnmmmmlkkifeecccccb``_^]]][[[XZsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJ~~~|||_SNJSNJdsqpponnmmmmlkkfffecccccb``_^]]][[[XsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJ~~~|_SMJJJJJJJSNJgsqpponnmmmmlkgfffecccccb``_^]]][[[sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJ~~bTNJJJJJJJJJJJJJSOJlsqppoonmmmmlggfffecccccb``_^]]][[sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJbTNJJJJJJJJJJJJJJJJJJJSOJpsqqpoonmmmmhggfffecccccb``_^]]][sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJdTNJJJJJJJJJJJJJJJJJJJJJJJJJTOJvsqqpoonmmmihggfffecccccb``_^]]]sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJeTNJJJJJJJJJJQQQQQQJJJJJJJJJTRKzsqqpoonmmiihggfffecccccb``_^]]sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJfTNJJJJJJJJJJQQQQQQJJJJJJJJJTRK~sqqpoonmkiihggfffecccccb``__]sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJhTNJJJJJJJJJJQQQQQQJJJJJJJJJTRK sqqpoonlkiihggfffecccccb``__sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJiTNJJJJJJJJJJQQQQQQJJJJJJJJJTRK‹"sqqpoollkiihggfffecccccbb`_sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJkTNJJJJJJJJJJQQQQQQJJJJJJJJJTRKŽ!sqqpomllkiihggfffecccccbb`sqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJkTNJJJJJJJJJJQQQQQQJJJJJJJJJTRKsqqpmmllkiihggfffecccccbbsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJlTNJJJJJJJJJJQQQQQQJJJJJJJJJTRK“sqqmmmllkiihggfffeeccccbsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJlTOJJJJJJJJJJQQQQQQJJJJJJJJJTRK˜sq2mmmmllkiihggfffeeccccsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJoTOJJJJJJJJJJQQQQQQJJJJJJJJJTRKÛsq2nnmmmllkiihggfffeecccsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJoTOJJJJJJJJJJQQQQQQJJJJJJJJJTRKÞsq2׺konnmmmllkiihhgfffeeccsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJoTOJJJJJJJJJJQQQQQQJJJJJJJJJTRKâsqqpponnmmmllkkihhgfffeecsqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJoTOJJJJJJJJJJQQQQQQJJJJJJJJJTRKħssqpponnmmmllkkihhgfffeesqsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJTTJJJJJJJJJJQQQQQQJJJJJJJJJTRKŪeKsqsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJTTJJJJJJJJJJQQQQQQJJJJJJJJJTSKįeKsqsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJTTJJJJJJJJJJQQQQQQJJJJJJJJJTSKıeKsqsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJTTJJJJJJJJJJQQQQQQJJJJJJJJJTSJĵeKsqsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJTTJJJJJJJJJJQQQQQQJJJJJJJJJTSJŹeKsqsqsqJJJJJJJJJQQQJJJJJJJJJJJJTTJJJJJJJJJJQQQQQQJJJJJJJJJTSJŽeKsqsqJJJJJJJJJQQQJJJJJJJJJJJJTTJJJJJJJJJJQQQQQQJJJJJJJJJTTJeKsqJJJJJJJJJQQQJJJJJJJJJJJJUTJJJJJJJJJJQQQ|QQQJJJJJJJJJTTJnIJJJJJJJJJQQQJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJQQQQQQJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJQQQJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJQQQQQQJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJQQQJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJRRQRRQJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJQQQJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJQQQgrafx2_2.4+git20180105/LICENSE0000664000000000000000000003560613223665306013757 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS grafx2_2.4+git20180105/CONTRIBUTING.md0000664000000000000000000000060513223665306015172 0ustar rootrootWhile the sourcecode is currently hosted on [gitlab](https://gitlab.com/GrafX2/grafX2/), the bugtracker and developer docs are hosted on [Trac](http://pulkomandy.tk/projects/GrafX2). Drive your browser there for a lot of useful information on GrafX2 development, internals, and roadmap. You can also join the #grafx2 channel on Freenode for more direct interaction with other developers.grafx2_2.4+git20180105/tools/0000775000000000000000000000000013223665307014101 5ustar rootrootgrafx2_2.4+git20180105/tools/gifanalyzer/0000775000000000000000000000000013223665307016414 5ustar rootrootgrafx2_2.4+git20180105/tools/gifanalyzer/gifanalyzer.c0000664000000000000000000000437513223665307021104 0ustar rootroot/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program * Gif Analyzer tool Copyright 2010 Adrien Destugues Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include int main(int argc, char* argv[]) { FILE* theFile; if(argc != 2) { printf("%s file.gif\n",argv[0]); exit(-1); } theFile = fopen(argv[1], "r"); uint8_t buffer[256]; fread(buffer, 1, 6, theFile); buffer[6] = 0; printf("Signature: %6s\n", buffer); uint16_t w,h; fread(&w,2,1,theFile); fread(&h,2,1,theFile); printf("Resolution: %dx%d\n",w,h); fread(buffer,1,3,theFile); int colors = ((buffer[0]&0b01110000)>>4)+1; colors = pow(2,colors); int bpp = (buffer[0]&0xF) +1; printf("Color palette: %#02.2x\n",buffer[0]&0xFF); if (buffer[0] & 0b10000000) printf("\tGlobal palette\n"); printf("\tColor count: %d\n", colors); printf("\tBits per pixel: %d\n",bpp); printf("Index of background color: %d\n",buffer[1]); printf("(reserved byte: %d)\n",buffer[2]); printf("Color palette:\n"); for (int i = 0; i < pow(2,bpp); i++) { fread(buffer,1,3,theFile); printf("\t%d: %u %u %u\t",i,buffer[0], buffer[1], buffer[2]); if ((i+1)%4 ==0)puts(""); } int i = 0; do { fread(buffer,1,1,theFile); i++; } while (i != ','); if (i > 1); printf("Skipped %d meaningless bytes before image descriptor\n",i); uint16_t x,y; fread(&x,2,1,theFile); fread(&y,2,1,theFile); fread(&w,2,1,theFile); fread(&h,2,1,theFile); printf("Image descriptor\n"); printf("\tx=%d y=%d w=%d h=%d\n",x,y,w,h); fclose(theFile); } grafx2_2.4+git20180105/tools/Doxyfile0000664000000000000000000031056413223665307015620 0ustar rootroot# Doxyfile 1.8.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = GrafX2 # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = out # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = NO # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = NO # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a # new page for each member. If set to NO, the documentation of a member will be # part of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = YES # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined # locally in source files will be included in the documentation. If set to NO # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO these classes will be included in the various overviews. This option has # no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = NO # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the # todo list. This list is created by putting \todo commands in the # documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the # test list. This list is created by putting \test commands in the # documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES the list # will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO doxygen will only warn about wrong or incomplete parameter # documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = YES # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. # Note: If this tag is empty the current directory is searched. INPUT = # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank the # following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, # *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, # *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = SDLMain.* \ *.py # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER ) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES, then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = NO # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = NO # If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the # clang parser (see: http://clang.llvm.org/) for more accurate parsing at the # cost of reduced performance. This can be particularly helpful with template # rich C++ code for which doxygen's built-in parser lacks the necessary type # information. # Note: The availability of this option depends on whether or not doxygen was # compiled with the --with-libclang option. # The default value is: NO. CLANG_ASSISTED_PARSING = NO # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_OPTIONS = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefor more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra stylesheet files is of importance (e.g. the last # stylesheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler ( hhc.exe). If non-empty # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated ( # YES) or that it should be included in the master .chm file ( NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated ( # YES) or a normal table of contents ( NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = YES # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /