SDL_gfxPrimitives.c 186 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743
  1. /*
  2. SDL_gfxPrimitives.c: graphics primitives for SDL surfaces
  3. Copyright (C) 2001-2012 Andreas Schiffler
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. Andreas Schiffler -- aschiffler at ferzkopp dot net
  19. */
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <math.h>
  23. #include <string.h>
  24. #include "SDL_gfxPrimitives.h"
  25. #include "SDL_rotozoom.h"
  26. #include "SDL_gfxPrimitives_font.h"
  27. #include "SDL_gfxBlitFunc.h"
  28. /* -===================- */
  29. #define DEFAULT_ALPHA_PIXEL_ROUTINE
  30. #undef EXPERIMENTAL_ALPHA_PIXEL_ROUTINE
  31. #define ALPHA_PIXEL_ADDITIVE_BLEND
  32. /* ---- Structures */
  33. /*!
  34. \brief The structure passed to the internal Bresenham iterator.
  35. */
  36. typedef struct {
  37. Sint16 x, y;
  38. int dx, dy, s1, s2, swapdir, error;
  39. Uint32 count;
  40. } SDL_gfxBresenhamIterator;
  41. /*!
  42. \brief The structure passed to the internal Murphy iterator.
  43. */
  44. typedef struct {
  45. Uint32 color;
  46. SDL_Surface *dst;
  47. int u, v; /* delta x , delta y */
  48. int ku, kt, kv, kd; /* loop constants */
  49. int oct2;
  50. int quad4;
  51. Sint16 last1x, last1y, last2x, last2y, first1x, first1y, first2x, first2y, tempx, tempy;
  52. } SDL_gfxMurphyIterator;
  53. /* ----- Defines for pixel clipping tests */
  54. #define clip_xmin(surface) surface->clip_rect.x
  55. #define clip_xmax(surface) surface->clip_rect.x+surface->clip_rect.w-1
  56. #define clip_ymin(surface) surface->clip_rect.y
  57. #define clip_ymax(surface) surface->clip_rect.y+surface->clip_rect.h-1
  58. /*!
  59. \brief Internal pixel drawing - fast, no blending, no locking, clipping.
  60. \param dst The surface to draw on.
  61. \param x The horizontal coordinate of the pixel.
  62. \param y The vertical position of the pixel.
  63. \param color The color value of the pixel to draw.
  64. \returns Returns 0 on success, -1 on failure.
  65. */
  66. int fastPixelColorNolock(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color) {
  67. int bpp;
  68. Uint8 *p;
  69. /*
  70. * Honor clipping setup at pixel level
  71. */
  72. if ((x >= clip_xmin(dst)) && (x <= clip_xmax(dst)) && (y >= clip_ymin(dst)) && (y <= clip_ymax(dst))) {
  73. /*
  74. * Get destination format
  75. */
  76. bpp = dst->format->BytesPerPixel;
  77. p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
  78. switch (bpp) {
  79. case 1:
  80. *p = color;
  81. break;
  82. case 2:
  83. *(Uint16 *) p = color;
  84. break;
  85. case 3:
  86. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  87. p[0] = (color >> 16) & 0xff;
  88. p[1] = (color >> 8) & 0xff;
  89. p[2] = color & 0xff;
  90. } else {
  91. p[0] = color & 0xff;
  92. p[1] = (color >> 8) & 0xff;
  93. p[2] = (color >> 16) & 0xff;
  94. }
  95. break;
  96. case 4:
  97. *(Uint32 *) p = color;
  98. break;
  99. } /* switch */
  100. }
  101. return (0);
  102. }
  103. /*!
  104. \brief Internal pixel drawing - fast, no blending, no locking, no clipping.
  105. Function is faster but dangerous since no clipping check is done.
  106. Code needs to make sure we stay in surface bounds before calling.
  107. \param dst The surface to draw on.
  108. \param x The horizontal coordinate of the pixel.
  109. \param y The vertical position of the pixel.
  110. \param color The color value of the pixel to draw.
  111. \returns Returns 0 on success, -1 on failure.
  112. */
  113. int fastPixelColorNolockNoclip(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color) {
  114. int bpp;
  115. Uint8 *p;
  116. /*
  117. * Get destination format
  118. */
  119. bpp = dst->format->BytesPerPixel;
  120. p = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
  121. switch (bpp) {
  122. case 1:
  123. *p = color;
  124. break;
  125. case 2:
  126. *(Uint16 *) p = color;
  127. break;
  128. case 3:
  129. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  130. p[0] = (color >> 16) & 0xff;
  131. p[1] = (color >> 8) & 0xff;
  132. p[2] = color & 0xff;
  133. } else {
  134. p[0] = color & 0xff;
  135. p[1] = (color >> 8) & 0xff;
  136. p[2] = (color >> 16) & 0xff;
  137. }
  138. break;
  139. case 4:
  140. *(Uint32 *) p = color;
  141. break;
  142. } /* switch */
  143. return (0);
  144. }
  145. /*!
  146. \brief Internal pixel drawing - fast, no blending, locking, clipping.
  147. \param dst The surface to draw on.
  148. \param x The horizontal coordinate of the pixel.
  149. \param y The vertical position of the pixel.
  150. \param color The color value of the pixel to draw.
  151. \returns Returns 0 on success, -1 on failure.
  152. */
  153. int fastPixelColor(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color) {
  154. int result;
  155. /*
  156. * Lock the surface
  157. */
  158. if (SDL_MUSTLOCK(dst)) {
  159. if (SDL_LockSurface(dst) < 0) {
  160. return (-1);
  161. }
  162. }
  163. result = fastPixelColorNolock(dst, x, y, color);
  164. /*
  165. * Unlock surface
  166. */
  167. if (SDL_MUSTLOCK(dst)) {
  168. SDL_UnlockSurface(dst);
  169. }
  170. return (result);
  171. }
  172. /*!
  173. \brief Internal pixel drawing - fast, no blending, locking, RGB input.
  174. \param dst The surface to draw on.
  175. \param x The horizontal coordinate of the pixel.
  176. \param y The vertical position of the pixel.
  177. \param r The red value of the pixel to draw.
  178. \param g The green value of the pixel to draw.
  179. \param b The blue value of the pixel to draw.
  180. \param a The alpha value of the pixel to draw.
  181. \returns Returns 0 on success, -1 on failure.
  182. */
  183. int fastPixelRGBA(SDL_Surface *dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  184. Uint32 color;
  185. /*
  186. * Setup color
  187. */
  188. color = SDL_MapRGBA(dst->format, r, g, b, a);
  189. /*
  190. * Draw
  191. */
  192. return (fastPixelColor(dst, x, y, color));
  193. }
  194. /*!
  195. \brief Internal pixel drawing - fast, no blending, no locking RGB input.
  196. \param dst The surface to draw on.
  197. \param x The horizontal coordinate of the pixel.
  198. \param y The vertical position of the pixel.
  199. \param r The red value of the pixel to draw.
  200. \param g The green value of the pixel to draw.
  201. \param b The blue value of the pixel to draw.
  202. \param a The alpha value of the pixel to draw.
  203. \returns Returns 0 on success, -1 on failure.
  204. */
  205. int fastPixelRGBANolock(SDL_Surface *dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  206. Uint32 color;
  207. /*
  208. * Setup color
  209. */
  210. color = SDL_MapRGBA(dst->format, r, g, b, a);
  211. /*
  212. * Draw
  213. */
  214. return (fastPixelColorNolock(dst, x, y, color));
  215. }
  216. /*!
  217. \brief Internal pixel drawing function with alpha blending where input color in in destination format.
  218. Contains two alternative 32 bit alpha blending routines which can be enabled at the source
  219. level with the defines DEFAULT_ALPHA_PIXEL_ROUTINE or EXPERIMENTAL_ALPHA_PIXEL_ROUTINE.
  220. Only the bits up to the surface depth are significant in the color value.
  221. \param dst The surface to draw on.
  222. \param x The horizontal coordinate of the pixel.
  223. \param y The vertical position of the pixel.
  224. \param color The color value of the pixel to draw.
  225. \param alpha The blend factor to apply while drawing.
  226. \returns Returns 0 on success, -1 on failure.
  227. */
  228. int _putPixelAlpha(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha) {
  229. SDL_PixelFormat *format;
  230. Uint32 Rmask, Gmask, Bmask, Amask;
  231. Uint32 Rshift, Gshift, Bshift, Ashift;
  232. Uint32 sR, sG, sB;
  233. Uint32 dR, dG, dB, dA;
  234. if (dst == NULL) {
  235. return (-1);
  236. }
  237. if (x >= clip_xmin(dst) && x <= clip_xmax(dst) &&
  238. y >= clip_ymin(dst) && y <= clip_ymax(dst)) {
  239. format = dst->format;
  240. switch (format->BytesPerPixel) {
  241. case 1: { /* Assuming 8-bpp */
  242. Uint8 *pixel = (Uint8 *) dst->pixels + y * dst->pitch + x;
  243. if (alpha == 255) {
  244. *pixel = color;
  245. } else {
  246. Uint8 R, G, B;
  247. SDL_Palette *palette = format->palette;
  248. SDL_Color *colors = palette->colors;
  249. SDL_Color dColor = colors[*pixel];
  250. SDL_Color sColor = colors[color];
  251. dR = dColor.r;
  252. dG = dColor.g;
  253. dB = dColor.b;
  254. sR = sColor.r;
  255. sG = sColor.g;
  256. sB = sColor.b;
  257. R = dR + ((sR - dR) * alpha >> 8);
  258. G = dG + ((sG - dG) * alpha >> 8);
  259. B = dB + ((sB - dB) * alpha >> 8);
  260. *pixel = SDL_MapRGB(format, R, G, B);
  261. }
  262. }
  263. break;
  264. case 2: { /* Probably 15-bpp or 16-bpp */
  265. Uint16 *pixel = (Uint16 *) dst->pixels + y * dst->pitch / 2 + x;
  266. if (alpha == 255) {
  267. *pixel = color;
  268. } else {
  269. Uint16 R, G, B, A;
  270. Uint16 dc = *pixel;
  271. Rmask = format->Rmask;
  272. Gmask = format->Gmask;
  273. Bmask = format->Bmask;
  274. Amask = format->Amask;
  275. dR = (dc & Rmask);
  276. dG = (dc & Gmask);
  277. dB = (dc & Bmask);
  278. R = (dR + (((color & Rmask) - dR) * alpha >> 8)) & Rmask;
  279. G = (dG + (((color & Gmask) - dG) * alpha >> 8)) & Gmask;
  280. B = (dB + (((color & Bmask) - dB) * alpha >> 8)) & Bmask;
  281. *pixel = R | G | B;
  282. if (Amask != 0) {
  283. dA = (dc & Amask);
  284. A = (dA + (((color & Amask) - dA) * alpha >> 8)) & Amask;
  285. *pixel |= A;
  286. }
  287. }
  288. }
  289. break;
  290. case 3: { /* Slow 24-bpp mode, usually not used */
  291. Uint8 R, G, B;
  292. Uint8 Rshift8, Gshift8, Bshift8;
  293. Uint8 *pixel = (Uint8 *) dst->pixels + y * dst->pitch + x * 3;
  294. Rshift = format->Rshift;
  295. Gshift = format->Gshift;
  296. Bshift = format->Bshift;
  297. Rshift8 = Rshift >> 3;
  298. Gshift8 = Gshift >> 3;
  299. Bshift8 = Bshift >> 3;
  300. sR = (color >> Rshift) & 0xFF;
  301. sG = (color >> Gshift) & 0xFF;
  302. sB = (color >> Bshift) & 0xFF;
  303. if (alpha == 255) {
  304. *(pixel + Rshift8) = sR;
  305. *(pixel + Gshift8) = sG;
  306. *(pixel + Bshift8) = sB;
  307. } else {
  308. dR = *((pixel) + Rshift8);
  309. dG = *((pixel) + Gshift8);
  310. dB = *((pixel) + Bshift8);
  311. R = dR + ((sR - dR) * alpha >> 8);
  312. G = dG + ((sG - dG) * alpha >> 8);
  313. B = dB + ((sB - dB) * alpha >> 8);
  314. *((pixel) + Rshift8) = R;
  315. *((pixel) + Gshift8) = G;
  316. *((pixel) + Bshift8) = B;
  317. }
  318. }
  319. break;
  320. #ifdef DEFAULT_ALPHA_PIXEL_ROUTINE
  321. case 4: { /* Probably :-) 32-bpp */
  322. Uint32 R, G, B, A;
  323. Uint32 *pixel = (Uint32 *) dst->pixels + y * dst->pitch / 4 + x;
  324. if (alpha == 255) {
  325. *pixel = color;
  326. } else {
  327. Uint32 dc = *pixel;
  328. Rmask = format->Rmask;
  329. Gmask = format->Gmask;
  330. Bmask = format->Bmask;
  331. Amask = format->Amask;
  332. Rshift = format->Rshift;
  333. Gshift = format->Gshift;
  334. Bshift = format->Bshift;
  335. Ashift = format->Ashift;
  336. dR = (dc & Rmask) >> Rshift;
  337. dG = (dc & Gmask) >> Gshift;
  338. dB = (dc & Bmask) >> Bshift;
  339. R = ((dR + ((((color & Rmask) >> Rshift) - dR) * alpha >> 8)) << Rshift) & Rmask;
  340. G = ((dG + ((((color & Gmask) >> Gshift) - dG) * alpha >> 8)) << Gshift) & Gmask;
  341. B = ((dB + ((((color & Bmask) >> Bshift) - dB) * alpha >> 8)) << Bshift) & Bmask;
  342. *pixel = R | G | B;
  343. if (Amask != 0) {
  344. dA = (dc & Amask) >> Ashift;
  345. #ifdef ALPHA_PIXEL_ADDITIVE_BLEND
  346. A = (dA | GFX_ALPHA_ADJUST_ARRAY[alpha & 255])
  347. << Ashift; // make destination less transparent...
  348. #else
  349. A = ((dA + ((((color & Amask) >> Ashift) - dA) * alpha >> 8)) << Ashift) & Amask;
  350. #endif
  351. *pixel |= A;
  352. }
  353. }
  354. }
  355. break;
  356. #endif
  357. #ifdef EXPERIMENTAL_ALPHA_PIXEL_ROUTINE
  358. case 4:{ /* Probably :-) 32-bpp */
  359. if (alpha == 255) {
  360. *((Uint32 *) dst->pixels + y * dst->pitch / 4 + x) = color;
  361. } else {
  362. Uint32 *pixel = (Uint32 *) dst->pixels + y * dst->pitch / 4 + x;
  363. Uint32 dR, dG, dB, dA;
  364. Uint32 dc = *pixel;
  365. Uint32 surfaceAlpha, preMultR, preMultG, preMultB;
  366. Uint32 aTmp;
  367. Rmask = format->Rmask;
  368. Gmask = format->Gmask;
  369. Bmask = format->Bmask;
  370. Amask = format->Amask;
  371. dR = (color & Rmask);
  372. dG = (color & Gmask);
  373. dB = (color & Bmask);
  374. dA = (color & Amask);
  375. Rshift = format->Rshift;
  376. Gshift = format->Gshift;
  377. Bshift = format->Bshift;
  378. Ashift = format->Ashift;
  379. preMultR = (alpha * (dR >> Rshift));
  380. preMultG = (alpha * (dG >> Gshift));
  381. preMultB = (alpha * (dB >> Bshift));
  382. surfaceAlpha = ((dc & Amask) >> Ashift);
  383. aTmp = (255 - alpha);
  384. if (A = 255 - ((aTmp * (255 - surfaceAlpha)) >> 8 )) {
  385. aTmp *= surfaceAlpha;
  386. R = (preMultR + ((aTmp * ((dc & Rmask) >> Rshift)) >> 8)) / A << Rshift & Rmask;
  387. G = (preMultG + ((aTmp * ((dc & Gmask) >> Gshift)) >> 8)) / A << Gshift & Gmask;
  388. B = (preMultB + ((aTmp * ((dc & Bmask) >> Bshift)) >> 8)) / A << Bshift & Bmask;
  389. }
  390. *pixel = R | G | B | (A << Ashift & Amask);
  391. }
  392. }
  393. break;
  394. #endif
  395. }
  396. }
  397. return (0);
  398. }
  399. /*!
  400. \brief Pixel draw with blending enabled if a<255.
  401. \param dst The surface to draw on.
  402. \param x X (horizontal) coordinate of the pixel.
  403. \param y Y (vertical) coordinate of the pixel.
  404. \param color The color value of the pixel to draw (0xRRGGBBAA).
  405. \returns Returns 0 on success, -1 on failure.
  406. */
  407. int pixelColor(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color) {
  408. Uint8 alpha;
  409. Uint32 mcolor;
  410. int result = 0;
  411. /*
  412. * Lock the surface
  413. */
  414. if (SDL_MUSTLOCK(dst)) {
  415. if (SDL_LockSurface(dst) < 0) {
  416. return (-1);
  417. }
  418. }
  419. /*
  420. * Setup color
  421. */
  422. alpha = color & 0x000000ff;
  423. mcolor =
  424. SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
  425. (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
  426. /*
  427. * Draw
  428. */
  429. result = _putPixelAlpha(dst, x, y, mcolor, alpha);
  430. /*
  431. * Unlock the surface
  432. */
  433. if (SDL_MUSTLOCK(dst)) {
  434. SDL_UnlockSurface(dst);
  435. }
  436. return (result);
  437. }
  438. /*!
  439. \brief Pixel draw with blending enabled if a<255 - no surface locking.
  440. \param dst The surface to draw on.
  441. \param x X (horizontal) coordinate of the pixel.
  442. \param y Y (vertical) coordinate of the pixel.
  443. \param color The color value of the pixel to draw (0xRRGGBBAA).
  444. \returns Returns 0 on success, -1 on failure.
  445. */
  446. int pixelColorNolock(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color) {
  447. Uint8 alpha;
  448. Uint32 mcolor;
  449. int result = 0;
  450. /*
  451. * Setup color
  452. */
  453. alpha = color & 0x000000ff;
  454. mcolor =
  455. SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
  456. (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
  457. /*
  458. * Draw
  459. */
  460. result = _putPixelAlpha(dst, x, y, mcolor, alpha);
  461. return (result);
  462. }
  463. /*!
  464. \brief Internal function to draw filled rectangle with alpha blending.
  465. Assumes color is in destination format.
  466. \param dst The surface to draw on.
  467. \param x1 X coordinate of the first corner (upper left) of the rectangle.
  468. \param y1 Y coordinate of the first corner (upper left) of the rectangle.
  469. \param x2 X coordinate of the second corner (lower right) of the rectangle.
  470. \param y2 Y coordinate of the second corner (lower right) of the rectangle.
  471. \param color The color value of the rectangle to draw (0xRRGGBBAA).
  472. \param alpha Alpha blending amount for pixels.
  473. \returns Returns 0 on success, -1 on failure.
  474. */
  475. int _filledRectAlpha(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha) {
  476. SDL_PixelFormat *format;
  477. Uint32 Rmask, Gmask, Bmask, Amask;
  478. Uint32 Rshift, Gshift, Bshift, Ashift;
  479. Uint32 sR, sG, sB, sA;
  480. Uint32 dR, dG, dB, dA;
  481. Sint16 x, y;
  482. if (dst == NULL) {
  483. return (-1);
  484. }
  485. format = dst->format;
  486. switch (format->BytesPerPixel) {
  487. case 1: { /* Assuming 8-bpp */
  488. Uint8 *row, *pixel;
  489. Uint8 R, G, B;
  490. SDL_Color *colors = format->palette->colors;
  491. SDL_Color dColor;
  492. SDL_Color sColor = colors[color];
  493. sR = sColor.r;
  494. sG = sColor.g;
  495. sB = sColor.b;
  496. for (y = y1; y <= y2; y++) {
  497. row = (Uint8 *) dst->pixels + y * dst->pitch;
  498. for (x = x1; x <= x2; x++) {
  499. if (alpha == 255) {
  500. *(row + x) = color;
  501. } else {
  502. pixel = row + x;
  503. dColor = colors[*pixel];
  504. dR = dColor.r;
  505. dG = dColor.g;
  506. dB = dColor.b;
  507. R = dR + ((sR - dR) * alpha >> 8);
  508. G = dG + ((sG - dG) * alpha >> 8);
  509. B = dB + ((sB - dB) * alpha >> 8);
  510. *pixel = SDL_MapRGB(format, R, G, B);
  511. }
  512. }
  513. }
  514. }
  515. break;
  516. case 2: { /* Probably 15-bpp or 16-bpp */
  517. Uint16 *row, *pixel;
  518. Uint16 R, G, B, A;
  519. Uint16 dc;
  520. Rmask = format->Rmask;
  521. Gmask = format->Gmask;
  522. Bmask = format->Bmask;
  523. Amask = format->Amask;
  524. sR = (color & Rmask);
  525. sG = (color & Gmask);
  526. sB = (color & Bmask);
  527. sA = (color & Amask);
  528. for (y = y1; y <= y2; y++) {
  529. row = (Uint16 *) dst->pixels + y * dst->pitch / 2;
  530. for (x = x1; x <= x2; x++) {
  531. if (alpha == 255) {
  532. *(row + x) = color;
  533. } else {
  534. pixel = row + x;
  535. dc = *pixel;
  536. dR = (dc & Rmask);
  537. dG = (dc & Gmask);
  538. dB = (dc & Bmask);
  539. R = (dR + ((sR - dR) * alpha >> 8)) & Rmask;
  540. G = (dG + ((sG - dG) * alpha >> 8)) & Gmask;
  541. B = (dB + ((sB - dB) * alpha >> 8)) & Bmask;
  542. *pixel = R | G | B;
  543. if (Amask != 0) {
  544. dA = (dc & Amask);
  545. A = (dA + ((sA - dA) * alpha >> 8)) & Amask;
  546. *pixel |= A;
  547. }
  548. }
  549. }
  550. }
  551. }
  552. break;
  553. case 3: { /* Slow 24-bpp mode, usually not used */
  554. Uint8 *row, *pixel;
  555. Uint8 R, G, B;
  556. Uint8 Rshift8, Gshift8, Bshift8;
  557. Rshift = format->Rshift;
  558. Gshift = format->Gshift;
  559. Bshift = format->Bshift;
  560. Rshift8 = Rshift >> 3;
  561. Gshift8 = Gshift >> 3;
  562. Bshift8 = Bshift >> 3;
  563. sR = (color >> Rshift) & 0xff;
  564. sG = (color >> Gshift) & 0xff;
  565. sB = (color >> Bshift) & 0xff;
  566. for (y = y1; y <= y2; y++) {
  567. row = (Uint8 *) dst->pixels + y * dst->pitch;
  568. for (x = x1; x <= x2; x++) {
  569. pixel = row + x * 3;
  570. if (alpha == 255) {
  571. *(pixel + Rshift8) = sR;
  572. *(pixel + Gshift8) = sG;
  573. *(pixel + Bshift8) = sB;
  574. } else {
  575. dR = *((pixel) + Rshift8);
  576. dG = *((pixel) + Gshift8);
  577. dB = *((pixel) + Bshift8);
  578. R = dR + ((sR - dR) * alpha >> 8);
  579. G = dG + ((sG - dG) * alpha >> 8);
  580. B = dB + ((sB - dB) * alpha >> 8);
  581. *((pixel) + Rshift8) = R;
  582. *((pixel) + Gshift8) = G;
  583. *((pixel) + Bshift8) = B;
  584. }
  585. }
  586. }
  587. }
  588. break;
  589. #ifdef DEFAULT_ALPHA_PIXEL_ROUTINE
  590. case 4: { /* Probably :-) 32-bpp */
  591. Uint32 *row, *pixel;
  592. Uint32 R, G, B, A;
  593. Uint32 dc;
  594. Rmask = format->Rmask;
  595. Gmask = format->Gmask;
  596. Bmask = format->Bmask;
  597. Amask = format->Amask;
  598. Rshift = format->Rshift;
  599. Gshift = format->Gshift;
  600. Bshift = format->Bshift;
  601. Ashift = format->Ashift;
  602. sR = (color & Rmask) >> Rshift;
  603. sG = (color & Gmask) >> Gshift;
  604. sB = (color & Bmask) >> Bshift;
  605. sA = (color & Amask) >> Ashift;
  606. for (y = y1; y <= y2; y++) {
  607. row = (Uint32 *) dst->pixels + y * dst->pitch / 4;
  608. for (x = x1; x <= x2; x++) {
  609. if (alpha == 255) {
  610. *(row + x) = color;
  611. } else {
  612. pixel = row + x;
  613. dc = *pixel;
  614. dR = (dc & Rmask) >> Rshift;
  615. dG = (dc & Gmask) >> Gshift;
  616. dB = (dc & Bmask) >> Bshift;
  617. R = ((dR + ((sR - dR) * alpha >> 8)) << Rshift) & Rmask;
  618. G = ((dG + ((sG - dG) * alpha >> 8)) << Gshift) & Gmask;
  619. B = ((dB + ((sB - dB) * alpha >> 8)) << Bshift) & Bmask;
  620. *pixel = R | G | B;
  621. if (Amask != 0) {
  622. dA = (dc & Amask) >> Ashift;
  623. #ifdef ALPHA_PIXEL_ADDITIVE_BLEND
  624. A = (dA | GFX_ALPHA_ADJUST_ARRAY[sA & 255])
  625. << Ashift; // make destination less transparent...
  626. #else
  627. A = ((dA + ((sA - dA) * alpha >> 8)) << Ashift) & Amask;
  628. #endif
  629. *pixel |= A;
  630. }
  631. }
  632. }
  633. }
  634. }
  635. break;
  636. #endif
  637. #ifdef EXPERIMENTAL_ALPHA_PIXEL_ROUTINE
  638. case 4:{ /* Probably :-) 32-bpp */
  639. Uint32 *row, *pixel;
  640. Uint32 dR, dG, dB, dA;
  641. Uint32 dc;
  642. Uint32 surfaceAlpha, preMultR, preMultG, preMultB;
  643. Uint32 aTmp;
  644. Rmask = format->Rmask;
  645. Gmask = format->Gmask;
  646. Bmask = format->Bmask;
  647. Amask = format->Amask;
  648. dR = (color & Rmask);
  649. dG = (color & Gmask);
  650. dB = (color & Bmask);
  651. dA = (color & Amask);
  652. Rshift = format->Rshift;
  653. Gshift = format->Gshift;
  654. Bshift = format->Bshift;
  655. Ashift = format->Ashift;
  656. preMultR = (alpha * (dR >> Rshift));
  657. preMultG = (alpha * (dG >> Gshift));
  658. preMultB = (alpha * (dB >> Bshift));
  659. for (y = y1; y <= y2; y++) {
  660. row = (Uint32 *) dst->pixels + y * dst->pitch / 4;
  661. for (x = x1; x <= x2; x++) {
  662. if (alpha == 255) {
  663. *(row + x) = color;
  664. } else {
  665. pixel = row + x;
  666. dc = *pixel;
  667. surfaceAlpha = ((dc & Amask) >> Ashift);
  668. aTmp = (255 - alpha);
  669. if (A = 255 - ((aTmp * (255 - surfaceAlpha)) >> 8 )) {
  670. aTmp *= surfaceAlpha;
  671. R = (preMultR + ((aTmp * ((dc & Rmask) >> Rshift)) >> 8)) / A << Rshift & Rmask;
  672. G = (preMultG + ((aTmp * ((dc & Gmask) >> Gshift)) >> 8)) / A << Gshift & Gmask;
  673. B = (preMultB + ((aTmp * ((dc & Bmask) >> Bshift)) >> 8)) / A << Bshift & Bmask;
  674. }
  675. *pixel = R | G | B | (A << Ashift & Amask);
  676. }
  677. }
  678. }
  679. }
  680. break;
  681. #endif
  682. }
  683. return (0);
  684. }
  685. /*!
  686. \brief Draw filled rectangle of RGBA color with alpha blending.
  687. \param dst The surface to draw on.
  688. \param x1 X coordinate of the first corner (upper left) of the rectangle.
  689. \param y1 Y coordinate of the first corner (upper left) of the rectangle.
  690. \param x2 X coordinate of the second corner (lower right) of the rectangle.
  691. \param y2 Y coordinate of the second corner (lower right) of the rectangle.
  692. \param color The color value of the rectangle to draw (0xRRGGBBAA).
  693. \returns Returns 0 on success, -1 on failure.
  694. */
  695. int filledRectAlpha(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) {
  696. Uint8 alpha;
  697. Uint32 mcolor;
  698. int result = 0;
  699. /*
  700. * Lock the surface
  701. */
  702. if (SDL_MUSTLOCK(dst)) {
  703. if (SDL_LockSurface(dst) < 0) {
  704. return (-1);
  705. }
  706. }
  707. /*
  708. * Setup color
  709. */
  710. alpha = color & 0x000000ff;
  711. mcolor =
  712. SDL_MapRGBA(dst->format, (color & 0xff000000) >> 24,
  713. (color & 0x00ff0000) >> 16, (color & 0x0000ff00) >> 8, alpha);
  714. /*
  715. * Draw
  716. */
  717. result = _filledRectAlpha(dst, x1, y1, x2, y2, mcolor, alpha);
  718. /*
  719. * Unlock the surface
  720. */
  721. if (SDL_MUSTLOCK(dst)) {
  722. SDL_UnlockSurface(dst);
  723. }
  724. return (result);
  725. }
  726. /*!
  727. \brief Internal function to draw horizontal line of RGBA color with alpha blending.
  728. \param dst The surface to draw on.
  729. \param x1 X coordinate of the first point (i.e. left) of the line.
  730. \param x2 X coordinate of the second point (i.e. right) of the line.
  731. \param y Y coordinate of the points of the line.
  732. \param color The color value of the line to draw (0xRRGGBBAA).
  733. \returns Returns 0 on success, -1 on failure.
  734. */
  735. int _HLineAlpha(SDL_Surface *dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color) {
  736. return (filledRectAlpha(dst, x1, y, x2, y, color));
  737. }
  738. /*!
  739. \brief Internal function to draw vertical line of RGBA color with alpha blending.
  740. \param dst The surface to draw on.
  741. \param x X coordinate of the points of the line.
  742. \param y1 Y coordinate of the first point (top) of the line.
  743. \param y2 Y coordinate of the second point (bottom) of the line.
  744. \param color The color value of the line to draw (0xRRGGBBAA).
  745. \returns Returns 0 on success, -1 on failure.
  746. */
  747. int _VLineAlpha(SDL_Surface *dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color) {
  748. return (filledRectAlpha(dst, x, y1, x, y2, color));
  749. }
  750. /*!
  751. \brief Pixel draw with blending enabled and using alpha weight on color.
  752. \param dst The surface to draw on.
  753. \param x The horizontal coordinate of the pixel.
  754. \param y The vertical position of the pixel.
  755. \param color The color value of the pixel to draw (0xRRGGBBAA).
  756. \param weight The weight multiplied into the alpha value of the pixel.
  757. \returns Returns 0 on success, -1 on failure.
  758. */
  759. int pixelColorWeight(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight) {
  760. Uint32 a;
  761. /*
  762. * Get alpha
  763. */
  764. a = (color & (Uint32) 0x000000ff);
  765. /*
  766. * Modify Alpha by weight
  767. */
  768. a = ((a * weight) >> 8);
  769. return (pixelColor(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a));
  770. }
  771. /*!
  772. \brief Pixel draw with blending enabled and using alpha weight on color - no locking.
  773. \param dst The surface to draw on.
  774. \param x The horizontal coordinate of the pixel.
  775. \param y The vertical position of the pixel.
  776. \param color The color value of the pixel to draw (0xRRGGBBAA).
  777. \param weight The weight multiplied into the alpha value of the pixel.
  778. \returns Returns 0 on success, -1 on failure.
  779. */
  780. int pixelColorWeightNolock(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color, Uint32 weight) {
  781. Uint32 a;
  782. /*
  783. * Get alpha
  784. */
  785. a = (color & (Uint32) 0x000000ff);
  786. /*
  787. * Modify Alpha by weight
  788. */
  789. a = ((a * weight) >> 8);
  790. return (pixelColorNolock(dst, x, y, (color & (Uint32) 0xffffff00) | (Uint32) a));
  791. }
  792. /*!
  793. \brief Pixel draw with blending enabled if a<255.
  794. \param dst The surface to draw on.
  795. \param x X (horizontal) coordinate of the pixel.
  796. \param y Y (vertical) coordinate of the pixel.
  797. \param r The red color value of the pixel to draw.
  798. \param g The green color value of the pixel to draw.
  799. \param b The blue color value of the pixel to draw.
  800. \param a The alpha value of the pixel to draw.
  801. \returns Returns 0 on success, -1 on failure.
  802. */
  803. int pixelRGBA(SDL_Surface *dst, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  804. Uint32 color;
  805. /*
  806. * Check Alpha
  807. */
  808. if (a == 255) {
  809. /*
  810. * No alpha blending required
  811. */
  812. /*
  813. * Setup color
  814. */
  815. color = SDL_MapRGBA(dst->format, r, g, b, a);
  816. /*
  817. * Draw
  818. */
  819. return (fastPixelColor(dst, x, y, color));
  820. } else {
  821. /*
  822. * Alpha blending required
  823. */
  824. /*
  825. * Draw
  826. */
  827. return (pixelColor(dst, x, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  828. }
  829. }
  830. /*!
  831. \brief Draw horizontal line without blending;
  832. Just stores the color value (including the alpha component) without blending.
  833. Only the same number of bits of the destination surface are transfered
  834. from the input color value.
  835. \param dst The surface to draw on.
  836. \param x1 X coordinate of the first point (i.e. left) of the line.
  837. \param x2 X coordinate of the second point (i.e. right) of the line.
  838. \param y Y coordinate of the points of the line.
  839. \param color The color value of the line to draw.
  840. \returns Returns 0 on success, -1 on failure.
  841. */
  842. int hlineColorStore(SDL_Surface *dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color) {
  843. Sint16 left, right, top, bottom;
  844. Uint8 *pixel, *pixellast;
  845. int dx;
  846. int pixx, pixy;
  847. Sint16 w;
  848. Sint16 xtmp;
  849. int result = -1;
  850. /*
  851. * Check visibility of clipping rectangle
  852. */
  853. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  854. return (0);
  855. }
  856. /*
  857. * Swap x1, x2 if required to ensure x1<=x2
  858. */
  859. if (x1 > x2) {
  860. xtmp = x1;
  861. x1 = x2;
  862. x2 = xtmp;
  863. }
  864. /*
  865. * Get clipping boundary and
  866. * check visibility of hline
  867. */
  868. left = dst->clip_rect.x;
  869. if (x2 < left) {
  870. return (0);
  871. }
  872. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  873. if (x1 > right) {
  874. return (0);
  875. }
  876. top = dst->clip_rect.y;
  877. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  878. if ((y < top) || (y > bottom)) {
  879. return (0);
  880. }
  881. /*
  882. * Clip x
  883. */
  884. if (x1 < left) {
  885. x1 = left;
  886. }
  887. if (x2 > right) {
  888. x2 = right;
  889. }
  890. /*
  891. * Calculate width
  892. */
  893. w = x2 - x1;
  894. /*
  895. * Lock the surface
  896. */
  897. if (SDL_MUSTLOCK(dst)) {
  898. if (SDL_LockSurface(dst) < 0) {
  899. return (-1);
  900. }
  901. }
  902. /*
  903. * More variable setup
  904. */
  905. dx = w;
  906. pixx = dst->format->BytesPerPixel;
  907. pixy = dst->pitch;
  908. pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y;
  909. /*
  910. * Draw
  911. */
  912. switch (dst->format->BytesPerPixel) {
  913. case 1:
  914. memset(pixel, color, dx + 1);
  915. break;
  916. case 2:
  917. pixellast = pixel + dx + dx;
  918. for (; pixel <= pixellast; pixel += pixx) {
  919. *(Uint16 *) pixel = color;
  920. }
  921. break;
  922. case 3:
  923. pixellast = pixel + dx + dx + dx;
  924. for (; pixel <= pixellast; pixel += pixx) {
  925. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  926. pixel[0] = (color >> 16) & 0xff;
  927. pixel[1] = (color >> 8) & 0xff;
  928. pixel[2] = color & 0xff;
  929. } else {
  930. pixel[0] = color & 0xff;
  931. pixel[1] = (color >> 8) & 0xff;
  932. pixel[2] = (color >> 16) & 0xff;
  933. }
  934. }
  935. break;
  936. default: /* case 4 */
  937. dx = dx + dx;
  938. pixellast = pixel + dx + dx;
  939. for (; pixel <= pixellast; pixel += pixx) {
  940. *(Uint32 *) pixel = color;
  941. }
  942. break;
  943. }
  944. /*
  945. * Unlock surface
  946. */
  947. if (SDL_MUSTLOCK(dst)) {
  948. SDL_UnlockSurface(dst);
  949. }
  950. /*
  951. * Set result code
  952. */
  953. result = 0;
  954. return (result);
  955. }
  956. /*!
  957. \brief Draw horizontal line without blending
  958. Just stores the color value (including the alpha component) without blending.
  959. Function should only be used for 32 bit target surfaces.
  960. \param dst The surface to draw on.
  961. \param x1 X coordinate of the first point (i.e. left) of the line.
  962. \param x2 X coordinate of the second point (i.e. right) of the line.
  963. \param y Y coordinate of the points of the line.
  964. \param r The red value of the line to draw.
  965. \param g The green value of the line to draw.
  966. \param b The blue value of the line to draw.
  967. \param a The alpha value of the line to draw.
  968. \returns Returns 0 on success, -1 on failure.
  969. */
  970. int hlineRGBAStore(SDL_Surface *dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  971. /*
  972. * Draw
  973. */
  974. return (hlineColorStore(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  975. }
  976. /*!
  977. \brief Draw horizontal line with blending.
  978. \param dst The surface to draw on.
  979. \param x1 X coordinate of the first point (i.e. left) of the line.
  980. \param x2 X coordinate of the second point (i.e. right) of the line.
  981. \param y Y coordinate of the points of the line.
  982. \param color The color value of the line to draw (0xRRGGBBAA).
  983. \returns Returns 0 on success, -1 on failure.
  984. */
  985. int hlineColor(SDL_Surface *dst, Sint16 x1, Sint16 x2, Sint16 y, Uint32 color) {
  986. Sint16 left, right, top, bottom;
  987. Uint8 *pixel, *pixellast;
  988. int dx;
  989. int pixx, pixy;
  990. Sint16 xtmp;
  991. int result = -1;
  992. Uint8 *colorptr;
  993. Uint8 color3[3];
  994. /*
  995. * Check visibility of clipping rectangle
  996. */
  997. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  998. return (0);
  999. }
  1000. /*
  1001. * Swap x1, x2 if required to ensure x1<=x2
  1002. */
  1003. if (x1 > x2) {
  1004. xtmp = x1;
  1005. x1 = x2;
  1006. x2 = xtmp;
  1007. }
  1008. /*
  1009. * Get clipping boundary and
  1010. * check visibility of hline
  1011. */
  1012. left = dst->clip_rect.x;
  1013. if (x2 < left) {
  1014. return (0);
  1015. }
  1016. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  1017. if (x1 > right) {
  1018. return (0);
  1019. }
  1020. top = dst->clip_rect.y;
  1021. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  1022. if ((y < top) || (y > bottom)) {
  1023. return (0);
  1024. }
  1025. /*
  1026. * Clip x
  1027. */
  1028. if (x1 < left) {
  1029. x1 = left;
  1030. }
  1031. if (x2 > right) {
  1032. x2 = right;
  1033. }
  1034. /*
  1035. * Calculate width difference
  1036. */
  1037. dx = x2 - x1;
  1038. /*
  1039. * Alpha check
  1040. */
  1041. if ((color & 255) == 255) {
  1042. /*
  1043. * No alpha-blending required
  1044. */
  1045. /*
  1046. * Setup color
  1047. */
  1048. colorptr = (Uint8 *) &color;
  1049. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  1050. color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
  1051. } else {
  1052. color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
  1053. }
  1054. /*
  1055. * Lock the surface
  1056. */
  1057. if (SDL_MUSTLOCK(dst)) {
  1058. if (SDL_LockSurface(dst) < 0) {
  1059. return (-1);
  1060. }
  1061. }
  1062. /*
  1063. * More variable setup
  1064. */
  1065. pixx = dst->format->BytesPerPixel;
  1066. pixy = dst->pitch;
  1067. pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y;
  1068. /*
  1069. * Draw
  1070. */
  1071. switch (dst->format->BytesPerPixel) {
  1072. case 1:
  1073. memset(pixel, color, dx + 1);
  1074. break;
  1075. case 2:
  1076. pixellast = pixel + dx + dx;
  1077. for (; pixel <= pixellast; pixel += pixx) {
  1078. *(Uint16 *) pixel = color;
  1079. }
  1080. break;
  1081. case 3:
  1082. pixellast = pixel + dx + dx + dx;
  1083. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  1084. color3[0] = (color >> 16) & 0xff;
  1085. color3[1] = (color >> 8) & 0xff;
  1086. color3[2] = color & 0xff;
  1087. } else {
  1088. color3[0] = color & 0xff;
  1089. color3[1] = (color >> 8) & 0xff;
  1090. color3[2] = (color >> 16) & 0xff;
  1091. }
  1092. for (; pixel <= pixellast; pixel += pixx) {
  1093. memcpy(pixel, color3, 3);
  1094. }
  1095. break;
  1096. default: /* case 4 */
  1097. dx = dx + dx;
  1098. pixellast = pixel + dx + dx;
  1099. for (; pixel <= pixellast; pixel += pixx) {
  1100. *(Uint32 *) pixel = color;
  1101. }
  1102. break;
  1103. }
  1104. /*
  1105. * Unlock surface
  1106. */
  1107. if (SDL_MUSTLOCK(dst)) {
  1108. SDL_UnlockSurface(dst);
  1109. }
  1110. /*
  1111. * Set result code
  1112. */
  1113. result = 0;
  1114. } else {
  1115. /*
  1116. * Alpha blending blit
  1117. */
  1118. result = _HLineAlpha(dst, x1, x1 + dx, y, color);
  1119. }
  1120. return (result);
  1121. }
  1122. /*!
  1123. \brief Draw horizontal line with blending.
  1124. \param dst The surface to draw on.
  1125. \param x1 X coordinate of the first point (i.e. left) of the line.
  1126. \param x2 X coordinate of the second point (i.e. right) of the line.
  1127. \param y Y coordinate of the points of the line.
  1128. \param r The red value of the line to draw.
  1129. \param g The green value of the line to draw.
  1130. \param b The blue value of the line to draw.
  1131. \param a The alpha value of the line to draw.
  1132. \returns Returns 0 on success, -1 on failure.
  1133. */
  1134. int hlineRGBA(SDL_Surface *dst, Sint16 x1, Sint16 x2, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  1135. /*
  1136. * Draw
  1137. */
  1138. return (hlineColor(dst, x1, x2, y, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  1139. }
  1140. /*!
  1141. \brief Draw vertical line with blending.
  1142. \param dst The surface to draw on.
  1143. \param x X coordinate of the points of the line.
  1144. \param y1 Y coordinate of the first point (i.e. top) of the line.
  1145. \param y2 Y coordinate of the second point (i.e. bottom) of the line.
  1146. \param color The color value of the line to draw (0xRRGGBBAA).
  1147. \returns Returns 0 on success, -1 on failure.
  1148. */
  1149. int vlineColor(SDL_Surface *dst, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color) {
  1150. Sint16 left, right, top, bottom;
  1151. Uint8 *pixel, *pixellast;
  1152. int dy;
  1153. int pixx, pixy;
  1154. Sint16 h;
  1155. Sint16 ytmp;
  1156. int result = -1;
  1157. Uint8 *colorptr;
  1158. /*
  1159. * Check visibility of clipping rectangle
  1160. */
  1161. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  1162. return (0);
  1163. }
  1164. /*
  1165. * Swap y1, y2 if required to ensure y1<=y2
  1166. */
  1167. if (y1 > y2) {
  1168. ytmp = y1;
  1169. y1 = y2;
  1170. y2 = ytmp;
  1171. }
  1172. /*
  1173. * Get clipping boundary and
  1174. * check visibility of vline
  1175. */
  1176. left = dst->clip_rect.x;
  1177. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  1178. if ((x < left) || (x > right)) {
  1179. return (0);
  1180. }
  1181. top = dst->clip_rect.y;
  1182. if (y2 < top) {
  1183. return (0);
  1184. }
  1185. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  1186. if (y1 > bottom) {
  1187. return (0);
  1188. }
  1189. /*
  1190. * Clip x
  1191. */
  1192. if (y1 < top) {
  1193. y1 = top;
  1194. }
  1195. if (y2 > bottom) {
  1196. y2 = bottom;
  1197. }
  1198. /*
  1199. * Calculate height
  1200. */
  1201. h = y2 - y1;
  1202. /*
  1203. * Alpha check
  1204. */
  1205. if ((color & 255) == 255) {
  1206. /*
  1207. * No alpha-blending required
  1208. */
  1209. /*
  1210. * Setup color
  1211. */
  1212. colorptr = (Uint8 *) &color;
  1213. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  1214. color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
  1215. } else {
  1216. color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
  1217. }
  1218. /*
  1219. * Lock the surface
  1220. */
  1221. if (SDL_MUSTLOCK(dst)) {
  1222. if (SDL_LockSurface(dst) < 0) {
  1223. return (-1);
  1224. }
  1225. }
  1226. /*
  1227. * More variable setup
  1228. */
  1229. dy = h;
  1230. pixx = dst->format->BytesPerPixel;
  1231. pixy = dst->pitch;
  1232. pixel = ((Uint8 *) dst->pixels) + pixx * (int) x + pixy * (int) y1;
  1233. pixellast = pixel + pixy * dy;
  1234. /*
  1235. * Draw
  1236. */
  1237. switch (dst->format->BytesPerPixel) {
  1238. case 1:
  1239. for (; pixel <= pixellast; pixel += pixy) {
  1240. *(Uint8 *) pixel = color;
  1241. }
  1242. break;
  1243. case 2:
  1244. for (; pixel <= pixellast; pixel += pixy) {
  1245. *(Uint16 *) pixel = color;
  1246. }
  1247. break;
  1248. case 3:
  1249. for (; pixel <= pixellast; pixel += pixy) {
  1250. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  1251. pixel[0] = (color >> 16) & 0xff;
  1252. pixel[1] = (color >> 8) & 0xff;
  1253. pixel[2] = color & 0xff;
  1254. } else {
  1255. pixel[0] = color & 0xff;
  1256. pixel[1] = (color >> 8) & 0xff;
  1257. pixel[2] = (color >> 16) & 0xff;
  1258. }
  1259. }
  1260. break;
  1261. default: /* case 4 */
  1262. for (; pixel <= pixellast; pixel += pixy) {
  1263. *(Uint32 *) pixel = color;
  1264. }
  1265. break;
  1266. }
  1267. /* Unlock surface */
  1268. if (SDL_MUSTLOCK(dst)) {
  1269. SDL_UnlockSurface(dst);
  1270. }
  1271. /*
  1272. * Set result code
  1273. */
  1274. result = 0;
  1275. } else {
  1276. /*
  1277. * Alpha blending blit
  1278. */
  1279. result = _VLineAlpha(dst, x, y1, y1 + h, color);
  1280. }
  1281. return (result);
  1282. }
  1283. /*!
  1284. \brief Draw vertical line with blending.
  1285. \param dst The surface to draw on.
  1286. \param x X coordinate of the points of the line.
  1287. \param y1 Y coordinate of the first point (i.e. top) of the line.
  1288. \param y2 Y coordinate of the second point (i.e. bottom) of the line.
  1289. \param r The red value of the line to draw.
  1290. \param g The green value of the line to draw.
  1291. \param b The blue value of the line to draw.
  1292. \param a The alpha value of the line to draw.
  1293. \returns Returns 0 on success, -1 on failure.
  1294. */
  1295. int vlineRGBA(SDL_Surface *dst, Sint16 x, Sint16 y1, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  1296. /*
  1297. * Draw
  1298. */
  1299. return (vlineColor(dst, x, y1, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  1300. }
  1301. /*!
  1302. \brief Draw rectangle with blending.
  1303. \param dst The surface to draw on.
  1304. \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
  1305. \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
  1306. \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
  1307. \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
  1308. \param color The color value of the rectangle to draw (0xRRGGBBAA).
  1309. \returns Returns 0 on success, -1 on failure.
  1310. */
  1311. int rectangleColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) {
  1312. int result;
  1313. Sint16 tmp;
  1314. /* Check destination surface */
  1315. if (dst == NULL) {
  1316. return -1;
  1317. }
  1318. /*
  1319. * Check visibility of clipping rectangle
  1320. */
  1321. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  1322. return 0;
  1323. }
  1324. /*
  1325. * Test for special cases of straight lines or single point
  1326. */
  1327. if (x1 == x2) {
  1328. if (y1 == y2) {
  1329. return (pixelColor(dst, x1, y1, color));
  1330. } else {
  1331. return (vlineColor(dst, x1, y1, y2, color));
  1332. }
  1333. } else {
  1334. if (y1 == y2) {
  1335. return (hlineColor(dst, x1, x2, y1, color));
  1336. }
  1337. }
  1338. /*
  1339. * Swap x1, x2 if required
  1340. */
  1341. if (x1 > x2) {
  1342. tmp = x1;
  1343. x1 = x2;
  1344. x2 = tmp;
  1345. }
  1346. /*
  1347. * Swap y1, y2 if required
  1348. */
  1349. if (y1 > y2) {
  1350. tmp = y1;
  1351. y1 = y2;
  1352. y2 = tmp;
  1353. }
  1354. /*
  1355. * Draw rectangle
  1356. */
  1357. result = 0;
  1358. result |= hlineColor(dst, x1, x2, y1, color);
  1359. result |= hlineColor(dst, x1, x2, y2, color);
  1360. y1 += 1;
  1361. y2 -= 1;
  1362. if (y1 <= y2) {
  1363. result |= vlineColor(dst, x1, y1, y2, color);
  1364. result |= vlineColor(dst, x2, y1, y2, color);
  1365. }
  1366. return (result);
  1367. }
  1368. /*!
  1369. \brief Draw rectangle with blending.
  1370. \param dst The surface to draw on.
  1371. \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
  1372. \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
  1373. \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
  1374. \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
  1375. \param r The red value of the rectangle to draw.
  1376. \param g The green value of the rectangle to draw.
  1377. \param b The blue value of the rectangle to draw.
  1378. \param a The alpha value of the rectangle to draw.
  1379. \returns Returns 0 on success, -1 on failure.
  1380. */
  1381. int rectangleRGBA(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  1382. /*
  1383. * Draw
  1384. */
  1385. return (rectangleColor
  1386. (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  1387. }
  1388. /*!
  1389. \brief Draw rounded-corner rectangle with blending.
  1390. \param dst The surface to draw on.
  1391. \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
  1392. \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
  1393. \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
  1394. \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
  1395. \param rad The radius of the corner arc.
  1396. \param color The color value of the rectangle to draw (0xRRGGBBAA).
  1397. \returns Returns 0 on success, -1 on failure.
  1398. */
  1399. int roundedRectangleColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color) {
  1400. int result;
  1401. Sint16 w, h, tmp;
  1402. Sint16 xx1, xx2, yy1, yy2;
  1403. /*
  1404. * Check destination surface
  1405. */
  1406. if (dst == NULL) {
  1407. return -1;
  1408. }
  1409. /*
  1410. * Check radius vor valid range
  1411. */
  1412. if (rad < 0) {
  1413. return -1;
  1414. }
  1415. /*
  1416. * Special case - no rounding
  1417. */
  1418. if (rad == 0) {
  1419. return rectangleColor(dst, x1, y1, x2, y2, color);
  1420. }
  1421. /*
  1422. * Check visibility of clipping rectangle
  1423. */
  1424. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  1425. return 0;
  1426. }
  1427. /*
  1428. * Test for special cases of straight lines or single point
  1429. */
  1430. if (x1 == x2) {
  1431. if (y1 == y2) {
  1432. return (pixelColor(dst, x1, y1, color));
  1433. } else {
  1434. return (vlineColor(dst, x1, y1, y2, color));
  1435. }
  1436. } else {
  1437. if (y1 == y2) {
  1438. return (hlineColor(dst, x1, x2, y1, color));
  1439. }
  1440. }
  1441. /*
  1442. * Swap x1, x2 if required
  1443. */
  1444. if (x1 > x2) {
  1445. tmp = x1;
  1446. x1 = x2;
  1447. x2 = tmp;
  1448. }
  1449. /*
  1450. * Swap y1, y2 if required
  1451. */
  1452. if (y1 > y2) {
  1453. tmp = y1;
  1454. y1 = y2;
  1455. y2 = tmp;
  1456. }
  1457. /*
  1458. * Calculate width&height
  1459. */
  1460. w = x2 - x1;
  1461. h = y2 - y1;
  1462. /*
  1463. * Maybe adjust radius
  1464. */
  1465. if ((rad * 2) > w) {
  1466. rad = w / 2;
  1467. }
  1468. if ((rad * 2) > h) {
  1469. rad = h / 2;
  1470. }
  1471. /*
  1472. * Draw corners
  1473. */
  1474. result = 0;
  1475. xx1 = x1 + rad;
  1476. xx2 = x2 - rad;
  1477. yy1 = y1 + rad;
  1478. yy2 = y2 - rad;
  1479. result |= arcColor(dst, xx1, yy1, rad, 180, 270, color);
  1480. result |= arcColor(dst, xx2, yy1, rad, 270, 360, color);
  1481. result |= arcColor(dst, xx1, yy2, rad, 90, 180, color);
  1482. result |= arcColor(dst, xx2, yy2, rad, 0, 90, color);
  1483. /*
  1484. * Draw lines
  1485. */
  1486. if (xx1 <= xx2) {
  1487. result |= hlineColor(dst, xx1, xx2, y1, color);
  1488. result |= hlineColor(dst, xx1, xx2, y2, color);
  1489. }
  1490. if (yy1 <= yy2) {
  1491. result |= vlineColor(dst, x1, yy1, yy2, color);
  1492. result |= vlineColor(dst, x2, yy1, yy2, color);
  1493. }
  1494. return result;
  1495. }
  1496. /*!
  1497. \brief Draw rounded-corner rectangle with blending.
  1498. \param dst The surface to draw on.
  1499. \param x1 X coordinate of the first point (i.e. top right) of the rectangle.
  1500. \param y1 Y coordinate of the first point (i.e. top right) of the rectangle.
  1501. \param x2 X coordinate of the second point (i.e. bottom left) of the rectangle.
  1502. \param y2 Y coordinate of the second point (i.e. bottom left) of the rectangle.
  1503. \param rad The radius of the corner arc.
  1504. \param r The red value of the rectangle to draw.
  1505. \param g The green value of the rectangle to draw.
  1506. \param b The blue value of the rectangle to draw.
  1507. \param a The alpha value of the rectangle to draw.
  1508. \returns Returns 0 on success, -1 on failure.
  1509. */
  1510. int roundedRectangleRGBA(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint8 r, Uint8 g,
  1511. Uint8 b, Uint8 a) {
  1512. /*
  1513. * Draw
  1514. */
  1515. return (roundedRectangleColor
  1516. (dst, x1, y1, x2, y2, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  1517. }
  1518. /*!
  1519. \brief Draw rounded-corner box (filled rectangle) with blending.
  1520. \param dst The surface to draw on.
  1521. \param x1 X coordinate of the first point (i.e. top right) of the box.
  1522. \param y1 Y coordinate of the first point (i.e. top right) of the box.
  1523. \param x2 X coordinate of the second point (i.e. bottom left) of the box.
  1524. \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
  1525. \param rad The radius of the corner arcs of the box.
  1526. \param color The color value of the box to draw (0xRRGGBBAA).
  1527. \returns Returns 0 on success, -1 on failure.
  1528. */
  1529. int roundedBoxColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 rad, Uint32 color) {
  1530. int result;
  1531. Sint16 w, h, tmp;
  1532. Sint16 xx1, xx2, yy1, yy2;
  1533. /*
  1534. * Check destination surface
  1535. */
  1536. if (dst == NULL) {
  1537. return -1;
  1538. }
  1539. /*
  1540. * Check radius vor valid range
  1541. */
  1542. if (rad < 0) {
  1543. return -1;
  1544. }
  1545. /*
  1546. * Special case - no rounding
  1547. */
  1548. if (rad == 0) {
  1549. return rectangleColor(dst, x1, y1, x2, y2, color);
  1550. }
  1551. /*
  1552. * Check visibility of clipping rectangle
  1553. */
  1554. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  1555. return 0;
  1556. }
  1557. /*
  1558. * Test for special cases of straight lines or single point
  1559. */
  1560. if (x1 == x2) {
  1561. if (y1 == y2) {
  1562. return (pixelColor(dst, x1, y1, color));
  1563. } else {
  1564. return (vlineColor(dst, x1, y1, y2, color));
  1565. }
  1566. } else {
  1567. if (y1 == y2) {
  1568. return (hlineColor(dst, x1, x2, y1, color));
  1569. }
  1570. }
  1571. /*
  1572. * Swap x1, x2 if required
  1573. */
  1574. if (x1 > x2) {
  1575. tmp = x1;
  1576. x1 = x2;
  1577. x2 = tmp;
  1578. }
  1579. /*
  1580. * Swap y1, y2 if required
  1581. */
  1582. if (y1 > y2) {
  1583. tmp = y1;
  1584. y1 = y2;
  1585. y2 = tmp;
  1586. }
  1587. /*
  1588. * Calculate width&height
  1589. */
  1590. w = x2 - x1;
  1591. h = y2 - y1;
  1592. /*
  1593. * Maybe adjust radius
  1594. */
  1595. if ((rad * 2) > w) {
  1596. rad = w / 2;
  1597. }
  1598. if ((rad * 2) > h) {
  1599. rad = h / 2;
  1600. }
  1601. /*
  1602. * Draw corners
  1603. */
  1604. result = 0;
  1605. xx1 = x1 + rad;
  1606. xx2 = x2 - rad;
  1607. yy1 = y1 + rad;
  1608. yy2 = y2 - rad;
  1609. result |= filledPieColor(dst, xx1, yy1, rad, 180, 270, color);
  1610. result |= filledPieColor(dst, xx2, yy1, rad, 270, 360, color);
  1611. result |= filledPieColor(dst, xx1, yy2, rad, 90, 180, color);
  1612. result |= filledPieColor(dst, xx2, yy2, rad, 0, 90, color);
  1613. /*
  1614. * Draw body
  1615. */
  1616. xx1++;
  1617. xx2--;
  1618. yy1++;
  1619. yy2--;
  1620. if (xx1 <= xx2) {
  1621. result |= boxColor(dst, xx1, y1, xx2, y2, color);
  1622. }
  1623. if (yy1 <= yy2) {
  1624. result |= boxColor(dst, x1, yy1, xx1 - 1, yy2, color);
  1625. result |= boxColor(dst, xx2 + 1, yy1, x2, yy2, color);
  1626. }
  1627. return result;
  1628. }
  1629. /*!
  1630. \brief Draw rounded-corner box (filled rectangle) with blending.
  1631. \param dst The surface to draw on.
  1632. \param x1 X coordinate of the first point (i.e. top right) of the box.
  1633. \param y1 Y coordinate of the first point (i.e. top right) of the box.
  1634. \param x2 X coordinate of the second point (i.e. bottom left) of the box.
  1635. \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
  1636. \param rad The radius of the corner arcs of the box.
  1637. \param r The red value of the box to draw.
  1638. \param g The green value of the box to draw.
  1639. \param b The blue value of the box to draw.
  1640. \param a The alpha value of the box to draw.
  1641. \returns Returns 0 on success, -1 on failure.
  1642. */
  1643. int roundedBoxRGBA(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2,
  1644. Sint16 y2, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  1645. /*
  1646. * Draw
  1647. */
  1648. return (roundedBoxColor
  1649. (dst, x1, y1, x2, y2, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  1650. }
  1651. /* --------- Clipping routines for line */
  1652. /* Clipping based heavily on code from */
  1653. /* http://www.ncsa.uiuc.edu/Vis/Graphics/src/clipCohSuth.c */
  1654. #define CLIP_LEFT_EDGE 0x1
  1655. #define CLIP_RIGHT_EDGE 0x2
  1656. #define CLIP_BOTTOM_EDGE 0x4
  1657. #define CLIP_TOP_EDGE 0x8
  1658. #define CLIP_INSIDE(a) (!a)
  1659. #define CLIP_REJECT(a, b) (a&b)
  1660. #define CLIP_ACCEPT(a, b) (!(a|b))
  1661. /*!
  1662. \brief Internal clip-encoding routine.
  1663. Calculates a segement-based clipping encoding for a point against a rectangle.
  1664. \param x X coordinate of point.
  1665. \param y Y coordinate of point.
  1666. \param left X coordinate of left edge of the rectangle.
  1667. \param top Y coordinate of top edge of the rectangle.
  1668. \param right X coordinate of right edge of the rectangle.
  1669. \param bottom Y coordinate of bottom edge of the rectangle.
  1670. */
  1671. static int _clipEncode(Sint16 x, Sint16 y, Sint16 left, Sint16 top, Sint16 right, Sint16 bottom) {
  1672. int code = 0;
  1673. if (x < left) {
  1674. code |= CLIP_LEFT_EDGE;
  1675. } else if (x > right) {
  1676. code |= CLIP_RIGHT_EDGE;
  1677. }
  1678. if (y < top) {
  1679. code |= CLIP_TOP_EDGE;
  1680. } else if (y > bottom) {
  1681. code |= CLIP_BOTTOM_EDGE;
  1682. }
  1683. return code;
  1684. }
  1685. /*!
  1686. \brief Clip line to a the clipping rectangle of a surface.
  1687. \param dst Target surface to draw on.
  1688. \param x1 Pointer to X coordinate of first point of line.
  1689. \param y1 Pointer to Y coordinate of first point of line.
  1690. \param x2 Pointer to X coordinate of second point of line.
  1691. \param y2 Pointer to Y coordinate of second point of line.
  1692. */
  1693. static int _clipLine(SDL_Surface *dst, Sint16 *x1, Sint16 *y1, Sint16 *x2, Sint16 *y2) {
  1694. Sint16 left, right, top, bottom;
  1695. int code1, code2;
  1696. int draw = 0;
  1697. Sint16 swaptmp;
  1698. float m;
  1699. /*
  1700. * Get clipping boundary
  1701. */
  1702. left = dst->clip_rect.x;
  1703. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  1704. top = dst->clip_rect.y;
  1705. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  1706. while (1) {
  1707. code1 = _clipEncode(*x1, *y1, left, top, right, bottom);
  1708. code2 = _clipEncode(*x2, *y2, left, top, right, bottom);
  1709. if (CLIP_ACCEPT(code1, code2)) {
  1710. draw = 1;
  1711. break;
  1712. } else if (CLIP_REJECT(code1, code2))
  1713. break;
  1714. else {
  1715. if (CLIP_INSIDE(code1)) {
  1716. swaptmp = *x2;
  1717. *x2 = *x1;
  1718. *x1 = swaptmp;
  1719. swaptmp = *y2;
  1720. *y2 = *y1;
  1721. *y1 = swaptmp;
  1722. swaptmp = code2;
  1723. code2 = code1;
  1724. code1 = swaptmp;
  1725. }
  1726. if (*x2 != *x1) {
  1727. m = (float) (*y2 - *y1) / (float) (*x2 - *x1);
  1728. } else {
  1729. m = 1.0f;
  1730. }
  1731. if (code1 & CLIP_LEFT_EDGE) {
  1732. *y1 += (Sint16) ((left - *x1) * m);
  1733. *x1 = left;
  1734. } else if (code1 & CLIP_RIGHT_EDGE) {
  1735. *y1 += (Sint16) ((right - *x1) * m);
  1736. *x1 = right;
  1737. } else if (code1 & CLIP_BOTTOM_EDGE) {
  1738. if (*x2 != *x1) {
  1739. *x1 += (Sint16) ((bottom - *y1) / m);
  1740. }
  1741. *y1 = bottom;
  1742. } else if (code1 & CLIP_TOP_EDGE) {
  1743. if (*x2 != *x1) {
  1744. *x1 += (Sint16) ((top - *y1) / m);
  1745. }
  1746. *y1 = top;
  1747. }
  1748. }
  1749. }
  1750. return draw;
  1751. }
  1752. /*!
  1753. \brief Draw box (filled rectangle) with blending.
  1754. \param dst The surface to draw on.
  1755. \param x1 X coordinate of the first point (i.e. top right) of the box.
  1756. \param y1 Y coordinate of the first point (i.e. top right) of the box.
  1757. \param x2 X coordinate of the second point (i.e. bottom left) of the box.
  1758. \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
  1759. \param color The color value of the box to draw (0xRRGGBBAA).
  1760. \returns Returns 0 on success, -1 on failure.
  1761. */
  1762. int boxColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) {
  1763. Sint16 left, right, top, bottom;
  1764. Uint8 *pixel, *pixellast;
  1765. int x, dx;
  1766. int dy;
  1767. int pixx, pixy;
  1768. Sint16 w, h, tmp;
  1769. int result;
  1770. Uint8 *colorptr;
  1771. /*
  1772. * Check visibility of clipping rectangle
  1773. */
  1774. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  1775. return (0);
  1776. }
  1777. /*
  1778. * Order coordinates to ensure that
  1779. * x1<=x2 and y1<=y2
  1780. */
  1781. if (x1 > x2) {
  1782. tmp = x1;
  1783. x1 = x2;
  1784. x2 = tmp;
  1785. }
  1786. if (y1 > y2) {
  1787. tmp = y1;
  1788. y1 = y2;
  1789. y2 = tmp;
  1790. }
  1791. /*
  1792. * Get clipping boundary and
  1793. * check visibility
  1794. */
  1795. left = dst->clip_rect.x;
  1796. if (x2 < left) {
  1797. return (0);
  1798. }
  1799. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  1800. if (x1 > right) {
  1801. return (0);
  1802. }
  1803. top = dst->clip_rect.y;
  1804. if (y2 < top) {
  1805. return (0);
  1806. }
  1807. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  1808. if (y1 > bottom) {
  1809. return (0);
  1810. }
  1811. /* Clip all points */
  1812. if (x1 < left) {
  1813. x1 = left;
  1814. } else if (x1 > right) {
  1815. x1 = right;
  1816. }
  1817. if (x2 < left) {
  1818. x2 = left;
  1819. } else if (x2 > right) {
  1820. x2 = right;
  1821. }
  1822. if (y1 < top) {
  1823. y1 = top;
  1824. } else if (y1 > bottom) {
  1825. y1 = bottom;
  1826. }
  1827. if (y2 < top) {
  1828. y2 = top;
  1829. } else if (y2 > bottom) {
  1830. y2 = bottom;
  1831. }
  1832. /*
  1833. * Test for special cases of straight line or single point
  1834. */
  1835. if (x1 == x2) {
  1836. if (y1 == y2) {
  1837. return (pixelColor(dst, x1, y1, color));
  1838. } else {
  1839. return (vlineColor(dst, x1, y1, y2, color));
  1840. }
  1841. }
  1842. if (y1 == y2) {
  1843. return (hlineColor(dst, x1, x2, y1, color));
  1844. }
  1845. /*
  1846. * Calculate width&height
  1847. */
  1848. w = x2 - x1;
  1849. h = y2 - y1;
  1850. /*
  1851. * Alpha check
  1852. */
  1853. if ((color & 255) == 255) {
  1854. /*
  1855. * No alpha-blending required
  1856. */
  1857. /*
  1858. * Setup color
  1859. */
  1860. colorptr = (Uint8 *) &color;
  1861. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  1862. color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
  1863. } else {
  1864. color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
  1865. }
  1866. /*
  1867. * Lock the surface
  1868. */
  1869. if (SDL_MUSTLOCK(dst)) {
  1870. if (SDL_LockSurface(dst) < 0) {
  1871. return (-1);
  1872. }
  1873. }
  1874. /*
  1875. * More variable setup
  1876. */
  1877. dx = w;
  1878. dy = h;
  1879. pixx = dst->format->BytesPerPixel;
  1880. pixy = dst->pitch;
  1881. pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
  1882. pixellast = pixel + pixx * dx + pixy * dy;
  1883. dx++;
  1884. /*
  1885. * Draw
  1886. */
  1887. switch (dst->format->BytesPerPixel) {
  1888. case 1:
  1889. for (; pixel <= pixellast; pixel += pixy) {
  1890. memset(pixel, (Uint8) color, dx);
  1891. }
  1892. break;
  1893. case 2:
  1894. pixy -= (pixx * dx);
  1895. for (; pixel <= pixellast; pixel += pixy) {
  1896. for (x = 0; x < dx; x++) {
  1897. *(Uint16 *) pixel = color;
  1898. pixel += pixx;
  1899. }
  1900. }
  1901. break;
  1902. case 3:
  1903. pixy -= (pixx * dx);
  1904. for (; pixel <= pixellast; pixel += pixy) {
  1905. for (x = 0; x < dx; x++) {
  1906. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  1907. pixel[0] = (color >> 16) & 0xff;
  1908. pixel[1] = (color >> 8) & 0xff;
  1909. pixel[2] = color & 0xff;
  1910. } else {
  1911. pixel[0] = color & 0xff;
  1912. pixel[1] = (color >> 8) & 0xff;
  1913. pixel[2] = (color >> 16) & 0xff;
  1914. }
  1915. pixel += pixx;
  1916. }
  1917. }
  1918. break;
  1919. default: /* case 4 */
  1920. pixy -= (pixx * dx);
  1921. for (; pixel <= pixellast; pixel += pixy) {
  1922. for (x = 0; x < dx; x++) {
  1923. *(Uint32 *) pixel = color;
  1924. pixel += pixx;
  1925. }
  1926. }
  1927. break;
  1928. }
  1929. /* Unlock surface */
  1930. if (SDL_MUSTLOCK(dst)) {
  1931. SDL_UnlockSurface(dst);
  1932. }
  1933. result = 0;
  1934. } else {
  1935. result = filledRectAlpha(dst, x1, y1, x1 + w, y1 + h, color);
  1936. }
  1937. return (result);
  1938. }
  1939. /*!
  1940. \brief Draw box (filled rectangle) with blending.
  1941. \param dst The surface to draw on.
  1942. \param x1 X coordinate of the first point (i.e. top right) of the box.
  1943. \param y1 Y coordinate of the first point (i.e. top right) of the box.
  1944. \param x2 X coordinate of the second point (i.e. bottom left) of the box.
  1945. \param y2 Y coordinate of the second point (i.e. bottom left) of the box.
  1946. \param r The red value of the box to draw.
  1947. \param g The green value of the box to draw.
  1948. \param b The blue value of the box to draw.
  1949. \param a The alpha value of the box to draw.
  1950. \returns Returns 0 on success, -1 on failure.
  1951. */
  1952. int boxRGBA(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  1953. /*
  1954. * Draw
  1955. */
  1956. return (boxColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  1957. }
  1958. /* ----- Line */
  1959. /* Non-alpha line drawing code adapted from routine */
  1960. /* by Pete Shinners, pete@shinners.org */
  1961. /* Originally from pygame, http://pygame.seul.org */
  1962. #define ABS(a) (((a)<0) ? -(a) : (a))
  1963. /*!
  1964. \brief Draw line with alpha blending.
  1965. \param dst The surface to draw on.
  1966. \param x1 X coordinate of the first point of the line.
  1967. \param y1 Y coordinate of the first point of the line.
  1968. \param x2 X coordinate of the second point of the line.
  1969. \param y2 Y coordinate of the second point of the line.
  1970. \param color The color value of the line to draw (0xRRGGBBAA).
  1971. \returns Returns 0 on success, -1 on failure.
  1972. */
  1973. int lineColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) {
  1974. int pixx, pixy;
  1975. int x, y;
  1976. int dx, dy;
  1977. int ax, ay;
  1978. int sx, sy;
  1979. int swaptmp;
  1980. Uint8 *pixel;
  1981. Uint8 *colorptr;
  1982. /*
  1983. * Clip line and test if we have to draw
  1984. */
  1985. if (!(_clipLine(dst, &x1, &y1, &x2, &y2))) {
  1986. return (0);
  1987. }
  1988. /*
  1989. * Test for special cases of straight lines or single point
  1990. */
  1991. if (x1 == x2) {
  1992. if (y1 < y2) {
  1993. return (vlineColor(dst, x1, y1, y2, color));
  1994. } else if (y1 > y2) {
  1995. return (vlineColor(dst, x1, y2, y1, color));
  1996. } else {
  1997. return (pixelColor(dst, x1, y1, color));
  1998. }
  1999. }
  2000. if (y1 == y2) {
  2001. if (x1 < x2) {
  2002. return (hlineColor(dst, x1, x2, y1, color));
  2003. } else if (x1 > x2) {
  2004. return (hlineColor(dst, x2, x1, y1, color));
  2005. }
  2006. }
  2007. /*
  2008. * Variable setup
  2009. */
  2010. dx = x2 - x1;
  2011. dy = y2 - y1;
  2012. sx = (dx >= 0) ? 1 : -1;
  2013. sy = (dy >= 0) ? 1 : -1;
  2014. /* Lock surface */
  2015. if (SDL_MUSTLOCK(dst)) {
  2016. if (SDL_LockSurface(dst) < 0) {
  2017. return (-1);
  2018. }
  2019. }
  2020. /*
  2021. * Check for alpha blending
  2022. */
  2023. if ((color & 255) == 255) {
  2024. /*
  2025. * No alpha blending - use fast pixel routines
  2026. */
  2027. /*
  2028. * Setup color
  2029. */
  2030. colorptr = (Uint8 *) &color;
  2031. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  2032. color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
  2033. } else {
  2034. color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
  2035. }
  2036. /*
  2037. * More variable setup
  2038. */
  2039. dx = sx * dx + 1;
  2040. dy = sy * dy + 1;
  2041. pixx = dst->format->BytesPerPixel;
  2042. pixy = dst->pitch;
  2043. pixel = ((Uint8 *) dst->pixels) + pixx * (int) x1 + pixy * (int) y1;
  2044. pixx *= sx;
  2045. pixy *= sy;
  2046. if (dx < dy) {
  2047. swaptmp = dx;
  2048. dx = dy;
  2049. dy = swaptmp;
  2050. swaptmp = pixx;
  2051. pixx = pixy;
  2052. pixy = swaptmp;
  2053. }
  2054. /*
  2055. * Draw
  2056. */
  2057. x = 0;
  2058. y = 0;
  2059. switch (dst->format->BytesPerPixel) {
  2060. case 1:
  2061. for (; x < dx; x++, pixel += pixx) {
  2062. *pixel = color;
  2063. y += dy;
  2064. if (y >= dx) {
  2065. y -= dx;
  2066. pixel += pixy;
  2067. }
  2068. }
  2069. break;
  2070. case 2:
  2071. for (; x < dx; x++, pixel += pixx) {
  2072. *(Uint16 *) pixel = color;
  2073. y += dy;
  2074. if (y >= dx) {
  2075. y -= dx;
  2076. pixel += pixy;
  2077. }
  2078. }
  2079. break;
  2080. case 3:
  2081. for (; x < dx; x++, pixel += pixx) {
  2082. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  2083. pixel[0] = (color >> 16) & 0xff;
  2084. pixel[1] = (color >> 8) & 0xff;
  2085. pixel[2] = color & 0xff;
  2086. } else {
  2087. pixel[0] = color & 0xff;
  2088. pixel[1] = (color >> 8) & 0xff;
  2089. pixel[2] = (color >> 16) & 0xff;
  2090. }
  2091. y += dy;
  2092. if (y >= dx) {
  2093. y -= dx;
  2094. pixel += pixy;
  2095. }
  2096. }
  2097. break;
  2098. default: /* case 4 */
  2099. for (; x < dx; x++, pixel += pixx) {
  2100. *(Uint32 *) pixel = color;
  2101. y += dy;
  2102. if (y >= dx) {
  2103. y -= dx;
  2104. pixel += pixy;
  2105. }
  2106. }
  2107. break;
  2108. }
  2109. } else {
  2110. /*
  2111. * Alpha blending required - use single-pixel blits
  2112. */
  2113. ax = ABS(dx) << 1;
  2114. ay = ABS(dy) << 1;
  2115. x = x1;
  2116. y = y1;
  2117. if (ax > ay) {
  2118. int d = ay - (ax >> 1);
  2119. while (x != x2) {
  2120. pixelColorNolock(dst, x, y, color);
  2121. if (d > 0 || (d == 0 && sx == 1)) {
  2122. y += sy;
  2123. d -= ax;
  2124. }
  2125. x += sx;
  2126. d += ay;
  2127. }
  2128. } else {
  2129. int d = ax - (ay >> 1);
  2130. while (y != y2) {
  2131. pixelColorNolock(dst, x, y, color);
  2132. if (d > 0 || ((d == 0) && (sy == 1))) {
  2133. x += sx;
  2134. d -= ay;
  2135. }
  2136. y += sy;
  2137. d += ax;
  2138. }
  2139. }
  2140. pixelColorNolock(dst, x, y, color);
  2141. }
  2142. /* Unlock surface */
  2143. if (SDL_MUSTLOCK(dst)) {
  2144. SDL_UnlockSurface(dst);
  2145. }
  2146. return (0);
  2147. }
  2148. /*!
  2149. \brief Draw line with alpha blending.
  2150. \param dst The surface to draw on.
  2151. \param x1 X coordinate of the first point of the line.
  2152. \param y1 Y coordinate of the first point of the line.
  2153. \param x2 X coordinate of the second point of the line.
  2154. \param y2 Y coordinate of the second point of the line.
  2155. \param r The red value of the line to draw.
  2156. \param g The green value of the line to draw.
  2157. \param b The blue value of the line to draw.
  2158. \param a The alpha value of the line to draw.
  2159. \returns Returns 0 on success, -1 on failure.
  2160. */
  2161. int lineRGBA(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  2162. /*
  2163. * Draw
  2164. */
  2165. return (lineColor(dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  2166. }
  2167. /* AA Line */
  2168. #define AAlevels 256
  2169. #define AAbits 8
  2170. /*!
  2171. \brief Internal function to draw anti-aliased line with alpha blending and endpoint control.
  2172. This implementation of the Wu antialiasing code is based on Mike Abrash's
  2173. DDJ article which was reprinted as Chapter 42 of his Graphics Programming
  2174. Black Book, but has been optimized to work with SDL and utilizes 32-bit
  2175. fixed-point arithmetic by A. Schiffler. The endpoint control allows the
  2176. supression to draw the last pixel useful for rendering continous aa-lines
  2177. with alpha<255.
  2178. \param dst The surface to draw on.
  2179. \param x1 X coordinate of the first point of the aa-line.
  2180. \param y1 Y coordinate of the first point of the aa-line.
  2181. \param x2 X coordinate of the second point of the aa-line.
  2182. \param y2 Y coordinate of the second point of the aa-line.
  2183. \param color The color value of the aa-line to draw (0xRRGGBBAA).
  2184. \param draw_endpoint Flag indicating if the endpoint should be drawn; draw if non-zero.
  2185. \returns Returns 0 on success, -1 on failure.
  2186. */
  2187. int _aalineColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, int draw_endpoint) {
  2188. Sint32 xx0, yy0, xx1, yy1;
  2189. int result;
  2190. Uint32 intshift, erracc, erradj;
  2191. Uint32 erracctmp, wgt, wgtcompmask;
  2192. int dx, dy, tmp, xdir, y0p1, x0pxdir;
  2193. /*
  2194. * Check visibility of clipping rectangle
  2195. */
  2196. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  2197. return (0);
  2198. }
  2199. /*
  2200. * Clip line and test if we have to draw
  2201. */
  2202. if (!(_clipLine(dst, &x1, &y1, &x2, &y2))) {
  2203. return (0);
  2204. }
  2205. /*
  2206. * Keep on working with 32bit numbers
  2207. */
  2208. xx0 = x1;
  2209. yy0 = y1;
  2210. xx1 = x2;
  2211. yy1 = y2;
  2212. /*
  2213. * Reorder points if required
  2214. */
  2215. if (yy0 > yy1) {
  2216. tmp = yy0;
  2217. yy0 = yy1;
  2218. yy1 = tmp;
  2219. tmp = xx0;
  2220. xx0 = xx1;
  2221. xx1 = tmp;
  2222. }
  2223. /*
  2224. * Calculate distance
  2225. */
  2226. dx = xx1 - xx0;
  2227. dy = yy1 - yy0;
  2228. /*
  2229. * Check for special cases
  2230. */
  2231. if (dx == 0) {
  2232. /*
  2233. * Vertical line
  2234. */
  2235. if (draw_endpoint) {
  2236. return (vlineColor(dst, x1, y1, y2, color));
  2237. } else {
  2238. if (dy > 0) {
  2239. return (vlineColor(dst, x1, yy0, yy0 + dy, color));
  2240. } else {
  2241. return (pixelColor(dst, x1, y1, color));
  2242. }
  2243. }
  2244. } else if (dy == 0) {
  2245. /*
  2246. * Horizontal line
  2247. */
  2248. if (draw_endpoint) {
  2249. return (hlineColor(dst, x1, x2, y1, color));
  2250. } else {
  2251. if (dx != 0) {
  2252. return (hlineColor(dst, xx0, xx0 + dx, y1, color));
  2253. } else {
  2254. return (pixelColor(dst, x1, y1, color));
  2255. }
  2256. }
  2257. } else if ((dx == dy) && (draw_endpoint)) {
  2258. /*
  2259. * Diagonal line (with endpoint)
  2260. */
  2261. return (lineColor(dst, x1, y1, x2, y2, color));
  2262. }
  2263. /*
  2264. * Adjust for negative dx and set xdir
  2265. */
  2266. if (dx >= 0) {
  2267. xdir = 1;
  2268. } else {
  2269. xdir = -1;
  2270. dx = (-dx);
  2271. }
  2272. /*
  2273. * Line is not horizontal, vertical or diagonal (with endpoint)
  2274. */
  2275. result = 0;
  2276. /*
  2277. * Zero accumulator
  2278. */
  2279. erracc = 0;
  2280. /*
  2281. * # of bits by which to shift erracc to get intensity level
  2282. */
  2283. intshift = 32 - AAbits;
  2284. /*
  2285. * Mask used to flip all bits in an intensity weighting
  2286. */
  2287. wgtcompmask = AAlevels - 1;
  2288. /* Lock surface */
  2289. if (SDL_MUSTLOCK(dst)) {
  2290. if (SDL_LockSurface(dst) < 0) {
  2291. return (-1);
  2292. }
  2293. }
  2294. /*
  2295. * Draw the initial pixel in the foreground color
  2296. */
  2297. result |= pixelColorNolock(dst, x1, y1, color);
  2298. /*
  2299. * x-major or y-major?
  2300. */
  2301. if (dy > dx) {
  2302. /*
  2303. * y-major. Calculate 16-bit fixed point fractional part of a pixel that
  2304. * X advances every time Y advances 1 pixel, truncating the result so that
  2305. * we won't overrun the endpoint along the X axis
  2306. */
  2307. /*
  2308. * Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy;
  2309. */
  2310. erradj = ((dx << 16) / dy) << 16;
  2311. /*
  2312. * draw all pixels other than the first and last
  2313. */
  2314. x0pxdir = xx0 + xdir;
  2315. while (--dy) {
  2316. erracctmp = erracc;
  2317. erracc += erradj;
  2318. if (erracc <= erracctmp) {
  2319. /*
  2320. * rollover in error accumulator, x coord advances
  2321. */
  2322. xx0 = x0pxdir;
  2323. x0pxdir += xdir;
  2324. }
  2325. yy0++; /* y-major so always advance Y */
  2326. /*
  2327. * the AAbits most significant bits of erracc give us the intensity
  2328. * weighting for this pixel, and the complement of the weighting for
  2329. * the paired pixel.
  2330. */
  2331. wgt = (erracc >> intshift) & 255;
  2332. result |= pixelColorWeightNolock(dst, xx0, yy0, color, 255 - wgt);
  2333. result |= pixelColorWeightNolock(dst, x0pxdir, yy0, color, wgt);
  2334. }
  2335. } else {
  2336. /*
  2337. * x-major line. Calculate 16-bit fixed-point fractional part of a pixel
  2338. * that Y advances each time X advances 1 pixel, truncating the result so
  2339. * that we won't overrun the endpoint along the X axis.
  2340. */
  2341. /*
  2342. * Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx;
  2343. */
  2344. erradj = ((dy << 16) / dx) << 16;
  2345. /*
  2346. * draw all pixels other than the first and last
  2347. */
  2348. y0p1 = yy0 + 1;
  2349. while (--dx) {
  2350. erracctmp = erracc;
  2351. erracc += erradj;
  2352. if (erracc <= erracctmp) {
  2353. /*
  2354. * Accumulator turned over, advance y
  2355. */
  2356. yy0 = y0p1;
  2357. y0p1++;
  2358. }
  2359. xx0 += xdir; /* x-major so always advance X */
  2360. /*
  2361. * the AAbits most significant bits of erracc give us the intensity
  2362. * weighting for this pixel, and the complement of the weighting for
  2363. * the paired pixel.
  2364. */
  2365. wgt = (erracc >> intshift) & 255;
  2366. result |= pixelColorWeightNolock(dst, xx0, yy0, color, 255 - wgt);
  2367. result |= pixelColorWeightNolock(dst, xx0, y0p1, color, wgt);
  2368. }
  2369. }
  2370. /*
  2371. * Do we have to draw the endpoint
  2372. */
  2373. if (draw_endpoint) {
  2374. /*
  2375. * Draw final pixel, always exactly intersected by the line and doesn't
  2376. * need to be weighted.
  2377. */
  2378. result |= pixelColorNolock(dst, x2, y2, color);
  2379. }
  2380. /* Unlock surface */
  2381. if (SDL_MUSTLOCK(dst)) {
  2382. SDL_UnlockSurface(dst);
  2383. }
  2384. return (result);
  2385. }
  2386. /*!
  2387. \brief Ddraw anti-aliased line with alpha blending.
  2388. \param dst The surface to draw on.
  2389. \param x1 X coordinate of the first point of the aa-line.
  2390. \param y1 Y coordinate of the first point of the aa-line.
  2391. \param x2 X coordinate of the second point of the aa-line.
  2392. \param y2 Y coordinate of the second point of the aa-line.
  2393. \param color The color value of the aa-line to draw (0xRRGGBBAA).
  2394. \returns Returns 0 on success, -1 on failure.
  2395. */
  2396. int aalineColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) {
  2397. return (_aalineColor(dst, x1, y1, x2, y2, color, 1));
  2398. }
  2399. /*!
  2400. \brief Draw anti-aliased line with alpha blending.
  2401. \param dst The surface to draw on.
  2402. \param x1 X coordinate of the first point of the aa-line.
  2403. \param y1 Y coordinate of the first point of the aa-line.
  2404. \param x2 X coordinate of the second point of the aa-line.
  2405. \param y2 Y coordinate of the second point of the aa-line.
  2406. \param r The red value of the aa-line to draw.
  2407. \param g The green value of the aa-line to draw.
  2408. \param b The blue value of the aa-line to draw.
  2409. \param a The alpha value of the aa-line to draw.
  2410. \returns Returns 0 on success, -1 on failure.
  2411. */
  2412. int aalineRGBA(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  2413. return (_aalineColor
  2414. (dst, x1, y1, x2, y2, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1));
  2415. }
  2416. /* ----- Circle */
  2417. /*!
  2418. \brief Draw circle with blending.
  2419. Note: Circle drawing routine is based on an algorithms from the sge library,
  2420. but modified by A. Schiffler for multiple pixel-draw removal and other
  2421. minor speedup changes.
  2422. \param dst The surface to draw on.
  2423. \param x X coordinate of the center of the circle.
  2424. \param y Y coordinate of the center of the circle.
  2425. \param rad Radius in pixels of the circle.
  2426. \param color The color value of the circle to draw (0xRRGGBBAA).
  2427. \returns Returns 0 on success, -1 on failure.
  2428. */
  2429. int circleColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color) {
  2430. Sint16 left, right, top, bottom;
  2431. int result;
  2432. Sint16 x1, y1, x2, y2;
  2433. Sint16 cx = 0;
  2434. Sint16 cy = rad;
  2435. Sint16 df = 1 - rad;
  2436. Sint16 d_e = 3;
  2437. Sint16 d_se = -2 * rad + 5;
  2438. Sint16 xpcx, xmcx, xpcy, xmcy;
  2439. Sint16 ypcy, ymcy, ypcx, ymcx;
  2440. Uint8 *colorptr;
  2441. /*
  2442. * Check visibility of clipping rectangle
  2443. */
  2444. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  2445. return (0);
  2446. }
  2447. /*
  2448. * Sanity check radius
  2449. */
  2450. if (rad < 0) {
  2451. return (-1);
  2452. }
  2453. /*
  2454. * Special case for rad=0 - draw a point
  2455. */
  2456. if (rad == 0) {
  2457. return (pixelColor(dst, x, y, color));
  2458. }
  2459. /*
  2460. * Get circle and clipping boundary and
  2461. * test if bounding box of circle is visible
  2462. */
  2463. x2 = x + rad;
  2464. left = dst->clip_rect.x;
  2465. if (x2 < left) {
  2466. return (0);
  2467. }
  2468. x1 = x - rad;
  2469. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  2470. if (x1 > right) {
  2471. return (0);
  2472. }
  2473. y2 = y + rad;
  2474. top = dst->clip_rect.y;
  2475. if (y2 < top) {
  2476. return (0);
  2477. }
  2478. y1 = y - rad;
  2479. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  2480. if (y1 > bottom) {
  2481. return (0);
  2482. }
  2483. /*
  2484. * Draw circle
  2485. */
  2486. result = 0;
  2487. /* Lock surface */
  2488. if (SDL_MUSTLOCK(dst)) {
  2489. if (SDL_LockSurface(dst) < 0) {
  2490. return (-1);
  2491. }
  2492. }
  2493. /*
  2494. * Alpha Check
  2495. */
  2496. if ((color & 255) == 255) {
  2497. /*
  2498. * No Alpha - direct memory writes
  2499. */
  2500. /*
  2501. * Setup color
  2502. */
  2503. colorptr = (Uint8 *) &color;
  2504. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  2505. color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
  2506. } else {
  2507. color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
  2508. }
  2509. /*
  2510. * Draw
  2511. */
  2512. do {
  2513. ypcy = y + cy;
  2514. ymcy = y - cy;
  2515. if (cx > 0) {
  2516. xpcx = x + cx;
  2517. xmcx = x - cx;
  2518. result |= fastPixelColorNolock(dst, xmcx, ypcy, color);
  2519. result |= fastPixelColorNolock(dst, xpcx, ypcy, color);
  2520. result |= fastPixelColorNolock(dst, xmcx, ymcy, color);
  2521. result |= fastPixelColorNolock(dst, xpcx, ymcy, color);
  2522. } else {
  2523. result |= fastPixelColorNolock(dst, x, ymcy, color);
  2524. result |= fastPixelColorNolock(dst, x, ypcy, color);
  2525. }
  2526. xpcy = x + cy;
  2527. xmcy = x - cy;
  2528. if ((cx > 0) && (cx != cy)) {
  2529. ypcx = y + cx;
  2530. ymcx = y - cx;
  2531. result |= fastPixelColorNolock(dst, xmcy, ypcx, color);
  2532. result |= fastPixelColorNolock(dst, xpcy, ypcx, color);
  2533. result |= fastPixelColorNolock(dst, xmcy, ymcx, color);
  2534. result |= fastPixelColorNolock(dst, xpcy, ymcx, color);
  2535. } else if (cx == 0) {
  2536. result |= fastPixelColorNolock(dst, xmcy, y, color);
  2537. result |= fastPixelColorNolock(dst, xpcy, y, color);
  2538. }
  2539. /*
  2540. * Update
  2541. */
  2542. if (df < 0) {
  2543. df += d_e;
  2544. d_e += 2;
  2545. d_se += 2;
  2546. } else {
  2547. df += d_se;
  2548. d_e += 2;
  2549. d_se += 4;
  2550. cy--;
  2551. }
  2552. cx++;
  2553. } while (cx <= cy);
  2554. /*
  2555. * Unlock surface
  2556. */
  2557. SDL_UnlockSurface(dst);
  2558. } else {
  2559. /*
  2560. * Using Alpha - blended pixel blits
  2561. */
  2562. do {
  2563. /*
  2564. * Draw
  2565. */
  2566. ypcy = y + cy;
  2567. ymcy = y - cy;
  2568. if (cx > 0) {
  2569. xpcx = x + cx;
  2570. xmcx = x - cx;
  2571. result |= pixelColorNolock(dst, xmcx, ypcy, color);
  2572. result |= pixelColorNolock(dst, xpcx, ypcy, color);
  2573. result |= pixelColorNolock(dst, xmcx, ymcy, color);
  2574. result |= pixelColorNolock(dst, xpcx, ymcy, color);
  2575. } else {
  2576. result |= pixelColorNolock(dst, x, ymcy, color);
  2577. result |= pixelColorNolock(dst, x, ypcy, color);
  2578. }
  2579. xpcy = x + cy;
  2580. xmcy = x - cy;
  2581. if ((cx > 0) && (cx != cy)) {
  2582. ypcx = y + cx;
  2583. ymcx = y - cx;
  2584. result |= pixelColorNolock(dst, xmcy, ypcx, color);
  2585. result |= pixelColorNolock(dst, xpcy, ypcx, color);
  2586. result |= pixelColorNolock(dst, xmcy, ymcx, color);
  2587. result |= pixelColorNolock(dst, xpcy, ymcx, color);
  2588. } else if (cx == 0) {
  2589. result |= pixelColorNolock(dst, xmcy, y, color);
  2590. result |= pixelColorNolock(dst, xpcy, y, color);
  2591. }
  2592. /*
  2593. * Update
  2594. */
  2595. if (df < 0) {
  2596. df += d_e;
  2597. d_e += 2;
  2598. d_se += 2;
  2599. } else {
  2600. df += d_se;
  2601. d_e += 2;
  2602. d_se += 4;
  2603. cy--;
  2604. }
  2605. cx++;
  2606. } while (cx <= cy);
  2607. } /* Alpha check */
  2608. /* Unlock surface */
  2609. if (SDL_MUSTLOCK(dst)) {
  2610. SDL_UnlockSurface(dst);
  2611. }
  2612. return (result);
  2613. }
  2614. /*!
  2615. \brief Draw circle with blending.
  2616. \param dst The surface to draw on.
  2617. \param x X coordinate of the center of the circle.
  2618. \param y Y coordinate of the center of the circle.
  2619. \param rad Radius in pixels of the circle.
  2620. \param r The red value of the circle to draw.
  2621. \param g The green value of the circle to draw.
  2622. \param b The blue value of the circle to draw.
  2623. \param a The alpha value of the circle to draw.
  2624. \returns Returns 0 on success, -1 on failure.
  2625. */
  2626. int circleRGBA(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  2627. /*
  2628. * Draw
  2629. */
  2630. return (circleColor(dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  2631. }
  2632. /* ----- Arc */
  2633. /*!
  2634. \brief Arc with blending.
  2635. Note Arc drawing is based on circle algorithm by A. Schiffler and
  2636. written by D. Raber. Calculates which octants arc goes through and
  2637. renders pixels accordingly.
  2638. \param dst The surface to draw on.
  2639. \param x X coordinate of the center of the arc.
  2640. \param y Y coordinate of the center of the arc.
  2641. \param rad Radius in pixels of the arc.
  2642. \param start Starting radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
  2643. \param end Ending radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
  2644. \param color The color value of the arc to draw (0xRRGGBBAA).
  2645. \returns Returns 0 on success, -1 on failure.
  2646. */
  2647. int arcColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color) {
  2648. Sint16 left, right, top, bottom;
  2649. int result;
  2650. Sint16 x1, y1, x2, y2;
  2651. Sint16 cx = 0;
  2652. Sint16 cy = rad;
  2653. Sint16 df = 1 - rad;
  2654. Sint16 d_e = 3;
  2655. Sint16 d_se = -2 * rad + 5;
  2656. Sint16 xpcx, xmcx, xpcy, xmcy;
  2657. Sint16 ypcy, ymcy, ypcx, ymcx;
  2658. Uint8 *colorptr;
  2659. Uint8 drawoct;
  2660. int startoct, endoct, oct, stopval_start = 0, stopval_end = 0;
  2661. double dstart, dend, temp = 0.;
  2662. /*
  2663. * Check visibility of clipping rectangle
  2664. */
  2665. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  2666. return (0);
  2667. }
  2668. /*
  2669. * Sanity check radius
  2670. */
  2671. if (rad < 0) {
  2672. return (-1);
  2673. }
  2674. /*
  2675. * Special case for rad=0 - draw a point
  2676. */
  2677. if (rad == 0) {
  2678. return (pixelColor(dst, x, y, color));
  2679. }
  2680. /*
  2681. * Get arc's circle and clipping boundary and
  2682. * test if bounding box of circle is visible
  2683. */
  2684. x2 = x + rad;
  2685. left = dst->clip_rect.x;
  2686. if (x2 < left) {
  2687. return (0);
  2688. }
  2689. x1 = x - rad;
  2690. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  2691. if (x1 > right) {
  2692. return (0);
  2693. }
  2694. y2 = y + rad;
  2695. top = dst->clip_rect.y;
  2696. if (y2 < top) {
  2697. return (0);
  2698. }
  2699. y1 = y - rad;
  2700. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  2701. if (y1 > bottom) {
  2702. return (0);
  2703. }
  2704. // Octant labelling
  2705. //
  2706. // \ 5 | 6 /
  2707. // \ | /
  2708. // 4 \ | / 7
  2709. // \|/
  2710. //------+------ +x
  2711. // /|\
  2712. // 3 / | \ 0
  2713. // / | \
  2714. // / 2 | 1 \
  2715. // +y
  2716. // Initially reset bitmask to 0x00000000
  2717. // the set whether or not to keep drawing a given octant.
  2718. // For example: 0x00111100 means we're drawing in octants 2-5
  2719. drawoct = 0;
  2720. /*
  2721. * Fixup angles
  2722. */
  2723. start %= 360;
  2724. end %= 360;
  2725. // 0 <= start & end < 360; note that sometimes start > end - if so, arc goes back through 0.
  2726. while (start < 0) start += 360;
  2727. while (end < 0) end += 360;
  2728. start %= 360;
  2729. end %= 360;
  2730. // now, we find which octants we're drawing in.
  2731. startoct = start / 45;
  2732. endoct = end / 45;
  2733. oct = startoct - 1; // we increment as first step in loop
  2734. // stopval_start, stopval_end;
  2735. // what values of cx to stop at.
  2736. do {
  2737. oct = (oct + 1) % 8;
  2738. if (oct == startoct) {
  2739. // need to compute stopval_start for this octant. Look at picture above if this is unclear
  2740. dstart = (double) start;
  2741. switch (oct) {
  2742. case 0:
  2743. case 3:
  2744. temp = sin(dstart * M_PI / 180.);
  2745. break;
  2746. case 1:
  2747. case 6:
  2748. temp = cos(dstart * M_PI / 180.);
  2749. break;
  2750. case 2:
  2751. case 5:
  2752. temp = -cos(dstart * M_PI / 180.);
  2753. break;
  2754. case 4:
  2755. case 7:
  2756. temp = -sin(dstart * M_PI / 180.);
  2757. break;
  2758. }
  2759. temp *= rad;
  2760. stopval_start = (int) temp; // always round down.
  2761. // This isn't arbitrary, but requires graph paper to explain well.
  2762. // The basic idea is that we're always changing drawoct after we draw, so we
  2763. // stop immediately after we render the last sensible pixel at x = ((int)temp).
  2764. // and whether to draw in this octant initially
  2765. if (oct % 2)
  2766. drawoct |= (1
  2767. << oct); // this is basically like saying drawoct[oct] = true, if drawoct were a bool array
  2768. else drawoct &= 255 - (1 << oct); // this is basically like saying drawoct[oct] = false
  2769. }
  2770. if (oct == endoct) {
  2771. // need to compute stopval_end for this octant
  2772. dend = (double) end;
  2773. switch (oct) {
  2774. case 0:
  2775. case 3:
  2776. temp = sin(dend * M_PI / 180);
  2777. break;
  2778. case 1:
  2779. case 6:
  2780. temp = cos(dend * M_PI / 180);
  2781. break;
  2782. case 2:
  2783. case 5:
  2784. temp = -cos(dend * M_PI / 180);
  2785. break;
  2786. case 4:
  2787. case 7:
  2788. temp = -sin(dend * M_PI / 180);
  2789. break;
  2790. }
  2791. temp *= rad;
  2792. stopval_end = (int) temp;
  2793. // and whether to draw in this octant initially
  2794. if (startoct == endoct) {
  2795. // note: we start drawing, stop, then start again in this case
  2796. // otherwise: we only draw in this octant, so initialize it to false, it will get set back to true
  2797. if (start > end) {
  2798. // unfortunately, if we're in the same octant and need to draw over the whole circle,
  2799. // we need to set the rest to true, because the while loop will end at the bottom.
  2800. drawoct = 255;
  2801. } else {
  2802. drawoct &= 255 - (1 << oct);
  2803. }
  2804. } else if (oct % 2) drawoct &= 255 - (1 << oct);
  2805. else drawoct |= (1 << oct);
  2806. } else if (oct != startoct) { // already verified that it's != endoct
  2807. drawoct |= (1 << oct); // draw this entire segment
  2808. }
  2809. } while (oct != endoct);
  2810. // so now we have what octants to draw and when to draw them. all that's left is the actual raster code.
  2811. /* Lock surface */
  2812. if (SDL_MUSTLOCK(dst)) {
  2813. if (SDL_LockSurface(dst) < 0) {
  2814. return (-1);
  2815. }
  2816. }
  2817. /*
  2818. * Draw arc
  2819. */
  2820. result = 0;
  2821. /*
  2822. * Alpha Check
  2823. */
  2824. if ((color & 255) == 255) {
  2825. /*
  2826. * No Alpha - direct memory writes
  2827. */
  2828. /*
  2829. * Setup color
  2830. */
  2831. colorptr = (Uint8 *) &color;
  2832. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  2833. color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
  2834. } else {
  2835. color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
  2836. }
  2837. /*
  2838. * Draw
  2839. */
  2840. do {
  2841. ypcy = y + cy;
  2842. ymcy = y - cy;
  2843. if (cx > 0) {
  2844. xpcx = x + cx;
  2845. xmcx = x - cx;
  2846. // always check if we're drawing a certain octant before adding a pixel to that octant.
  2847. if (drawoct & 4) result |= fastPixelColorNolock(dst, xmcx, ypcy, color); // drawoct & 4 = 22; drawoct[2]
  2848. if (drawoct & 2) result |= fastPixelColorNolock(dst, xpcx, ypcy, color);
  2849. if (drawoct & 32) result |= fastPixelColorNolock(dst, xmcx, ymcy, color);
  2850. if (drawoct & 64) result |= fastPixelColorNolock(dst, xpcx, ymcy, color);
  2851. } else {
  2852. if (drawoct & 6) result |= fastPixelColorNolock(dst, x, ypcy, color); // 4 + 2; drawoct[2] || drawoct[1]
  2853. if (drawoct & 96) result |= fastPixelColorNolock(dst, x, ymcy, color); // 32 + 64
  2854. }
  2855. xpcy = x + cy;
  2856. xmcy = x - cy;
  2857. if (cx > 0 && cx != cy) {
  2858. ypcx = y + cx;
  2859. ymcx = y - cx;
  2860. if (drawoct & 8) result |= fastPixelColorNolock(dst, xmcy, ypcx, color);
  2861. if (drawoct & 1) result |= fastPixelColorNolock(dst, xpcy, ypcx, color);
  2862. if (drawoct & 16) result |= fastPixelColorNolock(dst, xmcy, ymcx, color);
  2863. if (drawoct & 128) result |= fastPixelColorNolock(dst, xpcy, ymcx, color);
  2864. } else if (cx == 0) {
  2865. if (drawoct & 24) result |= fastPixelColorNolock(dst, xmcy, y, color); // 8 + 16
  2866. if (drawoct & 129) result |= fastPixelColorNolock(dst, xpcy, y, color); // 1 + 128
  2867. }
  2868. /*
  2869. * Update whether we're drawing an octant
  2870. */
  2871. if (stopval_start == cx) {
  2872. // works like an on-off switch because start & end may be in the same octant.
  2873. if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);
  2874. else drawoct |= (1 << startoct);
  2875. }
  2876. if (stopval_end == cx) {
  2877. if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
  2878. else drawoct |= (1 << endoct);
  2879. }
  2880. /*
  2881. * Update pixels
  2882. */
  2883. if (df < 0) {
  2884. df += d_e;
  2885. d_e += 2;
  2886. d_se += 2;
  2887. } else {
  2888. df += d_se;
  2889. d_e += 2;
  2890. d_se += 4;
  2891. cy--;
  2892. }
  2893. cx++;
  2894. } while (cx <= cy);
  2895. /*
  2896. * Unlock surface
  2897. */
  2898. SDL_UnlockSurface(dst);
  2899. } else {
  2900. /*
  2901. * Using Alpha - blended pixel blits
  2902. */
  2903. do {
  2904. ypcy = y + cy;
  2905. ymcy = y - cy;
  2906. if (cx > 0) {
  2907. xpcx = x + cx;
  2908. xmcx = x - cx;
  2909. // always check if we're drawing a certain octant before adding a pixel to that octant.
  2910. if (drawoct & 4) result |= pixelColorNolock(dst, xmcx, ypcy, color);
  2911. if (drawoct & 2) result |= pixelColorNolock(dst, xpcx, ypcy, color);
  2912. if (drawoct & 32) result |= pixelColorNolock(dst, xmcx, ymcy, color);
  2913. if (drawoct & 64) result |= pixelColorNolock(dst, xpcx, ymcy, color);
  2914. } else {
  2915. if (drawoct & 96) result |= pixelColorNolock(dst, x, ymcy, color);
  2916. if (drawoct & 6) result |= pixelColorNolock(dst, x, ypcy, color);
  2917. }
  2918. xpcy = x + cy;
  2919. xmcy = x - cy;
  2920. if (cx > 0 && cx != cy) {
  2921. ypcx = y + cx;
  2922. ymcx = y - cx;
  2923. if (drawoct & 8) result |= pixelColorNolock(dst, xmcy, ypcx, color);
  2924. if (drawoct & 1) result |= pixelColorNolock(dst, xpcy, ypcx, color);
  2925. if (drawoct & 16) result |= pixelColorNolock(dst, xmcy, ymcx, color);
  2926. if (drawoct & 128) result |= pixelColorNolock(dst, xpcy, ymcx, color);
  2927. } else if (cx == 0) {
  2928. if (drawoct & 24) result |= pixelColorNolock(dst, xmcy, y, color);
  2929. if (drawoct & 129) result |= pixelColorNolock(dst, xpcy, y, color);
  2930. }
  2931. /*
  2932. * Update whether we're drawing an octant
  2933. */
  2934. if (stopval_start == cx) {
  2935. // works like an on-off switch.
  2936. // This is just in case start & end are in the same octant.
  2937. if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);
  2938. else drawoct |= (1 << startoct);
  2939. }
  2940. if (stopval_end == cx) {
  2941. if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
  2942. else drawoct |= (1 << endoct);
  2943. }
  2944. /*
  2945. * Update pixels
  2946. */
  2947. if (df < 0) {
  2948. df += d_e;
  2949. d_e += 2;
  2950. d_se += 2;
  2951. } else {
  2952. df += d_se;
  2953. d_e += 2;
  2954. d_se += 4;
  2955. cy--;
  2956. }
  2957. cx++;
  2958. } while (cx <= cy);
  2959. } /* Alpha check */
  2960. /* Unlock surface */
  2961. if (SDL_MUSTLOCK(dst)) {
  2962. SDL_UnlockSurface(dst);
  2963. }
  2964. return (result);
  2965. }
  2966. /*!
  2967. \brief Arc with blending.
  2968. \param dst The surface to draw on.
  2969. \param x X coordinate of the center of the arc.
  2970. \param y Y coordinate of the center of the arc.
  2971. \param rad Radius in pixels of the arc.
  2972. \param start Starting radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
  2973. \param end Ending radius in degrees of the arc. 0 degrees is down, increasing counterclockwise.
  2974. \param r The red value of the arc to draw.
  2975. \param g The green value of the arc to draw.
  2976. \param b The blue value of the arc to draw.
  2977. \param a The alpha value of the arc to draw.
  2978. \returns Returns 0 on success, -1 on failure.
  2979. */
  2980. int arcRGBA(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b,
  2981. Uint8 a) {
  2982. /*
  2983. * Draw
  2984. */
  2985. return (arcColor(dst, x, y, rad, start, end,
  2986. ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  2987. }
  2988. /* ----- AA Circle */
  2989. /*!
  2990. \brief Draw anti-aliased circle with blending.
  2991. Note: The AA-circle routine is based on AA-ellipse with identical radii.
  2992. \param dst The surface to draw on.
  2993. \param x X coordinate of the center of the aa-circle.
  2994. \param y Y coordinate of the center of the aa-circle.
  2995. \param rad Radius in pixels of the aa-circle.
  2996. \param color The color value of the aa-circle to draw (0xRRGGBBAA).
  2997. \returns Returns 0 on success, -1 on failure.
  2998. */
  2999. int aacircleColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color) {
  3000. return (aaellipseColor(dst, x, y, rad, rad, color));
  3001. }
  3002. /*!
  3003. \brief Draw anti-aliased circle with blending.
  3004. \param dst The surface to draw on.
  3005. \param x X coordinate of the center of the aa-circle.
  3006. \param y Y coordinate of the center of the aa-circle.
  3007. \param rad Radius in pixels of the aa-circle.
  3008. \param r The red value of the aa-circle to draw.
  3009. \param g The green value of the aa-circle to draw.
  3010. \param b The blue value of the aa-circle to draw.
  3011. \param a The alpha value of the aa-circle to draw.
  3012. \returns Returns 0 on success, -1 on failure.
  3013. */
  3014. int aacircleRGBA(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  3015. /*
  3016. * Draw
  3017. */
  3018. return (aaellipseColor
  3019. (dst, x, y, rad, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  3020. }
  3021. /* ----- Filled Circle */
  3022. /*!
  3023. \brief Draw filled circle with blending.
  3024. Note: Based on algorithms from sge library with modifications by A. Schiffler for
  3025. multiple-hline draw removal and other minor speedup changes.
  3026. \param dst The surface to draw on.
  3027. \param x X coordinate of the center of the filled circle.
  3028. \param y Y coordinate of the center of the filled circle.
  3029. \param rad Radius in pixels of the filled circle.
  3030. \param color The color value of the filled circle to draw (0xRRGGBBAA).
  3031. \returns Returns 0 on success, -1 on failure.
  3032. */
  3033. int filledCircleColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color) {
  3034. Sint16 left, right, top, bottom;
  3035. int result;
  3036. Sint16 x1, y1, x2, y2;
  3037. Sint16 cx = 0;
  3038. Sint16 cy = rad;
  3039. Sint16 ocx = (Sint16) 0xffff;
  3040. Sint16 ocy = (Sint16) 0xffff;
  3041. Sint16 df = 1 - rad;
  3042. Sint16 d_e = 3;
  3043. Sint16 d_se = -2 * rad + 5;
  3044. Sint16 xpcx, xmcx, xpcy, xmcy;
  3045. Sint16 ypcy, ymcy, ypcx, ymcx;
  3046. /*
  3047. * Check visibility of clipping rectangle
  3048. */
  3049. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  3050. return (0);
  3051. }
  3052. /*
  3053. * Sanity check radius
  3054. */
  3055. if (rad < 0) {
  3056. return (-1);
  3057. }
  3058. /*
  3059. * Special case for rad=0 - draw a point
  3060. */
  3061. if (rad == 0) {
  3062. return (pixelColor(dst, x, y, color));
  3063. }
  3064. /*
  3065. * Get circle and clipping boundary and
  3066. * test if bounding box of circle is visible
  3067. */
  3068. x2 = x + rad;
  3069. left = dst->clip_rect.x;
  3070. if (x2 < left) {
  3071. return (0);
  3072. }
  3073. x1 = x - rad;
  3074. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  3075. if (x1 > right) {
  3076. return (0);
  3077. }
  3078. y2 = y + rad;
  3079. top = dst->clip_rect.y;
  3080. if (y2 < top) {
  3081. return (0);
  3082. }
  3083. y1 = y - rad;
  3084. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  3085. if (y1 > bottom) {
  3086. return (0);
  3087. }
  3088. /*
  3089. * Draw
  3090. */
  3091. result = 0;
  3092. do {
  3093. xpcx = x + cx;
  3094. xmcx = x - cx;
  3095. xpcy = x + cy;
  3096. xmcy = x - cy;
  3097. if (ocy != cy) {
  3098. if (cy > 0) {
  3099. ypcy = y + cy;
  3100. ymcy = y - cy;
  3101. result |= hlineColor(dst, xmcx, xpcx, ypcy, color);
  3102. result |= hlineColor(dst, xmcx, xpcx, ymcy, color);
  3103. } else {
  3104. result |= hlineColor(dst, xmcx, xpcx, y, color);
  3105. }
  3106. ocy = cy;
  3107. }
  3108. if (ocx != cx) {
  3109. if (cx != cy) {
  3110. if (cx > 0) {
  3111. ypcx = y + cx;
  3112. ymcx = y - cx;
  3113. result |= hlineColor(dst, xmcy, xpcy, ymcx, color);
  3114. result |= hlineColor(dst, xmcy, xpcy, ypcx, color);
  3115. } else {
  3116. result |= hlineColor(dst, xmcy, xpcy, y, color);
  3117. }
  3118. }
  3119. ocx = cx;
  3120. }
  3121. /*
  3122. * Update
  3123. */
  3124. if (df < 0) {
  3125. df += d_e;
  3126. d_e += 2;
  3127. d_se += 2;
  3128. } else {
  3129. df += d_se;
  3130. d_e += 2;
  3131. d_se += 4;
  3132. cy--;
  3133. }
  3134. cx++;
  3135. } while (cx <= cy);
  3136. return (result);
  3137. }
  3138. /*!
  3139. \brief Draw filled circle with blending.
  3140. \param dst The surface to draw on.
  3141. \param x X coordinate of the center of the filled circle.
  3142. \param y Y coordinate of the center of the filled circle.
  3143. \param rad Radius in pixels of the filled circle.
  3144. \param r The red value of the filled circle to draw.
  3145. \param g The green value of the filled circle to draw.
  3146. \param b The blue value of the filled circle to draw.
  3147. \param a The alpha value of the filled circle to draw.
  3148. \returns Returns 0 on success, -1 on failure.
  3149. */
  3150. int filledCircleRGBA(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  3151. /*
  3152. * Draw
  3153. */
  3154. return (filledCircleColor
  3155. (dst, x, y, rad, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  3156. }
  3157. /* ----- Ellipse */
  3158. /*!
  3159. \brief Draw ellipse with blending.
  3160. Note: Based on algorithms from sge library with modifications by A. Schiffler for
  3161. multiple-pixel draw removal and other minor speedup changes.
  3162. \param dst The surface to draw on.
  3163. \param x X coordinate of the center of the ellipse.
  3164. \param y Y coordinate of the center of the ellipse.
  3165. \param rx Horizontal radius in pixels of the ellipse.
  3166. \param ry Vertical radius in pixels of the ellipse.
  3167. \param color The color value of the ellipse to draw (0xRRGGBBAA).
  3168. \returns Returns 0 on success, -1 on failure.
  3169. */
  3170. int ellipseColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color) {
  3171. Sint16 left, right, top, bottom;
  3172. int result;
  3173. Sint16 x1, y1, x2, y2;
  3174. int ix, iy;
  3175. int h, i, j, k;
  3176. int oh, oi, oj, ok;
  3177. int xmh, xph, ypk, ymk;
  3178. int xmi, xpi, ymj, ypj;
  3179. int xmj, xpj, ymi, ypi;
  3180. int xmk, xpk, ymh, yph;
  3181. Uint8 *colorptr;
  3182. /*
  3183. * Check visibility of clipping rectangle
  3184. */
  3185. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  3186. return (0);
  3187. }
  3188. /*
  3189. * Sanity check radii
  3190. */
  3191. if ((rx < 0) || (ry < 0)) {
  3192. return (-1);
  3193. }
  3194. /*
  3195. * Special case for rx=0 - draw a vline
  3196. */
  3197. if (rx == 0) {
  3198. return (vlineColor(dst, x, y - ry, y + ry, color));
  3199. }
  3200. /*
  3201. * Special case for ry=0 - draw a hline
  3202. */
  3203. if (ry == 0) {
  3204. return (hlineColor(dst, x - rx, x + rx, y, color));
  3205. }
  3206. /*
  3207. * Get circle and clipping boundary and
  3208. * test if bounding box of circle is visible
  3209. */
  3210. x2 = x + rx;
  3211. left = dst->clip_rect.x;
  3212. if (x2 < left) {
  3213. return (0);
  3214. }
  3215. x1 = x - rx;
  3216. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  3217. if (x1 > right) {
  3218. return (0);
  3219. }
  3220. y2 = y + ry;
  3221. top = dst->clip_rect.y;
  3222. if (y2 < top) {
  3223. return (0);
  3224. }
  3225. y1 = y - ry;
  3226. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  3227. if (y1 > bottom) {
  3228. return (0);
  3229. }
  3230. /*
  3231. * Init vars
  3232. */
  3233. oh = oi = oj = ok = 0xFFFF;
  3234. /*
  3235. * Draw
  3236. */
  3237. result = 0;
  3238. /* Lock surface */
  3239. if (SDL_MUSTLOCK(dst)) {
  3240. if (SDL_LockSurface(dst) < 0) {
  3241. return (-1);
  3242. }
  3243. }
  3244. /*
  3245. * Check alpha
  3246. */
  3247. if ((color & 255) == 255) {
  3248. /*
  3249. * No Alpha - direct memory writes
  3250. */
  3251. /*
  3252. * Setup color
  3253. */
  3254. colorptr = (Uint8 *) &color;
  3255. if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  3256. color = SDL_MapRGBA(dst->format, colorptr[0], colorptr[1], colorptr[2], colorptr[3]);
  3257. } else {
  3258. color = SDL_MapRGBA(dst->format, colorptr[3], colorptr[2], colorptr[1], colorptr[0]);
  3259. }
  3260. if (rx > ry) {
  3261. ix = 0;
  3262. iy = rx * 64;
  3263. do {
  3264. h = (ix + 32) >> 6;
  3265. i = (iy + 32) >> 6;
  3266. j = (h * ry) / rx;
  3267. k = (i * ry) / rx;
  3268. if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
  3269. xph = x + h;
  3270. xmh = x - h;
  3271. if (k > 0) {
  3272. ypk = y + k;
  3273. ymk = y - k;
  3274. result |= fastPixelColorNolock(dst, xmh, ypk, color);
  3275. result |= fastPixelColorNolock(dst, xph, ypk, color);
  3276. result |= fastPixelColorNolock(dst, xmh, ymk, color);
  3277. result |= fastPixelColorNolock(dst, xph, ymk, color);
  3278. } else {
  3279. result |= fastPixelColorNolock(dst, xmh, y, color);
  3280. result |= fastPixelColorNolock(dst, xph, y, color);
  3281. }
  3282. ok = k;
  3283. xpi = x + i;
  3284. xmi = x - i;
  3285. if (j > 0) {
  3286. ypj = y + j;
  3287. ymj = y - j;
  3288. result |= fastPixelColorNolock(dst, xmi, ypj, color);
  3289. result |= fastPixelColorNolock(dst, xpi, ypj, color);
  3290. result |= fastPixelColorNolock(dst, xmi, ymj, color);
  3291. result |= fastPixelColorNolock(dst, xpi, ymj, color);
  3292. } else {
  3293. result |= fastPixelColorNolock(dst, xmi, y, color);
  3294. result |= fastPixelColorNolock(dst, xpi, y, color);
  3295. }
  3296. oj = j;
  3297. }
  3298. ix = ix + iy / rx;
  3299. iy = iy - ix / rx;
  3300. } while (i > h);
  3301. } else {
  3302. ix = 0;
  3303. iy = ry * 64;
  3304. do {
  3305. h = (ix + 32) >> 6;
  3306. i = (iy + 32) >> 6;
  3307. j = (h * rx) / ry;
  3308. k = (i * rx) / ry;
  3309. if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
  3310. xmj = x - j;
  3311. xpj = x + j;
  3312. if (i > 0) {
  3313. ypi = y + i;
  3314. ymi = y - i;
  3315. result |= fastPixelColorNolock(dst, xmj, ypi, color);
  3316. result |= fastPixelColorNolock(dst, xpj, ypi, color);
  3317. result |= fastPixelColorNolock(dst, xmj, ymi, color);
  3318. result |= fastPixelColorNolock(dst, xpj, ymi, color);
  3319. } else {
  3320. result |= fastPixelColorNolock(dst, xmj, y, color);
  3321. result |= fastPixelColorNolock(dst, xpj, y, color);
  3322. }
  3323. oi = i;
  3324. xmk = x - k;
  3325. xpk = x + k;
  3326. if (h > 0) {
  3327. yph = y + h;
  3328. ymh = y - h;
  3329. result |= fastPixelColorNolock(dst, xmk, yph, color);
  3330. result |= fastPixelColorNolock(dst, xpk, yph, color);
  3331. result |= fastPixelColorNolock(dst, xmk, ymh, color);
  3332. result |= fastPixelColorNolock(dst, xpk, ymh, color);
  3333. } else {
  3334. result |= fastPixelColorNolock(dst, xmk, y, color);
  3335. result |= fastPixelColorNolock(dst, xpk, y, color);
  3336. }
  3337. oh = h;
  3338. }
  3339. ix = ix + iy / ry;
  3340. iy = iy - ix / ry;
  3341. } while (i > h);
  3342. }
  3343. } else {
  3344. if (rx > ry) {
  3345. ix = 0;
  3346. iy = rx * 64;
  3347. do {
  3348. h = (ix + 32) >> 6;
  3349. i = (iy + 32) >> 6;
  3350. j = (h * ry) / rx;
  3351. k = (i * ry) / rx;
  3352. if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j)) {
  3353. xph = x + h;
  3354. xmh = x - h;
  3355. if (k > 0) {
  3356. ypk = y + k;
  3357. ymk = y - k;
  3358. result |= pixelColorNolock(dst, xmh, ypk, color);
  3359. result |= pixelColorNolock(dst, xph, ypk, color);
  3360. result |= pixelColorNolock(dst, xmh, ymk, color);
  3361. result |= pixelColorNolock(dst, xph, ymk, color);
  3362. } else {
  3363. result |= pixelColorNolock(dst, xmh, y, color);
  3364. result |= pixelColorNolock(dst, xph, y, color);
  3365. }
  3366. ok = k;
  3367. xpi = x + i;
  3368. xmi = x - i;
  3369. if (j > 0) {
  3370. ypj = y + j;
  3371. ymj = y - j;
  3372. result |= pixelColorNolock(dst, xmi, ypj, color);
  3373. result |= pixelColorNolock(dst, xpi, ypj, color);
  3374. result |= pixelColorNolock(dst, xmi, ymj, color);
  3375. result |= pixelColor(dst, xpi, ymj, color);
  3376. } else {
  3377. result |= pixelColorNolock(dst, xmi, y, color);
  3378. result |= pixelColorNolock(dst, xpi, y, color);
  3379. }
  3380. oj = j;
  3381. }
  3382. ix = ix + iy / rx;
  3383. iy = iy - ix / rx;
  3384. } while (i > h);
  3385. } else {
  3386. ix = 0;
  3387. iy = ry * 64;
  3388. do {
  3389. h = (ix + 32) >> 6;
  3390. i = (iy + 32) >> 6;
  3391. j = (h * rx) / ry;
  3392. k = (i * rx) / ry;
  3393. if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h))) {
  3394. xmj = x - j;
  3395. xpj = x + j;
  3396. if (i > 0) {
  3397. ypi = y + i;
  3398. ymi = y - i;
  3399. result |= pixelColorNolock(dst, xmj, ypi, color);
  3400. result |= pixelColorNolock(dst, xpj, ypi, color);
  3401. result |= pixelColorNolock(dst, xmj, ymi, color);
  3402. result |= pixelColorNolock(dst, xpj, ymi, color);
  3403. } else {
  3404. result |= pixelColorNolock(dst, xmj, y, color);
  3405. result |= pixelColorNolock(dst, xpj, y, color);
  3406. }
  3407. oi = i;
  3408. xmk = x - k;
  3409. xpk = x + k;
  3410. if (h > 0) {
  3411. yph = y + h;
  3412. ymh = y - h;
  3413. result |= pixelColorNolock(dst, xmk, yph, color);
  3414. result |= pixelColorNolock(dst, xpk, yph, color);
  3415. result |= pixelColorNolock(dst, xmk, ymh, color);
  3416. result |= pixelColorNolock(dst, xpk, ymh, color);
  3417. } else {
  3418. result |= pixelColorNolock(dst, xmk, y, color);
  3419. result |= pixelColorNolock(dst, xpk, y, color);
  3420. }
  3421. oh = h;
  3422. }
  3423. ix = ix + iy / ry;
  3424. iy = iy - ix / ry;
  3425. } while (i > h);
  3426. }
  3427. } /* Alpha check */
  3428. /* Unlock surface */
  3429. if (SDL_MUSTLOCK(dst)) {
  3430. SDL_UnlockSurface(dst);
  3431. }
  3432. return (result);
  3433. }
  3434. /*!
  3435. \brief Draw ellipse with blending.
  3436. \param dst The surface to draw on.
  3437. \param x X coordinate of the center of the ellipse.
  3438. \param y Y coordinate of the center of the ellipse.
  3439. \param rx Horizontal radius in pixels of the ellipse.
  3440. \param ry Vertical radius in pixels of the ellipse.
  3441. \param r The red value of the ellipse to draw.
  3442. \param g The green value of the ellipse to draw.
  3443. \param b The blue value of the ellipse to draw.
  3444. \param a The alpha value of the ellipse to draw.
  3445. \returns Returns 0 on success, -1 on failure.
  3446. */
  3447. int ellipseRGBA(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  3448. /*
  3449. * Draw
  3450. */
  3451. return (ellipseColor(dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  3452. }
  3453. /* ----- AA Ellipse */
  3454. /* Windows targets do not have lrint, so provide a local inline version */
  3455. #if defined(_MSC_VER)
  3456. /* Detect 64bit and use intrinsic version */
  3457. #ifdef _M_X64
  3458. #include <emmintrin.h>
  3459. static __inline long
  3460. lrint(float f)
  3461. {
  3462. return _mm_cvtss_si32(_mm_load_ss(&f));
  3463. }
  3464. #elif defined(_M_IX86)
  3465. __inline long int
  3466. lrint (double flt)
  3467. {
  3468. int intgr;
  3469. _asm
  3470. {
  3471. fld flt
  3472. fistp intgr
  3473. };
  3474. return intgr;
  3475. }
  3476. #elif defined(_M_ARM)
  3477. #include <armintr.h>
  3478. #pragma warning(push)
  3479. #pragma warning(disable: 4716)
  3480. __declspec(naked) long int
  3481. lrint (double flt)
  3482. {
  3483. __emit(0xEC410B10); // fmdrr d0, r0, r1
  3484. __emit(0xEEBD0B40); // ftosid s0, d0
  3485. __emit(0xEE100A10); // fmrs r0, s0
  3486. __emit(0xE12FFF1E); // bx lr
  3487. }
  3488. #pragma warning(pop)
  3489. #else
  3490. #error lrint needed for MSVC on non X86/AMD64/ARM targets.
  3491. #endif
  3492. #endif
  3493. /*!
  3494. \brief Draw anti-aliased ellipse with blending.
  3495. Note: Based on code from Anders Lindstroem, which is based on code from sge library,
  3496. which is based on code from TwinLib.
  3497. \param dst The surface to draw on.
  3498. \param x X coordinate of the center of the aa-ellipse.
  3499. \param y Y coordinate of the center of the aa-ellipse.
  3500. \param rx Horizontal radius in pixels of the aa-ellipse.
  3501. \param ry Vertical radius in pixels of the aa-ellipse.
  3502. \param color The color value of the aa-ellipse to draw (0xRRGGBBAA).
  3503. \returns Returns 0 on success, -1 on failure.
  3504. */
  3505. int aaellipseColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color) {
  3506. Sint16 left, right, top, bottom;
  3507. Sint16 x1, y1, x2, y2;
  3508. int i;
  3509. int a2, b2, ds, dt, dxt, t, s, d;
  3510. Sint16 xp, yp, xs, ys, dyt, od, xx, yy, xc2, yc2;
  3511. float cp;
  3512. double sab;
  3513. Uint8 weight, iweight;
  3514. int result;
  3515. /*
  3516. * Check visibility of clipping rectangle
  3517. */
  3518. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  3519. return (0);
  3520. }
  3521. /*
  3522. * Sanity check radii
  3523. */
  3524. if ((rx < 0) || (ry < 0)) {
  3525. return (-1);
  3526. }
  3527. /*
  3528. * Special case for rx=0 - draw a vline
  3529. */
  3530. if (rx == 0) {
  3531. return (vlineColor(dst, x, y - ry, y + ry, color));
  3532. }
  3533. /*
  3534. * Special case for ry=0 - draw an hline
  3535. */
  3536. if (ry == 0) {
  3537. return (hlineColor(dst, x - rx, x + rx, y, color));
  3538. }
  3539. /*
  3540. * Get circle and clipping boundary and
  3541. * test if bounding box of circle is visible
  3542. */
  3543. x2 = x + rx;
  3544. left = dst->clip_rect.x;
  3545. if (x2 < left) {
  3546. return (0);
  3547. }
  3548. x1 = x - rx;
  3549. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  3550. if (x1 > right) {
  3551. return (0);
  3552. }
  3553. y2 = y + ry;
  3554. top = dst->clip_rect.y;
  3555. if (y2 < top) {
  3556. return (0);
  3557. }
  3558. y1 = y - ry;
  3559. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  3560. if (y1 > bottom) {
  3561. return (0);
  3562. }
  3563. /* Variable setup */
  3564. a2 = rx * rx;
  3565. b2 = ry * ry;
  3566. ds = 2 * a2;
  3567. dt = 2 * b2;
  3568. xc2 = 2 * x;
  3569. yc2 = 2 * y;
  3570. sab = sqrt((double) (a2 + b2));
  3571. od = (Sint16) lrint(sab * 0.01) + 1; /* introduce some overdraw */
  3572. dxt = (Sint16) lrint((double) a2 / sab) + od;
  3573. t = 0;
  3574. s = -2 * a2 * ry;
  3575. d = 0;
  3576. xp = x;
  3577. yp = y - ry;
  3578. /* Lock surface */
  3579. if (SDL_MUSTLOCK(dst)) {
  3580. if (SDL_LockSurface(dst) < 0) {
  3581. return (-1);
  3582. }
  3583. }
  3584. /* Draw */
  3585. result = 0;
  3586. /* "End points" */
  3587. result |= pixelColorNolock(dst, xp, yp, color);
  3588. result |= pixelColorNolock(dst, xc2 - xp, yp, color);
  3589. result |= pixelColorNolock(dst, xp, yc2 - yp, color);
  3590. result |= pixelColorNolock(dst, xc2 - xp, yc2 - yp, color);
  3591. for (i = 1; i <= dxt; i++) {
  3592. xp--;
  3593. d += t - b2;
  3594. if (d >= 0)
  3595. ys = yp - 1;
  3596. else if ((d - s - a2) > 0) {
  3597. if ((2 * d - s - a2) >= 0)
  3598. ys = yp + 1;
  3599. else {
  3600. ys = yp;
  3601. yp++;
  3602. d -= s + a2;
  3603. s += ds;
  3604. }
  3605. } else {
  3606. yp++;
  3607. ys = yp + 1;
  3608. d -= s + a2;
  3609. s += ds;
  3610. }
  3611. t -= dt;
  3612. /* Calculate alpha */
  3613. if (s != 0) {
  3614. cp = (float) abs(d) / (float) abs(s);
  3615. if (cp > 1.0) {
  3616. cp = 1.0;
  3617. }
  3618. } else {
  3619. cp = 1.0;
  3620. }
  3621. /* Calculate weights */
  3622. weight = (Uint8) (cp * 255);
  3623. iweight = 255 - weight;
  3624. /* Upper half */
  3625. xx = xc2 - xp;
  3626. result |= pixelColorWeightNolock(dst, xp, yp, color, iweight);
  3627. result |= pixelColorWeightNolock(dst, xx, yp, color, iweight);
  3628. result |= pixelColorWeightNolock(dst, xp, ys, color, weight);
  3629. result |= pixelColorWeightNolock(dst, xx, ys, color, weight);
  3630. /* Lower half */
  3631. yy = yc2 - yp;
  3632. result |= pixelColorWeightNolock(dst, xp, yy, color, iweight);
  3633. result |= pixelColorWeightNolock(dst, xx, yy, color, iweight);
  3634. yy = yc2 - ys;
  3635. result |= pixelColorWeightNolock(dst, xp, yy, color, weight);
  3636. result |= pixelColorWeightNolock(dst, xx, yy, color, weight);
  3637. }
  3638. /* Replaces original approximation code dyt = abs(yp - yc); */
  3639. dyt = (Sint16) lrint((double) b2 / sab) + od;
  3640. for (i = 1; i <= dyt; i++) {
  3641. yp++;
  3642. d -= s + a2;
  3643. if (d <= 0)
  3644. xs = xp + 1;
  3645. else if ((d + t - b2) < 0) {
  3646. if ((2 * d + t - b2) <= 0)
  3647. xs = xp - 1;
  3648. else {
  3649. xs = xp;
  3650. xp--;
  3651. d += t - b2;
  3652. t -= dt;
  3653. }
  3654. } else {
  3655. xp--;
  3656. xs = xp - 1;
  3657. d += t - b2;
  3658. t -= dt;
  3659. }
  3660. s += ds;
  3661. /* Calculate alpha */
  3662. if (t != 0) {
  3663. cp = (float) abs(d) / (float) abs(t);
  3664. if (cp > 1.0) {
  3665. cp = 1.0;
  3666. }
  3667. } else {
  3668. cp = 1.0;
  3669. }
  3670. /* Calculate weight */
  3671. weight = (Uint8) (cp * 255);
  3672. iweight = 255 - weight;
  3673. /* Left half */
  3674. xx = xc2 - xp;
  3675. yy = yc2 - yp;
  3676. result |= pixelColorWeightNolock(dst, xp, yp, color, iweight);
  3677. result |= pixelColorWeightNolock(dst, xx, yp, color, iweight);
  3678. result |= pixelColorWeightNolock(dst, xp, yy, color, iweight);
  3679. result |= pixelColorWeightNolock(dst, xx, yy, color, iweight);
  3680. /* Right half */
  3681. xx = xc2 - xs;
  3682. result |= pixelColorWeightNolock(dst, xs, yp, color, weight);
  3683. result |= pixelColorWeightNolock(dst, xx, yp, color, weight);
  3684. result |= pixelColorWeightNolock(dst, xs, yy, color, weight);
  3685. result |= pixelColorWeightNolock(dst, xx, yy, color, weight);
  3686. }
  3687. /* Unlock surface */
  3688. if (SDL_MUSTLOCK(dst)) {
  3689. SDL_UnlockSurface(dst);
  3690. }
  3691. return (result);
  3692. }
  3693. /*!
  3694. \brief Draw anti-aliased ellipse with blending.
  3695. \param dst The surface to draw on.
  3696. \param x X coordinate of the center of the aa-ellipse.
  3697. \param y Y coordinate of the center of the aa-ellipse.
  3698. \param rx Horizontal radius in pixels of the aa-ellipse.
  3699. \param ry Vertical radius in pixels of the aa-ellipse.
  3700. \param r The red value of the aa-ellipse to draw.
  3701. \param g The green value of the aa-ellipse to draw.
  3702. \param b The blue value of the aa-ellipse to draw.
  3703. \param a The alpha value of the aa-ellipse to draw.
  3704. \returns Returns 0 on success, -1 on failure.
  3705. */
  3706. int aaellipseRGBA(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  3707. /*
  3708. * Draw
  3709. */
  3710. return (aaellipseColor
  3711. (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  3712. }
  3713. /* ---- Filled Ellipse */
  3714. /* Note: */
  3715. /* Based on algorithm from sge library with multiple-hline draw removal */
  3716. /* and other speedup changes. */
  3717. /*!
  3718. \brief Draw filled ellipse with blending.
  3719. Note: Based on algorithm from sge library with multiple-hline draw removal
  3720. and other speedup changes.
  3721. \param dst The surface to draw on.
  3722. \param x X coordinate of the center of the filled ellipse.
  3723. \param y Y coordinate of the center of the filled ellipse.
  3724. \param rx Horizontal radius in pixels of the filled ellipse.
  3725. \param ry Vertical radius in pixels of the filled ellipse.
  3726. \param color The color value of the filled ellipse to draw (0xRRGGBBAA).
  3727. \returns Returns 0 on success, -1 on failure.
  3728. */
  3729. int filledEllipseColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color) {
  3730. Sint16 left, right, top, bottom;
  3731. int result;
  3732. Sint16 x1, y1, x2, y2;
  3733. int ix, iy;
  3734. int h, i, j, k;
  3735. int oh, oi, oj, ok;
  3736. int xmh, xph;
  3737. int xmi, xpi;
  3738. int xmj, xpj;
  3739. int xmk, xpk;
  3740. /*
  3741. * Check visibility of clipping rectangle
  3742. */
  3743. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  3744. return (0);
  3745. }
  3746. /*
  3747. * Sanity check radii
  3748. */
  3749. if ((rx < 0) || (ry < 0)) {
  3750. return (-1);
  3751. }
  3752. /*
  3753. * Special case for rx=0 - draw a vline
  3754. */
  3755. if (rx == 0) {
  3756. return (vlineColor(dst, x, y - ry, y + ry, color));
  3757. }
  3758. /*
  3759. * Special case for ry=0 - draw a hline
  3760. */
  3761. if (ry == 0) {
  3762. return (hlineColor(dst, x - rx, x + rx, y, color));
  3763. }
  3764. /*
  3765. * Get circle and clipping boundary and
  3766. * test if bounding box of circle is visible
  3767. */
  3768. x2 = x + rx;
  3769. left = dst->clip_rect.x;
  3770. if (x2 < left) {
  3771. return (0);
  3772. }
  3773. x1 = x - rx;
  3774. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  3775. if (x1 > right) {
  3776. return (0);
  3777. }
  3778. y2 = y + ry;
  3779. top = dst->clip_rect.y;
  3780. if (y2 < top) {
  3781. return (0);
  3782. }
  3783. y1 = y - ry;
  3784. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  3785. if (y1 > bottom) {
  3786. return (0);
  3787. }
  3788. /*
  3789. * Init vars
  3790. */
  3791. oh = oi = oj = ok = 0xFFFF;
  3792. /*
  3793. * Draw
  3794. */
  3795. result = 0;
  3796. if (rx > ry) {
  3797. ix = 0;
  3798. iy = rx * 64;
  3799. do {
  3800. h = (ix + 32) >> 6;
  3801. i = (iy + 32) >> 6;
  3802. j = (h * ry) / rx;
  3803. k = (i * ry) / rx;
  3804. if ((ok != k) && (oj != k)) {
  3805. xph = x + h;
  3806. xmh = x - h;
  3807. if (k > 0) {
  3808. result |= hlineColor(dst, xmh, xph, y + k, color);
  3809. result |= hlineColor(dst, xmh, xph, y - k, color);
  3810. } else {
  3811. result |= hlineColor(dst, xmh, xph, y, color);
  3812. }
  3813. ok = k;
  3814. }
  3815. if ((oj != j) && (ok != j) && (k != j)) {
  3816. xmi = x - i;
  3817. xpi = x + i;
  3818. if (j > 0) {
  3819. result |= hlineColor(dst, xmi, xpi, y + j, color);
  3820. result |= hlineColor(dst, xmi, xpi, y - j, color);
  3821. } else {
  3822. result |= hlineColor(dst, xmi, xpi, y, color);
  3823. }
  3824. oj = j;
  3825. }
  3826. ix = ix + iy / rx;
  3827. iy = iy - ix / rx;
  3828. } while (i > h);
  3829. } else {
  3830. ix = 0;
  3831. iy = ry * 64;
  3832. do {
  3833. h = (ix + 32) >> 6;
  3834. i = (iy + 32) >> 6;
  3835. j = (h * rx) / ry;
  3836. k = (i * rx) / ry;
  3837. if ((oi != i) && (oh != i)) {
  3838. xmj = x - j;
  3839. xpj = x + j;
  3840. if (i > 0) {
  3841. result |= hlineColor(dst, xmj, xpj, y + i, color);
  3842. result |= hlineColor(dst, xmj, xpj, y - i, color);
  3843. } else {
  3844. result |= hlineColor(dst, xmj, xpj, y, color);
  3845. }
  3846. oi = i;
  3847. }
  3848. if ((oh != h) && (oi != h) && (i != h)) {
  3849. xmk = x - k;
  3850. xpk = x + k;
  3851. if (h > 0) {
  3852. result |= hlineColor(dst, xmk, xpk, y + h, color);
  3853. result |= hlineColor(dst, xmk, xpk, y - h, color);
  3854. } else {
  3855. result |= hlineColor(dst, xmk, xpk, y, color);
  3856. }
  3857. oh = h;
  3858. }
  3859. ix = ix + iy / ry;
  3860. iy = iy - ix / ry;
  3861. } while (i > h);
  3862. }
  3863. return (result);
  3864. }
  3865. /*!
  3866. \brief Draw filled ellipse with blending.
  3867. \param dst The surface to draw on.
  3868. \param x X coordinate of the center of the filled ellipse.
  3869. \param y Y coordinate of the center of the filled ellipse.
  3870. \param rx Horizontal radius in pixels of the filled ellipse.
  3871. \param ry Vertical radius in pixels of the filled ellipse.
  3872. \param r The red value of the filled ellipse to draw.
  3873. \param g The green value of the filled ellipse to draw.
  3874. \param b The blue value of the filled ellipse to draw.
  3875. \param a The alpha value of the filled ellipse to draw.
  3876. \returns Returns 0 on success, -1 on failure.
  3877. */
  3878. int filledEllipseRGBA(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  3879. /*
  3880. * Draw
  3881. */
  3882. return (filledEllipseColor
  3883. (dst, x, y, rx, ry, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  3884. }
  3885. /* ----- pie */
  3886. /*!
  3887. \brief Internal float (low-speed) pie-calc implementation by drawing polygons.
  3888. Note: Determines vertex array and uses polygon or filledPolygon drawing routines to render.
  3889. \param dst The surface to draw on.
  3890. \param x X coordinate of the center of the pie.
  3891. \param y Y coordinate of the center of the pie.
  3892. \param rad Radius in pixels of the pie.
  3893. \param start Starting radius in degrees of the pie.
  3894. \param end Ending radius in degrees of the pie.
  3895. \param color The color value of the pie to draw (0xRRGGBBAA).
  3896. \param filled Flag indicating if the pie should be filled (=1) or not (=0).
  3897. \returns Returns 0 on success, -1 on failure.
  3898. */
  3899. int _pieColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color, Uint8 filled) {
  3900. Sint16 left, right, top, bottom;
  3901. Sint16 x1, y1, x2, y2;
  3902. int result;
  3903. double angle, start_angle, end_angle;
  3904. double deltaAngle;
  3905. double dr;
  3906. int numpoints, i;
  3907. Sint16 *vx, *vy;
  3908. /*
  3909. * Check visibility of clipping rectangle
  3910. */
  3911. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  3912. return (0);
  3913. }
  3914. /*
  3915. * Sanity check radii
  3916. */
  3917. if (rad < 0) {
  3918. return (-1);
  3919. }
  3920. /*
  3921. * Fixup angles
  3922. */
  3923. start = start % 360;
  3924. end = end % 360;
  3925. /*
  3926. * Special case for rad=0 - draw a point
  3927. */
  3928. if (rad == 0) {
  3929. return (pixelColor(dst, x, y, color));
  3930. }
  3931. /*
  3932. * Clip against circle, not pie (not 100% optimal).
  3933. * Get pie's circle and clipping boundary and
  3934. * test if bounding box of circle is visible
  3935. */
  3936. x2 = x + rad;
  3937. left = dst->clip_rect.x;
  3938. if (x2 < left) {
  3939. return (0);
  3940. }
  3941. x1 = x - rad;
  3942. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  3943. if (x1 > right) {
  3944. return (0);
  3945. }
  3946. y2 = y + rad;
  3947. top = dst->clip_rect.y;
  3948. if (y2 < top) {
  3949. return (0);
  3950. }
  3951. y1 = y - rad;
  3952. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  3953. if (y1 > bottom) {
  3954. return (0);
  3955. }
  3956. /*
  3957. * Variable setup
  3958. */
  3959. dr = (double) rad;
  3960. deltaAngle = 3.0 / dr;
  3961. start_angle = (double) start * (2.0 * M_PI / 360.0);
  3962. end_angle = (double) end * (2.0 * M_PI / 360.0);
  3963. if (start > end) {
  3964. end_angle += (2.0 * M_PI);
  3965. }
  3966. /* We will always have at least 2 points */
  3967. numpoints = 2;
  3968. /* Count points (rather than calculating it) */
  3969. angle = start_angle;
  3970. while (angle < end_angle) {
  3971. angle += deltaAngle;
  3972. numpoints++;
  3973. }
  3974. /* Allocate combined vertex array */
  3975. vx = vy = (Sint16 *) malloc(2 * sizeof(Uint16) * numpoints);
  3976. if (vx == NULL) {
  3977. return (-1);
  3978. }
  3979. /* Update point to start of vy */
  3980. vy += numpoints;
  3981. /* Center */
  3982. vx[0] = x;
  3983. vy[0] = y;
  3984. /* First vertex */
  3985. angle = start_angle;
  3986. vx[1] = x + (int) (dr * cos(angle));
  3987. vy[1] = y + (int) (dr * sin(angle));
  3988. if (numpoints < 3) {
  3989. result = lineColor(dst, vx[0], vy[0], vx[1], vy[1], color);
  3990. } else {
  3991. /* Calculate other vertices */
  3992. i = 2;
  3993. angle = start_angle;
  3994. while (angle < end_angle) {
  3995. angle += deltaAngle;
  3996. if (angle > end_angle) {
  3997. angle = end_angle;
  3998. }
  3999. vx[i] = x + (int) (dr * cos(angle));
  4000. vy[i] = y + (int) (dr * sin(angle));
  4001. i++;
  4002. }
  4003. /* Draw */
  4004. if (filled) {
  4005. result = filledPolygonColor(dst, vx, vy, numpoints, color);
  4006. } else {
  4007. result = polygonColor(dst, vx, vy, numpoints, color);
  4008. }
  4009. }
  4010. /* Free combined vertex array */
  4011. free(vx);
  4012. return (result);
  4013. }
  4014. /*!
  4015. \brief Draw pie (outline) with alpha blending.
  4016. \param dst The surface to draw on.
  4017. \param x X coordinate of the center of the pie.
  4018. \param y Y coordinate of the center of the pie.
  4019. \param rad Radius in pixels of the pie.
  4020. \param start Starting radius in degrees of the pie.
  4021. \param end Ending radius in degrees of the pie.
  4022. \param color The color value of the pie to draw (0xRRGGBBAA).
  4023. \returns Returns 0 on success, -1 on failure.
  4024. */
  4025. int pieColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad,
  4026. Sint16 start, Sint16 end, Uint32 color) {
  4027. return (_pieColor(dst, x, y, rad, start, end, color, 0));
  4028. }
  4029. /*!
  4030. \brief Draw pie (outline) with alpha blending.
  4031. \param dst The surface to draw on.
  4032. \param x X coordinate of the center of the pie.
  4033. \param y Y coordinate of the center of the pie.
  4034. \param rad Radius in pixels of the pie.
  4035. \param start Starting radius in degrees of the pie.
  4036. \param end Ending radius in degrees of the pie.
  4037. \param r The red value of the pie to draw.
  4038. \param g The green value of the pie to draw.
  4039. \param b The blue value of the pie to draw.
  4040. \param a The alpha value of the pie to draw.
  4041. \returns Returns 0 on success, -1 on failure.
  4042. */
  4043. int pieRGBA(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad,
  4044. Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  4045. return (_pieColor(dst, x, y, rad, start, end,
  4046. ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 0));
  4047. }
  4048. /*!
  4049. \brief Draw filled pie with alpha blending.
  4050. \param dst The surface to draw on.
  4051. \param x X coordinate of the center of the filled pie.
  4052. \param y Y coordinate of the center of the filled pie.
  4053. \param rad Radius in pixels of the filled pie.
  4054. \param start Starting radius in degrees of the filled pie.
  4055. \param end Ending radius in degrees of the filled pie.
  4056. \param color The color value of the filled pie to draw (0xRRGGBBAA).
  4057. \returns Returns 0 on success, -1 on failure.
  4058. */
  4059. int filledPieColor(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad, Sint16 start, Sint16 end, Uint32 color) {
  4060. return (_pieColor(dst, x, y, rad, start, end, color, 1));
  4061. }
  4062. /*!
  4063. \brief Draw filled pie with alpha blending.
  4064. \param dst The surface to draw on.
  4065. \param x X coordinate of the center of the filled pie.
  4066. \param y Y coordinate of the center of the filled pie.
  4067. \param rad Radius in pixels of the filled pie.
  4068. \param start Starting radius in degrees of the filled pie.
  4069. \param end Ending radius in degrees of the filled pie.
  4070. \param r The red value of the filled pie to draw.
  4071. \param g The green value of the filled pie to draw.
  4072. \param b The blue value of the filled pie to draw.
  4073. \param a The alpha value of the filled pie to draw.
  4074. \returns Returns 0 on success, -1 on failure.
  4075. */
  4076. int filledPieRGBA(SDL_Surface *dst, Sint16 x, Sint16 y, Sint16 rad,
  4077. Sint16 start, Sint16 end, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  4078. return (_pieColor(dst, x, y, rad, start, end,
  4079. ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, 1));
  4080. }
  4081. /* ------ Trigon */
  4082. /*!
  4083. \brief Draw trigon (triangle outline) with alpha blending.
  4084. Note: Creates vertex array and uses polygon routine to render.
  4085. \param dst The surface to draw on.
  4086. \param x1 X coordinate of the first point of the trigon.
  4087. \param y1 Y coordinate of the first point of the trigon.
  4088. \param x2 X coordinate of the second point of the trigon.
  4089. \param y2 Y coordinate of the second point of the trigon.
  4090. \param x3 X coordinate of the third point of the trigon.
  4091. \param y3 Y coordinate of the third point of the trigon.
  4092. \param color The color value of the trigon to draw (0xRRGGBBAA).
  4093. \returns Returns 0 on success, -1 on failure.
  4094. */
  4095. int trigonColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color) {
  4096. Sint16 vx[3];
  4097. Sint16 vy[3];
  4098. vx[0] = x1;
  4099. vx[1] = x2;
  4100. vx[2] = x3;
  4101. vy[0] = y1;
  4102. vy[1] = y2;
  4103. vy[2] = y3;
  4104. return (polygonColor(dst, vx, vy, 3, color));
  4105. }
  4106. /*!
  4107. \brief Draw trigon (triangle outline) with alpha blending.
  4108. \param dst The surface to draw on.
  4109. \param x1 X coordinate of the first point of the trigon.
  4110. \param y1 Y coordinate of the first point of the trigon.
  4111. \param x2 X coordinate of the second point of the trigon.
  4112. \param y2 Y coordinate of the second point of the trigon.
  4113. \param x3 X coordinate of the third point of the trigon.
  4114. \param y3 Y coordinate of the third point of the trigon.
  4115. \param r The red value of the trigon to draw.
  4116. \param g The green value of the trigon to draw.
  4117. \param b The blue value of the trigon to draw.
  4118. \param a The alpha value of the trigon to draw.
  4119. \returns Returns 0 on success, -1 on failure.
  4120. */
  4121. int trigonRGBA(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
  4122. Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  4123. Sint16 vx[3];
  4124. Sint16 vy[3];
  4125. vx[0] = x1;
  4126. vx[1] = x2;
  4127. vx[2] = x3;
  4128. vy[0] = y1;
  4129. vy[1] = y2;
  4130. vy[2] = y3;
  4131. return (polygonRGBA(dst, vx, vy, 3, r, g, b, a));
  4132. }
  4133. /* ------ AA-Trigon */
  4134. /*!
  4135. \brief Draw anti-aliased trigon (triangle outline) with alpha blending.
  4136. Note: Creates vertex array and uses aapolygon routine to render.
  4137. \param dst The surface to draw on.
  4138. \param x1 X coordinate of the first point of the aa-trigon.
  4139. \param y1 Y coordinate of the first point of the aa-trigon.
  4140. \param x2 X coordinate of the second point of the aa-trigon.
  4141. \param y2 Y coordinate of the second point of the aa-trigon.
  4142. \param x3 X coordinate of the third point of the aa-trigon.
  4143. \param y3 Y coordinate of the third point of the aa-trigon.
  4144. \param color The color value of the aa-trigon to draw (0xRRGGBBAA).
  4145. \returns Returns 0 on success, -1 on failure.
  4146. */
  4147. int aatrigonColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color) {
  4148. Sint16 vx[3];
  4149. Sint16 vy[3];
  4150. vx[0] = x1;
  4151. vx[1] = x2;
  4152. vx[2] = x3;
  4153. vy[0] = y1;
  4154. vy[1] = y2;
  4155. vy[2] = y3;
  4156. return (aapolygonColor(dst, vx, vy, 3, color));
  4157. }
  4158. /*!
  4159. \brief Draw anti-aliased trigon (triangle outline) with alpha blending.
  4160. \param dst The surface to draw on.
  4161. \param x1 X coordinate of the first point of the aa-trigon.
  4162. \param y1 Y coordinate of the first point of the aa-trigon.
  4163. \param x2 X coordinate of the second point of the aa-trigon.
  4164. \param y2 Y coordinate of the second point of the aa-trigon.
  4165. \param x3 X coordinate of the third point of the aa-trigon.
  4166. \param y3 Y coordinate of the third point of the aa-trigon.
  4167. \param r The red value of the aa-trigon to draw.
  4168. \param g The green value of the aa-trigon to draw.
  4169. \param b The blue value of the aa-trigon to draw.
  4170. \param a The alpha value of the aa-trigon to draw.
  4171. \returns Returns 0 on success, -1 on failure.
  4172. */
  4173. int aatrigonRGBA(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
  4174. Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  4175. Sint16 vx[3];
  4176. Sint16 vy[3];
  4177. vx[0] = x1;
  4178. vx[1] = x2;
  4179. vx[2] = x3;
  4180. vy[0] = y1;
  4181. vy[1] = y2;
  4182. vy[2] = y3;
  4183. return (aapolygonRGBA(dst, vx, vy, 3, r, g, b, a));
  4184. }
  4185. /* ------ Filled Trigon */
  4186. /*!
  4187. \brief Draw filled trigon (triangle) with alpha blending.
  4188. Note: Creates vertex array and uses aapolygon routine to render.
  4189. \param dst The surface to draw on.
  4190. \param x1 X coordinate of the first point of the filled trigon.
  4191. \param y1 Y coordinate of the first point of the filled trigon.
  4192. \param x2 X coordinate of the second point of the filled trigon.
  4193. \param y2 Y coordinate of the second point of the filled trigon.
  4194. \param x3 X coordinate of the third point of the filled trigon.
  4195. \param y3 Y coordinate of the third point of the filled trigon.
  4196. \param color The color value of the filled trigon to draw (0xRRGGBBAA).
  4197. \returns Returns 0 on success, -1 on failure.
  4198. */
  4199. int
  4200. filledTrigonColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color) {
  4201. Sint16 vx[3];
  4202. Sint16 vy[3];
  4203. vx[0] = x1;
  4204. vx[1] = x2;
  4205. vx[2] = x3;
  4206. vy[0] = y1;
  4207. vy[1] = y2;
  4208. vy[2] = y3;
  4209. return (filledPolygonColor(dst, vx, vy, 3, color));
  4210. }
  4211. /*!
  4212. \brief Draw filled trigon (triangle) with alpha blending.
  4213. Note: Creates vertex array and uses aapolygon routine to render.
  4214. \param dst The surface to draw on.
  4215. \param x1 X coordinate of the first point of the filled trigon.
  4216. \param y1 Y coordinate of the first point of the filled trigon.
  4217. \param x2 X coordinate of the second point of the filled trigon.
  4218. \param y2 Y coordinate of the second point of the filled trigon.
  4219. \param x3 X coordinate of the third point of the filled trigon.
  4220. \param y3 Y coordinate of the third point of the filled trigon.
  4221. \param r The red value of the filled trigon to draw.
  4222. \param g The green value of the filled trigon to draw.
  4223. \param b The blue value of the filled trigon to draw.
  4224. \param a The alpha value of the filled trigon to draw.
  4225. \returns Returns 0 on success, -1 on failure.
  4226. */
  4227. int filledTrigonRGBA(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3,
  4228. Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  4229. Sint16 vx[3];
  4230. Sint16 vy[3];
  4231. vx[0] = x1;
  4232. vx[1] = x2;
  4233. vx[2] = x3;
  4234. vy[0] = y1;
  4235. vy[1] = y2;
  4236. vy[2] = y3;
  4237. return (filledPolygonRGBA(dst, vx, vy, 3, r, g, b, a));
  4238. }
  4239. /* ---- Polygon */
  4240. /*!
  4241. \brief Draw polygon with alpha blending.
  4242. \param dst The surface to draw on.
  4243. \param vx Vertex array containing X coordinates of the points of the polygon.
  4244. \param vy Vertex array containing Y coordinates of the points of the polygon.
  4245. \param n Number of points in the vertex array. Minimum number is 3.
  4246. \param color The color value of the polygon to draw (0xRRGGBBAA).
  4247. \returns Returns 0 on success, -1 on failure.
  4248. */
  4249. int polygonColor(SDL_Surface *dst, const Sint16 *vx, const Sint16 *vy, int n, Uint32 color) {
  4250. int result;
  4251. int i;
  4252. const Sint16 *x1, *y1, *x2, *y2;
  4253. /*
  4254. * Check visibility of clipping rectangle
  4255. */
  4256. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  4257. return (0);
  4258. }
  4259. /*
  4260. * Vertex array NULL check
  4261. */
  4262. if (vx == NULL) {
  4263. return (-1);
  4264. }
  4265. if (vy == NULL) {
  4266. return (-1);
  4267. }
  4268. /*
  4269. * Sanity check
  4270. */
  4271. if (n < 3) {
  4272. return (-1);
  4273. }
  4274. /*
  4275. * Pointer setup
  4276. */
  4277. x1 = x2 = vx;
  4278. y1 = y2 = vy;
  4279. x2++;
  4280. y2++;
  4281. /*
  4282. * Draw
  4283. */
  4284. result = 0;
  4285. for (i = 1; i < n; i++) {
  4286. result |= lineColor(dst, *x1, *y1, *x2, *y2, color);
  4287. x1 = x2;
  4288. y1 = y2;
  4289. x2++;
  4290. y2++;
  4291. }
  4292. result |= lineColor(dst, *x1, *y1, *vx, *vy, color);
  4293. return (result);
  4294. }
  4295. /*!
  4296. \brief Draw polygon with alpha blending.
  4297. \param dst The surface to draw on.
  4298. \param vx Vertex array containing X coordinates of the points of the polygon.
  4299. \param vy Vertex array containing Y coordinates of the points of the polygon.
  4300. \param n Number of points in the vertex array. Minimum number is 3.
  4301. \param r The red value of the polygon to draw.
  4302. \param g The green value of the polygon to draw.
  4303. \param b The blue value of the polygon to draw.
  4304. \param a The alpha value of the polygon to draw.
  4305. \returns Returns 0 on success, -1 on failure.
  4306. */
  4307. int polygonRGBA(SDL_Surface *dst, const Sint16 *vx, const Sint16 *vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  4308. /*
  4309. * Draw
  4310. */
  4311. return (polygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  4312. }
  4313. /* ---- AA-Polygon */
  4314. /*!
  4315. \brief Draw anti-aliased polygon with alpha blending.
  4316. \param dst The surface to draw on.
  4317. \param vx Vertex array containing X coordinates of the points of the aa-polygon.
  4318. \param vy Vertex array containing Y coordinates of the points of the aa-polygon.
  4319. \param n Number of points in the vertex array. Minimum number is 3.
  4320. \param color The color value of the aa-polygon to draw (0xRRGGBBAA).
  4321. \returns Returns 0 on success, -1 on failure.
  4322. */
  4323. int aapolygonColor(SDL_Surface *dst, const Sint16 *vx, const Sint16 *vy, int n, Uint32 color) {
  4324. int result;
  4325. int i;
  4326. const Sint16 *x1, *y1, *x2, *y2;
  4327. /*
  4328. * Check visibility of clipping rectangle
  4329. */
  4330. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  4331. return (0);
  4332. }
  4333. /*
  4334. * Vertex array NULL check
  4335. */
  4336. if (vx == NULL) {
  4337. return (-1);
  4338. }
  4339. if (vy == NULL) {
  4340. return (-1);
  4341. }
  4342. /*
  4343. * Sanity check
  4344. */
  4345. if (n < 3) {
  4346. return (-1);
  4347. }
  4348. /*
  4349. * Pointer setup
  4350. */
  4351. x1 = x2 = vx;
  4352. y1 = y2 = vy;
  4353. x2++;
  4354. y2++;
  4355. /*
  4356. * Draw
  4357. */
  4358. result = 0;
  4359. for (i = 1; i < n; i++) {
  4360. result |= _aalineColor(dst, *x1, *y1, *x2, *y2, color, 0);
  4361. x1 = x2;
  4362. y1 = y2;
  4363. x2++;
  4364. y2++;
  4365. }
  4366. result |= _aalineColor(dst, *x1, *y1, *vx, *vy, color, 0);
  4367. return (result);
  4368. }
  4369. /*!
  4370. \brief Draw anti-aliased polygon with alpha blending.
  4371. \param dst The surface to draw on.
  4372. \param vx Vertex array containing X coordinates of the points of the aa-polygon.
  4373. \param vy Vertex array containing Y coordinates of the points of the aa-polygon.
  4374. \param n Number of points in the vertex array. Minimum number is 3.
  4375. \param r The red value of the aa-polygon to draw.
  4376. \param g The green value of the aa-polygon to draw.
  4377. \param b The blue value of the aa-polygon to draw.
  4378. \param a The alpha value of the aa-polygon to draw.
  4379. \returns Returns 0 on success, -1 on failure.
  4380. */
  4381. int aapolygonRGBA(SDL_Surface *dst, const Sint16 *vx, const Sint16 *vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  4382. /*
  4383. * Draw
  4384. */
  4385. return (aapolygonColor(dst, vx, vy, n, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  4386. }
  4387. /* ---- Filled Polygon */
  4388. /*!
  4389. \brief Internal helper qsort callback functions used in filled polygon drawing.
  4390. \param a The surface to draw on.
  4391. \param b Vertex array containing X coordinates of the points of the polygon.
  4392. \returns Returns 0 if a==b, a negative number if a<b or a positive number if a>b.
  4393. */
  4394. int _gfxPrimitivesCompareInt(const void *a, const void *b) {
  4395. return (*(const int *) a) - (*(const int *) b);
  4396. }
  4397. /*!
  4398. \brief Global vertex array to use if optional parameters are not given in filledPolygonMT calls.
  4399. Note: Used for non-multithreaded (default) operation of filledPolygonMT.
  4400. */
  4401. static int *gfxPrimitivesPolyIntsGlobal = NULL;
  4402. /*!
  4403. \brief Flag indicating if global vertex array was already allocated.
  4404. Note: Used for non-multithreaded (default) operation of filledPolygonMT.
  4405. */
  4406. static int gfxPrimitivesPolyAllocatedGlobal = 0;
  4407. /*!
  4408. \brief Draw filled polygon with alpha blending (multi-threaded capable).
  4409. Note: The last two parameters are optional; but are required for multithreaded operation.
  4410. \param dst The surface to draw on.
  4411. \param vx Vertex array containing X coordinates of the points of the filled polygon.
  4412. \param vy Vertex array containing Y coordinates of the points of the filled polygon.
  4413. \param n Number of points in the vertex array. Minimum number is 3.
  4414. \param color The color value of the filled polygon to draw (0xRRGGBBAA).
  4415. \param polyInts Preallocated, temporary vertex array used for sorting vertices. Required for multithreaded operation; set to NULL otherwise.
  4416. \param polyAllocated Flag indicating if temporary vertex array was allocated. Required for multithreaded operation; set to NULL otherwise.
  4417. \returns Returns 0 on success, -1 on failure.
  4418. */
  4419. int filledPolygonColorMT(SDL_Surface *dst, const Sint16 *vx, const Sint16 *vy, int n, Uint32 color, int **polyInts,
  4420. int *polyAllocated) {
  4421. int result;
  4422. int i;
  4423. int y, xa, xb;
  4424. int miny, maxy;
  4425. int x1, y1;
  4426. int x2, y2;
  4427. int ind1, ind2;
  4428. int ints;
  4429. int *gfxPrimitivesPolyInts = NULL;
  4430. int *gfxPrimitivesPolyIntsNew = NULL;
  4431. int gfxPrimitivesPolyAllocated = 0;
  4432. /*
  4433. * Check visibility of clipping rectangle
  4434. */
  4435. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  4436. return (0);
  4437. }
  4438. /*
  4439. * Vertex array NULL check
  4440. */
  4441. if (vx == NULL) {
  4442. return (-1);
  4443. }
  4444. if (vy == NULL) {
  4445. return (-1);
  4446. }
  4447. /*
  4448. * Sanity check number of edges
  4449. */
  4450. if (n < 3) {
  4451. return -1;
  4452. }
  4453. /*
  4454. * Map polygon cache
  4455. */
  4456. if ((polyInts == NULL) || (polyAllocated == NULL)) {
  4457. /* Use global cache */
  4458. gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
  4459. gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
  4460. } else {
  4461. /* Use local cache */
  4462. gfxPrimitivesPolyInts = *polyInts;
  4463. gfxPrimitivesPolyAllocated = *polyAllocated;
  4464. }
  4465. /*
  4466. * Allocate temp array, only grow array
  4467. */
  4468. if (!gfxPrimitivesPolyAllocated) {
  4469. gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
  4470. gfxPrimitivesPolyAllocated = n;
  4471. } else {
  4472. if (gfxPrimitivesPolyAllocated < n) {
  4473. gfxPrimitivesPolyIntsNew = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
  4474. if (!gfxPrimitivesPolyIntsNew) {
  4475. if (!gfxPrimitivesPolyInts) {
  4476. free(gfxPrimitivesPolyInts);
  4477. gfxPrimitivesPolyInts = NULL;
  4478. }
  4479. gfxPrimitivesPolyAllocated = 0;
  4480. } else {
  4481. gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsNew;
  4482. gfxPrimitivesPolyAllocated = n;
  4483. }
  4484. }
  4485. }
  4486. /*
  4487. * Check temp array
  4488. */
  4489. if (gfxPrimitivesPolyInts == NULL) {
  4490. gfxPrimitivesPolyAllocated = 0;
  4491. }
  4492. /*
  4493. * Update cache variables
  4494. */
  4495. if ((polyInts == NULL) || (polyAllocated == NULL)) {
  4496. gfxPrimitivesPolyIntsGlobal = gfxPrimitivesPolyInts;
  4497. gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
  4498. } else {
  4499. *polyInts = gfxPrimitivesPolyInts;
  4500. *polyAllocated = gfxPrimitivesPolyAllocated;
  4501. }
  4502. /*
  4503. * Check temp array again
  4504. */
  4505. if (gfxPrimitivesPolyInts == NULL) {
  4506. return (-1);
  4507. }
  4508. /*
  4509. * Determine Y maxima
  4510. */
  4511. miny = vy[0];
  4512. maxy = vy[0];
  4513. for (i = 1; (i < n); i++) {
  4514. if (vy[i] < miny) {
  4515. miny = vy[i];
  4516. } else if (vy[i] > maxy) {
  4517. maxy = vy[i];
  4518. }
  4519. }
  4520. /*
  4521. * Draw, scanning y
  4522. */
  4523. result = 0;
  4524. for (y = miny; (y <= maxy); y++) {
  4525. ints = 0;
  4526. for (i = 0; (i < n); i++) {
  4527. if (!i) {
  4528. ind1 = n - 1;
  4529. ind2 = 0;
  4530. } else {
  4531. ind1 = i - 1;
  4532. ind2 = i;
  4533. }
  4534. y1 = vy[ind1];
  4535. y2 = vy[ind2];
  4536. if (y1 < y2) {
  4537. x1 = vx[ind1];
  4538. x2 = vx[ind2];
  4539. } else if (y1 > y2) {
  4540. y2 = vy[ind1];
  4541. y1 = vy[ind2];
  4542. x2 = vx[ind1];
  4543. x1 = vx[ind2];
  4544. } else {
  4545. continue;
  4546. }
  4547. if (((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2))) {
  4548. gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
  4549. }
  4550. }
  4551. qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
  4552. for (i = 0; (i < ints); i += 2) {
  4553. xa = gfxPrimitivesPolyInts[i] + 1;
  4554. xa = (xa >> 16) + ((xa & 32768) >> 15);
  4555. xb = gfxPrimitivesPolyInts[i + 1] - 1;
  4556. xb = (xb >> 16) + ((xb & 32768) >> 15);
  4557. result |= hlineColor(dst, xa, xb, y, color);
  4558. }
  4559. }
  4560. return (result);
  4561. }
  4562. /*!
  4563. \brief Draw filled polygon with alpha blending (multi-threaded capable).
  4564. Note: The last two parameters are optional; but are required for multithreaded operation.
  4565. \param dst The surface to draw on.
  4566. \param vx Vertex array containing X coordinates of the points of the filled polygon.
  4567. \param vy Vertex array containing Y coordinates of the points of the filled polygon.
  4568. \param n Number of points in the vertex array. Minimum number is 3.
  4569. \param r The red value of the filled polygon to draw.
  4570. \param g The green value of the filled polygon to draw.
  4571. \param b The blue value of the filed polygon to draw.
  4572. \param a The alpha value of the filled polygon to draw.
  4573. \param polyInts Preallocated, temporary vertex array used for sorting vertices. Required for multithreaded operation; set to NULL otherwise.
  4574. \param polyAllocated Flag indicating if temporary vertex array was allocated. Required for multithreaded operation; set to NULL otherwise.
  4575. \returns Returns 0 on success, -1 on failure.
  4576. */
  4577. int filledPolygonRGBAMT(SDL_Surface *dst, const Sint16 *vx, const Sint16 *vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a,
  4578. int **polyInts, int *polyAllocated) {
  4579. /*
  4580. * Draw
  4581. */
  4582. return (filledPolygonColorMT(dst, vx, vy, n,
  4583. ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, polyInts,
  4584. polyAllocated));
  4585. }
  4586. /*!
  4587. \brief Draw filled polygon with alpha blending.
  4588. Note: Standard filledPolygon function is calling multithreaded version with NULL parameters
  4589. to use the global vertex cache.
  4590. \param dst The surface to draw on.
  4591. \param vx Vertex array containing X coordinates of the points of the filled polygon.
  4592. \param vy Vertex array containing Y coordinates of the points of the filled polygon.
  4593. \param n Number of points in the vertex array. Minimum number is 3.
  4594. \param color The color value of the filled polygon to draw (0xRRGGBBAA).
  4595. \returns Returns 0 on success, -1 on failure.
  4596. */
  4597. int filledPolygonColor(SDL_Surface *dst, const Sint16 *vx, const Sint16 *vy, int n, Uint32 color) {
  4598. /*
  4599. * Draw
  4600. */
  4601. return (filledPolygonColorMT(dst, vx, vy, n, color, NULL, NULL));
  4602. }
  4603. /*!
  4604. \brief Draw filled polygon with alpha blending.
  4605. \param dst The surface to draw on.
  4606. \param vx Vertex array containing X coordinates of the points of the filled polygon.
  4607. \param vy Vertex array containing Y coordinates of the points of the filled polygon.
  4608. \param n Number of points in the vertex array. Minimum number is 3.
  4609. \param r The red value of the filled polygon to draw.
  4610. \param g The green value of the filled polygon to draw.
  4611. \param b The blue value of the filed polygon to draw.
  4612. \param a The alpha value of the filled polygon to draw.
  4613. \returns Returns 0 on success, -1 on failure.
  4614. */
  4615. int filledPolygonRGBA(SDL_Surface *dst, const Sint16 *vx, const Sint16 *vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  4616. /*
  4617. * Draw
  4618. */
  4619. return (filledPolygonColorMT(dst, vx, vy, n,
  4620. ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a, NULL, NULL));
  4621. }
  4622. /*!
  4623. \brief Internal function to draw a textured horizontal line.
  4624. \param dst The surface to draw on.
  4625. \param x1 X coordinate of the first point (i.e. left) of the line.
  4626. \param x2 X coordinate of the second point (i.e. right) of the line.
  4627. \param y Y coordinate of the points of the line.
  4628. \param texture The texture surface to retrieve color information from.
  4629. \param texture_dx The X offset for the texture lookup.
  4630. \param texture_dy The Y offset for the textured lookup.
  4631. \returns Returns 0 on success, -1 on failure.
  4632. */
  4633. int
  4634. _HLineTextured(SDL_Surface *dst, Sint16 x1, Sint16 x2, Sint16 y, SDL_Surface *texture, int texture_dx, int texture_dy) {
  4635. Sint16 left, right, top, bottom;
  4636. Sint16 w;
  4637. Sint16 xtmp;
  4638. int result = 0;
  4639. int texture_x_walker;
  4640. int texture_y_start;
  4641. SDL_Rect source_rect, dst_rect;
  4642. int pixels_written, write_width;
  4643. /*
  4644. * Check visibility of clipping rectangle
  4645. */
  4646. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  4647. return (0);
  4648. }
  4649. /*
  4650. * Swap x1, x2 if required to ensure x1<=x2
  4651. */
  4652. if (x1 > x2) {
  4653. xtmp = x1;
  4654. x1 = x2;
  4655. x2 = xtmp;
  4656. }
  4657. /*
  4658. * Get clipping boundary and
  4659. * check visibility of hline
  4660. */
  4661. left = dst->clip_rect.x;
  4662. if (x2 < left) {
  4663. return (0);
  4664. }
  4665. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  4666. if (x1 > right) {
  4667. return (0);
  4668. }
  4669. top = dst->clip_rect.y;
  4670. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  4671. if ((y < top) || (y > bottom)) {
  4672. return (0);
  4673. }
  4674. /*
  4675. * Clip x
  4676. */
  4677. if (x1 < left) {
  4678. x1 = left;
  4679. }
  4680. if (x2 > right) {
  4681. x2 = right;
  4682. }
  4683. /*
  4684. * Calculate width to draw
  4685. */
  4686. w = x2 - x1 + 1;
  4687. /*
  4688. * Determine where in the texture we start drawing
  4689. */
  4690. texture_x_walker = (x1 - texture_dx) % texture->w;
  4691. if (texture_x_walker < 0) {
  4692. texture_x_walker = texture->w + texture_x_walker;
  4693. }
  4694. texture_y_start = (y + texture_dy) % texture->h;
  4695. if (texture_y_start < 0) {
  4696. texture_y_start = texture->h + texture_y_start;
  4697. }
  4698. // setup the source rectangle; we are only drawing one horizontal line
  4699. source_rect.y = texture_y_start;
  4700. source_rect.x = texture_x_walker;
  4701. source_rect.h = 1;
  4702. // we will draw to the current y
  4703. dst_rect.y = y;
  4704. // if there are enough pixels left in the current row of the texture
  4705. // draw it all at once
  4706. if (w <= texture->w - texture_x_walker) {
  4707. source_rect.w = w;
  4708. source_rect.x = texture_x_walker;
  4709. dst_rect.x = x1;
  4710. result = (SDL_BlitSurface(texture, &source_rect, dst, &dst_rect) == 0);
  4711. } else { // we need to draw multiple times
  4712. // draw the first segment
  4713. pixels_written = texture->w - texture_x_walker;
  4714. source_rect.w = pixels_written;
  4715. source_rect.x = texture_x_walker;
  4716. dst_rect.x = x1;
  4717. result |= (SDL_BlitSurface(texture, &source_rect, dst, &dst_rect) == 0);
  4718. write_width = texture->w;
  4719. // now draw the rest
  4720. // set the source x to 0
  4721. source_rect.x = 0;
  4722. while (pixels_written < w) {
  4723. if (write_width >= w - pixels_written) {
  4724. write_width = w - pixels_written;
  4725. }
  4726. source_rect.w = write_width;
  4727. dst_rect.x = x1 + pixels_written;
  4728. result |= (SDL_BlitSurface(texture, &source_rect, dst, &dst_rect) == 0);
  4729. pixels_written += write_width;
  4730. }
  4731. }
  4732. return result;
  4733. }
  4734. /*!
  4735. \brief Draws a polygon filled with the given texture (Multi-Threading Capable).
  4736. This operation use internally SDL_BlitSurface for lines of the source texture. It supports
  4737. alpha drawing.
  4738. To get the best performance of this operation you need to make sure the texture and the dst surface have the same format
  4739. (see http://docs.mandragor.org/files/Common_libs_documentation/SDL/SDL_Documentation_project_en/sdlblitsurface.html).
  4740. The last two parameters are optional, but required for multithreaded operation. When set to NULL, uses global static temp array.
  4741. \param dst the destination surface,
  4742. \param vx array of x vector components
  4743. \param vy array of x vector components
  4744. \param n the amount of vectors in the vx and vy array
  4745. \param texture the sdl surface to use to fill the polygon
  4746. \param texture_dx the offset of the texture relative to the screeen. if you move the polygon 10 pixels
  4747. to the left and want the texture to apear the same you need to increase the texture_dx value
  4748. \param texture_dy see texture_dx
  4749. \param polyInts preallocated temp array storage for vertex sorting (used for multi-threaded operation)
  4750. \param polyAllocated flag indicating oif the temp array was allocated (used for multi-threaded operation)
  4751. \returns Returns 0 on success, -1 on failure.
  4752. */
  4753. int texturedPolygonMT(SDL_Surface *dst, const Sint16 *vx, const Sint16 *vy, int n,
  4754. SDL_Surface *texture, int texture_dx, int texture_dy, int **polyInts, int *polyAllocated) {
  4755. int result;
  4756. int i;
  4757. int y, xa, xb;
  4758. int minx, maxx, miny, maxy;
  4759. int x1, y1;
  4760. int x2, y2;
  4761. int ind1, ind2;
  4762. int ints;
  4763. int *gfxPrimitivesPolyInts = NULL;
  4764. int gfxPrimitivesPolyAllocated = 0;
  4765. /*
  4766. * Check visibility of clipping rectangle
  4767. */
  4768. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  4769. return (0);
  4770. }
  4771. /*
  4772. * Sanity check number of edges
  4773. */
  4774. if (n < 3) {
  4775. return -1;
  4776. }
  4777. /*
  4778. * Map polygon cache
  4779. */
  4780. if ((polyInts == NULL) || (polyAllocated == NULL)) {
  4781. /* Use global cache */
  4782. gfxPrimitivesPolyInts = gfxPrimitivesPolyIntsGlobal;
  4783. gfxPrimitivesPolyAllocated = gfxPrimitivesPolyAllocatedGlobal;
  4784. } else {
  4785. /* Use local cache */
  4786. gfxPrimitivesPolyInts = *polyInts;
  4787. gfxPrimitivesPolyAllocated = *polyAllocated;
  4788. }
  4789. /*
  4790. * Allocate temp array, only grow array
  4791. */
  4792. if (!gfxPrimitivesPolyAllocated) {
  4793. gfxPrimitivesPolyInts = (int *) malloc(sizeof(int) * n);
  4794. gfxPrimitivesPolyAllocated = n;
  4795. } else {
  4796. if (gfxPrimitivesPolyAllocated < n) {
  4797. gfxPrimitivesPolyInts = (int *) realloc(gfxPrimitivesPolyInts, sizeof(int) * n);
  4798. gfxPrimitivesPolyAllocated = n;
  4799. }
  4800. }
  4801. /*
  4802. * Check temp array
  4803. */
  4804. if (gfxPrimitivesPolyInts == NULL) {
  4805. gfxPrimitivesPolyAllocated = 0;
  4806. }
  4807. /*
  4808. * Update cache variables
  4809. */
  4810. if ((polyInts == NULL) || (polyAllocated == NULL)) {
  4811. gfxPrimitivesPolyIntsGlobal = gfxPrimitivesPolyInts;
  4812. gfxPrimitivesPolyAllocatedGlobal = gfxPrimitivesPolyAllocated;
  4813. } else {
  4814. *polyInts = gfxPrimitivesPolyInts;
  4815. *polyAllocated = gfxPrimitivesPolyAllocated;
  4816. }
  4817. /*
  4818. * Check temp array again
  4819. */
  4820. if (gfxPrimitivesPolyInts == NULL) {
  4821. return (-1);
  4822. }
  4823. /*
  4824. * Determine X,Y minima,maxima
  4825. */
  4826. miny = vy[0];
  4827. maxy = vy[0];
  4828. minx = vx[0];
  4829. maxx = vx[0];
  4830. for (i = 1; (i < n); i++) {
  4831. if (vy[i] < miny) {
  4832. miny = vy[i];
  4833. } else if (vy[i] > maxy) {
  4834. maxy = vy[i];
  4835. }
  4836. if (vx[i] < minx) {
  4837. minx = vx[i];
  4838. } else if (vx[i] > maxx) {
  4839. maxx = vx[i];
  4840. }
  4841. }
  4842. if (maxx < 0 || minx > dst->w) {
  4843. return -1;
  4844. }
  4845. if (maxy < 0 || miny > dst->h) {
  4846. return -1;
  4847. }
  4848. /*
  4849. * Draw, scanning y
  4850. */
  4851. result = 0;
  4852. for (y = miny; (y <= maxy); y++) {
  4853. ints = 0;
  4854. for (i = 0; (i < n); i++) {
  4855. if (!i) {
  4856. ind1 = n - 1;
  4857. ind2 = 0;
  4858. } else {
  4859. ind1 = i - 1;
  4860. ind2 = i;
  4861. }
  4862. y1 = vy[ind1];
  4863. y2 = vy[ind2];
  4864. if (y1 < y2) {
  4865. x1 = vx[ind1];
  4866. x2 = vx[ind2];
  4867. } else if (y1 > y2) {
  4868. y2 = vy[ind1];
  4869. y1 = vy[ind2];
  4870. x2 = vx[ind1];
  4871. x1 = vx[ind2];
  4872. } else {
  4873. continue;
  4874. }
  4875. if (((y >= y1) && (y < y2)) || ((y == maxy) && (y > y1) && (y <= y2))) {
  4876. gfxPrimitivesPolyInts[ints++] = ((65536 * (y - y1)) / (y2 - y1)) * (x2 - x1) + (65536 * x1);
  4877. }
  4878. }
  4879. qsort(gfxPrimitivesPolyInts, ints, sizeof(int), _gfxPrimitivesCompareInt);
  4880. for (i = 0; (i < ints); i += 2) {
  4881. xa = gfxPrimitivesPolyInts[i] + 1;
  4882. xa = (xa >> 16) + ((xa & 32768) >> 15);
  4883. xb = gfxPrimitivesPolyInts[i + 1] - 1;
  4884. xb = (xb >> 16) + ((xb & 32768) >> 15);
  4885. result |= _HLineTextured(dst, xa, xb, y, texture, texture_dx, texture_dy);
  4886. }
  4887. }
  4888. return (result);
  4889. }
  4890. /*!
  4891. \brief Draws a polygon filled with the given texture.
  4892. This standard version is calling multithreaded versions with NULL cache parameters.
  4893. \param dst the destination surface,
  4894. \param vx array of x vector components
  4895. \param vy array of x vector components
  4896. \param n the amount of vectors in the vx and vy array
  4897. \param texture the sdl surface to use to fill the polygon
  4898. \param texture_dx the offset of the texture relative to the screeen. if you move the polygon 10 pixels
  4899. to the left and want the texture to apear the same you need to increase the texture_dx value
  4900. \param texture_dy see texture_dx
  4901. \returns Returns 0 on success, -1 on failure.
  4902. */
  4903. int texturedPolygon(SDL_Surface *dst, const Sint16 *vx, const Sint16 *vy, int n, SDL_Surface *texture, int texture_dx,
  4904. int texture_dy) {
  4905. /*
  4906. * Draw
  4907. */
  4908. return (texturedPolygonMT(dst, vx, vy, n, texture, texture_dx, texture_dy, NULL, NULL));
  4909. }
  4910. /* ---- Character */
  4911. /*!
  4912. \brief Global cache for NxM pixel font surfaces created at runtime.
  4913. */
  4914. static SDL_Surface *gfxPrimitivesFont[256];
  4915. /*!
  4916. \brief Global cache of the color used for the font surfaces created at runtime.
  4917. */
  4918. static Uint32 gfxPrimitivesFontColor[256];
  4919. /*!
  4920. \brief Pointer to the current font data. Default is a 8x8 pixel internal font.
  4921. */
  4922. static const unsigned char *currentFontdata = gfxPrimitivesFontdata;
  4923. /*!
  4924. \brief Width of the current font. Default is 8.
  4925. */
  4926. static Uint32 charWidth = 8;
  4927. /*!
  4928. \brief Height of the current font. Default is 8.
  4929. */
  4930. static Uint32 charHeight = 8;
  4931. /*!
  4932. \brief Width for rendering. Autocalculated.
  4933. */
  4934. static Uint32 charWidthLocal = 8;
  4935. /*!
  4936. \brief Height for rendering. Autocalculated.
  4937. */
  4938. static Uint32 charHeightLocal = 8;
  4939. /*!
  4940. \brief Pitch of the current font in bytes. Default is 1.
  4941. */
  4942. static Uint32 charPitch = 1;
  4943. /*!
  4944. \brief Characters 90deg clockwise rotations. Default is 0. Max is 3.
  4945. */
  4946. static Uint32 charRotation = 0;
  4947. /*!
  4948. \brief Character data size in bytes of the current font. Default is 8.
  4949. */
  4950. static Uint32 charSize = 8;
  4951. /*!
  4952. \brief Sets or resets the current global font data.
  4953. The font data array is organized in follows:
  4954. [fontdata] = [character 0][character 1]...[character 255] where
  4955. [character n] = [byte 1 row 1][byte 2 row 1]...[byte {pitch} row 1][byte 1 row 2] ...[byte {pitch} row height] where
  4956. [byte n] = [bit 0]...[bit 7] where
  4957. [bit n] = [0 for transparent pixel|1 for colored pixel]
  4958. \param fontdata Pointer to array of font data. Set to NULL, to reset global font to the default 8x8 font.
  4959. \param cw Width of character in bytes. Ignored if fontdata==NULL.
  4960. \param ch Height of character in bytes. Ignored if fontdata==NULL.
  4961. */
  4962. void gfxPrimitivesSetFont(const void *fontdata, Uint32 cw, Uint32 ch) {
  4963. int i;
  4964. if ((fontdata) && (cw) && (ch)) {
  4965. currentFontdata = fontdata;
  4966. charWidth = cw;
  4967. charHeight = ch;
  4968. } else {
  4969. currentFontdata = gfxPrimitivesFontdata;
  4970. charWidth = 8;
  4971. charHeight = 8;
  4972. }
  4973. charPitch = (charWidth + 7) / 8;
  4974. charSize = charPitch * charHeight;
  4975. /* Maybe flip width/height for rendering */
  4976. if ((charRotation == 1) || (charRotation == 3)) {
  4977. charWidthLocal = charHeight;
  4978. charHeightLocal = charWidth;
  4979. } else {
  4980. charWidthLocal = charWidth;
  4981. charHeightLocal = charHeight;
  4982. }
  4983. /* Clear character cache */
  4984. for (i = 0; i < 256; i++) {
  4985. if (gfxPrimitivesFont[i]) {
  4986. SDL_FreeSurface(gfxPrimitivesFont[i]);
  4987. gfxPrimitivesFont[i] = NULL;
  4988. }
  4989. }
  4990. }
  4991. /*!
  4992. \brief Sets current global font character rotation steps.
  4993. Default is 0 (no rotation). 1 = 90deg clockwise. 2 = 180deg clockwise. 3 = 270deg clockwise.
  4994. Changing the rotation, will reset the character cache.
  4995. \param rotation Number of 90deg clockwise steps to rotate
  4996. */
  4997. void gfxPrimitivesSetFontRotation(Uint32 rotation) {
  4998. int i;
  4999. rotation = rotation & 3;
  5000. if (charRotation != rotation) {
  5001. /* Store rotation */
  5002. charRotation = rotation;
  5003. /* Maybe flip width/height for rendering */
  5004. if ((charRotation == 1) || (charRotation == 3)) {
  5005. charWidthLocal = charHeight;
  5006. charHeightLocal = charWidth;
  5007. } else {
  5008. charWidthLocal = charWidth;
  5009. charHeightLocal = charHeight;
  5010. }
  5011. /* Clear character cache */
  5012. for (i = 0; i < 256; i++) {
  5013. if (gfxPrimitivesFont[i]) {
  5014. SDL_FreeSurface(gfxPrimitivesFont[i]);
  5015. gfxPrimitivesFont[i] = NULL;
  5016. }
  5017. }
  5018. }
  5019. }
  5020. /*!
  5021. \brief Draw a character of the currently set font.
  5022. On first call for a particular character and color combination, the function needs to
  5023. generate the character surface (slower. Subsequent calls blit a cached surface (fast).
  5024. Uses alpha blending if A<255 in color.
  5025. \param dst The surface to draw on.
  5026. \param x X (horizontal) coordinate of the upper left corner of the character.
  5027. \param y Y (vertical) coordinate of the upper left corner of the character.
  5028. \param c The character to draw.
  5029. \param color The color value of the character to draw (0xRRGGBBAA).
  5030. \returns Returns 0 on success, -1 on failure.
  5031. */
  5032. int characterColor(SDL_Surface *dst, Sint16 x, Sint16 y, char c, Uint32 color) {
  5033. Sint16 left, right, top, bottom;
  5034. Sint16 x1, y1, x2, y2;
  5035. SDL_Rect srect;
  5036. SDL_Rect drect;
  5037. int result;
  5038. Uint32 ix, iy;
  5039. const unsigned char *charpos;
  5040. Uint8 *curpos;
  5041. int forced_redraw;
  5042. Uint8 patt, mask;
  5043. Uint8 *linepos;
  5044. Uint32 pitch;
  5045. SDL_Surface *rotatedCharacter;
  5046. Uint32 ci;
  5047. /*
  5048. * Check visibility of clipping rectangle
  5049. */
  5050. if ((dst->clip_rect.w == 0) || (dst->clip_rect.h == 0)) {
  5051. return (0);
  5052. }
  5053. /*
  5054. * Get text and clipping boundary and
  5055. * test if bounding box of character is visible
  5056. */
  5057. left = dst->clip_rect.x;
  5058. x2 = x + charWidthLocal;
  5059. if (x2 < left) {
  5060. return (0);
  5061. }
  5062. right = dst->clip_rect.x + dst->clip_rect.w - 1;
  5063. x1 = x;
  5064. if (x1 > right) {
  5065. return (0);
  5066. }
  5067. top = dst->clip_rect.y;
  5068. y2 = y + charHeightLocal;
  5069. if (y2 < top) {
  5070. return (0);
  5071. }
  5072. bottom = dst->clip_rect.y + dst->clip_rect.h - 1;
  5073. y1 = y;
  5074. if (y1 > bottom) {
  5075. return (0);
  5076. }
  5077. /*
  5078. * Setup source rectangle
  5079. */
  5080. srect.x = 0;
  5081. srect.y = 0;
  5082. srect.w = charWidthLocal;
  5083. srect.h = charHeightLocal;
  5084. /*
  5085. * Setup destination rectangle
  5086. */
  5087. drect.x = x;
  5088. drect.y = y;
  5089. drect.w = charWidthLocal;
  5090. drect.h = charHeightLocal;
  5091. /* Character index in cache */
  5092. ci = (unsigned char) c;
  5093. /*
  5094. * Create new charWidth x charHeight bitmap surface if not already present.
  5095. * Might get rotated later.
  5096. */
  5097. if (gfxPrimitivesFont[ci] == NULL) {
  5098. gfxPrimitivesFont[ci] =
  5099. SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_HWSURFACE | SDL_SRCALPHA,
  5100. charWidth, charHeight, 32,
  5101. 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
  5102. /*
  5103. * Check pointer
  5104. */
  5105. if (gfxPrimitivesFont[ci] == NULL) {
  5106. return (-1);
  5107. }
  5108. /*
  5109. * Definitely redraw
  5110. */
  5111. forced_redraw = 1;
  5112. } else {
  5113. forced_redraw = 0;
  5114. }
  5115. /*
  5116. * Check if color has changed
  5117. */
  5118. if ((gfxPrimitivesFontColor[ci] != color) || (forced_redraw)) {
  5119. /*
  5120. * Redraw character
  5121. */
  5122. SDL_SetAlpha(gfxPrimitivesFont[ci], SDL_SRCALPHA, 255);
  5123. gfxPrimitivesFontColor[ci] = color;
  5124. /* Lock font-surface */
  5125. if (SDL_LockSurface(gfxPrimitivesFont[ci]) != 0)
  5126. return (-1);
  5127. /*
  5128. * Variable setup
  5129. */
  5130. charpos = currentFontdata + ci * charSize;
  5131. linepos = (Uint8 *) gfxPrimitivesFont[ci]->pixels;
  5132. pitch = gfxPrimitivesFont[ci]->pitch;
  5133. /*
  5134. * Drawing loop
  5135. */
  5136. patt = 0;
  5137. for (iy = 0; iy < charHeight; iy++) {
  5138. mask = 0x00;
  5139. curpos = linepos;
  5140. for (ix = 0; ix < charWidth; ix++) {
  5141. if (!(mask >>= 1)) {
  5142. patt = *charpos++;
  5143. mask = 0x80;
  5144. }
  5145. if (patt & mask)
  5146. *(Uint32 *) curpos = color;
  5147. else
  5148. *(Uint32 *) curpos = 0;
  5149. curpos += 4;
  5150. }
  5151. linepos += pitch;
  5152. }
  5153. /* Unlock font-surface */
  5154. SDL_UnlockSurface(gfxPrimitivesFont[ci]);
  5155. /* Maybe rotate and replace cached image */
  5156. if (charRotation > 0) {
  5157. rotatedCharacter = rotateSurface90Degrees(gfxPrimitivesFont[ci], charRotation);
  5158. SDL_FreeSurface(gfxPrimitivesFont[ci]);
  5159. gfxPrimitivesFont[ci] = rotatedCharacter;
  5160. }
  5161. }
  5162. /*
  5163. * Draw bitmap onto destination surface
  5164. */
  5165. result = SDL_BlitSurface(gfxPrimitivesFont[ci], &srect, dst, &drect);
  5166. return (result);
  5167. }
  5168. /*!
  5169. \brief Draw a character of the currently set font.
  5170. \param dst The surface to draw on.
  5171. \param x X (horizontal) coordinate of the upper left corner of the character.
  5172. \param y Y (vertical) coordinate of the upper left corner of the character.
  5173. \param c The character to draw.
  5174. \param r The red value of the character to draw.
  5175. \param g The green value of the character to draw.
  5176. \param b The blue value of the character to draw.
  5177. \param a The alpha value of the character to draw.
  5178. \returns Returns 0 on success, -1 on failure.
  5179. */
  5180. int characterRGBA(SDL_Surface *dst, Sint16 x, Sint16 y, char c, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  5181. /*
  5182. * Draw
  5183. */
  5184. return (characterColor(dst, x, y, c, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  5185. }
  5186. /*!
  5187. \brief Draw a string in the currently set font.
  5188. The spacing between consequtive characters in the string is the fixed number of pixels
  5189. of the character width of the current global font.
  5190. \param dst The surface to draw on.
  5191. \param x X (horizontal) coordinate of the upper left corner of the string.
  5192. \param y Y (vertical) coordinate of the upper left corner of the string.
  5193. \param s The string to draw.
  5194. \param color The color value of the string to draw (0xRRGGBBAA).
  5195. \returns Returns 0 on success, -1 on failure.
  5196. */
  5197. int stringColor(SDL_Surface *dst, Sint16 x, Sint16 y, const char *s, Uint32 color) {
  5198. int result = 0;
  5199. Sint16 curx = x;
  5200. Sint16 cury = y;
  5201. const char *curchar = s;
  5202. while (*curchar && !result) {
  5203. result |= characterColor(dst, curx, cury, *curchar, color);
  5204. switch (charRotation) {
  5205. case 0:
  5206. curx += charWidthLocal;
  5207. break;
  5208. case 2:
  5209. curx -= charWidthLocal;
  5210. break;
  5211. case 1:
  5212. cury += charHeightLocal;
  5213. break;
  5214. case 3:
  5215. cury -= charHeightLocal;
  5216. break;
  5217. }
  5218. curchar++;
  5219. }
  5220. return (result);
  5221. }
  5222. /*!
  5223. \brief Draw a string in the currently set font.
  5224. \param dst The surface to draw on.
  5225. \param x X (horizontal) coordinate of the upper left corner of the string.
  5226. \param y Y (vertical) coordinate of the upper left corner of the string.
  5227. \param s The string to draw.
  5228. \param r The red value of the string to draw.
  5229. \param g The green value of the string to draw.
  5230. \param b The blue value of the string to draw.
  5231. \param a The alpha value of the string to draw.
  5232. \returns Returns 0 on success, -1 on failure.
  5233. */
  5234. int stringRGBA(SDL_Surface *dst, Sint16 x, Sint16 y, const char *s, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  5235. /*
  5236. * Draw
  5237. */
  5238. return (stringColor(dst, x, y, s, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  5239. }
  5240. /* ---- Bezier curve */
  5241. /*!
  5242. \brief Internal function to calculate bezier interpolator of data array with ndata values at position 't'.
  5243. \param data Array of values.
  5244. \param ndata Size of array.
  5245. \param t Position for which to calculate interpolated value. t should be between [0, ndata].
  5246. \returns Interpolated value at position t, value[0] when t<0, value[n-1] when t>n.
  5247. */
  5248. double _evaluateBezier(double *data, int ndata, double t) {
  5249. double mu, result;
  5250. int n, k, kn, nn, nkn;
  5251. double blend, muk, munk;
  5252. /* Sanity check bounds */
  5253. if (t < 0.0) {
  5254. return (data[0]);
  5255. }
  5256. if (t >= (double) ndata) {
  5257. return (data[ndata - 1]);
  5258. }
  5259. /* Adjust t to the range 0.0 to 1.0 */
  5260. mu = t / (double) ndata;
  5261. /* Calculate interpolate */
  5262. n = ndata - 1;
  5263. result = 0.0;
  5264. muk = 1;
  5265. munk = pow(1 - mu, (double) n);
  5266. for (k = 0; k <= n; k++) {
  5267. nn = n;
  5268. kn = k;
  5269. nkn = n - k;
  5270. blend = muk * munk;
  5271. muk *= mu;
  5272. munk /= (1 - mu);
  5273. while (nn >= 1) {
  5274. blend *= nn;
  5275. nn--;
  5276. if (kn > 1) {
  5277. blend /= (double) kn;
  5278. kn--;
  5279. }
  5280. if (nkn > 1) {
  5281. blend /= (double) nkn;
  5282. nkn--;
  5283. }
  5284. }
  5285. result += data[k] * blend;
  5286. }
  5287. return (result);
  5288. }
  5289. /*!
  5290. \brief Draw a bezier curve with alpha blending.
  5291. \param dst The surface to draw on.
  5292. \param vx Vertex array containing X coordinates of the points of the bezier curve.
  5293. \param vy Vertex array containing Y coordinates of the points of the bezier curve.
  5294. \param n Number of points in the vertex array. Minimum number is 3.
  5295. \param s Number of steps for the interpolation. Minimum number is 2.
  5296. \param color The color value of the bezier curve to draw (0xRRGGBBAA).
  5297. \returns Returns 0 on success, -1 on failure.
  5298. */
  5299. int bezierColor(SDL_Surface *dst, const Sint16 *vx, const Sint16 *vy, int n, int s, Uint32 color) {
  5300. int result;
  5301. int i;
  5302. double *x, *y, t, stepsize;
  5303. Sint16 x1, y1, x2, y2;
  5304. /*
  5305. * Sanity check
  5306. */
  5307. if (n < 3) {
  5308. return (-1);
  5309. }
  5310. if (s < 2) {
  5311. return (-1);
  5312. }
  5313. /*
  5314. * Variable setup
  5315. */
  5316. stepsize = (double) 1.0 / (double) s;
  5317. /* Transfer vertices into float arrays */
  5318. if ((x = (double *) malloc(sizeof(double) * (n + 1))) == NULL) {
  5319. return (-1);
  5320. }
  5321. if ((y = (double *) malloc(sizeof(double) * (n + 1))) == NULL) {
  5322. free(x);
  5323. return (-1);
  5324. }
  5325. for (i = 0; i < n; i++) {
  5326. x[i] = (double) vx[i];
  5327. y[i] = (double) vy[i];
  5328. }
  5329. x[n] = (double) vx[0];
  5330. y[n] = (double) vy[0];
  5331. /*
  5332. * Draw
  5333. */
  5334. result = 0;
  5335. t = 0.0;
  5336. x1 = (Sint16) lrint(_evaluateBezier(x, n + 1, t));
  5337. y1 = (Sint16) lrint(_evaluateBezier(y, n + 1, t));
  5338. for (i = 0; i <= (n * s); i++) {
  5339. t += stepsize;
  5340. x2 = (Sint16) _evaluateBezier(x, n, t);
  5341. y2 = (Sint16) _evaluateBezier(y, n, t);
  5342. result |= lineColor(dst, x1, y1, x2, y2, color);
  5343. x1 = x2;
  5344. y1 = y2;
  5345. }
  5346. /* Clean up temporary array */
  5347. free(x);
  5348. free(y);
  5349. return (result);
  5350. }
  5351. /*!
  5352. \brief Draw a bezier curve with alpha blending.
  5353. \param dst The surface to draw on.
  5354. \param vx Vertex array containing X coordinates of the points of the bezier curve.
  5355. \param vy Vertex array containing Y coordinates of the points of the bezier curve.
  5356. \param n Number of points in the vertex array. Minimum number is 3.
  5357. \param s Number of steps for the interpolation. Minimum number is 2.
  5358. \param r The red value of the bezier curve to draw.
  5359. \param g The green value of the bezier curve to draw.
  5360. \param b The blue value of the bezier curve to draw.
  5361. \param a The alpha value of the bezier curve to draw.
  5362. \returns Returns 0 on success, -1 on failure.
  5363. */
  5364. int bezierRGBA(SDL_Surface *dst, const Sint16 *vx, const Sint16 *vy, int n, int s, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
  5365. /*
  5366. * Draw
  5367. */
  5368. return (bezierColor(dst, vx, vy, n, s, ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  5369. }
  5370. /*!
  5371. \brief Internal function to initialize the Bresenham line iterator.
  5372. Example of use:
  5373. SDL_gfxBresenhamIterator b;
  5374. _bresenhamInitialize (&b, x1, y1, x2, y2);
  5375. do {
  5376. plot(b.x, b.y);
  5377. } while (_bresenhamIterate(&b)==0);
  5378. \param b Pointer to struct for bresenham line drawing state.
  5379. \param x1 X coordinate of the first point of the line.
  5380. \param y1 Y coordinate of the first point of the line.
  5381. \param x2 X coordinate of the second point of the line.
  5382. \param y2 Y coordinate of the second point of the line.
  5383. \returns Returns 0 on success, -1 on failure.
  5384. */
  5385. int _bresenhamInitialize(SDL_gfxBresenhamIterator *b, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2) {
  5386. int temp;
  5387. if (b == NULL) {
  5388. return (-1);
  5389. }
  5390. b->x = x1;
  5391. b->y = y1;
  5392. /* dx = abs(x2-x1), s1 = sign(x2-x1) */
  5393. if ((b->dx = x2 - x1) != 0) {
  5394. if (b->dx < 0) {
  5395. b->dx = -b->dx;
  5396. b->s1 = -1;
  5397. } else {
  5398. b->s1 = 1;
  5399. }
  5400. } else {
  5401. b->s1 = 0;
  5402. }
  5403. /* dy = abs(y2-y1), s2 = sign(y2-y1) */
  5404. if ((b->dy = y2 - y1) != 0) {
  5405. if (b->dy < 0) {
  5406. b->dy = -b->dy;
  5407. b->s2 = -1;
  5408. } else {
  5409. b->s2 = 1;
  5410. }
  5411. } else {
  5412. b->s2 = 0;
  5413. }
  5414. if (b->dy > b->dx) {
  5415. temp = b->dx;
  5416. b->dx = b->dy;
  5417. b->dy = temp;
  5418. b->swapdir = 1;
  5419. } else {
  5420. b->swapdir = 0;
  5421. }
  5422. b->count = (b->dx < 0) ? 0 : (unsigned int) b->dx;
  5423. b->dy <<= 1;
  5424. b->error = b->dy - b->dx;
  5425. b->dx <<= 1;
  5426. return (0);
  5427. }
  5428. /*!
  5429. \brief Internal function to move Bresenham line iterator to the next position.
  5430. Maybe updates the x and y coordinates of the iterator struct.
  5431. \param b Pointer to struct for bresenham line drawing state.
  5432. \returns Returns 0 on success, 1 if last point was reached, 2 if moving past end-of-line, -1 on failure.
  5433. */
  5434. int _bresenhamIterate(SDL_gfxBresenhamIterator *b) {
  5435. if (b == NULL) {
  5436. return (-1);
  5437. }
  5438. /* last point check */
  5439. if (b->count == 0) {
  5440. return (2);
  5441. }
  5442. while (b->error >= 0) {
  5443. if (b->swapdir) {
  5444. b->x += b->s1;
  5445. } else {
  5446. b->y += b->s2;
  5447. }
  5448. b->error -= b->dx;
  5449. }
  5450. if (b->swapdir) {
  5451. b->y += b->s2;
  5452. } else {
  5453. b->x += b->s1;
  5454. }
  5455. b->error += b->dy;
  5456. b->count--;
  5457. /* count==0 indicates "end-of-line" */
  5458. return ((b->count) ? 0 : 1);
  5459. }
  5460. /*!
  5461. \brief Internal function to to draw parallel lines with Murphy algorithm.
  5462. \param m Pointer to struct for murphy iterator.
  5463. \param x X coordinate of point.
  5464. \param y Y coordinate of point.
  5465. \param d1 Direction square/diagonal.
  5466. */
  5467. void _murphyParaline(SDL_gfxMurphyIterator *m, Sint16 x, Sint16 y, int d1) {
  5468. int p;
  5469. d1 = -d1;
  5470. /*
  5471. * Lock the surface
  5472. */
  5473. if (SDL_MUSTLOCK(m->dst)) {
  5474. SDL_LockSurface(m->dst);
  5475. }
  5476. for (p = 0; p <= m->u; p++) {
  5477. pixelColorNolock(m->dst, x, y, m->color);
  5478. if (d1 <= m->kt) {
  5479. if (m->oct2 == 0) {
  5480. x++;
  5481. } else {
  5482. if (m->quad4 == 0) {
  5483. y++;
  5484. } else {
  5485. y--;
  5486. }
  5487. }
  5488. d1 += m->kv;
  5489. } else {
  5490. x++;
  5491. if (m->quad4 == 0) {
  5492. y++;
  5493. } else {
  5494. y--;
  5495. }
  5496. d1 += m->kd;
  5497. }
  5498. }
  5499. /* Unlock surface */
  5500. if (SDL_MUSTLOCK(m->dst)) {
  5501. SDL_UnlockSurface(m->dst);
  5502. }
  5503. m->tempx = x;
  5504. m->tempy = y;
  5505. }
  5506. /*!
  5507. \brief Internal function to to draw one iteration of the Murphy algorithm.
  5508. \param m Pointer to struct for murphy iterator.
  5509. \param miter Iteration count.
  5510. \param ml1bx X coordinate of a point.
  5511. \param ml1by Y coordinate of a point.
  5512. \param ml2bx X coordinate of a point.
  5513. \param ml2by Y coordinate of a point.
  5514. \param ml1x X coordinate of a point.
  5515. \param ml1y Y coordinate of a point.
  5516. \param ml2x X coordinate of a point.
  5517. \param ml2y Y coordinate of a point.
  5518. */
  5519. void _murphyIteration(SDL_gfxMurphyIterator *m, Uint8 miter,
  5520. Uint16 ml1bx, Uint16 ml1by, Uint16 ml2bx, Uint16 ml2by,
  5521. Uint16 ml1x, Uint16 ml1y, Uint16 ml2x, Uint16 ml2y) {
  5522. int atemp1, atemp2;
  5523. int ftmp1, ftmp2;
  5524. Uint16 m1x, m1y, m2x, m2y;
  5525. Uint16 fix, fiy, lax, lay, curx, cury;
  5526. Uint16 px[4], py[4];
  5527. SDL_gfxBresenhamIterator b;
  5528. if (miter > 1) {
  5529. if (m->first1x != -32768) {
  5530. fix = (m->first1x + m->first2x) / 2;
  5531. fiy = (m->first1y + m->first2y) / 2;
  5532. lax = (m->last1x + m->last2x) / 2;
  5533. lay = (m->last1y + m->last2y) / 2;
  5534. curx = (ml1x + ml2x) / 2;
  5535. cury = (ml1y + ml2y) / 2;
  5536. atemp1 = (fix - curx);
  5537. atemp2 = (fiy - cury);
  5538. ftmp1 = atemp1 * atemp1 + atemp2 * atemp2;
  5539. atemp1 = (lax - curx);
  5540. atemp2 = (lay - cury);
  5541. ftmp2 = atemp1 * atemp1 + atemp2 * atemp2;
  5542. if (ftmp1 <= ftmp2) {
  5543. m1x = m->first1x;
  5544. m1y = m->first1y;
  5545. m2x = m->first2x;
  5546. m2y = m->first2y;
  5547. } else {
  5548. m1x = m->last1x;
  5549. m1y = m->last1y;
  5550. m2x = m->last2x;
  5551. m2y = m->last2y;
  5552. }
  5553. atemp1 = (m2x - ml2x);
  5554. atemp2 = (m2y - ml2y);
  5555. ftmp1 = atemp1 * atemp1 + atemp2 * atemp2;
  5556. atemp1 = (m2x - ml2bx);
  5557. atemp2 = (m2y - ml2by);
  5558. ftmp2 = atemp1 * atemp1 + atemp2 * atemp2;
  5559. if (ftmp2 >= ftmp1) {
  5560. ftmp1 = ml2bx;
  5561. ftmp2 = ml2by;
  5562. ml2bx = ml2x;
  5563. ml2by = ml2y;
  5564. ml2x = ftmp1;
  5565. ml2y = ftmp2;
  5566. ftmp1 = ml1bx;
  5567. ftmp2 = ml1by;
  5568. ml1bx = ml1x;
  5569. ml1by = ml1y;
  5570. ml1x = ftmp1;
  5571. ml1y = ftmp2;
  5572. }
  5573. /*
  5574. * Lock the surface
  5575. */
  5576. if (SDL_MUSTLOCK(m->dst)) {
  5577. SDL_LockSurface(m->dst);
  5578. }
  5579. _bresenhamInitialize(&b, m2x, m2y, m1x, m1y);
  5580. do {
  5581. pixelColorNolock(m->dst, b.x, b.y, m->color);
  5582. } while (_bresenhamIterate(&b) == 0);
  5583. _bresenhamInitialize(&b, m1x, m1y, ml1bx, ml1by);
  5584. do {
  5585. pixelColorNolock(m->dst, b.x, b.y, m->color);
  5586. } while (_bresenhamIterate(&b) == 0);
  5587. _bresenhamInitialize(&b, ml1bx, ml1by, ml2bx, ml2by);
  5588. do {
  5589. pixelColorNolock(m->dst, b.x, b.y, m->color);
  5590. } while (_bresenhamIterate(&b) == 0);
  5591. _bresenhamInitialize(&b, ml2bx, ml2by, m2x, m2y);
  5592. do {
  5593. pixelColorNolock(m->dst, b.x, b.y, m->color);
  5594. } while (_bresenhamIterate(&b) == 0);
  5595. /* Unlock surface */
  5596. if (SDL_MUSTLOCK(m->dst)) {
  5597. SDL_UnlockSurface(m->dst);
  5598. }
  5599. px[0] = m1x;
  5600. px[1] = m2x;
  5601. px[2] = ml1bx;
  5602. px[3] = ml2bx;
  5603. py[0] = m1y;
  5604. py[1] = m2y;
  5605. py[2] = ml1by;
  5606. py[3] = ml2by;
  5607. polygonColor(m->dst, px, py, 4, m->color);
  5608. }
  5609. }
  5610. m->last1x = ml1x;
  5611. m->last1y = ml1y;
  5612. m->last2x = ml2x;
  5613. m->last2y = ml2y;
  5614. m->first1x = ml1bx;
  5615. m->first1y = ml1by;
  5616. m->first2x = ml2bx;
  5617. m->first2y = ml2by;
  5618. }
  5619. #define HYPOT(x, y) sqrt((double)(x)*(double)(x)+(double)(y)*(double)(y))
  5620. /*!
  5621. \brief Internal function to to draw wide lines with Murphy algorithm.
  5622. Draws lines parallel to ideal line.
  5623. \param m Pointer to struct for murphy iterator.
  5624. \param x1 X coordinate of first point.
  5625. \param y1 Y coordinate of first point.
  5626. \param x2 X coordinate of second point.
  5627. \param y2 Y coordinate of second point.
  5628. \param width Width of line.
  5629. \param miter Iteration count.
  5630. */
  5631. void _murphyWideline(SDL_gfxMurphyIterator *m, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 miter) {
  5632. float offset = (float) width / 2.f;
  5633. Sint16 temp;
  5634. Sint16 ptx, pty, ptxx, ptxy, ml1x, ml1y, ml2x, ml2y, ml1bx, ml1by, ml2bx, ml2by;
  5635. int d0, d1; /* difference terms d0=perpendicular to line, d1=along line */
  5636. int q; /* pel counter,q=perpendicular to line */
  5637. int tmp;
  5638. int dd; /* distance along line */
  5639. int tk; /* thickness threshold */
  5640. double ang; /* angle for initial point calculation */
  5641. double sang, cang;
  5642. /* Initialisation */
  5643. m->u = x2 - x1; /* delta x */
  5644. m->v = y2 - y1; /* delta y */
  5645. if (m->u < 0) { /* swap to make sure we are in quadrants 1 or 4 */
  5646. temp = x1;
  5647. x1 = x2;
  5648. x2 = temp;
  5649. temp = y1;
  5650. y1 = y2;
  5651. y2 = temp;
  5652. m->u *= -1;
  5653. m->v *= -1;
  5654. }
  5655. if (m->v < 0) { /* swap to 1st quadrant and flag */
  5656. m->v *= -1;
  5657. m->quad4 = 1;
  5658. } else {
  5659. m->quad4 = 0;
  5660. }
  5661. if (m->v > m->u) { /* swap things if in 2 octant */
  5662. tmp = m->u;
  5663. m->u = m->v;
  5664. m->v = tmp;
  5665. m->oct2 = 1;
  5666. } else {
  5667. m->oct2 = 0;
  5668. }
  5669. m->ku = m->u + m->u; /* change in l for square shift */
  5670. m->kv = m->v + m->v; /* change in d for square shift */
  5671. m->kd = m->kv - m->ku; /* change in d for diagonal shift */
  5672. m->kt = m->u - m->kv; /* diag/square decision threshold */
  5673. d0 = 0;
  5674. d1 = 0;
  5675. dd = 0;
  5676. ang = atan((double) m->v / (double) m->u); /* calc new initial point - offset both sides of ideal */
  5677. sang = sin(ang);
  5678. cang = cos(ang);
  5679. if (m->oct2 == 0) {
  5680. ptx = x1 + (Sint16) lrint(offset * sang);
  5681. if (m->quad4 == 0) {
  5682. pty = y1 - (Sint16) lrint(offset * cang);
  5683. } else {
  5684. pty = y1 + (Sint16) lrint(offset * cang);
  5685. }
  5686. } else {
  5687. ptx = x1 - (Sint16) lrint(offset * cang);
  5688. if (m->quad4 == 0) {
  5689. pty = y1 + (Sint16) lrint(offset * sang);
  5690. } else {
  5691. pty = y1 - (Sint16) lrint(offset * sang);
  5692. }
  5693. }
  5694. /* used here for constant thickness line */
  5695. tk = (int) (4. * HYPOT(ptx - x1, pty - y1) * HYPOT(m->u, m->v));
  5696. if (miter == 0) {
  5697. m->first1x = -32768;
  5698. m->first1y = -32768;
  5699. m->first2x = -32768;
  5700. m->first2y = -32768;
  5701. m->last1x = -32768;
  5702. m->last1y = -32768;
  5703. m->last2x = -32768;
  5704. m->last2y = -32768;
  5705. }
  5706. ptxx = ptx;
  5707. ptxy = pty;
  5708. for (q = 0; dd <= tk; q++) { /* outer loop, stepping perpendicular to line */
  5709. _murphyParaline(m, ptx, pty, d1); /* call to inner loop - right edge */
  5710. if (q == 0) {
  5711. ml1x = ptx;
  5712. ml1y = pty;
  5713. ml1bx = m->tempx;
  5714. ml1by = m->tempy;
  5715. } else {
  5716. ml2x = ptx;
  5717. ml2y = pty;
  5718. ml2bx = m->tempx;
  5719. ml2by = m->tempy;
  5720. }
  5721. if (d0 < m->kt) { /* square move */
  5722. if (m->oct2 == 0) {
  5723. if (m->quad4 == 0) {
  5724. pty++;
  5725. } else {
  5726. pty--;
  5727. }
  5728. } else {
  5729. ptx++;
  5730. }
  5731. } else { /* diagonal move */
  5732. dd += m->kv;
  5733. d0 -= m->ku;
  5734. if (d1 < m->kt) { /* normal diagonal */
  5735. if (m->oct2 == 0) {
  5736. ptx--;
  5737. if (m->quad4 == 0) {
  5738. pty++;
  5739. } else {
  5740. pty--;
  5741. }
  5742. } else {
  5743. ptx++;
  5744. if (m->quad4 == 0) {
  5745. pty--;
  5746. } else {
  5747. pty++;
  5748. }
  5749. }
  5750. d1 += m->kv;
  5751. } else { /* double square move, extra parallel line */
  5752. if (m->oct2 == 0) {
  5753. ptx--;
  5754. } else {
  5755. if (m->quad4 == 0) {
  5756. pty--;
  5757. } else {
  5758. pty++;
  5759. }
  5760. }
  5761. d1 += m->kd;
  5762. if (dd > tk) {
  5763. _murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y);
  5764. return; /* breakout on the extra line */
  5765. }
  5766. _murphyParaline(m, ptx, pty, d1);
  5767. if (m->oct2 == 0) {
  5768. if (m->quad4 == 0) {
  5769. pty++;
  5770. } else {
  5771. pty--;
  5772. }
  5773. } else {
  5774. ptx++;
  5775. }
  5776. }
  5777. }
  5778. dd += m->ku;
  5779. d0 += m->kv;
  5780. }
  5781. _murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y);
  5782. }
  5783. /*!
  5784. \brief Draw a thick line with alpha blending.
  5785. \param dst The surface to draw on.
  5786. \param x1 X coordinate of the first point of the line.
  5787. \param y1 Y coordinate of the first point of the line.
  5788. \param x2 X coordinate of the second point of the line.
  5789. \param y2 Y coordinate of the second point of the line.
  5790. \param width Width of the line in pixels. Must be >0.
  5791. \param color The color value of the line to draw (0xRRGGBBAA).
  5792. \returns Returns 0 on success, -1 on failure.
  5793. */
  5794. int thickLineColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint32 color) {
  5795. int wh;
  5796. SDL_gfxMurphyIterator m;
  5797. if (dst == NULL) return -1;
  5798. if (width < 1) return -1;
  5799. /* Special case: thick "point" */
  5800. if ((x1 == x2) && (y1 == y2)) {
  5801. wh = width / 2;
  5802. return boxColor(dst, x1 - wh, y1 - wh, x2 + width, y2 + width, color);
  5803. }
  5804. m.dst = dst;
  5805. m.color = color;
  5806. _murphyWideline(&m, x1, y1, x2, y2, width, 0);
  5807. _murphyWideline(&m, x1, y1, x2, y2, width, 1);
  5808. return (0);
  5809. }
  5810. /*!
  5811. \brief Draw a thick line with alpha blending.
  5812. \param dst The surface to draw on.
  5813. \param x1 X coordinate of the first point of the line.
  5814. \param y1 Y coordinate of the first point of the line.
  5815. \param x2 X coordinate of the second point of the line.
  5816. \param y2 Y coordinate of the second point of the line.
  5817. \param width Width of the line in pixels. Must be >0.
  5818. \param r The red value of the character to draw.
  5819. \param g The green value of the character to draw.
  5820. \param b The blue value of the character to draw.
  5821. \param a The alpha value of the character to draw.
  5822. \returns Returns 0 on success, -1 on failure.
  5823. */
  5824. int thickLineRGBA(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 r, Uint8 g, Uint8 b,
  5825. Uint8 a) {
  5826. return (thickLineColor(dst, x1, y1, x2, y2, width,
  5827. ((Uint32) r << 24) | ((Uint32) g << 16) | ((Uint32) b << 8) | (Uint32) a));
  5828. }