imgui_draw.cpp 363 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315
  1. // dear imgui, v1.92.2b
  2. // (drawing and font code)
  3. /*
  4. Index of this file:
  5. // [SECTION] STB libraries implementation
  6. // [SECTION] Style functions
  7. // [SECTION] ImDrawList
  8. // [SECTION] ImTriangulator, ImDrawList concave polygon fill
  9. // [SECTION] ImDrawList Shadow Primitives
  10. // [SECTION] ImDrawListSplitter
  11. // [SECTION] ImDrawData
  12. // [SECTION] Helpers ShadeVertsXXX functions
  13. // [SECTION] ImFontAtlasShadowTexConfig
  14. // [SECTION] ImFontConfig
  15. // [SECTION] ImFontAtlas, ImFontAtlasBuilder
  16. // [SECTION] ImFontAtlas: backend for stb_truetype
  17. // [SECTION] ImFontAtlas: glyph ranges helpers
  18. // [SECTION] ImFontGlyphRangesBuilder
  19. // [SECTION] ImFont
  20. // [SECTION] ImGui Internal Render Helpers
  21. // [SECTION] Decompression code
  22. // [SECTION] Default font data (ProggyClean.ttf)
  23. */
  24. #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
  25. #define _CRT_SECURE_NO_WARNINGS
  26. #endif
  27. #ifndef IMGUI_DEFINE_MATH_OPERATORS
  28. #define IMGUI_DEFINE_MATH_OPERATORS
  29. #endif
  30. #include "imgui.h"
  31. #ifndef IMGUI_DISABLE
  32. #include "imgui_internal.h"
  33. #ifdef IMGUI_ENABLE_FREETYPE
  34. #include "misc/freetype/imgui_freetype.h"
  35. #endif
  36. #include <stdio.h> // vsnprintf, sscanf, printf
  37. #include <stdint.h> // intptr_t
  38. // Visual Studio warnings
  39. #ifdef _MSC_VER
  40. #pragma warning (disable: 4127) // condition expression is constant
  41. #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
  42. #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
  43. #pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
  44. #pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer)
  45. #endif
  46. // Clang/GCC warnings with -Weverything
  47. #if defined(__clang__)
  48. #if __has_warning("-Wunknown-warning-option")
  49. #pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!
  50. #endif
  51. #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
  52. #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
  53. #pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
  54. #pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is.
  55. #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
  56. #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
  57. #pragma clang diagnostic ignored "-Wcomma" // warning: possible misuse of comma operator here
  58. #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier
  59. #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
  60. #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
  61. #pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter
  62. #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
  63. #pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type
  64. #pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier
  65. #pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label
  66. #elif defined(__GNUC__)
  67. #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
  68. #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
  69. #pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
  70. #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
  71. #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
  72. #pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer
  73. #pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1
  74. #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
  75. #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers
  76. #endif
  77. //-------------------------------------------------------------------------
  78. // [SECTION] STB libraries implementation (for stb_truetype and stb_rect_pack)
  79. //-------------------------------------------------------------------------
  80. // Compile time options:
  81. //#define IMGUI_STB_NAMESPACE ImStb
  82. //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
  83. //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
  84. //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
  85. //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
  86. #ifdef IMGUI_STB_NAMESPACE
  87. namespace IMGUI_STB_NAMESPACE
  88. {
  89. #endif
  90. #ifdef _MSC_VER
  91. #pragma warning (push)
  92. #pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration
  93. #pragma warning (disable: 6011) // (stb_rectpack) Dereferencing NULL pointer 'cur->next'.
  94. #pragma warning (disable: 6385) // (stb_truetype) Reading invalid data from 'buffer': the readable size is '_Old_3`kernel_width' bytes, but '3' bytes may be read.
  95. #pragma warning (disable: 28182) // (stb_rectpack) Dereferencing NULL pointer. 'cur' contains the same NULL value as 'cur->next' did.
  96. #endif
  97. #if defined(__clang__)
  98. #pragma clang diagnostic push
  99. #pragma clang diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
  100. #pragma clang diagnostic ignored "-Wmissing-prototypes"
  101. #pragma clang diagnostic ignored "-Wimplicit-fallthrough"
  102. #endif
  103. #if defined(__GNUC__)
  104. #pragma GCC diagnostic push
  105. #pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits]
  106. #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" // warning: this statement may fall through
  107. #endif
  108. #ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
  109. #ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in another compilation unit
  110. #define STBRP_STATIC
  111. #define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0)
  112. #define STBRP_SORT ImQsort
  113. #define STB_RECT_PACK_IMPLEMENTATION
  114. #endif
  115. #ifdef IMGUI_STB_RECT_PACK_FILENAME
  116. #include IMGUI_STB_RECT_PACK_FILENAME
  117. #else
  118. #include "imstb_rectpack.h"
  119. #endif
  120. #endif
  121. #ifdef IMGUI_ENABLE_STB_TRUETYPE
  122. #ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
  123. #ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in another compilation unit
  124. #define STBTT_malloc(x,u) ((void)(u), IM_ALLOC(x))
  125. #define STBTT_free(x,u) ((void)(u), IM_FREE(x))
  126. #define STBTT_assert(x) do { IM_ASSERT(x); } while(0)
  127. #define STBTT_fmod(x,y) ImFmod(x,y)
  128. #define STBTT_sqrt(x) ImSqrt(x)
  129. #define STBTT_pow(x,y) ImPow(x,y)
  130. #define STBTT_fabs(x) ImFabs(x)
  131. #define STBTT_ifloor(x) ((int)ImFloor(x))
  132. #define STBTT_iceil(x) ((int)ImCeil(x))
  133. #define STBTT_strlen(x) ImStrlen(x)
  134. #define STBTT_STATIC
  135. #define STB_TRUETYPE_IMPLEMENTATION
  136. #else
  137. #define STBTT_DEF extern
  138. #endif
  139. #ifdef IMGUI_STB_TRUETYPE_FILENAME
  140. #include IMGUI_STB_TRUETYPE_FILENAME
  141. #else
  142. #include "imstb_truetype.h"
  143. #endif
  144. #endif
  145. #endif // IMGUI_ENABLE_STB_TRUETYPE
  146. #if defined(__GNUC__)
  147. #pragma GCC diagnostic pop
  148. #endif
  149. #if defined(__clang__)
  150. #pragma clang diagnostic pop
  151. #endif
  152. #if defined(_MSC_VER)
  153. #pragma warning (pop)
  154. #endif
  155. #ifdef IMGUI_STB_NAMESPACE
  156. } // namespace ImStb
  157. using namespace IMGUI_STB_NAMESPACE;
  158. #endif
  159. //-----------------------------------------------------------------------------
  160. // [SECTION] Style functions
  161. //-----------------------------------------------------------------------------
  162. void ImGui::StyleColorsDark(ImGuiStyle* dst)
  163. {
  164. ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
  165. ImVec4* colors = style->Colors;
  166. colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
  167. colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
  168. colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
  169. colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
  170. colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
  171. colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
  172. colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
  173. colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f);
  174. colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
  175. colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
  176. colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
  177. colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f);
  178. colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
  179. colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
  180. colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
  181. colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
  182. colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
  183. colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
  184. colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
  185. colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f);
  186. colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
  187. colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
  188. colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
  189. colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
  190. colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
  191. colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
  192. colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
  193. colors[ImGuiCol_Separator] = colors[ImGuiCol_Border];
  194. colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f);
  195. colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f);
  196. colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.20f);
  197. colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
  198. colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
  199. colors[ImGuiCol_InputTextCursor] = colors[ImGuiCol_Text];
  200. colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
  201. colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
  202. colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
  203. colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive];
  204. colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
  205. colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
  206. colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.50f, 0.50f, 0.50f, 0.00f);
  207. colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
  208. colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
  209. colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
  210. colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
  211. colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f);
  212. colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f); // Prefer using Alpha=1.0 here
  213. colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); // Prefer using Alpha=1.0 here
  214. colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
  215. colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);
  216. colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive];
  217. colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
  218. colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border];
  219. colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
  220. colors[ImGuiCol_NavCursor] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
  221. colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
  222. colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
  223. colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
  224. colors[ImGuiCol_WindowShadow] = ImVec4(0.08f, 0.08f, 0.08f, 0.35f);
  225. }
  226. void ImGui::StyleColorsClassic(ImGuiStyle* dst)
  227. {
  228. ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
  229. ImVec4* colors = style->Colors;
  230. colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
  231. colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
  232. colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.85f);
  233. colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
  234. colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f);
  235. colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
  236. colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
  237. colors[ImGuiCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f);
  238. colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.47f, 0.69f, 0.40f);
  239. colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.41f, 0.64f, 0.69f);
  240. colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f);
  241. colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f);
  242. colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f);
  243. colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f);
  244. colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f);
  245. colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f);
  246. colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
  247. colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
  248. colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
  249. colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
  250. colors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
  251. colors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f);
  252. colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.48f, 0.71f, 0.79f);
  253. colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f);
  254. colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f);
  255. colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f);
  256. colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f);
  257. colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 0.60f);
  258. colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f);
  259. colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f);
  260. colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f);
  261. colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
  262. colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
  263. colors[ImGuiCol_InputTextCursor] = colors[ImGuiCol_Text];
  264. colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
  265. colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
  266. colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
  267. colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive];
  268. colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
  269. colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
  270. colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.53f, 0.53f, 0.87f, 0.00f);
  271. colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
  272. colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
  273. colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
  274. colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
  275. colors[ImGuiCol_TableHeaderBg] = ImVec4(0.27f, 0.27f, 0.38f, 1.00f);
  276. colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.45f, 1.00f); // Prefer using Alpha=1.0 here
  277. colors[ImGuiCol_TableBorderLight] = ImVec4(0.26f, 0.26f, 0.28f, 1.00f); // Prefer using Alpha=1.0 here
  278. colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
  279. colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f);
  280. colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive];
  281. colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
  282. colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border];
  283. colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
  284. colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered];
  285. colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
  286. colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
  287. colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
  288. colors[ImGuiCol_WindowShadow] = ImVec4(0.08f, 0.08f, 0.08f, 0.35f);
  289. }
  290. // Those light colors are better suited with a thicker font than the default one + FrameBorder
  291. void ImGui::StyleColorsLight(ImGuiStyle* dst)
  292. {
  293. ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
  294. ImVec4* colors = style->Colors;
  295. colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
  296. colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
  297. colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f);
  298. colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
  299. colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f);
  300. colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f);
  301. colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
  302. colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
  303. colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
  304. colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
  305. colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f);
  306. colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f);
  307. colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f);
  308. colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
  309. colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f);
  310. colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f);
  311. colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f);
  312. colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f);
  313. colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
  314. colors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f);
  315. colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f);
  316. colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
  317. colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
  318. colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
  319. colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
  320. colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
  321. colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
  322. colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.62f);
  323. colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f);
  324. colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f);
  325. colors[ImGuiCol_ResizeGrip] = ImVec4(0.35f, 0.35f, 0.35f, 0.17f);
  326. colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
  327. colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
  328. colors[ImGuiCol_InputTextCursor] = colors[ImGuiCol_Text];
  329. colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
  330. colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f);
  331. colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
  332. colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive];
  333. colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
  334. colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
  335. colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.26f, 0.59f, 1.00f, 0.00f);
  336. colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
  337. colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
  338. colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
  339. colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f);
  340. colors[ImGuiCol_TableHeaderBg] = ImVec4(0.78f, 0.87f, 0.98f, 1.00f);
  341. colors[ImGuiCol_TableBorderStrong] = ImVec4(0.57f, 0.57f, 0.64f, 1.00f); // Prefer using Alpha=1.0 here
  342. colors[ImGuiCol_TableBorderLight] = ImVec4(0.68f, 0.68f, 0.74f, 1.00f); // Prefer using Alpha=1.0 here
  343. colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
  344. colors[ImGuiCol_TableRowBgAlt] = ImVec4(0.30f, 0.30f, 0.30f, 0.09f);
  345. colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive];
  346. colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
  347. colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border];
  348. colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
  349. colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered];
  350. colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f);
  351. colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f);
  352. colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
  353. colors[ImGuiCol_WindowShadow] = ImVec4(0.08f, 0.08f, 0.08f, 0.35f);
  354. }
  355. //-----------------------------------------------------------------------------
  356. // [SECTION] ImFontAtlasShadowTexConfig
  357. //-----------------------------------------------------------------------------
  358. void ImFontAtlasShadowTexConfig::SetupDefaults()
  359. {
  360. TexCornerSize = 16;
  361. TexEdgeSize = 1;
  362. TexFalloffPower = 4.8f;
  363. TexDistanceFieldOffset = 3.8f;
  364. TexBlur = true;
  365. }
  366. int ImFontAtlasShadowTexConfig::CalcConvexTexWidth() const
  367. {
  368. // We have to pad the texture enough that we don't go off the edges when we expand the corner triangles
  369. return (int)((TexCornerSize / ImCos(IM_PI * 0.25f)) + (GetConvexTexPadding() * 2));
  370. }
  371. int ImFontAtlasShadowTexConfig::CalcConvexTexHeight() const
  372. {
  373. return CalcConvexTexWidth(); // Same value
  374. }
  375. //-----------------------------------------------------------------------------
  376. // [SECTION] ImDrawList
  377. //-----------------------------------------------------------------------------
  378. ImDrawListSharedData::ImDrawListSharedData()
  379. {
  380. memset(this, 0, sizeof(*this));
  381. InitialFringeScale = 1.0f;
  382. for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++)
  383. {
  384. const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx);
  385. ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a));
  386. }
  387. ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);
  388. }
  389. ImDrawListSharedData::~ImDrawListSharedData()
  390. {
  391. IM_ASSERT(DrawLists.Size == 0);
  392. }
  393. void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error)
  394. {
  395. if (CircleSegmentMaxError == max_error)
  396. return;
  397. IM_ASSERT(max_error > 0.0f);
  398. CircleSegmentMaxError = max_error;
  399. for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++)
  400. {
  401. const float radius = (float)i;
  402. CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : IM_DRAWLIST_ARCFAST_SAMPLE_MAX);
  403. }
  404. ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);
  405. }
  406. ImDrawList::ImDrawList(ImDrawListSharedData* shared_data)
  407. {
  408. memset(this, 0, sizeof(*this));
  409. _SetDrawListSharedData(shared_data);
  410. }
  411. ImDrawList::~ImDrawList()
  412. {
  413. _ClearFreeMemory();
  414. _SetDrawListSharedData(NULL);
  415. }
  416. void ImDrawList::_SetDrawListSharedData(ImDrawListSharedData* data)
  417. {
  418. if (_Data != NULL)
  419. _Data->DrawLists.find_erase_unsorted(this);
  420. _Data = data;
  421. if (_Data != NULL)
  422. _Data->DrawLists.push_back(this);
  423. }
  424. // Initialize before use in a new frame. We always have a command ready in the buffer.
  425. // In the majority of cases, you would want to call PushClipRect() and PushTexture() after this.
  426. void ImDrawList::_ResetForNewFrame()
  427. {
  428. // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory.
  429. IM_STATIC_ASSERT(offsetof(ImDrawCmd, ClipRect) == 0);
  430. IM_STATIC_ASSERT(offsetof(ImDrawCmd, TexRef) == sizeof(ImVec4));
  431. IM_STATIC_ASSERT(offsetof(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureRef));
  432. if (_Splitter._Count > 1)
  433. _Splitter.Merge(this);
  434. CmdBuffer.resize(0);
  435. IdxBuffer.resize(0);
  436. VtxBuffer.resize(0);
  437. Flags = _Data->InitialFlags;
  438. memset(&_CmdHeader, 0, sizeof(_CmdHeader));
  439. _VtxCurrentIdx = 0;
  440. _VtxWritePtr = NULL;
  441. _IdxWritePtr = NULL;
  442. _ClipRectStack.resize(0);
  443. _TextureStack.resize(0);
  444. _CallbacksDataBuf.resize(0);
  445. _Path.resize(0);
  446. _Splitter.Clear();
  447. CmdBuffer.push_back(ImDrawCmd());
  448. _FringeScale = _Data->InitialFringeScale;
  449. }
  450. void ImDrawList::_ClearFreeMemory()
  451. {
  452. CmdBuffer.clear();
  453. IdxBuffer.clear();
  454. VtxBuffer.clear();
  455. Flags = ImDrawListFlags_None;
  456. _VtxCurrentIdx = 0;
  457. _VtxWritePtr = NULL;
  458. _IdxWritePtr = NULL;
  459. _ClipRectStack.clear();
  460. _TextureStack.clear();
  461. _CallbacksDataBuf.clear();
  462. _Path.clear();
  463. _Splitter.ClearFreeMemory();
  464. }
  465. ImDrawList* ImDrawList::CloneOutput() const
  466. {
  467. ImDrawList* dst = IM_NEW(ImDrawList(_Data));
  468. dst->CmdBuffer = CmdBuffer;
  469. dst->IdxBuffer = IdxBuffer;
  470. dst->VtxBuffer = VtxBuffer;
  471. dst->Flags = Flags;
  472. return dst;
  473. }
  474. void ImDrawList::AddDrawCmd()
  475. {
  476. ImDrawCmd draw_cmd;
  477. draw_cmd.ClipRect = _CmdHeader.ClipRect; // Same as calling ImDrawCmd_HeaderCopy()
  478. draw_cmd.TexRef = _CmdHeader.TexRef;
  479. draw_cmd.VtxOffset = _CmdHeader.VtxOffset;
  480. draw_cmd.IdxOffset = IdxBuffer.Size;
  481. IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);
  482. CmdBuffer.push_back(draw_cmd);
  483. }
  484. // Pop trailing draw command (used before merging or presenting to user)
  485. // Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL
  486. void ImDrawList::_PopUnusedDrawCmd()
  487. {
  488. while (CmdBuffer.Size > 0)
  489. {
  490. ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
  491. if (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL)
  492. return;// break;
  493. CmdBuffer.pop_back();
  494. }
  495. }
  496. void ImDrawList::AddCallback(ImDrawCallback callback, void* userdata, size_t userdata_size)
  497. {
  498. IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
  499. ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
  500. IM_ASSERT(curr_cmd->UserCallback == NULL);
  501. if (curr_cmd->ElemCount != 0)
  502. {
  503. AddDrawCmd();
  504. curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
  505. }
  506. curr_cmd->UserCallback = callback;
  507. if (userdata_size == 0)
  508. {
  509. // Store user data directly in command (no indirection)
  510. curr_cmd->UserCallbackData = userdata;
  511. curr_cmd->UserCallbackDataSize = 0;
  512. curr_cmd->UserCallbackDataOffset = -1;
  513. }
  514. else
  515. {
  516. // Copy and store user data in a buffer
  517. IM_ASSERT(userdata != NULL);
  518. IM_ASSERT(userdata_size < (1u << 31));
  519. curr_cmd->UserCallbackData = NULL; // Will be resolved during Render()
  520. curr_cmd->UserCallbackDataSize = (int)userdata_size;
  521. curr_cmd->UserCallbackDataOffset = _CallbacksDataBuf.Size;
  522. _CallbacksDataBuf.resize(_CallbacksDataBuf.Size + (int)userdata_size);
  523. memcpy(_CallbacksDataBuf.Data + (size_t)curr_cmd->UserCallbackDataOffset, userdata, userdata_size);
  524. }
  525. AddDrawCmd(); // Force a new command after us (see comment below)
  526. }
  527. // Compare ClipRect, TexRef and VtxOffset with a single memcmp()
  528. #define ImDrawCmd_HeaderSize (offsetof(ImDrawCmd, VtxOffset) + sizeof(unsigned int))
  529. #define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TexRef, VtxOffset
  530. #define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TexRef, VtxOffset
  531. #define ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1) (CMD_0->IdxOffset + CMD_0->ElemCount == CMD_1->IdxOffset)
  532. // Try to merge two last draw commands
  533. void ImDrawList::_TryMergeDrawCmds()
  534. {
  535. IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
  536. ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
  537. ImDrawCmd* prev_cmd = curr_cmd - 1;
  538. if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL)
  539. {
  540. prev_cmd->ElemCount += curr_cmd->ElemCount;
  541. CmdBuffer.pop_back();
  542. }
  543. }
  544. // Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack.
  545. // The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only.
  546. void ImDrawList::_OnChangedClipRect()
  547. {
  548. // If current command is used with different settings we need to add a new command
  549. IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
  550. ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
  551. if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0)
  552. {
  553. AddDrawCmd();
  554. return;
  555. }
  556. IM_ASSERT(curr_cmd->UserCallback == NULL);
  557. // Try to merge with previous command if it matches, else use current command
  558. ImDrawCmd* prev_cmd = curr_cmd - 1;
  559. if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL)
  560. {
  561. CmdBuffer.pop_back();
  562. return;
  563. }
  564. curr_cmd->ClipRect = _CmdHeader.ClipRect;
  565. }
  566. void ImDrawList::_OnChangedTexture()
  567. {
  568. // If current command is used with different settings we need to add a new command
  569. IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
  570. ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
  571. if (curr_cmd->ElemCount != 0 && curr_cmd->TexRef != _CmdHeader.TexRef)
  572. {
  573. AddDrawCmd();
  574. return;
  575. }
  576. // Unlike other _OnChangedXXX functions this may be called by ImFontAtlasUpdateDrawListsTextures() in more locations so we need to handle this case.
  577. if (curr_cmd->UserCallback != NULL)
  578. return;
  579. // Try to merge with previous command if it matches, else use current command
  580. ImDrawCmd* prev_cmd = curr_cmd - 1;
  581. if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL)
  582. {
  583. CmdBuffer.pop_back();
  584. return;
  585. }
  586. curr_cmd->TexRef = _CmdHeader.TexRef;
  587. }
  588. void ImDrawList::_OnChangedVtxOffset()
  589. {
  590. // We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this.
  591. _VtxCurrentIdx = 0;
  592. IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
  593. ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
  594. //IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349
  595. if (curr_cmd->ElemCount != 0)
  596. {
  597. AddDrawCmd();
  598. return;
  599. }
  600. IM_ASSERT(curr_cmd->UserCallback == NULL);
  601. curr_cmd->VtxOffset = _CmdHeader.VtxOffset;
  602. }
  603. int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const
  604. {
  605. // Automatic segment count
  606. const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy
  607. if (radius_idx >= 0 && radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts))
  608. return _Data->CircleSegmentCounts[radius_idx]; // Use cached value
  609. else
  610. return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError);
  611. }
  612. // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
  613. void ImDrawList::PushClipRect(const ImVec2& cr_min, const ImVec2& cr_max, bool intersect_with_current_clip_rect)
  614. {
  615. ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
  616. if (intersect_with_current_clip_rect)
  617. {
  618. ImVec4 current = _CmdHeader.ClipRect;
  619. if (cr.x < current.x) cr.x = current.x;
  620. if (cr.y < current.y) cr.y = current.y;
  621. if (cr.z > current.z) cr.z = current.z;
  622. if (cr.w > current.w) cr.w = current.w;
  623. }
  624. cr.z = ImMax(cr.x, cr.z);
  625. cr.w = ImMax(cr.y, cr.w);
  626. _ClipRectStack.push_back(cr);
  627. _CmdHeader.ClipRect = cr;
  628. _OnChangedClipRect();
  629. }
  630. void ImDrawList::PushClipRectFullScreen()
  631. {
  632. PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w));
  633. }
  634. void ImDrawList::PopClipRect()
  635. {
  636. _ClipRectStack.pop_back();
  637. _CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1];
  638. _OnChangedClipRect();
  639. }
  640. void ImDrawList::PushTexture(ImTextureRef tex_ref)
  641. {
  642. _TextureStack.push_back(tex_ref);
  643. _CmdHeader.TexRef = tex_ref;
  644. if (tex_ref._TexData != NULL)
  645. IM_ASSERT(tex_ref._TexData->WantDestroyNextFrame == false);
  646. _OnChangedTexture();
  647. }
  648. void ImDrawList::PopTexture()
  649. {
  650. _TextureStack.pop_back();
  651. _CmdHeader.TexRef = (_TextureStack.Size == 0) ? ImTextureRef() : _TextureStack.Data[_TextureStack.Size - 1];
  652. _OnChangedTexture();
  653. }
  654. // This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTexture()/PopTexture().
  655. void ImDrawList::_SetTexture(ImTextureRef tex_ref)
  656. {
  657. if (_CmdHeader.TexRef == tex_ref)
  658. return;
  659. _CmdHeader.TexRef = tex_ref;
  660. _TextureStack.back() = tex_ref;
  661. _OnChangedTexture();
  662. }
  663. // Reserve space for a number of vertices and indices.
  664. // You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or
  665. // submit the intermediate results. PrimUnreserve() can be used to release unused allocations.
  666. void ImDrawList::PrimReserve(int idx_count, int vtx_count)
  667. {
  668. // Large mesh support (when enabled)
  669. IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);
  670. if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset))
  671. {
  672. // FIXME: In theory we should be testing that vtx_count <64k here.
  673. // In practice, RenderText() relies on reserving ahead for a worst case scenario so it is currently useful for us
  674. // to not make that check until we rework the text functions to handle clipping and large horizontal lines better.
  675. _CmdHeader.VtxOffset = VtxBuffer.Size;
  676. _OnChangedVtxOffset();
  677. }
  678. ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
  679. draw_cmd->ElemCount += idx_count;
  680. int vtx_buffer_old_size = VtxBuffer.Size;
  681. VtxBuffer.resize(vtx_buffer_old_size + vtx_count);
  682. _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size;
  683. int idx_buffer_old_size = IdxBuffer.Size;
  684. IdxBuffer.resize(idx_buffer_old_size + idx_count);
  685. _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size;
  686. }
  687. // Release the number of reserved vertices/indices from the end of the last reservation made with PrimReserve().
  688. void ImDrawList::PrimUnreserve(int idx_count, int vtx_count)
  689. {
  690. IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);
  691. ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
  692. draw_cmd->ElemCount -= idx_count;
  693. VtxBuffer.shrink(VtxBuffer.Size - vtx_count);
  694. IdxBuffer.shrink(IdxBuffer.Size - idx_count);
  695. }
  696. // Fully unrolled with inline call to keep our debug builds decently fast.
  697. void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)
  698. {
  699. ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel);
  700. ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
  701. _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
  702. _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
  703. _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
  704. _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
  705. _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
  706. _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;
  707. _VtxWritePtr += 4;
  708. _VtxCurrentIdx += 4;
  709. _IdxWritePtr += 6;
  710. }
  711. void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col)
  712. {
  713. ImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y);
  714. ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
  715. _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
  716. _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
  717. _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
  718. _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
  719. _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
  720. _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
  721. _VtxWritePtr += 4;
  722. _VtxCurrentIdx += 4;
  723. _IdxWritePtr += 6;
  724. }
  725. void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col)
  726. {
  727. ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
  728. _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
  729. _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
  730. _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
  731. _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
  732. _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
  733. _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
  734. _VtxWritePtr += 4;
  735. _VtxCurrentIdx += 4;
  736. _IdxWritePtr += 6;
  737. }
  738. // On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds.
  739. // - Those macros expects l-values and need to be used as their own statement.
  740. // - Those macros are intentionally not surrounded by the 'do {} while (0)' idiom because even that translates to runtime with debug compilers.
  741. #define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } (void)0
  742. #define IM_FIXNORMAL2F_MAX_INVLEN2 100.0f // 500.0f (see #4053, #3366)
  743. #define IM_FIXNORMAL2F(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } (void)0
  744. // TODO: Thickness anti-aliased lines cap are missing their AA fringe.
  745. // We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
  746. void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness)
  747. {
  748. if (points_count < 2 || (col & IM_COL32_A_MASK) == 0)
  749. return;
  750. const bool closed = (flags & ImDrawFlags_Closed) != 0;
  751. const ImVec2 opaque_uv = _Data->TexUvWhitePixel;
  752. const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw
  753. const bool thick_line = (thickness > _FringeScale);
  754. if (Flags & ImDrawListFlags_AntiAliasedLines)
  755. {
  756. // Anti-aliased stroke
  757. const float AA_SIZE = _FringeScale;
  758. const ImU32 col_trans = col & ~IM_COL32_A_MASK;
  759. // Thicknesses <1.0 should behave like thickness 1.0
  760. thickness = ImMax(thickness, 1.0f);
  761. const int integer_thickness = (int)thickness;
  762. const float fractional_thickness = thickness - integer_thickness;
  763. // Do we want to draw this line using a texture?
  764. // - For now, only draw integer-width lines using textures to avoid issues with the way scaling occurs, could be improved.
  765. // - If AA_SIZE is not 1.0f we cannot use the texture path.
  766. const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f) && (AA_SIZE == 1.0f);
  767. // We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTex unless ImFontAtlasFlags_NoBakedLines is off
  768. IM_ASSERT_PARANOID(!use_texture || !(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines));
  769. const int idx_count = use_texture ? (count * 6) : (thick_line ? count * 18 : count * 12);
  770. const int vtx_count = use_texture ? (points_count * 2) : (thick_line ? points_count * 4 : points_count * 3);
  771. PrimReserve(idx_count, vtx_count);
  772. // Temporary buffer
  773. // The first <points_count> items are normals at each line point, then after that there are either 2 or 4 temp points for each line point
  774. _Data->TempBuffer.reserve_discard(points_count * ((use_texture || !thick_line) ? 3 : 5));
  775. ImVec2* temp_normals = _Data->TempBuffer.Data;
  776. ImVec2* temp_points = temp_normals + points_count;
  777. // Calculate normals (tangents) for each line segment
  778. for (int i1 = 0; i1 < count; i1++)
  779. {
  780. const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
  781. float dx = points[i2].x - points[i1].x;
  782. float dy = points[i2].y - points[i1].y;
  783. IM_NORMALIZE2F_OVER_ZERO(dx, dy);
  784. temp_normals[i1].x = dy;
  785. temp_normals[i1].y = -dx;
  786. }
  787. if (!closed)
  788. temp_normals[points_count - 1] = temp_normals[points_count - 2];
  789. // If we are drawing a one-pixel-wide line without a texture, or a textured line of any width, we only need 2 or 3 vertices per point
  790. if (use_texture || !thick_line)
  791. {
  792. // [PATH 1] Texture-based lines (thick or non-thick)
  793. // [PATH 2] Non texture-based lines (non-thick)
  794. // The width of the geometry we need to draw - this is essentially <thickness> pixels for the line itself, plus "one pixel" for AA.
  795. // - In the texture-based path, we don't use AA_SIZE here because the +1 is tied to the generated texture
  796. // (see ImFontAtlasBuildRenderLinesTexData() function), and so alternate values won't work without changes to that code.
  797. // - In the non texture-based paths, we would allow AA_SIZE to potentially be != 1.0f with a patch (e.g. fringe_scale patch to
  798. // allow scaling geometry while preserving one-screen-pixel AA fringe).
  799. const float half_draw_size = use_texture ? ((thickness * 0.5f) + 1) : AA_SIZE;
  800. // If line is not closed, the first and last points need to be generated differently as there are no normals to blend
  801. if (!closed)
  802. {
  803. temp_points[0] = points[0] + temp_normals[0] * half_draw_size;
  804. temp_points[1] = points[0] - temp_normals[0] * half_draw_size;
  805. temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * half_draw_size;
  806. temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * half_draw_size;
  807. }
  808. // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges
  809. // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps)
  810. // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
  811. unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment
  812. for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment
  813. {
  814. const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; // i2 is the second point of the line segment
  815. const unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_texture ? 2 : 3)); // Vertex index for end of segment
  816. // Average normals
  817. float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
  818. float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
  819. IM_FIXNORMAL2F(dm_x, dm_y);
  820. dm_x *= half_draw_size; // dm_x, dm_y are offset to the outer edge of the AA area
  821. dm_y *= half_draw_size;
  822. // Add temporary vertices for the outer edges
  823. ImVec2* out_vtx = &temp_points[i2 * 2];
  824. out_vtx[0].x = points[i2].x + dm_x;
  825. out_vtx[0].y = points[i2].y + dm_y;
  826. out_vtx[1].x = points[i2].x - dm_x;
  827. out_vtx[1].y = points[i2].y - dm_y;
  828. if (use_texture)
  829. {
  830. // Add indices for two triangles
  831. _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri
  832. _IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Left tri
  833. _IdxWritePtr += 6;
  834. }
  835. else
  836. {
  837. // Add indexes for four triangles
  838. _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); // Right tri 1
  839. _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Right tri 2
  840. _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); // Left tri 1
  841. _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); // Left tri 2
  842. _IdxWritePtr += 12;
  843. }
  844. idx1 = idx2;
  845. }
  846. // Add vertices for each point on the line
  847. if (use_texture)
  848. {
  849. // If we're using textures we only need to emit the left/right edge vertices
  850. ImVec4 tex_uvs = _Data->TexUvLines[integer_thickness];
  851. /*if (fractional_thickness != 0.0f) // Currently always zero when use_texture==false!
  852. {
  853. const ImVec4 tex_uvs_1 = _Data->TexUvLines[integer_thickness + 1];
  854. tex_uvs.x = tex_uvs.x + (tex_uvs_1.x - tex_uvs.x) * fractional_thickness; // inlined ImLerp()
  855. tex_uvs.y = tex_uvs.y + (tex_uvs_1.y - tex_uvs.y) * fractional_thickness;
  856. tex_uvs.z = tex_uvs.z + (tex_uvs_1.z - tex_uvs.z) * fractional_thickness;
  857. tex_uvs.w = tex_uvs.w + (tex_uvs_1.w - tex_uvs.w) * fractional_thickness;
  858. }*/
  859. ImVec2 tex_uv0(tex_uvs.x, tex_uvs.y);
  860. ImVec2 tex_uv1(tex_uvs.z, tex_uvs.w);
  861. for (int i = 0; i < points_count; i++)
  862. {
  863. _VtxWritePtr[0].pos = temp_points[i * 2 + 0]; _VtxWritePtr[0].uv = tex_uv0; _VtxWritePtr[0].col = col; // Left-side outer edge
  864. _VtxWritePtr[1].pos = temp_points[i * 2 + 1]; _VtxWritePtr[1].uv = tex_uv1; _VtxWritePtr[1].col = col; // Right-side outer edge
  865. _VtxWritePtr += 2;
  866. }
  867. }
  868. else
  869. {
  870. // If we're not using a texture, we need the center vertex as well
  871. for (int i = 0; i < points_count; i++)
  872. {
  873. _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; // Center of line
  874. _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans; // Left-side outer edge
  875. _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans; // Right-side outer edge
  876. _VtxWritePtr += 3;
  877. }
  878. }
  879. }
  880. else
  881. {
  882. // [PATH 2] Non texture-based lines (thick): we need to draw the solid line core and thus require four vertices per point
  883. const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
  884. // If line is not closed, the first and last points need to be generated differently as there are no normals to blend
  885. if (!closed)
  886. {
  887. const int points_last = points_count - 1;
  888. temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE);
  889. temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness);
  890. temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness);
  891. temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE);
  892. temp_points[points_last * 4 + 0] = points[points_last] + temp_normals[points_last] * (half_inner_thickness + AA_SIZE);
  893. temp_points[points_last * 4 + 1] = points[points_last] + temp_normals[points_last] * (half_inner_thickness);
  894. temp_points[points_last * 4 + 2] = points[points_last] - temp_normals[points_last] * (half_inner_thickness);
  895. temp_points[points_last * 4 + 3] = points[points_last] - temp_normals[points_last] * (half_inner_thickness + AA_SIZE);
  896. }
  897. // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges
  898. // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps)
  899. // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
  900. unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment
  901. for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment
  902. {
  903. const int i2 = (i1 + 1) == points_count ? 0 : (i1 + 1); // i2 is the second point of the line segment
  904. const unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : (idx1 + 4); // Vertex index for end of segment
  905. // Average normals
  906. float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
  907. float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
  908. IM_FIXNORMAL2F(dm_x, dm_y);
  909. float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE);
  910. float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE);
  911. float dm_in_x = dm_x * half_inner_thickness;
  912. float dm_in_y = dm_y * half_inner_thickness;
  913. // Add temporary vertices
  914. ImVec2* out_vtx = &temp_points[i2 * 4];
  915. out_vtx[0].x = points[i2].x + dm_out_x;
  916. out_vtx[0].y = points[i2].y + dm_out_y;
  917. out_vtx[1].x = points[i2].x + dm_in_x;
  918. out_vtx[1].y = points[i2].y + dm_in_y;
  919. out_vtx[2].x = points[i2].x - dm_in_x;
  920. out_vtx[2].y = points[i2].y - dm_in_y;
  921. out_vtx[3].x = points[i2].x - dm_out_x;
  922. out_vtx[3].y = points[i2].y - dm_out_y;
  923. // Add indexes
  924. _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2);
  925. _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 1);
  926. _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0);
  927. _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1);
  928. _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3);
  929. _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2);
  930. _IdxWritePtr += 18;
  931. idx1 = idx2;
  932. }
  933. // Add vertices
  934. for (int i = 0; i < points_count; i++)
  935. {
  936. _VtxWritePtr[0].pos = temp_points[i * 4 + 0]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col_trans;
  937. _VtxWritePtr[1].pos = temp_points[i * 4 + 1]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col;
  938. _VtxWritePtr[2].pos = temp_points[i * 4 + 2]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col;
  939. _VtxWritePtr[3].pos = temp_points[i * 4 + 3]; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col_trans;
  940. _VtxWritePtr += 4;
  941. }
  942. }
  943. _VtxCurrentIdx += (ImDrawIdx)vtx_count;
  944. }
  945. else
  946. {
  947. // [PATH 4] Non texture-based, Non anti-aliased lines
  948. const int idx_count = count * 6;
  949. const int vtx_count = count * 4; // FIXME-OPT: Not sharing edges
  950. PrimReserve(idx_count, vtx_count);
  951. for (int i1 = 0; i1 < count; i1++)
  952. {
  953. const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
  954. const ImVec2& p1 = points[i1];
  955. const ImVec2& p2 = points[i2];
  956. float dx = p2.x - p1.x;
  957. float dy = p2.y - p1.y;
  958. IM_NORMALIZE2F_OVER_ZERO(dx, dy);
  959. dx *= (thickness * 0.5f);
  960. dy *= (thickness * 0.5f);
  961. _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col;
  962. _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col;
  963. _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col;
  964. _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col;
  965. _VtxWritePtr += 4;
  966. _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2);
  967. _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3);
  968. _IdxWritePtr += 6;
  969. _VtxCurrentIdx += 4;
  970. }
  971. }
  972. }
  973. // - We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds.
  974. // - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing.
  975. void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
  976. {
  977. if (points_count < 3 || (col & IM_COL32_A_MASK) == 0)
  978. return;
  979. const ImVec2 uv = _Data->TexUvWhitePixel;
  980. if (Flags & ImDrawListFlags_AntiAliasedFill)
  981. {
  982. // Anti-aliased Fill
  983. const float AA_SIZE = _FringeScale;
  984. const ImU32 col_trans = col & ~IM_COL32_A_MASK;
  985. const int idx_count = (points_count - 2)*3 + points_count * 6;
  986. const int vtx_count = (points_count * 2);
  987. PrimReserve(idx_count, vtx_count);
  988. // Add indexes for fill
  989. unsigned int vtx_inner_idx = _VtxCurrentIdx;
  990. unsigned int vtx_outer_idx = _VtxCurrentIdx + 1;
  991. for (int i = 2; i < points_count; i++)
  992. {
  993. _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1));
  994. _IdxWritePtr += 3;
  995. }
  996. // Compute normals
  997. _Data->TempBuffer.reserve_discard(points_count);
  998. ImVec2* temp_normals = _Data->TempBuffer.Data;
  999. for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
  1000. {
  1001. const ImVec2& p0 = points[i0];
  1002. const ImVec2& p1 = points[i1];
  1003. float dx = p1.x - p0.x;
  1004. float dy = p1.y - p0.y;
  1005. IM_NORMALIZE2F_OVER_ZERO(dx, dy);
  1006. temp_normals[i0].x = dy;
  1007. temp_normals[i0].y = -dx;
  1008. }
  1009. for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
  1010. {
  1011. // Average normals
  1012. const ImVec2& n0 = temp_normals[i0];
  1013. const ImVec2& n1 = temp_normals[i1];
  1014. float dm_x = (n0.x + n1.x) * 0.5f;
  1015. float dm_y = (n0.y + n1.y) * 0.5f;
  1016. IM_FIXNORMAL2F(dm_x, dm_y);
  1017. dm_x *= AA_SIZE * 0.5f;
  1018. dm_y *= AA_SIZE * 0.5f;
  1019. // Add vertices
  1020. _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner
  1021. _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer
  1022. _VtxWritePtr += 2;
  1023. // Add indexes for fringes
  1024. _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1));
  1025. _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1));
  1026. _IdxWritePtr += 6;
  1027. }
  1028. _VtxCurrentIdx += (ImDrawIdx)vtx_count;
  1029. }
  1030. else
  1031. {
  1032. // Non Anti-aliased Fill
  1033. const int idx_count = (points_count - 2)*3;
  1034. const int vtx_count = points_count;
  1035. PrimReserve(idx_count, vtx_count);
  1036. for (int i = 0; i < vtx_count; i++)
  1037. {
  1038. _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
  1039. _VtxWritePtr++;
  1040. }
  1041. for (int i = 2; i < points_count; i++)
  1042. {
  1043. _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i);
  1044. _IdxWritePtr += 3;
  1045. }
  1046. _VtxCurrentIdx += (ImDrawIdx)vtx_count;
  1047. }
  1048. }
  1049. void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step)
  1050. {
  1051. if (radius < 0.5f)
  1052. {
  1053. _Path.push_back(center);
  1054. return;
  1055. }
  1056. // Calculate arc auto segment step size
  1057. if (a_step <= 0)
  1058. a_step = IM_DRAWLIST_ARCFAST_SAMPLE_MAX / _CalcCircleAutoSegmentCount(radius);
  1059. // Make sure we never do steps larger than one quarter of the circle
  1060. a_step = ImClamp(a_step, 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4);
  1061. const int sample_range = ImAbs(a_max_sample - a_min_sample);
  1062. const int a_next_step = a_step;
  1063. int samples = sample_range + 1;
  1064. bool extra_max_sample = false;
  1065. if (a_step > 1)
  1066. {
  1067. samples = sample_range / a_step + 1;
  1068. const int overstep = sample_range % a_step;
  1069. if (overstep > 0)
  1070. {
  1071. extra_max_sample = true;
  1072. samples++;
  1073. // When we have overstep to avoid awkwardly looking one long line and one tiny one at the end,
  1074. // distribute first step range evenly between them by reducing first step size.
  1075. if (sample_range > 0)
  1076. a_step -= (a_step - overstep) / 2;
  1077. }
  1078. }
  1079. _Path.resize(_Path.Size + samples);
  1080. ImVec2* out_ptr = _Path.Data + (_Path.Size - samples);
  1081. int sample_index = a_min_sample;
  1082. if (sample_index < 0 || sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX)
  1083. {
  1084. sample_index = sample_index % IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
  1085. if (sample_index < 0)
  1086. sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
  1087. }
  1088. if (a_max_sample >= a_min_sample)
  1089. {
  1090. for (int a = a_min_sample; a <= a_max_sample; a += a_step, sample_index += a_step, a_step = a_next_step)
  1091. {
  1092. // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more
  1093. if (sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX)
  1094. sample_index -= IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
  1095. const ImVec2 s = _Data->ArcFastVtx[sample_index];
  1096. out_ptr->x = center.x + s.x * radius;
  1097. out_ptr->y = center.y + s.y * radius;
  1098. out_ptr++;
  1099. }
  1100. }
  1101. else
  1102. {
  1103. for (int a = a_min_sample; a >= a_max_sample; a -= a_step, sample_index -= a_step, a_step = a_next_step)
  1104. {
  1105. // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more
  1106. if (sample_index < 0)
  1107. sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
  1108. const ImVec2 s = _Data->ArcFastVtx[sample_index];
  1109. out_ptr->x = center.x + s.x * radius;
  1110. out_ptr->y = center.y + s.y * radius;
  1111. out_ptr++;
  1112. }
  1113. }
  1114. if (extra_max_sample)
  1115. {
  1116. int normalized_max_sample = a_max_sample % IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
  1117. if (normalized_max_sample < 0)
  1118. normalized_max_sample += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
  1119. const ImVec2 s = _Data->ArcFastVtx[normalized_max_sample];
  1120. out_ptr->x = center.x + s.x * radius;
  1121. out_ptr->y = center.y + s.y * radius;
  1122. out_ptr++;
  1123. }
  1124. IM_ASSERT_PARANOID(_Path.Data + _Path.Size == out_ptr);
  1125. }
  1126. void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)
  1127. {
  1128. if (radius < 0.5f)
  1129. {
  1130. _Path.push_back(center);
  1131. return;
  1132. }
  1133. // Note that we are adding a point at both a_min and a_max.
  1134. // If you are trying to draw a full closed circle you don't want the overlapping points!
  1135. _Path.reserve(_Path.Size + (num_segments + 1));
  1136. for (int i = 0; i <= num_segments; i++)
  1137. {
  1138. const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
  1139. _Path.push_back(ImVec2(center.x + ImCos(a) * radius, center.y + ImSin(a) * radius));
  1140. }
  1141. }
  1142. // 0: East, 3: South, 6: West, 9: North, 12: East
  1143. void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12)
  1144. {
  1145. if (radius < 0.5f)
  1146. {
  1147. _Path.push_back(center);
  1148. return;
  1149. }
  1150. _PathArcToFastEx(center, radius, a_min_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, a_max_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, 0);
  1151. }
  1152. void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)
  1153. {
  1154. if (radius < 0.5f)
  1155. {
  1156. _Path.push_back(center);
  1157. return;
  1158. }
  1159. if (num_segments > 0)
  1160. {
  1161. _PathArcToN(center, radius, a_min, a_max, num_segments);
  1162. return;
  1163. }
  1164. // Automatic segment count
  1165. if (radius <= _Data->ArcFastRadiusCutoff)
  1166. {
  1167. const bool a_is_reverse = a_max < a_min;
  1168. // We are going to use precomputed values for mid samples.
  1169. // Determine first and last sample in lookup table that belong to the arc.
  1170. const float a_min_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_min / (IM_PI * 2.0f);
  1171. const float a_max_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_max / (IM_PI * 2.0f);
  1172. const int a_min_sample = a_is_reverse ? (int)ImFloor(a_min_sample_f) : (int)ImCeil(a_min_sample_f);
  1173. const int a_max_sample = a_is_reverse ? (int)ImCeil(a_max_sample_f) : (int)ImFloor(a_max_sample_f);
  1174. const int a_mid_samples = a_is_reverse ? ImMax(a_min_sample - a_max_sample, 0) : ImMax(a_max_sample - a_min_sample, 0);
  1175. const float a_min_segment_angle = a_min_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
  1176. const float a_max_segment_angle = a_max_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
  1177. const bool a_emit_start = ImAbs(a_min_segment_angle - a_min) >= 1e-5f;
  1178. const bool a_emit_end = ImAbs(a_max - a_max_segment_angle) >= 1e-5f;
  1179. _Path.reserve(_Path.Size + (a_mid_samples + 1 + (a_emit_start ? 1 : 0) + (a_emit_end ? 1 : 0)));
  1180. if (a_emit_start)
  1181. _Path.push_back(ImVec2(center.x + ImCos(a_min) * radius, center.y + ImSin(a_min) * radius));
  1182. if (a_mid_samples > 0)
  1183. _PathArcToFastEx(center, radius, a_min_sample, a_max_sample, 0);
  1184. if (a_emit_end)
  1185. _Path.push_back(ImVec2(center.x + ImCos(a_max) * radius, center.y + ImSin(a_max) * radius));
  1186. }
  1187. else
  1188. {
  1189. const float arc_length = ImAbs(a_max - a_min);
  1190. const int circle_segment_count = _CalcCircleAutoSegmentCount(radius);
  1191. const int arc_segment_count = ImMax((int)ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0f)), (int)(2.0f * IM_PI / arc_length));
  1192. _PathArcToN(center, radius, a_min, a_max, arc_segment_count);
  1193. }
  1194. }
  1195. void ImDrawList::PathEllipticalArcTo(const ImVec2& center, const ImVec2& radius, float rot, float a_min, float a_max, int num_segments)
  1196. {
  1197. if (num_segments <= 0)
  1198. num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here.
  1199. _Path.reserve(_Path.Size + (num_segments + 1));
  1200. const float cos_rot = ImCos(rot);
  1201. const float sin_rot = ImSin(rot);
  1202. for (int i = 0; i <= num_segments; i++)
  1203. {
  1204. const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
  1205. ImVec2 point(ImCos(a) * radius.x, ImSin(a) * radius.y);
  1206. const ImVec2 rel((point.x * cos_rot) - (point.y * sin_rot), (point.x * sin_rot) + (point.y * cos_rot));
  1207. point.x = rel.x + center.x;
  1208. point.y = rel.y + center.y;
  1209. _Path.push_back(point);
  1210. }
  1211. }
  1212. ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t)
  1213. {
  1214. float u = 1.0f - t;
  1215. float w1 = u * u * u;
  1216. float w2 = 3 * u * u * t;
  1217. float w3 = 3 * u * t * t;
  1218. float w4 = t * t * t;
  1219. return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x, w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y);
  1220. }
  1221. ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t)
  1222. {
  1223. float u = 1.0f - t;
  1224. float w1 = u * u;
  1225. float w2 = 2 * u * t;
  1226. float w3 = t * t;
  1227. return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x, w1 * p1.y + w2 * p2.y + w3 * p3.y);
  1228. }
  1229. // Closely mimics ImBezierCubicClosestPointCasteljau() in imgui.cpp
  1230. static void PathBezierCubicCurveToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
  1231. {
  1232. float dx = x4 - x1;
  1233. float dy = y4 - y1;
  1234. float d2 = (x2 - x4) * dy - (y2 - y4) * dx;
  1235. float d3 = (x3 - x4) * dy - (y3 - y4) * dx;
  1236. d2 = (d2 >= 0) ? d2 : -d2;
  1237. d3 = (d3 >= 0) ? d3 : -d3;
  1238. if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
  1239. {
  1240. path->push_back(ImVec2(x4, y4));
  1241. }
  1242. else if (level < 10)
  1243. {
  1244. float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;
  1245. float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;
  1246. float x34 = (x3 + x4) * 0.5f, y34 = (y3 + y4) * 0.5f;
  1247. float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;
  1248. float x234 = (x23 + x34) * 0.5f, y234 = (y23 + y34) * 0.5f;
  1249. float x1234 = (x123 + x234) * 0.5f, y1234 = (y123 + y234) * 0.5f;
  1250. PathBezierCubicCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
  1251. PathBezierCubicCurveToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
  1252. }
  1253. }
  1254. static void PathBezierQuadraticCurveToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float tess_tol, int level)
  1255. {
  1256. float dx = x3 - x1, dy = y3 - y1;
  1257. float det = (x2 - x3) * dy - (y2 - y3) * dx;
  1258. if (det * det * 4.0f < tess_tol * (dx * dx + dy * dy))
  1259. {
  1260. path->push_back(ImVec2(x3, y3));
  1261. }
  1262. else if (level < 10)
  1263. {
  1264. float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;
  1265. float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;
  1266. float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;
  1267. PathBezierQuadraticCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, tess_tol, level + 1);
  1268. PathBezierQuadraticCurveToCasteljau(path, x123, y123, x23, y23, x3, y3, tess_tol, level + 1);
  1269. }
  1270. }
  1271. void ImDrawList::PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments)
  1272. {
  1273. ImVec2 p1 = _Path.back();
  1274. if (num_segments == 0)
  1275. {
  1276. IM_ASSERT(_Data->CurveTessellationTol > 0.0f);
  1277. PathBezierCubicCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated
  1278. }
  1279. else
  1280. {
  1281. float t_step = 1.0f / (float)num_segments;
  1282. for (int i_step = 1; i_step <= num_segments; i_step++)
  1283. _Path.push_back(ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step));
  1284. }
  1285. }
  1286. void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments)
  1287. {
  1288. ImVec2 p1 = _Path.back();
  1289. if (num_segments == 0)
  1290. {
  1291. IM_ASSERT(_Data->CurveTessellationTol > 0.0f);
  1292. PathBezierQuadraticCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, _Data->CurveTessellationTol, 0);// Auto-tessellated
  1293. }
  1294. else
  1295. {
  1296. float t_step = 1.0f / (float)num_segments;
  1297. for (int i_step = 1; i_step <= num_segments; i_step++)
  1298. _Path.push_back(ImBezierQuadraticCalc(p1, p2, p3, t_step * i_step));
  1299. }
  1300. }
  1301. static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags)
  1302. {
  1303. /*
  1304. IM_STATIC_ASSERT(ImDrawFlags_RoundCornersTopLeft == (1 << 4));
  1305. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
  1306. // Obsoleted in 1.82 (from February 2021). This code was stripped/simplified and mostly commented in 1.90 (from September 2023)
  1307. // - Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All)
  1308. if (flags == ~0) { return ImDrawFlags_RoundCornersAll; }
  1309. // - Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations). Read details in older version of this code.
  1310. if (flags >= 0x01 && flags <= 0x0F) { return (flags << 4); }
  1311. // We cannot support hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f'
  1312. #endif
  1313. */
  1314. // If this assert triggers, please update your code replacing hardcoded values with new ImDrawFlags_RoundCorners* values.
  1315. // Note that ImDrawFlags_Closed (== 0x01) is an invalid flag for AddRect(), AddRectFilled(), PathRect() etc. anyway.
  1316. // See details in 1.82 Changelog as well as 2021/03/12 and 2023/09/08 entries in "API BREAKING CHANGES" section.
  1317. IM_ASSERT((flags & 0x0F) == 0 && "Misuse of legacy hardcoded ImDrawCornerFlags values!");
  1318. if ((flags & ImDrawFlags_RoundCornersMask_) == 0)
  1319. flags |= ImDrawFlags_RoundCornersAll;
  1320. return flags;
  1321. }
  1322. void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags)
  1323. {
  1324. if (rounding >= 0.5f)
  1325. {
  1326. flags = FixRectCornerFlags(flags);
  1327. rounding = ImMin(rounding, ImFabs(b.x - a.x) * (((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f) - 1.0f);
  1328. rounding = ImMin(rounding, ImFabs(b.y - a.y) * (((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f) - 1.0f);
  1329. }
  1330. if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
  1331. {
  1332. PathLineTo(a);
  1333. PathLineTo(ImVec2(b.x, a.y));
  1334. PathLineTo(b);
  1335. PathLineTo(ImVec2(a.x, b.y));
  1336. }
  1337. else
  1338. {
  1339. const float rounding_tl = (flags & ImDrawFlags_RoundCornersTopLeft) ? rounding : 0.0f;
  1340. const float rounding_tr = (flags & ImDrawFlags_RoundCornersTopRight) ? rounding : 0.0f;
  1341. const float rounding_br = (flags & ImDrawFlags_RoundCornersBottomRight) ? rounding : 0.0f;
  1342. const float rounding_bl = (flags & ImDrawFlags_RoundCornersBottomLeft) ? rounding : 0.0f;
  1343. PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9);
  1344. PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12);
  1345. PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3);
  1346. PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6);
  1347. }
  1348. }
  1349. void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness)
  1350. {
  1351. if ((col & IM_COL32_A_MASK) == 0)
  1352. return;
  1353. PathLineTo(p1 + ImVec2(0.5f, 0.5f));
  1354. PathLineTo(p2 + ImVec2(0.5f, 0.5f));
  1355. PathStroke(col, 0, thickness);
  1356. }
  1357. // p_min = upper-left, p_max = lower-right
  1358. // Note we don't render 1 pixels sized rectangles properly.
  1359. void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags, float thickness)
  1360. {
  1361. if ((col & IM_COL32_A_MASK) == 0)
  1362. return;
  1363. if (Flags & ImDrawListFlags_AntiAliasedLines)
  1364. PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, flags);
  1365. else
  1366. PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, flags); // Better looking lower-right corner and rounded non-AA shapes.
  1367. PathStroke(col, ImDrawFlags_Closed, thickness);
  1368. }
  1369. void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags)
  1370. {
  1371. if ((col & IM_COL32_A_MASK) == 0)
  1372. return;
  1373. if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
  1374. {
  1375. PrimReserve(6, 4);
  1376. PrimRect(p_min, p_max, col);
  1377. }
  1378. else
  1379. {
  1380. PathRect(p_min, p_max, rounding, flags);
  1381. PathFillConvex(col);
  1382. }
  1383. }
  1384. // p_min = upper-left, p_max = lower-right
  1385. void ImDrawList::AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left)
  1386. {
  1387. if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0)
  1388. return;
  1389. const ImVec2 uv = _Data->TexUvWhitePixel;
  1390. PrimReserve(6, 4);
  1391. PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2));
  1392. PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3));
  1393. PrimWriteVtx(p_min, uv, col_upr_left);
  1394. PrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right);
  1395. PrimWriteVtx(p_max, uv, col_bot_right);
  1396. PrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left);
  1397. }
  1398. void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness)
  1399. {
  1400. if ((col & IM_COL32_A_MASK) == 0)
  1401. return;
  1402. PathLineTo(p1);
  1403. PathLineTo(p2);
  1404. PathLineTo(p3);
  1405. PathLineTo(p4);
  1406. PathStroke(col, ImDrawFlags_Closed, thickness);
  1407. }
  1408. void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col)
  1409. {
  1410. if ((col & IM_COL32_A_MASK) == 0)
  1411. return;
  1412. PathLineTo(p1);
  1413. PathLineTo(p2);
  1414. PathLineTo(p3);
  1415. PathLineTo(p4);
  1416. PathFillConvex(col);
  1417. }
  1418. void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness)
  1419. {
  1420. if ((col & IM_COL32_A_MASK) == 0)
  1421. return;
  1422. PathLineTo(p1);
  1423. PathLineTo(p2);
  1424. PathLineTo(p3);
  1425. PathStroke(col, ImDrawFlags_Closed, thickness);
  1426. }
  1427. void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col)
  1428. {
  1429. if ((col & IM_COL32_A_MASK) == 0)
  1430. return;
  1431. PathLineTo(p1);
  1432. PathLineTo(p2);
  1433. PathLineTo(p3);
  1434. PathFillConvex(col);
  1435. }
  1436. void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)
  1437. {
  1438. if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f)
  1439. return;
  1440. if (num_segments <= 0)
  1441. {
  1442. // Use arc with automatic segment count
  1443. _PathArcToFastEx(center, radius - 0.5f, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0);
  1444. _Path.Size--;
  1445. }
  1446. else
  1447. {
  1448. // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
  1449. num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
  1450. // Because we are filling a closed shape we remove 1 from the count of segments/points
  1451. const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
  1452. PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
  1453. }
  1454. PathStroke(col, ImDrawFlags_Closed, thickness);
  1455. }
  1456. void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
  1457. {
  1458. if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f)
  1459. return;
  1460. if (num_segments <= 0)
  1461. {
  1462. // Use arc with automatic segment count
  1463. _PathArcToFastEx(center, radius, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0);
  1464. _Path.Size--;
  1465. }
  1466. else
  1467. {
  1468. // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
  1469. num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
  1470. // Because we are filling a closed shape we remove 1 from the count of segments/points
  1471. const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
  1472. PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
  1473. }
  1474. PathFillConvex(col);
  1475. }
  1476. // Guaranteed to honor 'num_segments'
  1477. void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)
  1478. {
  1479. if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
  1480. return;
  1481. // Because we are filling a closed shape we remove 1 from the count of segments/points
  1482. const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
  1483. PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
  1484. PathStroke(col, ImDrawFlags_Closed, thickness);
  1485. }
  1486. // Guaranteed to honor 'num_segments'
  1487. void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
  1488. {
  1489. if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
  1490. return;
  1491. // Because we are filling a closed shape we remove 1 from the count of segments/points
  1492. const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
  1493. PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
  1494. PathFillConvex(col);
  1495. }
  1496. // Ellipse
  1497. void ImDrawList::AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot, int num_segments, float thickness)
  1498. {
  1499. if ((col & IM_COL32_A_MASK) == 0)
  1500. return;
  1501. if (num_segments <= 0)
  1502. num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here.
  1503. // Because we are filling a closed shape we remove 1 from the count of segments/points
  1504. const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
  1505. PathEllipticalArcTo(center, radius, rot, 0.0f, a_max, num_segments - 1);
  1506. PathStroke(col, true, thickness);
  1507. }
  1508. void ImDrawList::AddEllipseFilled(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot, int num_segments)
  1509. {
  1510. if ((col & IM_COL32_A_MASK) == 0)
  1511. return;
  1512. if (num_segments <= 0)
  1513. num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here.
  1514. // Because we are filling a closed shape we remove 1 from the count of segments/points
  1515. const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
  1516. PathEllipticalArcTo(center, radius, rot, 0.0f, a_max, num_segments - 1);
  1517. PathFillConvex(col);
  1518. }
  1519. // Cubic Bezier takes 4 controls points
  1520. void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments)
  1521. {
  1522. if ((col & IM_COL32_A_MASK) == 0)
  1523. return;
  1524. PathLineTo(p1);
  1525. PathBezierCubicCurveTo(p2, p3, p4, num_segments);
  1526. PathStroke(col, 0, thickness);
  1527. }
  1528. // Quadratic Bezier takes 3 controls points
  1529. void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments)
  1530. {
  1531. if ((col & IM_COL32_A_MASK) == 0)
  1532. return;
  1533. PathLineTo(p1);
  1534. PathBezierQuadraticCurveTo(p2, p3, num_segments);
  1535. PathStroke(col, 0, thickness);
  1536. }
  1537. void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect)
  1538. {
  1539. if ((col & IM_COL32_A_MASK) == 0)
  1540. return;
  1541. // Accept null ranges
  1542. if (text_begin == text_end || text_begin[0] == 0)
  1543. return;
  1544. // No need to strlen() here: font->RenderText() will do it and may early out.
  1545. // Pull default font/size from the shared ImDrawListSharedData instance
  1546. if (font == NULL)
  1547. font = _Data->Font;
  1548. if (font_size == 0.0f)
  1549. font_size = _Data->FontSize;
  1550. ImVec4 clip_rect = _CmdHeader.ClipRect;
  1551. if (cpu_fine_clip_rect)
  1552. {
  1553. clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
  1554. clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
  1555. clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
  1556. clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
  1557. }
  1558. font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);
  1559. }
  1560. void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)
  1561. {
  1562. AddText(_Data->Font, _Data->FontSize, pos, col, text_begin, text_end);
  1563. }
  1564. void ImDrawList::AddImage(ImTextureRef tex_ref, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col)
  1565. {
  1566. if ((col & IM_COL32_A_MASK) == 0)
  1567. return;
  1568. const bool push_texture_id = tex_ref != _CmdHeader.TexRef;
  1569. if (push_texture_id)
  1570. PushTexture(tex_ref);
  1571. PrimReserve(6, 4);
  1572. PrimRectUV(p_min, p_max, uv_min, uv_max, col);
  1573. if (push_texture_id)
  1574. PopTexture();
  1575. }
  1576. void ImDrawList::AddImageQuad(ImTextureRef tex_ref, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1, const ImVec2& uv2, const ImVec2& uv3, const ImVec2& uv4, ImU32 col)
  1577. {
  1578. if ((col & IM_COL32_A_MASK) == 0)
  1579. return;
  1580. const bool push_texture_id = tex_ref != _CmdHeader.TexRef;
  1581. if (push_texture_id)
  1582. PushTexture(tex_ref);
  1583. PrimReserve(6, 4);
  1584. PrimQuadUV(p1, p2, p3, p4, uv1, uv2, uv3, uv4, col);
  1585. if (push_texture_id)
  1586. PopTexture();
  1587. }
  1588. void ImDrawList::AddImageRounded(ImTextureRef tex_ref, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags)
  1589. {
  1590. if ((col & IM_COL32_A_MASK) == 0)
  1591. return;
  1592. flags = FixRectCornerFlags(flags);
  1593. if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
  1594. {
  1595. AddImage(tex_ref, p_min, p_max, uv_min, uv_max, col);
  1596. return;
  1597. }
  1598. const bool push_texture_id = tex_ref != _CmdHeader.TexRef;
  1599. if (push_texture_id)
  1600. PushTexture(tex_ref);
  1601. int vert_start_idx = VtxBuffer.Size;
  1602. PathRect(p_min, p_max, rounding, flags);
  1603. PathFillConvex(col);
  1604. int vert_end_idx = VtxBuffer.Size;
  1605. ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true);
  1606. if (push_texture_id)
  1607. PopTexture();
  1608. }
  1609. //-----------------------------------------------------------------------------
  1610. // [SECTION] ImTriangulator, ImDrawList concave polygon fill
  1611. //-----------------------------------------------------------------------------
  1612. // Triangulate concave polygons. Based on "Triangulation by Ear Clipping" paper, O(N^2) complexity.
  1613. // Reference: https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
  1614. // Provided as a convenience for user but not used by main library.
  1615. //-----------------------------------------------------------------------------
  1616. // - ImTriangulator [Internal]
  1617. // - AddConcavePolyFilled()
  1618. //-----------------------------------------------------------------------------
  1619. enum ImTriangulatorNodeType
  1620. {
  1621. ImTriangulatorNodeType_Convex,
  1622. ImTriangulatorNodeType_Ear,
  1623. ImTriangulatorNodeType_Reflex
  1624. };
  1625. struct ImTriangulatorNode
  1626. {
  1627. ImTriangulatorNodeType Type;
  1628. int Index;
  1629. ImVec2 Pos;
  1630. ImTriangulatorNode* Next;
  1631. ImTriangulatorNode* Prev;
  1632. void Unlink() { Next->Prev = Prev; Prev->Next = Next; }
  1633. };
  1634. struct ImTriangulatorNodeSpan
  1635. {
  1636. ImTriangulatorNode** Data = NULL;
  1637. int Size = 0;
  1638. void push_back(ImTriangulatorNode* node) { Data[Size++] = node; }
  1639. void find_erase_unsorted(int idx) { for (int i = Size - 1; i >= 0; i--) if (Data[i]->Index == idx) { Data[i] = Data[Size - 1]; Size--; return; } }
  1640. };
  1641. struct ImTriangulator
  1642. {
  1643. static int EstimateTriangleCount(int points_count) { return (points_count < 3) ? 0 : points_count - 2; }
  1644. static int EstimateScratchBufferSize(int points_count) { return sizeof(ImTriangulatorNode) * points_count + sizeof(ImTriangulatorNode*) * points_count * 2; }
  1645. void Init(const ImVec2* points, int points_count, void* scratch_buffer);
  1646. void GetNextTriangle(unsigned int out_triangle[3]); // Return relative indexes for next triangle
  1647. // Internal functions
  1648. void BuildNodes(const ImVec2* points, int points_count);
  1649. void BuildReflexes();
  1650. void BuildEars();
  1651. void FlipNodeList();
  1652. bool IsEar(int i0, int i1, int i2, const ImVec2& v0, const ImVec2& v1, const ImVec2& v2) const;
  1653. void ReclassifyNode(ImTriangulatorNode* node);
  1654. // Internal members
  1655. int _TrianglesLeft = 0;
  1656. ImTriangulatorNode* _Nodes = NULL;
  1657. ImTriangulatorNodeSpan _Ears;
  1658. ImTriangulatorNodeSpan _Reflexes;
  1659. };
  1660. // Distribute storage for nodes, ears and reflexes.
  1661. // FIXME-OPT: if everything is convex, we could report it to caller and let it switch to an convex renderer
  1662. // (this would require first building reflexes to bail to convex if empty, without even building nodes)
  1663. void ImTriangulator::Init(const ImVec2* points, int points_count, void* scratch_buffer)
  1664. {
  1665. IM_ASSERT(scratch_buffer != NULL && points_count >= 3);
  1666. _TrianglesLeft = EstimateTriangleCount(points_count);
  1667. _Nodes = (ImTriangulatorNode*)scratch_buffer; // points_count x Node
  1668. _Ears.Data = (ImTriangulatorNode**)(_Nodes + points_count); // points_count x Node*
  1669. _Reflexes.Data = (ImTriangulatorNode**)(_Nodes + points_count) + points_count; // points_count x Node*
  1670. BuildNodes(points, points_count);
  1671. BuildReflexes();
  1672. BuildEars();
  1673. }
  1674. void ImTriangulator::BuildNodes(const ImVec2* points, int points_count)
  1675. {
  1676. for (int i = 0; i < points_count; i++)
  1677. {
  1678. _Nodes[i].Type = ImTriangulatorNodeType_Convex;
  1679. _Nodes[i].Index = i;
  1680. _Nodes[i].Pos = points[i];
  1681. _Nodes[i].Next = _Nodes + i + 1;
  1682. _Nodes[i].Prev = _Nodes + i - 1;
  1683. }
  1684. _Nodes[0].Prev = _Nodes + points_count - 1;
  1685. _Nodes[points_count - 1].Next = _Nodes;
  1686. }
  1687. void ImTriangulator::BuildReflexes()
  1688. {
  1689. ImTriangulatorNode* n1 = _Nodes;
  1690. for (int i = _TrianglesLeft; i >= 0; i--, n1 = n1->Next)
  1691. {
  1692. if (ImTriangleIsClockwise(n1->Prev->Pos, n1->Pos, n1->Next->Pos))
  1693. continue;
  1694. n1->Type = ImTriangulatorNodeType_Reflex;
  1695. _Reflexes.push_back(n1);
  1696. }
  1697. }
  1698. void ImTriangulator::BuildEars()
  1699. {
  1700. ImTriangulatorNode* n1 = _Nodes;
  1701. for (int i = _TrianglesLeft; i >= 0; i--, n1 = n1->Next)
  1702. {
  1703. if (n1->Type != ImTriangulatorNodeType_Convex)
  1704. continue;
  1705. if (!IsEar(n1->Prev->Index, n1->Index, n1->Next->Index, n1->Prev->Pos, n1->Pos, n1->Next->Pos))
  1706. continue;
  1707. n1->Type = ImTriangulatorNodeType_Ear;
  1708. _Ears.push_back(n1);
  1709. }
  1710. }
  1711. void ImTriangulator::GetNextTriangle(unsigned int out_triangle[3])
  1712. {
  1713. if (_Ears.Size == 0)
  1714. {
  1715. FlipNodeList();
  1716. ImTriangulatorNode* node = _Nodes;
  1717. for (int i = _TrianglesLeft; i >= 0; i--, node = node->Next)
  1718. node->Type = ImTriangulatorNodeType_Convex;
  1719. _Reflexes.Size = 0;
  1720. BuildReflexes();
  1721. BuildEars();
  1722. // If we still don't have ears, it means geometry is degenerated.
  1723. if (_Ears.Size == 0)
  1724. {
  1725. // Return first triangle available, mimicking the behavior of convex fill.
  1726. IM_ASSERT(_TrianglesLeft > 0); // Geometry is degenerated
  1727. _Ears.Data[0] = _Nodes;
  1728. _Ears.Size = 1;
  1729. }
  1730. }
  1731. ImTriangulatorNode* ear = _Ears.Data[--_Ears.Size];
  1732. out_triangle[0] = ear->Prev->Index;
  1733. out_triangle[1] = ear->Index;
  1734. out_triangle[2] = ear->Next->Index;
  1735. ear->Unlink();
  1736. if (ear == _Nodes)
  1737. _Nodes = ear->Next;
  1738. ReclassifyNode(ear->Prev);
  1739. ReclassifyNode(ear->Next);
  1740. _TrianglesLeft--;
  1741. }
  1742. void ImTriangulator::FlipNodeList()
  1743. {
  1744. ImTriangulatorNode* prev = _Nodes;
  1745. ImTriangulatorNode* temp = _Nodes;
  1746. ImTriangulatorNode* current = _Nodes->Next;
  1747. prev->Next = prev;
  1748. prev->Prev = prev;
  1749. while (current != _Nodes)
  1750. {
  1751. temp = current->Next;
  1752. current->Next = prev;
  1753. prev->Prev = current;
  1754. _Nodes->Next = current;
  1755. current->Prev = _Nodes;
  1756. prev = current;
  1757. current = temp;
  1758. }
  1759. _Nodes = prev;
  1760. }
  1761. // A triangle is an ear is no other vertex is inside it. We can test reflexes vertices only (see reference algorithm)
  1762. bool ImTriangulator::IsEar(int i0, int i1, int i2, const ImVec2& v0, const ImVec2& v1, const ImVec2& v2) const
  1763. {
  1764. ImTriangulatorNode** p_end = _Reflexes.Data + _Reflexes.Size;
  1765. for (ImTriangulatorNode** p = _Reflexes.Data; p < p_end; p++)
  1766. {
  1767. ImTriangulatorNode* reflex = *p;
  1768. if (reflex->Index != i0 && reflex->Index != i1 && reflex->Index != i2)
  1769. if (ImTriangleContainsPoint(v0, v1, v2, reflex->Pos))
  1770. return false;
  1771. }
  1772. return true;
  1773. }
  1774. void ImTriangulator::ReclassifyNode(ImTriangulatorNode* n1)
  1775. {
  1776. // Classify node
  1777. ImTriangulatorNodeType type;
  1778. const ImTriangulatorNode* n0 = n1->Prev;
  1779. const ImTriangulatorNode* n2 = n1->Next;
  1780. if (!ImTriangleIsClockwise(n0->Pos, n1->Pos, n2->Pos))
  1781. type = ImTriangulatorNodeType_Reflex;
  1782. else if (IsEar(n0->Index, n1->Index, n2->Index, n0->Pos, n1->Pos, n2->Pos))
  1783. type = ImTriangulatorNodeType_Ear;
  1784. else
  1785. type = ImTriangulatorNodeType_Convex;
  1786. // Update lists when a type changes
  1787. if (type == n1->Type)
  1788. return;
  1789. if (n1->Type == ImTriangulatorNodeType_Reflex)
  1790. _Reflexes.find_erase_unsorted(n1->Index);
  1791. else if (n1->Type == ImTriangulatorNodeType_Ear)
  1792. _Ears.find_erase_unsorted(n1->Index);
  1793. if (type == ImTriangulatorNodeType_Reflex)
  1794. _Reflexes.push_back(n1);
  1795. else if (type == ImTriangulatorNodeType_Ear)
  1796. _Ears.push_back(n1);
  1797. n1->Type = type;
  1798. }
  1799. // Use ear-clipping algorithm to triangulate a simple polygon (no self-interaction, no holes).
  1800. // (Reminder: we don't perform any coarse clipping/culling in ImDrawList layer!
  1801. // It is up to caller to ensure not making costly calls that will be outside of visible area.
  1802. // As concave fill is noticeably more expensive than other primitives, be mindful of this...
  1803. // Caller can build AABB of points, and avoid filling if 'draw_list->_CmdHeader.ClipRect.Overlays(points_bb) == false')
  1804. void ImDrawList::AddConcavePolyFilled(const ImVec2* points, const int points_count, ImU32 col)
  1805. {
  1806. if (points_count < 3 || (col & IM_COL32_A_MASK) == 0)
  1807. return;
  1808. const ImVec2 uv = _Data->TexUvWhitePixel;
  1809. ImTriangulator triangulator;
  1810. unsigned int triangle[3];
  1811. if (Flags & ImDrawListFlags_AntiAliasedFill)
  1812. {
  1813. // Anti-aliased Fill
  1814. const float AA_SIZE = _FringeScale;
  1815. const ImU32 col_trans = col & ~IM_COL32_A_MASK;
  1816. const int idx_count = (points_count - 2) * 3 + points_count * 6;
  1817. const int vtx_count = (points_count * 2);
  1818. PrimReserve(idx_count, vtx_count);
  1819. // Add indexes for fill
  1820. unsigned int vtx_inner_idx = _VtxCurrentIdx;
  1821. unsigned int vtx_outer_idx = _VtxCurrentIdx + 1;
  1822. _Data->TempBuffer.reserve_discard((ImTriangulator::EstimateScratchBufferSize(points_count) + sizeof(ImVec2)) / sizeof(ImVec2));
  1823. triangulator.Init(points, points_count, _Data->TempBuffer.Data);
  1824. while (triangulator._TrianglesLeft > 0)
  1825. {
  1826. triangulator.GetNextTriangle(triangle);
  1827. _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (triangle[0] << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (triangle[1] << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (triangle[2] << 1));
  1828. _IdxWritePtr += 3;
  1829. }
  1830. // Compute normals
  1831. _Data->TempBuffer.reserve_discard(points_count);
  1832. ImVec2* temp_normals = _Data->TempBuffer.Data;
  1833. for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
  1834. {
  1835. const ImVec2& p0 = points[i0];
  1836. const ImVec2& p1 = points[i1];
  1837. float dx = p1.x - p0.x;
  1838. float dy = p1.y - p0.y;
  1839. IM_NORMALIZE2F_OVER_ZERO(dx, dy);
  1840. temp_normals[i0].x = dy;
  1841. temp_normals[i0].y = -dx;
  1842. }
  1843. for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
  1844. {
  1845. // Average normals
  1846. const ImVec2& n0 = temp_normals[i0];
  1847. const ImVec2& n1 = temp_normals[i1];
  1848. float dm_x = (n0.x + n1.x) * 0.5f;
  1849. float dm_y = (n0.y + n1.y) * 0.5f;
  1850. IM_FIXNORMAL2F(dm_x, dm_y);
  1851. dm_x *= AA_SIZE * 0.5f;
  1852. dm_y *= AA_SIZE * 0.5f;
  1853. // Add vertices
  1854. _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner
  1855. _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer
  1856. _VtxWritePtr += 2;
  1857. // Add indexes for fringes
  1858. _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1));
  1859. _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1));
  1860. _IdxWritePtr += 6;
  1861. }
  1862. _VtxCurrentIdx += (ImDrawIdx)vtx_count;
  1863. }
  1864. else
  1865. {
  1866. // Non Anti-aliased Fill
  1867. const int idx_count = (points_count - 2) * 3;
  1868. const int vtx_count = points_count;
  1869. PrimReserve(idx_count, vtx_count);
  1870. for (int i = 0; i < vtx_count; i++)
  1871. {
  1872. _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
  1873. _VtxWritePtr++;
  1874. }
  1875. _Data->TempBuffer.reserve_discard((ImTriangulator::EstimateScratchBufferSize(points_count) + sizeof(ImVec2)) / sizeof(ImVec2));
  1876. triangulator.Init(points, points_count, _Data->TempBuffer.Data);
  1877. while (triangulator._TrianglesLeft > 0)
  1878. {
  1879. triangulator.GetNextTriangle(triangle);
  1880. _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx + triangle[0]); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + triangle[1]); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + triangle[2]);
  1881. _IdxWritePtr += 3;
  1882. }
  1883. _VtxCurrentIdx += (ImDrawIdx)vtx_count;
  1884. }
  1885. }
  1886. //-----------------------------------------------------------------------------
  1887. // [SECTION] ImDrawList Shadow Primitives
  1888. //-----------------------------------------------------------------------------
  1889. // - AddSubtractedRect() [Internal]
  1890. // - ClipPolygonShape() [Internal]
  1891. // - AddSubtractedRect() [Internal]
  1892. // - AddRectShadow()
  1893. //-----------------------------------------------------------------------------
  1894. // Adds a rectangle (A) with another rectangle (B) subtracted from it (i.e. the portion of A covered by B is not drawn). Does not handle rounded corners (use the version that takes a convex polygon for that).
  1895. static void AddSubtractedRect(ImDrawList* draw_list, const ImVec2& a_min, const ImVec2& a_max, const ImVec2& a_min_uv, const ImVec2& a_max_uv, ImVec2 b_min, ImVec2 b_max, ImU32 col)
  1896. {
  1897. // Early out without drawing anything if A is zero-size
  1898. if (a_min.x >= a_max.x || a_min.y >= a_max.y)
  1899. return;
  1900. // Early out without drawing anything if B covers A entirely
  1901. if (a_min.x >= b_min.x && a_max.x <= b_max.x && a_min.y >= b_min.y && a_max.y <= b_max.y)
  1902. return;
  1903. // First clip the extents of B to A
  1904. b_min = ImMax(b_min, a_min);
  1905. b_max = ImMin(b_max, a_max);
  1906. if (b_min.x >= b_max.x || b_min.y >= b_max.y)
  1907. {
  1908. // B is entirely outside A, so just draw A as-is
  1909. draw_list->PrimReserve(6, 4);
  1910. draw_list->PrimRectUV(a_min, a_max, a_min_uv, a_max_uv, col);
  1911. return;
  1912. }
  1913. // Otherwise we need to emit (up to) four quads to cover the visible area...
  1914. // Our layout looks like this (numbers are vertex indices, letters are quads):
  1915. //
  1916. // 0---8------9-----1
  1917. // | | B | |
  1918. // + 4------5 +
  1919. // | A |xxxxxx| C |
  1920. // | |xxxxxx| |
  1921. // + 7------6 +
  1922. // | | D | |
  1923. // 3---11-----10----2
  1924. const int max_verts = 12;
  1925. const int max_indices = 6 * 4; // At most four quads
  1926. draw_list->PrimReserve(max_indices, max_verts);
  1927. ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
  1928. ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
  1929. ImDrawIdx idx = (ImDrawIdx)draw_list->_VtxCurrentIdx;
  1930. // Write vertices
  1931. vtx_write[0].pos = ImVec2(a_min.x, a_min.y); vtx_write[0].uv = ImVec2(a_min_uv.x, a_min_uv.y); vtx_write[0].col = col;
  1932. vtx_write[1].pos = ImVec2(a_max.x, a_min.y); vtx_write[1].uv = ImVec2(a_max_uv.x, a_min_uv.y); vtx_write[1].col = col;
  1933. vtx_write[2].pos = ImVec2(a_max.x, a_max.y); vtx_write[2].uv = ImVec2(a_max_uv.x, a_max_uv.y); vtx_write[2].col = col;
  1934. vtx_write[3].pos = ImVec2(a_min.x, a_max.y); vtx_write[3].uv = ImVec2(a_min_uv.x, a_max_uv.y); vtx_write[3].col = col;
  1935. const ImVec2 pos_to_uv_scale = (a_max_uv - a_min_uv) / (a_max - a_min); // Guaranteed never to be a /0 because we check for zero-size A above
  1936. const ImVec2 pos_to_uv_offset = (a_min_uv / pos_to_uv_scale) - a_min;
  1937. // Helper that generates an interpolated UV based on position
  1938. #define LERP_UV(x_pos, y_pos) (ImVec2(((x_pos) + pos_to_uv_offset.x) * pos_to_uv_scale.x, ((y_pos) + pos_to_uv_offset.y) * pos_to_uv_scale.y))
  1939. vtx_write[4].pos = ImVec2(b_min.x, b_min.y); vtx_write[4].uv = LERP_UV(b_min.x, b_min.y); vtx_write[4].col = col;
  1940. vtx_write[5].pos = ImVec2(b_max.x, b_min.y); vtx_write[5].uv = LERP_UV(b_max.x, b_min.y); vtx_write[5].col = col;
  1941. vtx_write[6].pos = ImVec2(b_max.x, b_max.y); vtx_write[6].uv = LERP_UV(b_max.x, b_max.y); vtx_write[6].col = col;
  1942. vtx_write[7].pos = ImVec2(b_min.x, b_max.y); vtx_write[7].uv = LERP_UV(b_min.x, b_max.y); vtx_write[7].col = col;
  1943. vtx_write[8].pos = ImVec2(b_min.x, a_min.y); vtx_write[8].uv = LERP_UV(b_min.x, a_min.y); vtx_write[8].col = col;
  1944. vtx_write[9].pos = ImVec2(b_max.x, a_min.y); vtx_write[9].uv = LERP_UV(b_max.x, a_min.y); vtx_write[9].col = col;
  1945. vtx_write[10].pos = ImVec2(b_max.x, a_max.y); vtx_write[10].uv = LERP_UV(b_max.x, a_max.y); vtx_write[10].col = col;
  1946. vtx_write[11].pos = ImVec2(b_min.x, a_max.y); vtx_write[11].uv = LERP_UV(b_min.x, a_max.y); vtx_write[11].col = col;
  1947. #undef LERP_UV
  1948. draw_list->_VtxWritePtr += 12;
  1949. draw_list->_VtxCurrentIdx += 12;
  1950. // Write indices for each quad (if it is visible)
  1951. if (b_min.x > a_min.x) // A
  1952. {
  1953. idx_write[0] = (ImDrawIdx)(idx + 0); idx_write[1] = (ImDrawIdx)(idx + 8); idx_write[2] = (ImDrawIdx)(idx + 11);
  1954. idx_write[3] = (ImDrawIdx)(idx + 0); idx_write[4] = (ImDrawIdx)(idx + 11); idx_write[5] = (ImDrawIdx)(idx + 3);
  1955. idx_write += 6;
  1956. }
  1957. if (b_min.y > a_min.y) // B
  1958. {
  1959. idx_write[0] = (ImDrawIdx)(idx + 8); idx_write[1] = (ImDrawIdx)(idx + 9); idx_write[2] = (ImDrawIdx)(idx + 5);
  1960. idx_write[3] = (ImDrawIdx)(idx + 8); idx_write[4] = (ImDrawIdx)(idx + 5); idx_write[5] = (ImDrawIdx)(idx + 4);
  1961. idx_write += 6;
  1962. }
  1963. if (a_max.x > b_max.x) // C
  1964. {
  1965. idx_write[0] = (ImDrawIdx)(idx + 9); idx_write[1] = (ImDrawIdx)(idx + 1); idx_write[2] = (ImDrawIdx)(idx + 2);
  1966. idx_write[3] = (ImDrawIdx)(idx + 9); idx_write[4] = (ImDrawIdx)(idx + 2); idx_write[5] = (ImDrawIdx)(idx + 10);
  1967. idx_write += 6;
  1968. }
  1969. if (a_max.y > b_max.y) // D
  1970. {
  1971. idx_write[0] = (ImDrawIdx)(idx + 7); idx_write[1] = (ImDrawIdx)(idx + 6); idx_write[2] = (ImDrawIdx)(idx + 10);
  1972. idx_write[3] = (ImDrawIdx)(idx + 7); idx_write[4] = (ImDrawIdx)(idx + 10); idx_write[5] = (ImDrawIdx)(idx + 11);
  1973. idx_write += 6;
  1974. }
  1975. const int used_indices = (int)(idx_write - draw_list->_IdxWritePtr);
  1976. draw_list->_IdxWritePtr = idx_write;
  1977. draw_list->PrimUnreserve(max_indices - used_indices, 0);
  1978. }
  1979. // Clip a polygonal shape to a rectangle, writing the results into dest_points. The number of points emitted is returned (may be zero if the polygon was entirely outside the rectangle, or the source polygon was not valid). dest_points may still be written to even if zero was returned.
  1980. // allocated_dest_points should contain the number of allocated points in dest_points - in general this should be the number of source points + 4 to accommodate the worst case. If this is exceeded data will be truncated and -1 returned. Stack space work area is allocated based on this value so it shouldn't be too large.
  1981. static int ClipPolygonShape(ImVec2* src_points, int num_src_points, ImVec2* dest_points, int allocated_dest_points, ImVec2 clip_rect_min, ImVec2 clip_rect_max)
  1982. {
  1983. // Early-out with an empty result if clipping region is zero-sized
  1984. if (clip_rect_max.x <= clip_rect_min.x || clip_rect_max.y <= clip_rect_min.y)
  1985. return 0;
  1986. // Early-out if there is no source geometry
  1987. if (num_src_points < 3)
  1988. return 0;
  1989. // The four clip planes here are indexed as:
  1990. // 0 = X-, 1 = X+, 2 = Y-, 3 = Y+
  1991. ImU8* outflags[2]; // Double-buffered flags for each vertex indicating which of the four clip planes it is outside of
  1992. outflags[0] = (ImU8*)alloca(2 * allocated_dest_points * sizeof(ImU8));
  1993. outflags[1] = outflags[0] + allocated_dest_points;
  1994. // Calculate initial outflags
  1995. ImU8 outflags_anded = 0xFF;
  1996. ImU8 outflags_ored = 0;
  1997. for (int point_idx = 0; point_idx < num_src_points; point_idx++)
  1998. {
  1999. const ImVec2 pos = src_points[point_idx];
  2000. const ImU8 point_outflags = (pos.x < clip_rect_min.x ? 1 : 0) | (pos.x > clip_rect_max.x ? 2 : 0) | (pos.y < clip_rect_min.y ? 4 : 0) | (pos.y > clip_rect_max.y ? 8 : 0);
  2001. outflags[0][point_idx] = point_outflags; // Writing to buffer 0
  2002. outflags_anded &= point_outflags;
  2003. outflags_ored |= point_outflags;
  2004. }
  2005. if (outflags_anded != 0) // Entirely clipped by any one plane, so nothing remains
  2006. return 0;
  2007. if (outflags_ored == 0) // Entirely within bounds, so trivial accept
  2008. {
  2009. if (allocated_dest_points < num_src_points)
  2010. return -1; // Not sure what the caller was thinking if this happens, but we should handle it gracefully
  2011. memcpy(dest_points, src_points, num_src_points * sizeof(ImVec2));
  2012. return num_src_points;
  2013. }
  2014. // Shape needs clipping
  2015. ImVec2* clip_buf[2]; // Double-buffered work area
  2016. clip_buf[0] = (ImVec2*)alloca(2 * allocated_dest_points * sizeof(ImVec2)); //-V630
  2017. clip_buf[1] = clip_buf[0] + allocated_dest_points;
  2018. memcpy(clip_buf[0], src_points, num_src_points * sizeof(ImVec2));
  2019. int clip_buf_size = num_src_points; // Number of vertices currently in the clip buffer
  2020. int read_buffer_idx = 0; // The index of the clip buffer/out-flags we are reading (0 or 1)
  2021. for (int clip_plane = 0; clip_plane < 4; clip_plane++) // 0 = X-, 1 = X+, 2 = Y-, 3 = Y+
  2022. {
  2023. const int clip_plane_bit = 1 << clip_plane; // Bit mask for our current plane in out-flags
  2024. if ((outflags_ored & clip_plane_bit) == 0)
  2025. continue; // All vertices are inside this plane, so no need to clip
  2026. ImVec2* read_vert = &clip_buf[read_buffer_idx][0]; // Clip buffer vertex we are currently reading
  2027. ImVec2* write_vert = &clip_buf[1 - read_buffer_idx][0]; // Clip buffer vertex we are currently writing
  2028. ImVec2* write_vert_end = write_vert + allocated_dest_points; // End of the write buffer
  2029. ImU8* read_outflags = &outflags[read_buffer_idx][0]; // Out-flag we are currently reading
  2030. ImU8* write_outflags = &outflags[1 - read_buffer_idx][0]; // Out-flag we are currently writing
  2031. // Keep track of the last vertex visited, initially the last in the list
  2032. ImVec2* last_vert = &read_vert[clip_buf_size - 1];
  2033. ImU8 last_outflags = read_outflags[clip_buf_size - 1];
  2034. for (int vert = 0; vert < clip_buf_size; vert++)
  2035. {
  2036. ImU8 current_outflags = *(read_outflags++);
  2037. bool out = (current_outflags & clip_plane_bit) != 0;
  2038. if (((current_outflags ^ last_outflags) & clip_plane_bit) == 0) // We haven't crossed the clip plane
  2039. {
  2040. if (!out)
  2041. {
  2042. // Emit vertex as-is
  2043. if (write_vert >= write_vert_end)
  2044. return -1; // Ran out of buffer space, so abort
  2045. *(write_vert++) = *read_vert;
  2046. *(write_outflags++) = current_outflags;
  2047. }
  2048. }
  2049. else
  2050. {
  2051. // Emit a vertex at the intersection point
  2052. float t = 0.0f;
  2053. ImVec2 pos0 = *last_vert;
  2054. ImVec2 pos1 = *read_vert;
  2055. ImVec2 intersect_pos;
  2056. switch (clip_plane)
  2057. {
  2058. case 0: t = (clip_rect_min.x - pos0.x) / (pos1.x - pos0.x); intersect_pos = ImVec2(clip_rect_min.x, pos0.y + ((pos1.y - pos0.y) * t)); break; // X-
  2059. case 1: t = (clip_rect_max.x - pos0.x) / (pos1.x - pos0.x); intersect_pos = ImVec2(clip_rect_max.x, pos0.y + ((pos1.y - pos0.y) * t)); break; // X+
  2060. case 2: t = (clip_rect_min.y - pos0.y) / (pos1.y - pos0.y); intersect_pos = ImVec2(pos0.x + ((pos1.x - pos0.x) * t), clip_rect_min.y); break; // Y-
  2061. case 3: t = (clip_rect_max.y - pos0.y) / (pos1.y - pos0.y); intersect_pos = ImVec2(pos0.x + ((pos1.x - pos0.x) * t), clip_rect_max.y); break; // Y+
  2062. }
  2063. if (write_vert >= write_vert_end)
  2064. return -1; // Ran out of buffer space, so abort
  2065. // Write new out-flags for the vertex we just emitted
  2066. *(write_vert++) = intersect_pos;
  2067. *(write_outflags++) = (intersect_pos.x < clip_rect_min.x ? 1 : 0) | (intersect_pos.x > clip_rect_max.x ? 2 : 0) | (intersect_pos.y < clip_rect_min.y ? 4 : 0) | (intersect_pos.y > clip_rect_max.y ? 8 : 0);
  2068. if (!out)
  2069. {
  2070. // When coming back in, also emit the actual vertex
  2071. if (write_vert >= write_vert_end)
  2072. return -1; // Ran out of buffer space, so abort
  2073. *(write_vert++) = *read_vert;
  2074. *(write_outflags++) = current_outflags;
  2075. }
  2076. last_outflags = current_outflags;
  2077. }
  2078. last_vert = read_vert;
  2079. read_vert++; // Advance to next vertex
  2080. }
  2081. clip_buf_size = (int)(write_vert - &clip_buf[1 - read_buffer_idx][0]); // Update buffer size
  2082. read_buffer_idx = 1 - read_buffer_idx; // Swap buffers
  2083. }
  2084. if (clip_buf_size < 3)
  2085. return 0; // Nothing to return
  2086. // Copy results to output buffer, removing any redundant vertices
  2087. int num_out_verts = 0;
  2088. ImVec2 last_vert = clip_buf[read_buffer_idx][clip_buf_size - 1];
  2089. for (int i = 0; i < clip_buf_size; i++)
  2090. {
  2091. ImVec2 vert = clip_buf[read_buffer_idx][i];
  2092. if (ImLengthSqr(vert - last_vert) <= 0.00001f)
  2093. continue;
  2094. dest_points[num_out_verts++] = vert;
  2095. last_vert = vert;
  2096. }
  2097. // Return size (IF this is still a valid shape)
  2098. return (num_out_verts > 2) ? num_out_verts : 0;
  2099. }
  2100. // Adds a rectangle (A) with a convex shape (B) subtracted from it (i.e. the portion of A covered by B is not drawn).
  2101. static void AddSubtractedRect(ImDrawList* draw_list, const ImVec2& a_min, const ImVec2& a_max, const ImVec2& a_min_uv, const ImVec2& a_max_uv, ImVec2* b_points, int num_b_points, ImU32 col)
  2102. {
  2103. // Early out without drawing anything if A is zero-size
  2104. if (a_min.x >= a_max.x || a_min.y >= a_max.y)
  2105. return;
  2106. // First clip B to A
  2107. const int max_clipped_points = num_b_points + 4;
  2108. ImVec2* clipped_b_points = (ImVec2*)alloca(max_clipped_points * sizeof(ImVec2)); //-V630
  2109. const int num_clipped_points = ClipPolygonShape(b_points, num_b_points, clipped_b_points, max_clipped_points, a_min, a_max);
  2110. IM_ASSERT(num_clipped_points >= 0); // -1 would indicate max_clipped_points was too small, which shouldn't happen
  2111. b_points = clipped_b_points;
  2112. num_b_points = num_clipped_points;
  2113. if (num_clipped_points == 0)
  2114. {
  2115. // B is entirely outside A, so just draw A as-is
  2116. draw_list->PrimReserve(6, 4);
  2117. draw_list->PrimRectUV(a_min, a_max, a_min_uv, a_max_uv, col);
  2118. }
  2119. else
  2120. {
  2121. // We need to generate clipped geometry
  2122. // To do this we walk the inner polygon and connect each edge to one of the four corners of our rectangle based on the quadrant their normal points at
  2123. const int max_verts = num_b_points + 4; // Inner points plus the four corners
  2124. const int max_indices = (num_b_points * 3) + (4 * 3); // Worst case is one triangle per inner edge and then four filler triangles
  2125. draw_list->PrimReserve(max_indices, max_verts);
  2126. ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
  2127. ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
  2128. ImDrawIdx inner_idx = (ImDrawIdx)draw_list->_VtxCurrentIdx; // Starting index for inner vertices
  2129. // Write inner vertices
  2130. const ImVec2 pos_to_uv_scale = (a_max_uv - a_min_uv) / (a_max - a_min); // Guaranteed never to be a /0 because we check for zero-size A above
  2131. const ImVec2 pos_to_uv_offset = (a_min_uv / pos_to_uv_scale) - a_min;
  2132. // Helper that generates an interpolated UV based on position
  2133. #define LERP_UV(x_pos, y_pos) (ImVec2(((x_pos) + pos_to_uv_offset.x) * pos_to_uv_scale.x, ((y_pos) + pos_to_uv_offset.y) * pos_to_uv_scale.y))
  2134. for (int i = 0; i < num_b_points; i++)
  2135. {
  2136. vtx_write[i].pos = b_points[i];
  2137. vtx_write[i].uv = LERP_UV(b_points[i].x, b_points[i].y);
  2138. vtx_write[i].col = col;
  2139. }
  2140. #undef LERP_UV
  2141. vtx_write += num_b_points;
  2142. // Write outer vertices
  2143. ImDrawIdx outer_idx = (ImDrawIdx)(inner_idx + num_b_points); // Starting index for outer vertices
  2144. ImVec2 outer_verts[4];
  2145. outer_verts[0] = ImVec2(a_min.x, a_min.y); // X- Y- (quadrant 0, top left)
  2146. outer_verts[1] = ImVec2(a_max.x, a_min.y); // X+ Y- (quadrant 1, top right)
  2147. outer_verts[2] = ImVec2(a_max.x, a_max.y); // X+ Y+ (quadrant 2, bottom right)
  2148. outer_verts[3] = ImVec2(a_min.x, a_max.y); // X- Y+ (quadrant 3, bottom left)
  2149. vtx_write[0].pos = outer_verts[0]; vtx_write[0].uv = ImVec2(a_min_uv.x, a_min_uv.y); vtx_write[0].col = col;
  2150. vtx_write[1].pos = outer_verts[1]; vtx_write[1].uv = ImVec2(a_max_uv.x, a_min_uv.y); vtx_write[1].col = col;
  2151. vtx_write[2].pos = outer_verts[2]; vtx_write[2].uv = ImVec2(a_max_uv.x, a_max_uv.y); vtx_write[2].col = col;
  2152. vtx_write[3].pos = outer_verts[3]; vtx_write[3].uv = ImVec2(a_min_uv.x, a_max_uv.y); vtx_write[3].col = col;
  2153. draw_list->_VtxCurrentIdx += num_b_points + 4;
  2154. draw_list->_VtxWritePtr += num_b_points + 4;
  2155. // Now walk the inner vertices in order
  2156. ImVec2 last_inner_vert = b_points[num_b_points - 1];
  2157. int last_inner_vert_idx = num_b_points - 1;
  2158. int last_outer_vert_idx = -1;
  2159. int first_outer_vert_idx = -1;
  2160. // Triangle-area based check for degenerate triangles
  2161. // Min area (0.1f) is doubled (* 2.0f) because we're calculating (area * 2) here
  2162. #define IS_DEGENERATE(a, b, c) (ImFabs((((a).x * ((b).y - (c).y)) + ((b).x * ((c).y - (a).y)) + ((c).x * ((a).y - (b).y)))) < (0.1f * 2.0f))
  2163. // Check the winding order of the inner vertices using the sign of the triangle area, and set the outer vertex winding to match
  2164. int outer_vertex_winding = (((b_points[0].x * (b_points[1].y - b_points[2].y)) + (b_points[1].x * (b_points[2].y - b_points[0].y)) + (b_points[2].x * (b_points[0].y - b_points[1].y))) < 0.0f) ? -1 : 1;
  2165. for (int inner_vert_idx = 0; inner_vert_idx < num_b_points; inner_vert_idx++)
  2166. {
  2167. ImVec2 current_inner_vert = b_points[inner_vert_idx];
  2168. // Calculate normal (not actually normalized, as for our purposes here it doesn't need to be)
  2169. ImVec2 normal(current_inner_vert.y - last_inner_vert.y, -(current_inner_vert.x - last_inner_vert.x));
  2170. // Calculate the outer vertex index based on the quadrant the normal points at (0=top left, 1=top right, 2=bottom right, 3=bottom left)
  2171. int outer_vert_idx = (ImFabs(normal.x) > ImFabs(normal.y)) ? ((normal.x >= 0.0f) ? ((normal.y > 0.0f) ? 2 : 1) : ((normal.y > 0.0f) ? 3 : 0)) : ((normal.y >= 0.0f) ? ((normal.x > 0.0f) ? 2 : 3) : ((normal.x > 0.0f) ? 1 : 0));
  2172. ImVec2 outer_vert = outer_verts[outer_vert_idx];
  2173. // Write the main triangle (connecting the inner edge to the corner)
  2174. if (!IS_DEGENERATE(last_inner_vert, current_inner_vert, outer_vert))
  2175. {
  2176. idx_write[0] = (ImDrawIdx)(inner_idx + last_inner_vert_idx);
  2177. idx_write[1] = (ImDrawIdx)(inner_idx + inner_vert_idx);
  2178. idx_write[2] = (ImDrawIdx)(outer_idx + outer_vert_idx);
  2179. idx_write += 3;
  2180. }
  2181. // We don't initially know which outer vertex we are going to start from, so set that here when processing the first inner vertex
  2182. if (first_outer_vert_idx == -1)
  2183. {
  2184. first_outer_vert_idx = outer_vert_idx;
  2185. last_outer_vert_idx = outer_vert_idx;
  2186. }
  2187. // Now walk the outer edge and write any filler triangles needed (connecting outer edges to the inner vertex)
  2188. while (outer_vert_idx != last_outer_vert_idx)
  2189. {
  2190. int next_outer_vert_idx = (last_outer_vert_idx + outer_vertex_winding) & 3;
  2191. if (!IS_DEGENERATE(outer_verts[last_outer_vert_idx], outer_verts[next_outer_vert_idx], last_inner_vert))
  2192. {
  2193. idx_write[0] = (ImDrawIdx)(outer_idx + last_outer_vert_idx);
  2194. idx_write[1] = (ImDrawIdx)(outer_idx + next_outer_vert_idx);
  2195. idx_write[2] = (ImDrawIdx)(inner_idx + last_inner_vert_idx);
  2196. idx_write += 3;
  2197. }
  2198. last_outer_vert_idx = next_outer_vert_idx;
  2199. }
  2200. last_inner_vert = current_inner_vert;
  2201. last_inner_vert_idx = inner_vert_idx;
  2202. }
  2203. // Write remaining filler triangles for any un-traversed outer edges
  2204. if (first_outer_vert_idx != -1)
  2205. {
  2206. while (first_outer_vert_idx != last_outer_vert_idx)
  2207. {
  2208. int next_outer_vert_idx = (last_outer_vert_idx + outer_vertex_winding) & 3;
  2209. if (!IS_DEGENERATE(outer_verts[last_outer_vert_idx], outer_verts[next_outer_vert_idx], last_inner_vert))
  2210. {
  2211. idx_write[0] = (ImDrawIdx)(outer_idx + last_outer_vert_idx);
  2212. idx_write[1] = (ImDrawIdx)(outer_idx + next_outer_vert_idx);
  2213. idx_write[2] = (ImDrawIdx)(inner_idx + last_inner_vert_idx);
  2214. idx_write += 3;
  2215. }
  2216. last_outer_vert_idx = next_outer_vert_idx;
  2217. }
  2218. }
  2219. #undef IS_DEGENERATE
  2220. int used_indices = (int)(idx_write - draw_list->_IdxWritePtr);
  2221. draw_list->_IdxWritePtr = idx_write;
  2222. draw_list->PrimUnreserve(max_indices - used_indices, 0);
  2223. }
  2224. }
  2225. void ImDrawList::AddShadowRect(const ImVec2& obj_min, const ImVec2& obj_max, ImU32 shadow_col, float shadow_thickness, const ImVec2& shadow_offset, ImDrawFlags flags, float obj_rounding)
  2226. {
  2227. if ((shadow_col & IM_COL32_A_MASK) == 0)
  2228. return;
  2229. ImVec2* inner_rect_points = NULL; // Points that make up the shape of the inner rectangle (used when it has rounded corners)
  2230. int inner_rect_points_count = 0;
  2231. // Generate a path describing the inner rectangle and copy it to our buffer
  2232. const bool is_filled = (flags & ImDrawFlags_ShadowCutOutShapeBackground) == 0;
  2233. const bool is_rounded = (obj_rounding > 0.0f) && ((flags & ImDrawFlags_RoundCornersMask_) != ImDrawFlags_RoundCornersNone); // Do we have rounded corners?
  2234. if (is_rounded && !is_filled)
  2235. {
  2236. IM_ASSERT(_Path.Size == 0);
  2237. PathRect(obj_min, obj_max, obj_rounding, flags);
  2238. inner_rect_points_count = _Path.Size;
  2239. inner_rect_points = (ImVec2*)alloca(inner_rect_points_count * sizeof(ImVec2)); //-V630
  2240. memcpy(inner_rect_points, _Path.Data, inner_rect_points_count * sizeof(ImVec2));
  2241. _Path.Size = 0;
  2242. }
  2243. if (is_filled)
  2244. PrimReserve(6 * 9, 4 * 9); // Reserve space for adding unclipped chunks
  2245. // Draw the relevant chunks of the texture (the texture is split into a 3x3 grid)
  2246. // FIXME-OPT: Might make sense to optimize/unroll for the fast paths (filled or not rounded)
  2247. for (int x = 0; x < 3; x++)
  2248. {
  2249. for (int y = 0; y < 3; y++)
  2250. {
  2251. const int uv_index = x + (y + y + y); // y*3 formatted so as to ensure the compiler avoids an actual multiply
  2252. const ImVec4 uvs = _Data->ShadowRectUvs[uv_index];
  2253. ImVec2 draw_min, draw_max;
  2254. switch (x)
  2255. {
  2256. case 0: draw_min.x = obj_min.x - shadow_thickness; draw_max.x = obj_min.x; break;
  2257. case 1: draw_min.x = obj_min.x; draw_max.x = obj_max.x; break;
  2258. case 2: draw_min.x = obj_max.x; draw_max.x = obj_max.x + shadow_thickness; break;
  2259. }
  2260. switch (y)
  2261. {
  2262. case 0: draw_min.y = obj_min.y - shadow_thickness; draw_max.y = obj_min.y; break;
  2263. case 1: draw_min.y = obj_min.y; draw_max.y = obj_max.y; break;
  2264. case 2: draw_min.y = obj_max.y; draw_max.y = obj_max.y + shadow_thickness; break;
  2265. }
  2266. ImVec2 uv_min(uvs.x, uvs.y);
  2267. ImVec2 uv_max(uvs.z, uvs.w);
  2268. if (is_filled)
  2269. PrimRectUV(draw_min + shadow_offset, draw_max + shadow_offset, uv_min, uv_max, shadow_col); // No clipping path (draw entire shadow)
  2270. else if (is_rounded)
  2271. AddSubtractedRect(this, draw_min + shadow_offset, draw_max + shadow_offset, uv_min, uv_max, inner_rect_points, inner_rect_points_count, shadow_col); // Complex path for rounded rectangles
  2272. else
  2273. AddSubtractedRect(this, draw_min + shadow_offset, draw_max + shadow_offset, uv_min, uv_max, obj_min, obj_max, shadow_col); // Simple fast path for non-rounded rectangles
  2274. }
  2275. }
  2276. }
  2277. // Add a shadow for a convex shape described by points and num_points
  2278. void ImDrawList::AddShadowConvexPoly(const ImVec2* points, int points_count, ImU32 shadow_col, float shadow_thickness, const ImVec2& shadow_offset, ImDrawFlags flags)
  2279. {
  2280. const bool is_filled = (flags & ImDrawFlags_ShadowCutOutShapeBackground) == 0;
  2281. IM_ASSERT((is_filled || (ImLengthSqr(shadow_offset) < 0.00001f)) && "Drawing circle/convex shape shadows with no center fill and an offset is not currently supported");
  2282. IM_ASSERT(points_count >= 3);
  2283. // Calculate poly vertex order
  2284. const int vertex_winding = (((points[0].x * (points[1].y - points[2].y)) + (points[1].x * (points[2].y - points[0].y)) + (points[2].x * (points[0].y - points[1].y))) < 0.0f) ? -1 : 1;
  2285. // If we're using anti-aliasing, then inset the shadow by 0.5 pixels to avoid unpleasant fringing artifacts
  2286. const bool use_inset_distance = (Flags & ImDrawListFlags_AntiAliasedFill) && (!is_filled);
  2287. const float inset_distance = 0.5f;
  2288. const ImVec4 uvs = _Data->ShadowRectUvs[9];
  2289. int tex_width = _Data->Font->ContainerAtlas->TexData->Width;
  2290. int tex_height = _Data->Font->ContainerAtlas->TexData->Height;
  2291. float inv_tex_width = 1.0f / (float)tex_width;
  2292. float inv_tex_height = 1.0f / (float)tex_height;
  2293. ImVec2 solid_uv = ImVec2(uvs.z, uvs.w); // UV at the inside of an edge
  2294. ImVec2 edge_uv = ImVec2(uvs.x, uvs.w); // UV at the outside of an edge
  2295. ImVec2 solid_to_edge_delta_texels = edge_uv - solid_uv; // Delta between the solid/edge points in texel-space (we need this in pixels - or, to be more precise, to be at a 1:1 aspect ratio - for the rotation to work)
  2296. solid_to_edge_delta_texels.x *= (float)tex_width;
  2297. solid_to_edge_delta_texels.y *= (float)tex_height;
  2298. // Our basic algorithm here is that we generate a straight section along each edge, and then either one or two curved corner triangles at the corners,
  2299. // which use an appropriate chunk of the texture to generate a smooth curve.
  2300. const int num_edges = points_count;
  2301. // Normalize a vector
  2302. #define NORMALIZE(vec) ((vec) / ImLength((vec), 0.001f))
  2303. const int required_stack_mem = (num_edges * sizeof(ImVec2)) + (num_edges * sizeof(float));
  2304. ImU8* base_mem_for_normals_and_edges = (ImU8*)alloca(required_stack_mem);
  2305. ImU8* mem_for_normals_and_edges = (ImU8*)base_mem_for_normals_and_edges;
  2306. // Calculate edge normals
  2307. ImVec2* edge_normals = (ImVec2*)(void*)mem_for_normals_and_edges;
  2308. mem_for_normals_and_edges += num_edges * sizeof(ImVec2);
  2309. for (int edge_index = 0; edge_index < num_edges; edge_index++)
  2310. {
  2311. ImVec2 edge_start = points[edge_index]; // No need to apply offset here because the normal is unaffected
  2312. ImVec2 edge_end = points[(edge_index + 1) % num_edges];
  2313. ImVec2 edge_normal = NORMALIZE(ImVec2(edge_end.y - edge_start.y, -(edge_end.x - edge_start.x)));
  2314. edge_normals[edge_index] = edge_normal * (float)vertex_winding; // Flip normals for reverse winding
  2315. }
  2316. // Pre-calculate edge scales
  2317. // We need to do this because we need the edge strips to have widths that match up with the corner sections, otherwise pixel cracking can occur along the boundaries
  2318. float* edge_size_scales = (float*)(void*)mem_for_normals_and_edges;
  2319. mem_for_normals_and_edges += num_edges * sizeof(float);
  2320. IM_ASSERT_PARANOID(mem_for_normals_and_edges == (base_mem_for_normals_and_edges + required_stack_mem)); // Check we used exactly what we allocated
  2321. {
  2322. ImVec2 prev_edge_normal = edge_normals[num_edges - 1];
  2323. for (int edge_index = 0; edge_index < num_edges; edge_index++)
  2324. {
  2325. ImVec2 edge_normal = edge_normals[edge_index];
  2326. float cos_angle_coverage = ImDot(edge_normal, prev_edge_normal);
  2327. if (cos_angle_coverage < 0.999999f)
  2328. {
  2329. // If we are covering more than 90 degrees we need an intermediate vertex to stop the required expansion tending towards infinity.
  2330. // And thus the effective angle will be halved (matches the similar code in loop below)
  2331. float angle_coverage = ImAcos(cos_angle_coverage);
  2332. if (cos_angle_coverage <= 0.0f) // -V1051
  2333. angle_coverage *= 0.5f;
  2334. edge_size_scales[edge_index] = 1.0f / ImCos(angle_coverage * 0.5f); // How much we need to expand our size by to avoid clipping the corner of the texture off
  2335. }
  2336. else
  2337. {
  2338. edge_size_scales[edge_index] = 1.0f; // No corner, thus default scale
  2339. }
  2340. prev_edge_normal = edge_normal;
  2341. }
  2342. }
  2343. const int max_vertices = (4 + (3 * 2) + (is_filled ? 1 : 0)) * num_edges; // 4 vertices per edge plus 3*2 for potentially two corner triangles, plus one per vertex for fill
  2344. const int max_indices = ((6 + (3 * 2)) * num_edges) + (is_filled ? ((num_edges - 2) * 3) : 0); // 2 tris per edge plus up to two corner triangles, plus fill triangles
  2345. PrimReserve(max_indices, max_vertices);
  2346. ImDrawIdx* idx_write = _IdxWritePtr;
  2347. ImDrawVert* vtx_write = _VtxWritePtr;
  2348. ImDrawIdx current_idx = (ImDrawIdx)_VtxCurrentIdx;
  2349. //ImVec2 previous_edge_start = points[0] + offset;
  2350. ImVec2 prev_edge_normal = edge_normals[num_edges - 1];
  2351. ImVec2 edge_start = points[0] + shadow_offset;
  2352. if (use_inset_distance)
  2353. edge_start -= NORMALIZE(edge_normals[0] + prev_edge_normal) * inset_distance;
  2354. for (int edge_index = 0; edge_index < num_edges; edge_index++)
  2355. {
  2356. ImVec2 edge_end = points[(edge_index + 1) % num_edges] + shadow_offset;
  2357. ImVec2 edge_normal = edge_normals[edge_index];
  2358. const float size_scale_start = edge_size_scales[edge_index];
  2359. const float size_scale_end = edge_size_scales[(edge_index + 1) % num_edges];
  2360. if (use_inset_distance)
  2361. edge_end -= NORMALIZE(edge_normals[(edge_index + 1) % num_edges] + edge_normal) * inset_distance;
  2362. // Add corner section
  2363. float cos_angle_coverage = ImDot(edge_normal, prev_edge_normal);
  2364. if (cos_angle_coverage < 0.999999f) // Don't fill if the corner is actually straight
  2365. {
  2366. // If we are covering more than 90 degrees we need an intermediate vertex to stop the required expansion tending towards infinity.
  2367. // And thus the effective angle has been halved (matches the similar code in loop above)
  2368. int num_steps = (cos_angle_coverage <= 0.0f) ? 2 : 1;
  2369. for (int step = 0; step < num_steps; step++)
  2370. {
  2371. if (num_steps > 1)
  2372. {
  2373. if (step == 0)
  2374. edge_normal = NORMALIZE(edge_normal + prev_edge_normal); // Use half-way normal for first step
  2375. else
  2376. edge_normal = edge_normals[edge_index]; // Then use the "real" next edge normal for the second
  2377. cos_angle_coverage = ImDot(edge_normal, prev_edge_normal); // Recalculate angle
  2378. }
  2379. // Calculate UV for the section of the curved texture
  2380. const float angle_coverage = ImAcos(cos_angle_coverage);
  2381. const float sin_angle_coverage = ImSin(angle_coverage);
  2382. ImVec2 edge_delta = solid_to_edge_delta_texels;
  2383. edge_delta *= size_scale_start;
  2384. ImVec2 rotated_edge_delta = ImVec2((edge_delta.x * cos_angle_coverage) + (edge_delta.y * sin_angle_coverage), (edge_delta.x * sin_angle_coverage) + (edge_delta.y * cos_angle_coverage));
  2385. // Convert from texels back into UV space
  2386. edge_delta.x *= inv_tex_width;
  2387. edge_delta.y *= inv_tex_height;
  2388. rotated_edge_delta.x *= inv_tex_width;
  2389. rotated_edge_delta.y *= inv_tex_height;
  2390. ImVec2 expanded_edge_uv = solid_uv + edge_delta;
  2391. ImVec2 other_edge_uv = solid_uv + rotated_edge_delta; // Rotated UV to encompass the necessary section of the curve
  2392. float expanded_thickness = shadow_thickness * size_scale_start;
  2393. // Add a triangle to fill the corner
  2394. ImVec2 outer_edge_start = edge_start + (prev_edge_normal * expanded_thickness);
  2395. ImVec2 outer_edge_end = edge_start + (edge_normal * expanded_thickness);
  2396. vtx_write->pos = edge_start; vtx_write->col = shadow_col; vtx_write->uv = solid_uv; vtx_write++;
  2397. vtx_write->pos = outer_edge_end; vtx_write->col = shadow_col; vtx_write->uv = expanded_edge_uv; vtx_write++;
  2398. vtx_write->pos = outer_edge_start; vtx_write->col = shadow_col; vtx_write->uv = other_edge_uv; vtx_write++;
  2399. *(idx_write++) = current_idx;
  2400. *(idx_write++) = current_idx + 1;
  2401. *(idx_write++) = current_idx + 2;
  2402. current_idx += 3;
  2403. prev_edge_normal = edge_normal;
  2404. }
  2405. }
  2406. // Add section along edge
  2407. const float edge_length = ImLength(edge_end - edge_start, 0.0f);
  2408. if (edge_length > 0.00001f) // Don't try and process degenerate edges
  2409. {
  2410. ImVec2 outer_edge_start = edge_start + (edge_normal * shadow_thickness * size_scale_start);
  2411. ImVec2 outer_edge_end = edge_end + (edge_normal * shadow_thickness * size_scale_end);
  2412. ImVec2 scaled_edge_uv_start = solid_uv + ((edge_uv - solid_uv) * size_scale_start);
  2413. ImVec2 scaled_edge_uv_end = solid_uv + ((edge_uv - solid_uv) * size_scale_end);
  2414. // Write vertices, inner first, then outer
  2415. vtx_write->pos = edge_start; vtx_write->col = shadow_col; vtx_write->uv = solid_uv; vtx_write++;
  2416. vtx_write->pos = edge_end; vtx_write->col = shadow_col; vtx_write->uv = solid_uv; vtx_write++;
  2417. vtx_write->pos = outer_edge_end; vtx_write->col = shadow_col; vtx_write->uv = scaled_edge_uv_end; vtx_write++;
  2418. vtx_write->pos = outer_edge_start; vtx_write->col = shadow_col; vtx_write->uv = scaled_edge_uv_start; vtx_write++;
  2419. *(idx_write++) = current_idx;
  2420. *(idx_write++) = current_idx + 1;
  2421. *(idx_write++) = current_idx + 2;
  2422. *(idx_write++) = current_idx;
  2423. *(idx_write++) = current_idx + 2;
  2424. *(idx_write++) = current_idx + 3;
  2425. current_idx += 4;
  2426. }
  2427. edge_start = edge_end;
  2428. }
  2429. // Fill if requested
  2430. if (is_filled)
  2431. {
  2432. // Add vertices
  2433. for (int edge_index = 0; edge_index < num_edges; edge_index++)
  2434. {
  2435. vtx_write->pos = points[edge_index] + shadow_offset;
  2436. vtx_write->col = shadow_col;
  2437. vtx_write->uv = solid_uv;
  2438. vtx_write++;
  2439. }
  2440. // Add triangles
  2441. for (int edge_index = 2; edge_index < num_edges; edge_index++)
  2442. {
  2443. *(idx_write++) = current_idx;
  2444. *(idx_write++) = (ImDrawIdx)(current_idx + edge_index - 1);
  2445. *(idx_write++) = (ImDrawIdx)(current_idx + edge_index);
  2446. }
  2447. current_idx += (ImDrawIdx)num_edges;
  2448. }
  2449. // Release any unused vertices/indices
  2450. int used_indices = (int)(idx_write - _IdxWritePtr);
  2451. int used_vertices = (int)(vtx_write - _VtxWritePtr);
  2452. _IdxWritePtr = idx_write;
  2453. _VtxWritePtr = vtx_write;
  2454. _VtxCurrentIdx = current_idx;
  2455. PrimUnreserve(max_indices - used_indices, max_vertices - used_vertices);
  2456. #undef NORMALIZE
  2457. }
  2458. // Draw a shadow for a circular object
  2459. // Uses the draw path and so wipes any existing data there
  2460. void ImDrawList::AddShadowCircle(const ImVec2& obj_center, float obj_radius, ImU32 shadow_col, float shadow_thickness, const ImVec2& shadow_offset, ImDrawFlags flags, int num_segments)
  2461. {
  2462. // Obtain segment count
  2463. if (num_segments <= 0)
  2464. {
  2465. // Automatic segment count
  2466. const int radius_idx = (int)obj_radius - 1;
  2467. if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts))
  2468. num_segments = _Data->CircleSegmentCounts[radius_idx]; // Use cached value
  2469. else
  2470. num_segments = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(obj_radius, _Data->CircleSegmentMaxError);
  2471. }
  2472. else
  2473. {
  2474. // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
  2475. num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
  2476. }
  2477. // Generate a path describing the inner circle and copy it to our buffer
  2478. IM_ASSERT(_Path.Size == 0);
  2479. const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
  2480. if (num_segments == 12)
  2481. PathArcToFast(obj_center, obj_radius, 0, 12 - 1);
  2482. else
  2483. PathArcTo(obj_center, obj_radius, 0.0f, a_max, num_segments - 1);
  2484. // Draw the shadow using the convex shape code
  2485. AddShadowConvexPoly(_Path.Data, _Path.Size, shadow_col, shadow_thickness, shadow_offset, flags);
  2486. _Path.Size = 0;
  2487. }
  2488. void ImDrawList::AddShadowNGon(const ImVec2& obj_center, float obj_radius, ImU32 shadow_col, float shadow_thickness, const ImVec2& shadow_offset, ImDrawFlags flags, int num_segments)
  2489. {
  2490. IM_ASSERT(num_segments != 0);
  2491. AddShadowCircle(obj_center, obj_radius, shadow_col, shadow_thickness, shadow_offset, flags, num_segments);
  2492. }
  2493. //-----------------------------------------------------------------------------
  2494. // [SECTION] ImDrawListSplitter
  2495. //-----------------------------------------------------------------------------
  2496. // FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector swap..
  2497. //-----------------------------------------------------------------------------
  2498. void ImDrawListSplitter::ClearFreeMemory()
  2499. {
  2500. for (int i = 0; i < _Channels.Size; i++)
  2501. {
  2502. if (i == _Current)
  2503. memset(&_Channels[i], 0, sizeof(_Channels[i])); // Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again
  2504. _Channels[i]._CmdBuffer.clear();
  2505. _Channels[i]._IdxBuffer.clear();
  2506. }
  2507. _Current = 0;
  2508. _Count = 1;
  2509. _Channels.clear();
  2510. }
  2511. void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count)
  2512. {
  2513. IM_UNUSED(draw_list);
  2514. IM_ASSERT(_Current == 0 && _Count <= 1 && "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter.");
  2515. int old_channels_count = _Channels.Size;
  2516. if (old_channels_count < channels_count)
  2517. {
  2518. _Channels.reserve(channels_count); // Avoid over reserving since this is likely to stay stable
  2519. _Channels.resize(channels_count);
  2520. }
  2521. _Count = channels_count;
  2522. // Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer
  2523. // The content of Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to.
  2524. // When we switch to the next channel, we'll copy draw_list->_CmdBuffer/_IdxBuffer into Channels[0] and then Channels[1] into draw_list->CmdBuffer/_IdxBuffer
  2525. memset(&_Channels[0], 0, sizeof(ImDrawChannel));
  2526. for (int i = 1; i < channels_count; i++)
  2527. {
  2528. if (i >= old_channels_count)
  2529. {
  2530. IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel();
  2531. }
  2532. else
  2533. {
  2534. _Channels[i]._CmdBuffer.resize(0);
  2535. _Channels[i]._IdxBuffer.resize(0);
  2536. }
  2537. }
  2538. }
  2539. void ImDrawListSplitter::Merge(ImDrawList* draw_list)
  2540. {
  2541. // Note that we never use or rely on _Channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use.
  2542. if (_Count <= 1)
  2543. return;
  2544. SetCurrentChannel(draw_list, 0);
  2545. draw_list->_PopUnusedDrawCmd();
  2546. // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command.
  2547. int new_cmd_buffer_count = 0;
  2548. int new_idx_buffer_count = 0;
  2549. ImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL;
  2550. int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0;
  2551. for (int i = 1; i < _Count; i++)
  2552. {
  2553. ImDrawChannel& ch = _Channels[i];
  2554. if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0 && ch._CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd()
  2555. ch._CmdBuffer.pop_back();
  2556. if (ch._CmdBuffer.Size > 0 && last_cmd != NULL)
  2557. {
  2558. // Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values ourselves.
  2559. // Manipulating IdxOffset (e.g. by reordering draw commands like done by RenderDimmedBackgroundBehindWindow()) is not supported within a splitter.
  2560. ImDrawCmd* next_cmd = &ch._CmdBuffer[0];
  2561. if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL)
  2562. {
  2563. // Merge previous channel last draw command with current channel first draw command if matching.
  2564. last_cmd->ElemCount += next_cmd->ElemCount;
  2565. idx_offset += next_cmd->ElemCount;
  2566. ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges.
  2567. }
  2568. }
  2569. if (ch._CmdBuffer.Size > 0)
  2570. last_cmd = &ch._CmdBuffer.back();
  2571. new_cmd_buffer_count += ch._CmdBuffer.Size;
  2572. new_idx_buffer_count += ch._IdxBuffer.Size;
  2573. for (int cmd_n = 0; cmd_n < ch._CmdBuffer.Size; cmd_n++)
  2574. {
  2575. ch._CmdBuffer.Data[cmd_n].IdxOffset = idx_offset;
  2576. idx_offset += ch._CmdBuffer.Data[cmd_n].ElemCount;
  2577. }
  2578. }
  2579. draw_list->CmdBuffer.resize(draw_list->CmdBuffer.Size + new_cmd_buffer_count);
  2580. draw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count);
  2581. // Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices)
  2582. ImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count;
  2583. ImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count;
  2584. for (int i = 1; i < _Count; i++)
  2585. {
  2586. ImDrawChannel& ch = _Channels[i];
  2587. if (int sz = ch._CmdBuffer.Size) { memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; }
  2588. if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; }
  2589. }
  2590. draw_list->_IdxWritePtr = idx_write;
  2591. // Ensure there's always a non-callback draw command trailing the command-buffer
  2592. if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL)
  2593. draw_list->AddDrawCmd();
  2594. // If current command is used with different settings we need to add a new command
  2595. ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1];
  2596. if (curr_cmd->ElemCount == 0)
  2597. ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TexRef, VtxOffset
  2598. else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)
  2599. draw_list->AddDrawCmd();
  2600. _Count = 1;
  2601. }
  2602. void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx)
  2603. {
  2604. IM_ASSERT(idx >= 0 && idx < _Count);
  2605. if (_Current == idx)
  2606. return;
  2607. // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap()
  2608. memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer));
  2609. memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer));
  2610. _Current = idx;
  2611. memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer));
  2612. memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer));
  2613. draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size;
  2614. // If current command is used with different settings we need to add a new command
  2615. ImDrawCmd* curr_cmd = (draw_list->CmdBuffer.Size == 0) ? NULL : &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1];
  2616. if (curr_cmd == NULL)
  2617. draw_list->AddDrawCmd();
  2618. else if (curr_cmd->ElemCount == 0)
  2619. ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TexRef, VtxOffset
  2620. else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)
  2621. draw_list->AddDrawCmd();
  2622. }
  2623. //-----------------------------------------------------------------------------
  2624. // [SECTION] ImDrawData
  2625. //-----------------------------------------------------------------------------
  2626. void ImDrawData::Clear()
  2627. {
  2628. Valid = false;
  2629. CmdListsCount = TotalIdxCount = TotalVtxCount = 0;
  2630. CmdLists.resize(0); // The ImDrawList are NOT owned by ImDrawData but e.g. by ImGuiContext, so we don't clear them.
  2631. DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.0f, 0.0f);
  2632. OwnerViewport = NULL;
  2633. Textures = NULL;
  2634. }
  2635. // Important: 'out_list' is generally going to be draw_data->CmdLists, but may be another temporary list
  2636. // as long at it is expected that the result will be later merged into draw_data->CmdLists[].
  2637. void ImGui::AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)
  2638. {
  2639. if (draw_list->CmdBuffer.Size == 0)
  2640. return;
  2641. if (draw_list->CmdBuffer.Size == 1 && draw_list->CmdBuffer[0].ElemCount == 0 && draw_list->CmdBuffer[0].UserCallback == NULL)
  2642. return;
  2643. // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
  2644. // May trigger for you if you are using PrimXXX functions incorrectly.
  2645. IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
  2646. IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
  2647. if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))
  2648. IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
  2649. // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
  2650. // If this assert triggers because you are drawing lots of stuff manually:
  2651. // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
  2652. // Be mindful that the lower-level ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to inspect draw list contents.
  2653. // - If you want large meshes with more than 64K vertices, you can either:
  2654. // (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
  2655. // Most example backends already support this from 1.71. Pre-1.71 backends won't.
  2656. // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them.
  2657. // (B) Or handle 32-bit indices in your renderer backend, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
  2658. // Most example backends already support this. For example, the OpenGL example code detect index size at compile-time:
  2659. // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
  2660. // Your own engine or render API may use different parameters or function calls to specify index sizes.
  2661. // 2 and 4 bytes indices are generally supported by most graphics API.
  2662. // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
  2663. // the 64K limit to split your draw commands in multiple draw lists.
  2664. if (sizeof(ImDrawIdx) == 2)
  2665. IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
  2666. // Resolve callback data pointers
  2667. if (draw_list->_CallbacksDataBuf.Size > 0)
  2668. for (ImDrawCmd& cmd : draw_list->CmdBuffer)
  2669. if (cmd.UserCallback != NULL && cmd.UserCallbackDataOffset != -1 && cmd.UserCallbackDataSize > 0)
  2670. cmd.UserCallbackData = draw_list->_CallbacksDataBuf.Data + cmd.UserCallbackDataOffset;
  2671. // Add to output list + records state in ImDrawData
  2672. out_list->push_back(draw_list);
  2673. draw_data->CmdListsCount++;
  2674. draw_data->TotalVtxCount += draw_list->VtxBuffer.Size;
  2675. draw_data->TotalIdxCount += draw_list->IdxBuffer.Size;
  2676. }
  2677. void ImDrawData::AddDrawList(ImDrawList* draw_list)
  2678. {
  2679. IM_ASSERT(CmdLists.Size == CmdListsCount);
  2680. draw_list->_PopUnusedDrawCmd();
  2681. ImGui::AddDrawListToDrawDataEx(this, &CmdLists, draw_list);
  2682. }
  2683. // For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering!
  2684. void ImDrawData::DeIndexAllBuffers()
  2685. {
  2686. ImVector<ImDrawVert> new_vtx_buffer;
  2687. TotalVtxCount = TotalIdxCount = 0;
  2688. for (ImDrawList* draw_list : CmdLists)
  2689. {
  2690. if (draw_list->IdxBuffer.empty())
  2691. continue;
  2692. new_vtx_buffer.resize(draw_list->IdxBuffer.Size);
  2693. for (int j = 0; j < draw_list->IdxBuffer.Size; j++)
  2694. new_vtx_buffer[j] = draw_list->VtxBuffer[draw_list->IdxBuffer[j]];
  2695. draw_list->VtxBuffer.swap(new_vtx_buffer);
  2696. draw_list->IdxBuffer.resize(0);
  2697. TotalVtxCount += draw_list->VtxBuffer.Size;
  2698. }
  2699. }
  2700. // Helper to scale the ClipRect field of each ImDrawCmd.
  2701. // Use if your final output buffer is at a different scale than draw_data->DisplaySize,
  2702. // or if there is a difference between your window resolution and framebuffer resolution.
  2703. void ImDrawData::ScaleClipRects(const ImVec2& fb_scale)
  2704. {
  2705. for (ImDrawList* draw_list : CmdLists)
  2706. for (ImDrawCmd& cmd : draw_list->CmdBuffer)
  2707. cmd.ClipRect = ImVec4(cmd.ClipRect.x * fb_scale.x, cmd.ClipRect.y * fb_scale.y, cmd.ClipRect.z * fb_scale.x, cmd.ClipRect.w * fb_scale.y);
  2708. }
  2709. //-----------------------------------------------------------------------------
  2710. // [SECTION] Helpers ShadeVertsXXX functions
  2711. //-----------------------------------------------------------------------------
  2712. // Generic linear color gradient, write to RGB fields, leave A untouched.
  2713. void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1)
  2714. {
  2715. ImVec2 gradient_extent = gradient_p1 - gradient_p0;
  2716. float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent);
  2717. ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
  2718. ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
  2719. const int col0_r = (int)(col0 >> IM_COL32_R_SHIFT) & 0xFF;
  2720. const int col0_g = (int)(col0 >> IM_COL32_G_SHIFT) & 0xFF;
  2721. const int col0_b = (int)(col0 >> IM_COL32_B_SHIFT) & 0xFF;
  2722. const int col_delta_r = ((int)(col1 >> IM_COL32_R_SHIFT) & 0xFF) - col0_r;
  2723. const int col_delta_g = ((int)(col1 >> IM_COL32_G_SHIFT) & 0xFF) - col0_g;
  2724. const int col_delta_b = ((int)(col1 >> IM_COL32_B_SHIFT) & 0xFF) - col0_b;
  2725. for (ImDrawVert* vert = vert_start; vert < vert_end; vert++)
  2726. {
  2727. float d = ImDot(vert->pos - gradient_p0, gradient_extent);
  2728. float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f);
  2729. int r = (int)(col0_r + col_delta_r * t);
  2730. int g = (int)(col0_g + col_delta_g * t);
  2731. int b = (int)(col0_b + col_delta_b * t);
  2732. vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK);
  2733. }
  2734. }
  2735. // Distribute UV over (a, b) rectangle
  2736. void ImGui::ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp)
  2737. {
  2738. const ImVec2 size = b - a;
  2739. const ImVec2 uv_size = uv_b - uv_a;
  2740. const ImVec2 scale = ImVec2(
  2741. size.x != 0.0f ? (uv_size.x / size.x) : 0.0f,
  2742. size.y != 0.0f ? (uv_size.y / size.y) : 0.0f);
  2743. ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
  2744. ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
  2745. if (clamp)
  2746. {
  2747. const ImVec2 min = ImMin(uv_a, uv_b);
  2748. const ImVec2 max = ImMax(uv_a, uv_b);
  2749. for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
  2750. vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max);
  2751. }
  2752. else
  2753. {
  2754. for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
  2755. vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale);
  2756. }
  2757. }
  2758. void ImGui::ShadeVertsTransformPos(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& pivot_in, float cos_a, float sin_a, const ImVec2& pivot_out)
  2759. {
  2760. ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
  2761. ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
  2762. for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
  2763. vertex->pos = ImRotate(vertex->pos- pivot_in, cos_a, sin_a) + pivot_out;
  2764. }
  2765. //-----------------------------------------------------------------------------
  2766. // [SECTION] ImFontConfig
  2767. //-----------------------------------------------------------------------------
  2768. // FIXME-NEWATLAS: Oversample specification could be more dynamic. For now, favoring automatic selection.
  2769. ImFontConfig::ImFontConfig()
  2770. {
  2771. memset(this, 0, sizeof(*this));
  2772. FontDataOwnedByAtlas = true;
  2773. OversampleH = 0; // Auto == 1 or 2 depending on size
  2774. OversampleV = 0; // Auto == 1
  2775. GlyphMaxAdvanceX = FLT_MAX;
  2776. RasterizerMultiply = 1.0f;
  2777. RasterizerDensity = 1.0f;
  2778. EllipsisChar = 0;
  2779. }
  2780. //-----------------------------------------------------------------------------
  2781. // [SECTION] ImTextureData
  2782. //-----------------------------------------------------------------------------
  2783. // - ImTextureData::Create()
  2784. // - ImTextureData::DestroyPixels()
  2785. //-----------------------------------------------------------------------------
  2786. int ImTextureDataGetFormatBytesPerPixel(ImTextureFormat format)
  2787. {
  2788. switch (format)
  2789. {
  2790. case ImTextureFormat_Alpha8: return 1;
  2791. case ImTextureFormat_RGBA32: return 4;
  2792. }
  2793. IM_ASSERT(0);
  2794. return 0;
  2795. }
  2796. const char* ImTextureDataGetStatusName(ImTextureStatus status)
  2797. {
  2798. switch (status)
  2799. {
  2800. case ImTextureStatus_OK: return "OK";
  2801. case ImTextureStatus_Destroyed: return "Destroyed";
  2802. case ImTextureStatus_WantCreate: return "WantCreate";
  2803. case ImTextureStatus_WantUpdates: return "WantUpdates";
  2804. case ImTextureStatus_WantDestroy: return "WantDestroy";
  2805. }
  2806. return "N/A";
  2807. }
  2808. const char* ImTextureDataGetFormatName(ImTextureFormat format)
  2809. {
  2810. switch (format)
  2811. {
  2812. case ImTextureFormat_Alpha8: return "Alpha8";
  2813. case ImTextureFormat_RGBA32: return "RGBA32";
  2814. }
  2815. return "N/A";
  2816. }
  2817. void ImTextureData::Create(ImTextureFormat format, int w, int h)
  2818. {
  2819. IM_ASSERT(Status == ImTextureStatus_Destroyed);
  2820. DestroyPixels();
  2821. Format = format;
  2822. Status = ImTextureStatus_WantCreate;
  2823. Width = w;
  2824. Height = h;
  2825. BytesPerPixel = ImTextureDataGetFormatBytesPerPixel(format);
  2826. UseColors = false;
  2827. Pixels = (unsigned char*)IM_ALLOC(Width * Height * BytesPerPixel);
  2828. IM_ASSERT(Pixels != NULL);
  2829. memset(Pixels, 0, Width * Height * BytesPerPixel);
  2830. UsedRect.x = UsedRect.y = UsedRect.w = UsedRect.h = 0;
  2831. UpdateRect.x = UpdateRect.y = (unsigned short)~0;
  2832. UpdateRect.w = UpdateRect.h = 0;
  2833. }
  2834. void ImTextureData::DestroyPixels()
  2835. {
  2836. if (Pixels)
  2837. IM_FREE(Pixels);
  2838. Pixels = NULL;
  2839. UseColors = false;
  2840. }
  2841. //-----------------------------------------------------------------------------
  2842. // [SECTION] ImFontAtlas, ImFontAtlasBuilder
  2843. //-----------------------------------------------------------------------------
  2844. // - Default texture data encoded in ASCII
  2845. // - ImFontAtlas()
  2846. // - ImFontAtlas::Clear()
  2847. // - ImFontAtlas::CompactCache()
  2848. // - ImFontAtlas::ClearInputData()
  2849. // - ImFontAtlas::ClearTexData()
  2850. // - ImFontAtlas::ClearFonts()
  2851. //-----------------------------------------------------------------------------
  2852. // - ImFontAtlasUpdateNewFrame()
  2853. // - ImFontAtlasTextureBlockConvert()
  2854. // - ImFontAtlasTextureBlockPostProcess()
  2855. // - ImFontAtlasTextureBlockPostProcessMultiply()
  2856. // - ImFontAtlasTextureBlockFill()
  2857. // - ImFontAtlasTextureBlockCopy()
  2858. // - ImFontAtlasTextureBlockQueueUpload()
  2859. //-----------------------------------------------------------------------------
  2860. // - ImFontAtlas::GetTexDataAsAlpha8() [legacy]
  2861. // - ImFontAtlas::GetTexDataAsRGBA32() [legacy]
  2862. // - ImFontAtlas::Build() [legacy]
  2863. //-----------------------------------------------------------------------------
  2864. // - ImFontAtlas::AddFont()
  2865. // - ImFontAtlas::AddFontDefault()
  2866. // - ImFontAtlas::AddFontFromFileTTF()
  2867. // - ImFontAtlas::AddFontFromMemoryTTF()
  2868. // - ImFontAtlas::AddFontFromMemoryCompressedTTF()
  2869. // - ImFontAtlas::AddFontFromMemoryCompressedBase85TTF()
  2870. // - ImFontAtlas::RemoveFont()
  2871. // - ImFontAtlasBuildNotifySetFont()
  2872. //-----------------------------------------------------------------------------
  2873. // - ImFontAtlas::AddCustomRect()
  2874. // - ImFontAtlas::RemoveCustomRect()
  2875. // - ImFontAtlas::GetCustomRect()
  2876. // - ImFontAtlas::AddCustomRectFontGlyph() [legacy]
  2877. // - ImFontAtlas::AddCustomRectFontGlyphForSize() [legacy]
  2878. // - ImFontAtlasGetMouseCursorTexData()
  2879. //-----------------------------------------------------------------------------
  2880. // - ImFontAtlasBuildMain()
  2881. // - ImFontAtlasBuildSetupFontLoader()
  2882. // - ImFontAtlasBuildPreloadAllGlyphRanges()
  2883. // - ImFontAtlasBuildUpdatePointers()
  2884. // - ImFontAtlasBuildRenderBitmapFromString()
  2885. // - ImFontAtlasBuildUpdateBasicTexData()
  2886. // - ImFontAtlasBuildUpdateLinesTexData()
  2887. // - ImFontAtlasBuildAddFont()
  2888. // - ImFontAtlasBuildSetupFontBakedEllipsis()
  2889. // - ImFontAtlasBuildSetupFontBakedBlanks()
  2890. // - ImFontAtlasBuildSetupFontBakedFallback()
  2891. // - ImFontAtlasBuildSetupFontSpecialGlyphs()
  2892. // - ImFontAtlasBuildDiscardBakes()
  2893. // - ImFontAtlasBuildDiscardFontBakedGlyph()
  2894. // - ImFontAtlasBuildDiscardFontBaked()
  2895. // - ImFontAtlasBuildDiscardFontBakes()
  2896. //-----------------------------------------------------------------------------
  2897. // - ImFontAtlasAddDrawListSharedData()
  2898. // - ImFontAtlasRemoveDrawListSharedData()
  2899. // - ImFontAtlasUpdateDrawListsTextures()
  2900. // - ImFontAtlasUpdateDrawListsSharedData()
  2901. //-----------------------------------------------------------------------------
  2902. // - ImFontAtlasBuildSetTexture()
  2903. // - ImFontAtlasBuildAddTexture()
  2904. // - ImFontAtlasBuildMakeSpace()
  2905. // - ImFontAtlasBuildRepackTexture()
  2906. // - ImFontAtlasBuildGrowTexture()
  2907. // - ImFontAtlasBuildRepackOrGrowTexture()
  2908. // - ImFontAtlasBuildGetTextureSizeEstimate()
  2909. // - ImFontAtlasBuildCompactTexture()
  2910. // - ImFontAtlasBuildInit()
  2911. // - ImFontAtlasBuildDestroy()
  2912. //-----------------------------------------------------------------------------
  2913. // - ImFontAtlasPackInit()
  2914. // - ImFontAtlasPackAllocRectEntry()
  2915. // - ImFontAtlasPackReuseRectEntry()
  2916. // - ImFontAtlasPackDiscardRect()
  2917. // - ImFontAtlasPackAddRect()
  2918. // - ImFontAtlasPackGetRect()
  2919. //-----------------------------------------------------------------------------
  2920. // - ImFontBaked_BuildGrowIndex()
  2921. // - ImFontBaked_BuildLoadGlyph()
  2922. // - ImFontBaked_BuildLoadGlyphAdvanceX()
  2923. // - ImFontAtlasDebugLogTextureRequests()
  2924. //-----------------------------------------------------------------------------
  2925. // - ImFontAtlasGetFontLoaderForStbTruetype()
  2926. //-----------------------------------------------------------------------------
  2927. // A work of art lies ahead! (. = white layer, X = black layer, others are blank)
  2928. // The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes.
  2929. // (This is used when io.MouseDrawCursor = true)
  2930. const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 122; // Actual texture will be 2 times that + 1 spacing.
  2931. const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
  2932. static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =
  2933. {
  2934. "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX - XX XX "
  2935. "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X -X..X X..X"
  2936. "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X -X...X X...X"
  2937. "X - X.X - X.....X - X.....X -X...X - X...X- X..X - X...X X...X "
  2938. "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X - X...X...X "
  2939. "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX - X.....X "
  2940. "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX - X...X "
  2941. "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX - X.X "
  2942. "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X - X...X "
  2943. "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X- X.....X "
  2944. "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X- X...X...X "
  2945. "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X- X...X X...X "
  2946. "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X-X...X X...X"
  2947. "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X-X..X X..X"
  2948. "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X- XX XX "
  2949. "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X--------------"
  2950. "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X - "
  2951. "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X - "
  2952. "X.X X..X - -X.......X- X.......X - XX XX - - X..........X - "
  2953. "XX X..X - - X.....X - X.....X - X.X X.X - - X........X - "
  2954. " X..X - - X...X - X...X - X..X X..X - - X........X - "
  2955. " XX - - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX - "
  2956. "------------- - X - X -X.....................X- ------------------- "
  2957. " ----------------------------------- X...XXXXXXXXXXXXX...X - "
  2958. " - X..X X..X - "
  2959. " - X.X X.X - "
  2960. " - XX XX - "
  2961. };
  2962. static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] =
  2963. {
  2964. // Pos ........ Size ......... Offset ......
  2965. { ImVec2( 0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow
  2966. { ImVec2(13,0), ImVec2( 7,16), ImVec2( 1, 8) }, // ImGuiMouseCursor_TextInput
  2967. { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll
  2968. { ImVec2(21,0), ImVec2( 9,23), ImVec2( 4,11) }, // ImGuiMouseCursor_ResizeNS
  2969. { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, // ImGuiMouseCursor_ResizeEW
  2970. { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW
  2971. { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE
  2972. { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand
  2973. { ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Wait // Arrow + custom code in ImGui::RenderMouseCursor()
  2974. { ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Progress // Arrow + custom code in ImGui::RenderMouseCursor()
  2975. { ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed
  2976. };
  2977. #define IM_FONTGLYPH_INDEX_UNUSED ((ImU16)-1) // 0xFFFF
  2978. #define IM_FONTGLYPH_INDEX_NOT_FOUND ((ImU16)-2) // 0xFFFE
  2979. ImFontAtlas::ImFontAtlas()
  2980. {
  2981. memset(this, 0, sizeof(*this));
  2982. TexDesiredFormat = ImTextureFormat_RGBA32;
  2983. TexGlyphPadding = 1;
  2984. TexMinWidth = 512;
  2985. TexMinHeight = 128;
  2986. TexMaxWidth = 8192;
  2987. TexMaxHeight = 8192;
  2988. TexRef._TexID = ImTextureID_Invalid;
  2989. RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update.
  2990. TexNextUniqueID = 1;
  2991. FontNextUniqueID = 1;
  2992. Builder = NULL;
  2993. // FIXME-SHADOWS: move elsewhere?
  2994. ShadowRectIds[0] = ShadowRectIds[1] = -1;
  2995. ShadowTexConfig.SetupDefaults();
  2996. }
  2997. ImFontAtlas::~ImFontAtlas()
  2998. {
  2999. IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
  3000. RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't.
  3001. ClearFonts();
  3002. ClearTexData();
  3003. TexList.clear_delete();
  3004. TexData = NULL;
  3005. }
  3006. void ImFontAtlas::Clear()
  3007. {
  3008. bool backup_renderer_has_textures = RendererHasTextures;
  3009. RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't.
  3010. ClearFonts();
  3011. ClearTexData();
  3012. RendererHasTextures = backup_renderer_has_textures;
  3013. }
  3014. void ImFontAtlas::CompactCache()
  3015. {
  3016. ImFontAtlasTextureCompact(this);
  3017. }
  3018. void ImFontAtlas::SetFontLoader(const ImFontLoader* font_loader)
  3019. {
  3020. ImFontAtlasBuildSetupFontLoader(this, font_loader);
  3021. }
  3022. void ImFontAtlas::ClearInputData()
  3023. {
  3024. IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
  3025. for (ImFont* font : Fonts)
  3026. ImFontAtlasFontDestroyOutput(this, font);
  3027. for (ImFontConfig& font_cfg : Sources)
  3028. ImFontAtlasFontDestroySourceData(this, &font_cfg);
  3029. for (ImFont* font : Fonts)
  3030. {
  3031. // When clearing this we lose access to the font name and other information used to build the font.
  3032. font->Sources.clear();
  3033. font->Flags |= ImFontFlags_NoLoadGlyphs;
  3034. }
  3035. Sources.clear();
  3036. // FIXME-SHADOWS: Move elsewhere?
  3037. ShadowRectIds[0] = ShadowRectIds[1] = -1;
  3038. }
  3039. // Clear CPU-side copy of the texture data.
  3040. void ImFontAtlas::ClearTexData()
  3041. {
  3042. IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
  3043. IM_ASSERT(RendererHasTextures == false && "Not supported for dynamic atlases, but you may call Clear().");
  3044. for (ImTextureData* tex : TexList)
  3045. tex->DestroyPixels();
  3046. //Locked = true; // Hoped to be able to lock this down but some reload patterns may not be happy with it.
  3047. }
  3048. void ImFontAtlas::ClearFonts()
  3049. {
  3050. // FIXME-NEWATLAS: Illegal to remove currently bound font.
  3051. IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
  3052. ImFontAtlasBuildDestroy(this);
  3053. ClearInputData();
  3054. Fonts.clear_delete();
  3055. TexIsBuilt = false;
  3056. for (ImDrawListSharedData* shared_data : DrawListSharedDatas)
  3057. if (shared_data->FontAtlas == this)
  3058. {
  3059. shared_data->Font = NULL;
  3060. shared_data->FontScale = shared_data->FontSize = 0.0f;
  3061. }
  3062. }
  3063. static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* atlas)
  3064. {
  3065. // [LEGACY] Copy back the ImGuiBackendFlags_RendererHasTextures flag from ImGui context.
  3066. // - This is the 1% exceptional case where that dependency if useful, to bypass an issue where otherwise at the
  3067. // time of an early call to Build(), it would be impossible for us to tell if the backend supports texture update.
  3068. // - Without this hack, we would have quite a pitfall as many legacy codebases have an early call to Build().
  3069. // Whereas conversely, the portion of people using ImDrawList without ImGui is expected to be pathologically rare.
  3070. for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
  3071. if (ImGuiContext* imgui_ctx = shared_data->Context)
  3072. {
  3073. atlas->RendererHasTextures = (imgui_ctx->IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0;
  3074. break;
  3075. }
  3076. }
  3077. // Called by NewFrame() for atlases owned by a context.
  3078. // If you manually manage font atlases, you'll need to call this yourself.
  3079. // - 'frame_count' needs to be provided because we can gc/prioritize baked fonts based on their age.
  3080. // - 'frame_count' may not match those of all imgui contexts using this atlas, as contexts may be updated as different frequencies. But generally you can use ImGui::GetFrameCount() on one of your context.
  3081. void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool renderer_has_textures)
  3082. {
  3083. IM_ASSERT(atlas->Builder == NULL || atlas->Builder->FrameCount < frame_count); // Protection against being called twice.
  3084. atlas->RendererHasTextures = renderer_has_textures;
  3085. // Check that font atlas was built or backend support texture reload in which case we can build now
  3086. if (atlas->RendererHasTextures)
  3087. {
  3088. atlas->TexIsBuilt = true;
  3089. if (atlas->Builder == NULL) // This will only happen if fonts were not already loaded.
  3090. ImFontAtlasBuildMain(atlas);
  3091. }
  3092. // Legacy backend
  3093. if (!atlas->RendererHasTextures)
  3094. IM_ASSERT_USER_ERROR(atlas->TexIsBuilt, "Backend does not support ImGuiBackendFlags_RendererHasTextures, and font atlas is not built! Update backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8().");
  3095. if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges)
  3096. IM_ASSERT_USER_ERROR(atlas->RendererHasTextures == false, "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With new backends: you don't need to call Build().");
  3097. // Clear BakedCurrent cache, this is important because it ensure the uncached path gets taken once.
  3098. // We also rely on ImFontBaked* pointers never crossing frames.
  3099. ImFontAtlasBuilder* builder = atlas->Builder;
  3100. builder->FrameCount = frame_count;
  3101. for (ImFont* font : atlas->Fonts)
  3102. font->LastBaked = NULL;
  3103. // Garbage collect BakedPool
  3104. if (builder->BakedDiscardedCount > 0)
  3105. {
  3106. int dst_n = 0, src_n = 0;
  3107. for (; src_n < builder->BakedPool.Size; src_n++)
  3108. {
  3109. ImFontBaked* p_src = &builder->BakedPool[src_n];
  3110. if (p_src->WantDestroy)
  3111. continue;
  3112. ImFontBaked* p_dst = &builder->BakedPool[dst_n++];
  3113. if (p_dst == p_src)
  3114. continue;
  3115. memcpy(p_dst, p_src, sizeof(ImFontBaked));
  3116. builder->BakedMap.SetVoidPtr(p_dst->BakedId, p_dst);
  3117. }
  3118. IM_ASSERT(dst_n + builder->BakedDiscardedCount == src_n);
  3119. builder->BakedPool.Size -= builder->BakedDiscardedCount;
  3120. builder->BakedDiscardedCount = 0;
  3121. }
  3122. // Update texture status
  3123. for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++)
  3124. {
  3125. ImTextureData* tex = atlas->TexList[tex_n];
  3126. bool remove_from_list = false;
  3127. if (tex->Status == ImTextureStatus_OK)
  3128. {
  3129. tex->Updates.resize(0);
  3130. tex->UpdateRect.x = tex->UpdateRect.y = (unsigned short)~0;
  3131. tex->UpdateRect.w = tex->UpdateRect.h = 0;
  3132. }
  3133. if (tex->Status == ImTextureStatus_WantCreate && atlas->RendererHasTextures)
  3134. IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture's TexID/BackendUserData but did not update Status to OK.");
  3135. if (tex->Status == ImTextureStatus_Destroyed)
  3136. {
  3137. IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture Status to Destroyed but did not clear TexID/BackendUserData!");
  3138. if (tex->WantDestroyNextFrame)
  3139. remove_from_list = true; // Destroy was scheduled by us
  3140. else
  3141. tex->Status = ImTextureStatus_WantCreate; // Destroy was done was backend (e.g. freed resources mid-run)
  3142. }
  3143. else if (tex->WantDestroyNextFrame && tex->Status != ImTextureStatus_WantDestroy)
  3144. {
  3145. // Request destroy.
  3146. // - Keep bool to true in order to differentiate a planned destroy vs a destroy decided by the backend.
  3147. // - We don't destroy pixels right away, as backend may have an in-flight copy from RAM.
  3148. IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates);
  3149. tex->Status = ImTextureStatus_WantDestroy;
  3150. }
  3151. // The backend may need defer destroying by a few frames, to handle texture used by previous in-flight rendering.
  3152. // We allow the texture staying in _WantDestroy state and increment a counter which the backend can use to take its decision.
  3153. if (tex->Status == ImTextureStatus_WantDestroy)
  3154. tex->UnusedFrames++;
  3155. // If a texture has never reached the backend, they don't need to know about it.
  3156. if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL)
  3157. remove_from_list = true;
  3158. // Destroy and remove
  3159. if (remove_from_list)
  3160. {
  3161. tex->DestroyPixels();
  3162. IM_DELETE(tex);
  3163. atlas->TexList.erase(atlas->TexList.begin() + tex_n);
  3164. tex_n--;
  3165. }
  3166. }
  3167. }
  3168. void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h)
  3169. {
  3170. IM_ASSERT(src_pixels != NULL && dst_pixels != NULL);
  3171. if (src_fmt == dst_fmt)
  3172. {
  3173. int line_sz = w * ImTextureDataGetFormatBytesPerPixel(src_fmt);
  3174. for (int ny = h; ny > 0; ny--, src_pixels += src_pitch, dst_pixels += dst_pitch)
  3175. memcpy(dst_pixels, src_pixels, line_sz);
  3176. }
  3177. else if (src_fmt == ImTextureFormat_Alpha8 && dst_fmt == ImTextureFormat_RGBA32)
  3178. {
  3179. for (int ny = h; ny > 0; ny--, src_pixels += src_pitch, dst_pixels += dst_pitch)
  3180. {
  3181. const ImU8* src_p = (const ImU8*)src_pixels;
  3182. ImU32* dst_p = (ImU32*)(void*)dst_pixels;
  3183. for (int nx = w; nx > 0; nx--)
  3184. *dst_p++ = IM_COL32(255, 255, 255, (unsigned int)(*src_p++));
  3185. }
  3186. }
  3187. else if (src_fmt == ImTextureFormat_RGBA32 && dst_fmt == ImTextureFormat_Alpha8)
  3188. {
  3189. for (int ny = h; ny > 0; ny--, src_pixels += src_pitch, dst_pixels += dst_pitch)
  3190. {
  3191. const ImU32* src_p = (const ImU32*)(void*)src_pixels;
  3192. ImU8* dst_p = (ImU8*)dst_pixels;
  3193. for (int nx = w; nx > 0; nx--)
  3194. *dst_p++ = ((*src_p++) >> IM_COL32_A_SHIFT) & 0xFF;
  3195. }
  3196. }
  3197. else
  3198. {
  3199. IM_ASSERT(0);
  3200. }
  3201. }
  3202. // Source buffer may be written to (used for in-place mods).
  3203. // Post-process hooks may eventually be added here.
  3204. void ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData* data)
  3205. {
  3206. // Multiply operator (legacy)
  3207. if (data->FontSrc->RasterizerMultiply != 1.0f)
  3208. ImFontAtlasTextureBlockPostProcessMultiply(data, data->FontSrc->RasterizerMultiply);
  3209. }
  3210. void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data, float multiply_factor)
  3211. {
  3212. unsigned char* pixels = (unsigned char*)data->Pixels;
  3213. int pitch = data->Pitch;
  3214. if (data->Format == ImTextureFormat_Alpha8)
  3215. {
  3216. for (int ny = data->Height; ny > 0; ny--, pixels += pitch)
  3217. {
  3218. ImU8* p = (ImU8*)pixels;
  3219. for (int nx = data->Width; nx > 0; nx--, p++)
  3220. {
  3221. unsigned int v = ImMin((unsigned int)(*p * multiply_factor), (unsigned int)255);
  3222. *p = (unsigned char)v;
  3223. }
  3224. }
  3225. }
  3226. else if (data->Format == ImTextureFormat_RGBA32) //-V547
  3227. {
  3228. for (int ny = data->Height; ny > 0; ny--, pixels += pitch)
  3229. {
  3230. ImU32* p = (ImU32*)(void*)pixels;
  3231. for (int nx = data->Width; nx > 0; nx--, p++)
  3232. {
  3233. unsigned int a = ImMin((unsigned int)(((*p >> IM_COL32_A_SHIFT) & 0xFF) * multiply_factor), (unsigned int)255);
  3234. *p = IM_COL32((*p >> IM_COL32_R_SHIFT) & 0xFF, (*p >> IM_COL32_G_SHIFT) & 0xFF, (*p >> IM_COL32_B_SHIFT) & 0xFF, a);
  3235. }
  3236. }
  3237. }
  3238. else
  3239. {
  3240. IM_ASSERT(0);
  3241. }
  3242. }
  3243. // Fill with single color. We don't use this directly but it is convenient for anyone working on uploading custom rects.
  3244. void ImFontAtlasTextureBlockFill(ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h, ImU32 col)
  3245. {
  3246. if (dst_tex->Format == ImTextureFormat_Alpha8)
  3247. {
  3248. ImU8 col_a = (col >> IM_COL32_A_SHIFT) & 0xFF;
  3249. for (int y = 0; y < h; y++)
  3250. memset((ImU8*)dst_tex->GetPixelsAt(dst_x, dst_y + y), col_a, w);
  3251. }
  3252. else
  3253. {
  3254. for (int y = 0; y < h; y++)
  3255. {
  3256. ImU32* p = (ImU32*)(void*)dst_tex->GetPixelsAt(dst_x, dst_y + y);
  3257. for (int x = w; x > 0; x--, p++)
  3258. *p = col;
  3259. }
  3260. }
  3261. }
  3262. // Copy block from one texture to another
  3263. void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h)
  3264. {
  3265. IM_ASSERT(src_tex->Pixels != NULL && dst_tex->Pixels != NULL);
  3266. IM_ASSERT(src_tex->Format == dst_tex->Format);
  3267. IM_ASSERT(src_x >= 0 && src_x + w <= src_tex->Width);
  3268. IM_ASSERT(src_y >= 0 && src_y + h <= src_tex->Height);
  3269. IM_ASSERT(dst_x >= 0 && dst_x + w <= dst_tex->Width);
  3270. IM_ASSERT(dst_y >= 0 && dst_y + h <= dst_tex->Height);
  3271. for (int y = 0; y < h; y++)
  3272. memcpy(dst_tex->GetPixelsAt(dst_x, dst_y + y), src_tex->GetPixelsAt(src_x, src_y + y), w * dst_tex->BytesPerPixel);
  3273. }
  3274. // Queue texture block update for renderer backend
  3275. void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h)
  3276. {
  3277. IM_ASSERT(tex->Status != ImTextureStatus_WantDestroy && tex->Status != ImTextureStatus_Destroyed);
  3278. IM_ASSERT(x >= 0 && x <= 0xFFFF && y >= 0 && y <= 0xFFFF && w >= 0 && x + w <= 0x10000 && h >= 0 && y + h <= 0x10000);
  3279. IM_UNUSED(atlas);
  3280. ImTextureRect req = { (unsigned short)x, (unsigned short)y, (unsigned short)w, (unsigned short)h };
  3281. int new_x1 = ImMax(tex->UpdateRect.w == 0 ? 0 : tex->UpdateRect.x + tex->UpdateRect.w, req.x + req.w);
  3282. int new_y1 = ImMax(tex->UpdateRect.h == 0 ? 0 : tex->UpdateRect.y + tex->UpdateRect.h, req.y + req.h);
  3283. tex->UpdateRect.x = ImMin(tex->UpdateRect.x, req.x);
  3284. tex->UpdateRect.y = ImMin(tex->UpdateRect.y, req.y);
  3285. tex->UpdateRect.w = (unsigned short)(new_x1 - tex->UpdateRect.x);
  3286. tex->UpdateRect.h = (unsigned short)(new_y1 - tex->UpdateRect.y);
  3287. tex->UsedRect.x = ImMin(tex->UsedRect.x, req.x);
  3288. tex->UsedRect.y = ImMin(tex->UsedRect.y, req.y);
  3289. tex->UsedRect.w = (unsigned short)(ImMax(tex->UsedRect.x + tex->UsedRect.w, req.x + req.w) - tex->UsedRect.x);
  3290. tex->UsedRect.h = (unsigned short)(ImMax(tex->UsedRect.y + tex->UsedRect.h, req.y + req.h) - tex->UsedRect.y);
  3291. atlas->TexIsBuilt = false;
  3292. // No need to queue if status is == ImTextureStatus_WantCreate
  3293. if (tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantUpdates)
  3294. {
  3295. tex->Status = ImTextureStatus_WantUpdates;
  3296. tex->Updates.push_back(req);
  3297. }
  3298. }
  3299. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
  3300. static void GetTexDataAsFormat(ImFontAtlas* atlas, ImTextureFormat format, unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
  3301. {
  3302. ImTextureData* tex = atlas->TexData;
  3303. if (!atlas->TexIsBuilt || tex == NULL || tex->Pixels == NULL || atlas->TexDesiredFormat != format)
  3304. {
  3305. atlas->TexDesiredFormat = format;
  3306. atlas->Build();
  3307. tex = atlas->TexData;
  3308. }
  3309. if (out_pixels) { *out_pixels = (unsigned char*)tex->Pixels; };
  3310. if (out_width) { *out_width = tex->Width; };
  3311. if (out_height) { *out_height = tex->Height; };
  3312. if (out_bytes_per_pixel) { *out_bytes_per_pixel = tex->BytesPerPixel; }
  3313. }
  3314. void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
  3315. {
  3316. GetTexDataAsFormat(this, ImTextureFormat_Alpha8, out_pixels, out_width, out_height, out_bytes_per_pixel);
  3317. }
  3318. void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
  3319. {
  3320. GetTexDataAsFormat(this, ImTextureFormat_RGBA32, out_pixels, out_width, out_height, out_bytes_per_pixel);
  3321. }
  3322. bool ImFontAtlas::Build()
  3323. {
  3324. ImFontAtlasBuildMain(this);
  3325. return true;
  3326. }
  3327. #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
  3328. ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in)
  3329. {
  3330. // Sanity Checks
  3331. IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
  3332. IM_ASSERT((font_cfg_in->FontData != NULL && font_cfg_in->FontDataSize > 0) || (font_cfg_in->FontLoader != NULL));
  3333. //IM_ASSERT(font_cfg_in->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?");
  3334. IM_ASSERT(font_cfg_in->RasterizerDensity > 0.0f && "Is ImFontConfig struct correctly initialized?");
  3335. if (font_cfg_in->GlyphOffset.x != 0.0f || font_cfg_in->GlyphOffset.y != 0.0f || font_cfg_in->GlyphMinAdvanceX != 0.0f || font_cfg_in->GlyphMaxAdvanceX != FLT_MAX)
  3336. IM_ASSERT(font_cfg_in->SizePixels != 0.0f && "Specifying glyph offset/advances requires a reference size to base it on.");
  3337. // Lazily create builder on the first call to AddFont
  3338. if (Builder == NULL)
  3339. ImFontAtlasBuildInit(this);
  3340. // Create new font
  3341. ImFont* font;
  3342. if (!font_cfg_in->MergeMode)
  3343. {
  3344. font = IM_NEW(ImFont)();
  3345. font->FontId = FontNextUniqueID++;
  3346. font->Flags = font_cfg_in->Flags;
  3347. font->LegacySize = font_cfg_in->SizePixels;
  3348. font->CurrentRasterizerDensity = font_cfg_in->RasterizerDensity;
  3349. Fonts.push_back(font);
  3350. }
  3351. else
  3352. {
  3353. IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
  3354. font = Fonts.back();
  3355. }
  3356. // Add to list
  3357. Sources.push_back(*font_cfg_in);
  3358. ImFontConfig* font_cfg = &Sources.back();
  3359. if (font_cfg->DstFont == NULL)
  3360. font_cfg->DstFont = font;
  3361. font->Sources.push_back(font_cfg);
  3362. ImFontAtlasBuildUpdatePointers(this); // Pointers to Sources are otherwise dangling after we called Sources.push_back().
  3363. if (font_cfg->FontDataOwnedByAtlas == false)
  3364. {
  3365. font_cfg->FontDataOwnedByAtlas = true;
  3366. font_cfg->FontData = ImMemdup(font_cfg->FontData, (size_t)font_cfg->FontDataSize);
  3367. }
  3368. // Sanity check
  3369. // We don't round cfg.SizePixels yet as relative size of merged fonts are used afterwards.
  3370. if (font_cfg->GlyphExcludeRanges != NULL)
  3371. {
  3372. int size = 0;
  3373. for (const ImWchar* p = font_cfg->GlyphExcludeRanges; p[0] != 0; p++, size++) {}
  3374. IM_ASSERT((size & 1) == 0 && "GlyphExcludeRanges[] size must be multiple of two!");
  3375. IM_ASSERT((size <= 64) && "GlyphExcludeRanges[] size must be small!");
  3376. font_cfg->GlyphExcludeRanges = (ImWchar*)ImMemdup(font_cfg->GlyphExcludeRanges, sizeof(font_cfg->GlyphExcludeRanges[0]) * (size + 1));
  3377. }
  3378. if (font_cfg->FontLoader != NULL)
  3379. {
  3380. IM_ASSERT(font_cfg->FontLoader->FontBakedLoadGlyph != NULL);
  3381. IM_ASSERT(font_cfg->FontLoader->LoaderInit == NULL && font_cfg->FontLoader->LoaderShutdown == NULL); // FIXME-NEWATLAS: Unsupported yet.
  3382. }
  3383. IM_ASSERT(font_cfg->FontLoaderData == NULL);
  3384. if (!ImFontAtlasFontSourceInit(this, font_cfg))
  3385. {
  3386. // Rollback (this is a fragile/rarely exercised code-path. TestSuite's "misc_atlas_add_invalid_font" aim to test this)
  3387. ImFontAtlasFontDestroySourceData(this, font_cfg);
  3388. Sources.pop_back();
  3389. font->Sources.pop_back();
  3390. if (!font_cfg->MergeMode)
  3391. {
  3392. IM_DELETE(font);
  3393. Fonts.pop_back();
  3394. }
  3395. return NULL;
  3396. }
  3397. ImFontAtlasFontSourceAddToFont(this, font, font_cfg);
  3398. return font;
  3399. }
  3400. // Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder)
  3401. static unsigned int stb_decompress_length(const unsigned char* input);
  3402. static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length);
  3403. static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; }
  3404. static void Decode85(const unsigned char* src, unsigned char* dst)
  3405. {
  3406. while (*src)
  3407. {
  3408. unsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4]))));
  3409. dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness.
  3410. src += 5;
  3411. dst += 4;
  3412. }
  3413. }
  3414. #ifndef IMGUI_DISABLE_DEFAULT_FONT
  3415. static const char* GetDefaultCompressedFontDataTTF(int* out_size);
  3416. #endif
  3417. // Load embedded ProggyClean.ttf at size 13, disable oversampling
  3418. ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
  3419. {
  3420. #ifndef IMGUI_DISABLE_DEFAULT_FONT
  3421. ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
  3422. if (!font_cfg_template)
  3423. {
  3424. font_cfg.OversampleH = font_cfg.OversampleV = 1;
  3425. font_cfg.PixelSnapH = true;
  3426. }
  3427. if (font_cfg.SizePixels <= 0.0f)
  3428. font_cfg.SizePixels = 13.0f * 1.0f;
  3429. if (font_cfg.Name[0] == '\0')
  3430. ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf");
  3431. font_cfg.EllipsisChar = (ImWchar)0x0085;
  3432. font_cfg.GlyphOffset.y += 1.0f * IM_TRUNC(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units
  3433. int ttf_compressed_size = 0;
  3434. const char* ttf_compressed = GetDefaultCompressedFontDataTTF(&ttf_compressed_size);
  3435. const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault();
  3436. ImFont* font = AddFontFromMemoryCompressedTTF(ttf_compressed, ttf_compressed_size, font_cfg.SizePixels, &font_cfg, glyph_ranges);
  3437. return font;
  3438. #else
  3439. IM_ASSERT(0 && "AddFontDefault() disabled in this build.");
  3440. IM_UNUSED(font_cfg_template);
  3441. return NULL;
  3442. #endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT
  3443. }
  3444. ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
  3445. {
  3446. IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
  3447. size_t data_size = 0;
  3448. void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0);
  3449. if (!data)
  3450. {
  3451. if (font_cfg_template == NULL || (font_cfg_template->Flags & ImFontFlags_NoLoadError) == 0)
  3452. {
  3453. IMGUI_DEBUG_LOG("While loading '%s'\n", filename);
  3454. IM_ASSERT_USER_ERROR(0, "Could not load font file!");
  3455. }
  3456. return NULL;
  3457. }
  3458. ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
  3459. if (font_cfg.Name[0] == '\0')
  3460. {
  3461. // Store a short copy of filename into into the font name for convenience
  3462. const char* p;
  3463. for (p = filename + ImStrlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
  3464. ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s", p);
  3465. }
  3466. return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges);
  3467. }
  3468. // NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().
  3469. ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
  3470. {
  3471. IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
  3472. ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
  3473. IM_ASSERT(font_cfg.FontData == NULL);
  3474. IM_ASSERT(font_data_size > 100 && "Incorrect value for font_data_size!"); // Heuristic to prevent accidentally passing a wrong value to font_data_size.
  3475. font_cfg.FontData = font_data;
  3476. font_cfg.FontDataSize = font_data_size;
  3477. font_cfg.SizePixels = size_pixels > 0.0f ? size_pixels : font_cfg.SizePixels;
  3478. if (glyph_ranges)
  3479. font_cfg.GlyphRanges = glyph_ranges;
  3480. return AddFont(&font_cfg);
  3481. }
  3482. ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
  3483. {
  3484. const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data);
  3485. unsigned char* buf_decompressed_data = (unsigned char*)IM_ALLOC(buf_decompressed_size);
  3486. stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
  3487. ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
  3488. IM_ASSERT(font_cfg.FontData == NULL);
  3489. font_cfg.FontDataOwnedByAtlas = true;
  3490. return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges);
  3491. }
  3492. ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
  3493. {
  3494. int compressed_ttf_size = (((int)ImStrlen(compressed_ttf_data_base85) + 4) / 5) * 4;
  3495. void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size);
  3496. Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
  3497. ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
  3498. IM_FREE(compressed_ttf);
  3499. return font;
  3500. }
  3501. // On font removal we need to remove references (otherwise we could queue removal?)
  3502. // We allow old_font == new_font which forces updating all values (e.g. sizes)
  3503. static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, ImFont* new_font)
  3504. {
  3505. for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
  3506. {
  3507. if (shared_data->Font == old_font)
  3508. shared_data->Font = new_font;
  3509. if (ImGuiContext* ctx = shared_data->Context)
  3510. {
  3511. if (ctx->IO.FontDefault == old_font)
  3512. ctx->IO.FontDefault = new_font;
  3513. if (ctx->Font == old_font)
  3514. {
  3515. ImGuiContext* curr_ctx = ImGui::GetCurrentContext();
  3516. bool need_bind_ctx = ctx != curr_ctx;
  3517. if (need_bind_ctx)
  3518. ImGui::SetCurrentContext(ctx);
  3519. ImGui::SetCurrentFont(new_font, ctx->FontSizeBase, ctx->FontSize);
  3520. if (need_bind_ctx)
  3521. ImGui::SetCurrentContext(curr_ctx);
  3522. }
  3523. for (ImFontStackData& font_stack_data : ctx->FontStack)
  3524. if (font_stack_data.Font == old_font)
  3525. font_stack_data.Font = new_font;
  3526. }
  3527. }
  3528. }
  3529. void ImFontAtlas::RemoveFont(ImFont* font)
  3530. {
  3531. IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
  3532. font->ClearOutputData();
  3533. ImFontAtlasFontDestroyOutput(this, font);
  3534. for (ImFontConfig* src : font->Sources)
  3535. ImFontAtlasFontDestroySourceData(this, src);
  3536. for (int src_n = 0; src_n < Sources.Size; src_n++)
  3537. if (Sources[src_n].DstFont == font)
  3538. Sources.erase(&Sources[src_n--]);
  3539. bool removed = Fonts.find_erase(font);
  3540. IM_ASSERT(removed);
  3541. IM_UNUSED(removed);
  3542. ImFontAtlasBuildUpdatePointers(this);
  3543. font->ContainerAtlas = NULL;
  3544. IM_DELETE(font);
  3545. // Notify external systems
  3546. ImFont* new_current_font = Fonts.empty() ? NULL : Fonts[0];
  3547. ImFontAtlasBuildNotifySetFont(this, font, new_current_font);
  3548. }
  3549. // At it is common to do an AddCustomRect() followed by a GetCustomRect(), we provide an optional 'ImFontAtlasRect* out_r = NULL' argument to retrieve the info straight away.
  3550. ImFontAtlasRectId ImFontAtlas::AddCustomRect(int width, int height, ImFontAtlasRect* out_r)
  3551. {
  3552. IM_ASSERT(width > 0 && width <= 0xFFFF);
  3553. IM_ASSERT(height > 0 && height <= 0xFFFF);
  3554. if (Builder == NULL)
  3555. ImFontAtlasBuildInit(this);
  3556. ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height);
  3557. if (r_id == ImFontAtlasRectId_Invalid)
  3558. return ImFontAtlasRectId_Invalid;
  3559. if (out_r != NULL)
  3560. GetCustomRect(r_id, out_r);
  3561. if (RendererHasTextures)
  3562. {
  3563. ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id);
  3564. ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h);
  3565. }
  3566. return r_id;
  3567. }
  3568. void ImFontAtlas::RemoveCustomRect(ImFontAtlasRectId id)
  3569. {
  3570. if (ImFontAtlasPackGetRectSafe(this, id) == NULL)
  3571. return;
  3572. ImFontAtlasPackDiscardRect(this, id);
  3573. }
  3574. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
  3575. // This API does not make sense anymore with scalable fonts.
  3576. // - Prefer adding a font source (ImFontConfig) using a custom/procedural loader.
  3577. // - You may use ImFontFlags_LockBakedSizes to limit an existing font to known baked sizes:
  3578. // ImFont* myfont = io.Fonts->AddFontFromFileTTF(....);
  3579. // myfont->GetFontBaked(16.0f);
  3580. // myfont->Flags |= ImFontFlags_LockBakedSizes;
  3581. ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset)
  3582. {
  3583. float font_size = font->LegacySize;
  3584. return AddCustomRectFontGlyphForSize(font, font_size, codepoint, width, height, advance_x, offset);
  3585. }
  3586. // FIXME: we automatically set glyph.Colored=true by default.
  3587. // If you need to alter this, you can write 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph().
  3588. ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset)
  3589. {
  3590. #ifdef IMGUI_USE_WCHAR32
  3591. IM_ASSERT(codepoint <= IM_UNICODE_CODEPOINT_MAX);
  3592. #endif
  3593. IM_ASSERT(font != NULL);
  3594. IM_ASSERT(width > 0 && width <= 0xFFFF);
  3595. IM_ASSERT(height > 0 && height <= 0xFFFF);
  3596. ImFontBaked* baked = font->GetFontBaked(font_size);
  3597. ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height);
  3598. if (r_id == ImFontAtlasRectId_Invalid)
  3599. return ImFontAtlasRectId_Invalid;
  3600. ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id);
  3601. if (RendererHasTextures)
  3602. ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h);
  3603. if (baked->IsGlyphLoaded(codepoint))
  3604. ImFontAtlasBakedDiscardFontGlyph(this, font, baked, baked->FindGlyph(codepoint));
  3605. ImFontGlyph glyph;
  3606. glyph.Codepoint = codepoint;
  3607. glyph.AdvanceX = advance_x;
  3608. glyph.X0 = offset.x;
  3609. glyph.Y0 = offset.y;
  3610. glyph.X1 = offset.x + r->w;
  3611. glyph.Y1 = offset.y + r->h;
  3612. glyph.Visible = true;
  3613. glyph.Colored = true; // FIXME: Arbitrary
  3614. glyph.PackId = r_id;
  3615. ImFontAtlasBakedAddFontGlyph(this, baked, font->Sources[0], &glyph);
  3616. return r_id;
  3617. }
  3618. #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
  3619. bool ImFontAtlas::GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect* out_r) const
  3620. {
  3621. ImTextureRect* r = ImFontAtlasPackGetRectSafe((ImFontAtlas*)this, id);
  3622. if (r == NULL)
  3623. return false;
  3624. IM_ASSERT(TexData->Width > 0 && TexData->Height > 0); // Font atlas needs to be built before we can calculate UV coordinates
  3625. if (out_r == NULL)
  3626. return true;
  3627. out_r->x = r->x;
  3628. out_r->y = r->y;
  3629. out_r->w = r->w;
  3630. out_r->h = r->h;
  3631. out_r->uv0 = ImVec2((float)(r->x), (float)(r->y)) * TexUvScale;
  3632. out_r->uv1 = ImVec2((float)(r->x + r->w), (float)(r->y + r->h)) * TexUvScale;
  3633. return true;
  3634. }
  3635. bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2])
  3636. {
  3637. if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT)
  3638. return false;
  3639. if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors)
  3640. return false;
  3641. ImTextureRect* r = ImFontAtlasPackGetRect(atlas, atlas->Builder->PackIdMouseCursors);
  3642. ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->x, (float)r->y);
  3643. ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1];
  3644. *out_size = size;
  3645. *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2];
  3646. out_uv_border[0] = (pos) * atlas->TexUvScale;
  3647. out_uv_border[1] = (pos + size) * atlas->TexUvScale;
  3648. pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;
  3649. out_uv_fill[0] = (pos) * atlas->TexUvScale;
  3650. out_uv_fill[1] = (pos + size) * atlas->TexUvScale;
  3651. return true;
  3652. }
  3653. // When atlas->RendererHasTextures = true, this is only called if no font were loaded.
  3654. void ImFontAtlasBuildMain(ImFontAtlas* atlas)
  3655. {
  3656. IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!");
  3657. if (atlas->TexData && atlas->TexData->Format != atlas->TexDesiredFormat)
  3658. ImFontAtlasBuildClear(atlas);
  3659. if (atlas->Builder == NULL)
  3660. ImFontAtlasBuildInit(atlas);
  3661. // Default font is none are specified
  3662. if (atlas->Sources.Size == 0)
  3663. atlas->AddFontDefault();
  3664. // [LEGACY] For backends not supporting RendererHasTextures: preload all glyphs
  3665. ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas);
  3666. if (atlas->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures
  3667. ImFontAtlasBuildLegacyPreloadAllGlyphRanges(atlas);
  3668. atlas->TexIsBuilt = true;
  3669. }
  3670. void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, ImFontBaked* baked, int* out_oversample_h, int* out_oversample_v)
  3671. {
  3672. // Automatically disable horizontal oversampling over size 36
  3673. const float raster_size = baked->Size * baked->RasterizerDensity * src->RasterizerDensity;
  3674. *out_oversample_h = (src->OversampleH != 0) ? src->OversampleH : (raster_size > 36.0f || src->PixelSnapH) ? 1 : 2;
  3675. *out_oversample_v = (src->OversampleV != 0) ? src->OversampleV : 1;
  3676. }
  3677. // Setup main font loader for the atlas
  3678. // Every font source (ImFontConfig) will use this unless ImFontConfig::FontLoader specify a custom loader.
  3679. void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* font_loader)
  3680. {
  3681. if (atlas->FontLoader == font_loader)
  3682. return;
  3683. IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!");
  3684. for (ImFont* font : atlas->Fonts)
  3685. ImFontAtlasFontDestroyOutput(atlas, font);
  3686. if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderShutdown)
  3687. atlas->FontLoader->LoaderShutdown(atlas);
  3688. atlas->FontLoader = font_loader;
  3689. atlas->FontLoaderName = font_loader ? font_loader->Name : "NULL";
  3690. IM_ASSERT(atlas->FontLoaderData == NULL);
  3691. if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderInit)
  3692. atlas->FontLoader->LoaderInit(atlas);
  3693. for (ImFont* font : atlas->Fonts)
  3694. ImFontAtlasFontInitOutput(atlas, font);
  3695. for (ImFont* font : atlas->Fonts)
  3696. for (ImFontConfig* src : font->Sources)
  3697. ImFontAtlasFontSourceAddToFont(atlas, font, src);
  3698. }
  3699. // Preload all glyph ranges for legacy backends.
  3700. // This may lead to multiple texture creation which might be a little slower than before.
  3701. void ImFontAtlasBuildLegacyPreloadAllGlyphRanges(ImFontAtlas* atlas)
  3702. {
  3703. atlas->Builder->PreloadedAllGlyphsRanges = true;
  3704. for (ImFont* font : atlas->Fonts)
  3705. {
  3706. ImFontBaked* baked = font->GetFontBaked(font->LegacySize);
  3707. if (font->FallbackChar != 0)
  3708. baked->FindGlyph(font->FallbackChar);
  3709. if (font->EllipsisChar != 0)
  3710. baked->FindGlyph(font->EllipsisChar);
  3711. for (ImFontConfig* src : font->Sources)
  3712. {
  3713. const ImWchar* ranges = src->GlyphRanges ? src->GlyphRanges : atlas->GetGlyphRangesDefault();
  3714. for (; ranges[0]; ranges += 2)
  3715. for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560
  3716. baked->FindGlyph((ImWchar)c);
  3717. }
  3718. }
  3719. }
  3720. // FIXME: May make ImFont::Sources a ImSpan<> and move ownership to ImFontAtlas
  3721. void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas)
  3722. {
  3723. for (ImFont* font : atlas->Fonts)
  3724. font->Sources.resize(0);
  3725. for (ImFontConfig& src : atlas->Sources)
  3726. src.DstFont->Sources.push_back(&src);
  3727. }
  3728. // Render a white-colored bitmap encoded in a string
  3729. void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char)
  3730. {
  3731. ImTextureData* tex = atlas->TexData;
  3732. IM_ASSERT(x >= 0 && x + w <= tex->Width);
  3733. IM_ASSERT(y >= 0 && y + h <= tex->Height);
  3734. switch (tex->Format)
  3735. {
  3736. case ImTextureFormat_Alpha8:
  3737. {
  3738. ImU8* out_p = (ImU8*)tex->GetPixelsAt(x, y);
  3739. for (int off_y = 0; off_y < h; off_y++, out_p += tex->Width, in_str += w)
  3740. for (int off_x = 0; off_x < w; off_x++)
  3741. out_p[off_x] = (in_str[off_x] == in_marker_char) ? 0xFF : 0x00;
  3742. break;
  3743. }
  3744. case ImTextureFormat_RGBA32:
  3745. {
  3746. ImU32* out_p = (ImU32*)tex->GetPixelsAt(x, y);
  3747. for (int off_y = 0; off_y < h; off_y++, out_p += tex->Width, in_str += w)
  3748. for (int off_x = 0; off_x < w; off_x++)
  3749. out_p[off_x] = (in_str[off_x] == in_marker_char) ? IM_COL32_WHITE : IM_COL32_BLACK_TRANS;
  3750. break;
  3751. }
  3752. }
  3753. }
  3754. static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas)
  3755. {
  3756. // Pack and store identifier so we can refresh UV coordinates on texture resize.
  3757. // FIXME-NEWATLAS: User/custom rects where user code wants to store UV coordinates will need to do the same thing.
  3758. ImFontAtlasBuilder* builder = atlas->Builder;
  3759. ImVec2i pack_size = (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) ? ImVec2i(2, 2) : ImVec2i(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H);
  3760. ImFontAtlasRect r;
  3761. bool add_and_draw = (atlas->GetCustomRect(builder->PackIdMouseCursors, &r) == false);
  3762. if (add_and_draw)
  3763. {
  3764. builder->PackIdMouseCursors = atlas->AddCustomRect(pack_size.x, pack_size.y, &r);
  3765. IM_ASSERT(builder->PackIdMouseCursors != ImFontAtlasRectId_Invalid);
  3766. // Draw to texture
  3767. if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors)
  3768. {
  3769. // 2x2 white pixels
  3770. ImFontAtlasBuildRenderBitmapFromString(atlas, r.x, r.y, 2, 2, "XX" "XX", 'X');
  3771. }
  3772. else
  3773. {
  3774. // 2x2 white pixels + mouse cursors
  3775. const int x_for_white = r.x;
  3776. const int x_for_black = r.x + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;
  3777. ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_white, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.');
  3778. ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_black, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X');
  3779. }
  3780. }
  3781. // Refresh UV coordinates
  3782. atlas->TexUvWhitePixel = ImVec2((r.x + 0.5f) * atlas->TexUvScale.x, (r.y + 0.5f) * atlas->TexUvScale.y);
  3783. }
  3784. static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas)
  3785. {
  3786. if (atlas->Flags & ImFontAtlasFlags_NoBakedLines)
  3787. return;
  3788. // Pack and store identifier so we can refresh UV coordinates on texture resize.
  3789. ImTextureData* tex = atlas->TexData;
  3790. ImFontAtlasBuilder* builder = atlas->Builder;
  3791. ImFontAtlasRect r;
  3792. bool add_and_draw = atlas->GetCustomRect(builder->PackIdLinesTexData, &r) == false;
  3793. if (add_and_draw)
  3794. {
  3795. ImVec2i pack_size = ImVec2i(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1);
  3796. builder->PackIdLinesTexData = atlas->AddCustomRect(pack_size.x, pack_size.y, &r);
  3797. IM_ASSERT(builder->PackIdLinesTexData != ImFontAtlasRectId_Invalid);
  3798. }
  3799. // Register texture region for thick lines
  3800. // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row
  3801. // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them
  3802. for (int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row
  3803. {
  3804. // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle
  3805. const int y = n;
  3806. const int line_width = n;
  3807. const int pad_left = (r.w - line_width) / 2;
  3808. const int pad_right = r.w - (pad_left + line_width);
  3809. IM_ASSERT(pad_left + line_width + pad_right == r.w && y < r.h); // Make sure we're inside the texture bounds before we start writing pixels
  3810. // Write each slice
  3811. if (add_and_draw && tex->Format == ImTextureFormat_Alpha8)
  3812. {
  3813. ImU8* write_ptr = (ImU8*)tex->GetPixelsAt(r.x, r.y + y);
  3814. for (int i = 0; i < pad_left; i++)
  3815. *(write_ptr + i) = 0x00;
  3816. for (int i = 0; i < line_width; i++)
  3817. *(write_ptr + pad_left + i) = 0xFF;
  3818. for (int i = 0; i < pad_right; i++)
  3819. *(write_ptr + pad_left + line_width + i) = 0x00;
  3820. }
  3821. else if (add_and_draw && tex->Format == ImTextureFormat_RGBA32)
  3822. {
  3823. ImU32* write_ptr = (ImU32*)(void*)tex->GetPixelsAt(r.x, r.y + y);
  3824. for (int i = 0; i < pad_left; i++)
  3825. *(write_ptr + i) = IM_COL32(255, 255, 255, 0);
  3826. for (int i = 0; i < line_width; i++)
  3827. *(write_ptr + pad_left + i) = IM_COL32_WHITE;
  3828. for (int i = 0; i < pad_right; i++)
  3829. *(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0);
  3830. }
  3831. // Refresh UV coordinates
  3832. ImVec2 uv0 = ImVec2((float)(r.x + pad_left - 1), (float)(r.y + y)) * atlas->TexUvScale;
  3833. ImVec2 uv1 = ImVec2((float)(r.x + pad_left + line_width + 1), (float)(r.y + y + 1)) * atlas->TexUvScale;
  3834. float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts
  3835. atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v);
  3836. }
  3837. }
  3838. static void ImFontAtlasBuildUpdateShadowTexData(ImFontAtlas* atlas); // FIXME-SHADOWS: Move impl here.
  3839. //-----------------------------------------------------------------------------------------------------------------------------
  3840. // Was tempted to lazily init FontSrc but wouldn't save much + makes it more complicated to detect invalid data at AddFont()
  3841. bool ImFontAtlasFontInitOutput(ImFontAtlas* atlas, ImFont* font)
  3842. {
  3843. bool ret = true;
  3844. for (ImFontConfig* src : font->Sources)
  3845. if (!ImFontAtlasFontSourceInit(atlas, src))
  3846. ret = false;
  3847. IM_ASSERT(ret); // Unclear how to react to this meaningfully. Assume that result will be same as initial AddFont() call.
  3848. return ret;
  3849. }
  3850. // Keep source/input FontData
  3851. void ImFontAtlasFontDestroyOutput(ImFontAtlas* atlas, ImFont* font)
  3852. {
  3853. font->ClearOutputData();
  3854. for (ImFontConfig* src : font->Sources)
  3855. {
  3856. const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
  3857. if (loader && loader->FontSrcDestroy != NULL)
  3858. loader->FontSrcDestroy(atlas, src);
  3859. }
  3860. }
  3861. //-----------------------------------------------------------------------------------------------------------------------------
  3862. bool ImFontAtlasFontSourceInit(ImFontAtlas* atlas, ImFontConfig* src)
  3863. {
  3864. const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
  3865. if (loader->FontSrcInit != NULL && !loader->FontSrcInit(atlas, src))
  3866. return false;
  3867. return true;
  3868. }
  3869. void ImFontAtlasFontSourceAddToFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src)
  3870. {
  3871. if (src->MergeMode == false)
  3872. {
  3873. font->ClearOutputData();
  3874. //font->FontSize = src->SizePixels;
  3875. font->ContainerAtlas = atlas;
  3876. IM_ASSERT(font->Sources[0] == src);
  3877. }
  3878. atlas->TexIsBuilt = false; // For legacy backends
  3879. ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src);
  3880. }
  3881. void ImFontAtlasFontDestroySourceData(ImFontAtlas* atlas, ImFontConfig* src)
  3882. {
  3883. IM_UNUSED(atlas);
  3884. if (src->FontDataOwnedByAtlas)
  3885. IM_FREE(src->FontData);
  3886. src->FontData = NULL;
  3887. if (src->GlyphExcludeRanges)
  3888. IM_FREE((void*)src->GlyphExcludeRanges);
  3889. src->GlyphExcludeRanges = NULL;
  3890. }
  3891. // Create a compact, baked "..." if it doesn't exist, by using the ".".
  3892. // This may seem overly complicated right now but the point is to exercise and improve a technique which should be increasingly used.
  3893. // FIXME-NEWATLAS: This borrows too much from FontLoader's FontLoadGlyph() handlers and suggest that we should add further helpers.
  3894. static ImFontGlyph* ImFontAtlasBuildSetupFontBakedEllipsis(ImFontAtlas* atlas, ImFontBaked* baked)
  3895. {
  3896. ImFont* font = baked->ContainerFont;
  3897. IM_ASSERT(font->EllipsisChar != 0);
  3898. const ImFontGlyph* dot_glyph = baked->FindGlyphNoFallback((ImWchar)'.');
  3899. if (dot_glyph == NULL)
  3900. dot_glyph = baked->FindGlyphNoFallback((ImWchar)0xFF0E);
  3901. if (dot_glyph == NULL)
  3902. return NULL;
  3903. ImFontAtlasRectId dot_r_id = dot_glyph->PackId; // Deep copy to avoid invalidation of glyphs and rect pointers
  3904. ImTextureRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id);
  3905. const int dot_spacing = 1;
  3906. const float dot_step = (dot_glyph->X1 - dot_glyph->X0) + dot_spacing;
  3907. ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, (dot_r->w * 3 + dot_spacing * 2), dot_r->h);
  3908. ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
  3909. ImFontGlyph glyph_in = {};
  3910. ImFontGlyph* glyph = &glyph_in;
  3911. glyph->Codepoint = font->EllipsisChar;
  3912. glyph->AdvanceX = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + dot_step * 3.0f - dot_spacing); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents.
  3913. glyph->X0 = dot_glyph->X0;
  3914. glyph->Y0 = dot_glyph->Y0;
  3915. glyph->X1 = dot_glyph->X0 + dot_step * 3 - dot_spacing;
  3916. glyph->Y1 = dot_glyph->Y1;
  3917. glyph->Visible = true;
  3918. glyph->PackId = pack_id;
  3919. glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, NULL, glyph);
  3920. dot_glyph = NULL; // Invalidated
  3921. // Copy to texture, post-process and queue update for backend
  3922. // FIXME-NEWATLAS-V2: Dot glyph is already post-processed as this point, so this would damage it.
  3923. dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id);
  3924. ImTextureData* tex = atlas->TexData;
  3925. for (int n = 0; n < 3; n++)
  3926. ImFontAtlasTextureBlockCopy(tex, dot_r->x, dot_r->y, tex, r->x + (dot_r->w + dot_spacing) * n, r->y, dot_r->w, dot_r->h);
  3927. ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h);
  3928. return glyph;
  3929. }
  3930. // Load fallback in order to obtain its index
  3931. // (this is called from in hot-path so we avoid extraneous parameters to minimize impact on code size)
  3932. static void ImFontAtlasBuildSetupFontBakedFallback(ImFontBaked* baked)
  3933. {
  3934. IM_ASSERT(baked->FallbackGlyphIndex == -1);
  3935. IM_ASSERT(baked->FallbackAdvanceX == 0.0f);
  3936. ImFont* font = baked->ContainerFont;
  3937. ImFontGlyph* fallback_glyph = NULL;
  3938. if (font->FallbackChar != 0)
  3939. fallback_glyph = baked->FindGlyphNoFallback(font->FallbackChar);
  3940. if (fallback_glyph == NULL)
  3941. {
  3942. ImFontGlyph* space_glyph = baked->FindGlyphNoFallback((ImWchar)' ');
  3943. ImFontGlyph glyph;
  3944. glyph.Codepoint = 0;
  3945. glyph.AdvanceX = space_glyph ? space_glyph->AdvanceX : IM_ROUND(baked->Size * 0.40f);
  3946. fallback_glyph = ImFontAtlasBakedAddFontGlyph(font->ContainerAtlas, baked, NULL, &glyph);
  3947. }
  3948. baked->FallbackGlyphIndex = baked->Glyphs.index_from_ptr(fallback_glyph); // Storing index avoid need to update pointer on growth and simplify inner loop code
  3949. baked->FallbackAdvanceX = fallback_glyph->AdvanceX;
  3950. }
  3951. static void ImFontAtlasBuildSetupFontBakedBlanks(ImFontAtlas* atlas, ImFontBaked* baked)
  3952. {
  3953. // Mark space as always hidden (not strictly correct/necessary. but some e.g. icons fonts don't have a space. it tends to look neater in previews)
  3954. ImFontGlyph* space_glyph = baked->FindGlyphNoFallback((ImWchar)' ');
  3955. if (space_glyph != NULL)
  3956. space_glyph->Visible = false;
  3957. // Setup Tab character.
  3958. // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
  3959. if (baked->FindGlyphNoFallback('\t') == NULL && space_glyph != NULL)
  3960. {
  3961. ImFontGlyph tab_glyph;
  3962. tab_glyph.Codepoint = '\t';
  3963. tab_glyph.AdvanceX = space_glyph->AdvanceX * IM_TABSIZE;
  3964. ImFontAtlasBakedAddFontGlyph(atlas, baked, NULL, &tab_glyph);
  3965. }
  3966. }
  3967. // Load/identify special glyphs
  3968. // (note that this is called again for fonts with MergeMode)
  3969. void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src)
  3970. {
  3971. IM_UNUSED(atlas);
  3972. IM_ASSERT(font->Sources.contains(src));
  3973. // Find Fallback character. Actual glyph loaded in GetFontBaked().
  3974. const ImWchar fallback_chars[] = { font->FallbackChar, (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' };
  3975. if (font->FallbackChar == 0)
  3976. for (ImWchar candidate_char : fallback_chars)
  3977. if (candidate_char != 0 && font->IsGlyphInFont(candidate_char))
  3978. {
  3979. font->FallbackChar = (ImWchar)candidate_char;
  3980. break;
  3981. }
  3982. // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
  3983. // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
  3984. // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots.
  3985. const ImWchar ellipsis_chars[] = { src->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 };
  3986. if (font->EllipsisChar == 0)
  3987. for (ImWchar candidate_char : ellipsis_chars)
  3988. if (candidate_char != 0 && font->IsGlyphInFont(candidate_char))
  3989. {
  3990. font->EllipsisChar = candidate_char;
  3991. break;
  3992. }
  3993. if (font->EllipsisChar == 0)
  3994. {
  3995. font->EllipsisChar = 0x0085;
  3996. font->EllipsisAutoBake = true;
  3997. }
  3998. }
  3999. void ImFontAtlasBakedDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph)
  4000. {
  4001. if (glyph->PackId != ImFontAtlasRectId_Invalid)
  4002. {
  4003. ImFontAtlasPackDiscardRect(atlas, glyph->PackId);
  4004. glyph->PackId = ImFontAtlasRectId_Invalid;
  4005. }
  4006. ImWchar c = (ImWchar)glyph->Codepoint;
  4007. IM_ASSERT(font->FallbackChar != c && font->EllipsisChar != c); // Unsupported for simplicity
  4008. IM_ASSERT(glyph >= baked->Glyphs.Data && glyph < baked->Glyphs.Data + baked->Glyphs.Size);
  4009. IM_UNUSED(font);
  4010. baked->IndexLookup[c] = IM_FONTGLYPH_INDEX_UNUSED;
  4011. baked->IndexAdvanceX[c] = baked->FallbackAdvanceX;
  4012. }
  4013. ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density, ImGuiID baked_id)
  4014. {
  4015. IMGUI_DEBUG_LOG_FONT("[font] Created baked %.2fpx\n", font_size);
  4016. ImFontBaked* baked = atlas->Builder->BakedPool.push_back(ImFontBaked());
  4017. baked->Size = font_size;
  4018. baked->RasterizerDensity = font_rasterizer_density;
  4019. baked->BakedId = baked_id;
  4020. baked->ContainerFont = font;
  4021. baked->LastUsedFrame = atlas->Builder->FrameCount;
  4022. // Initialize backend data
  4023. size_t loader_data_size = 0;
  4024. for (ImFontConfig* src : font->Sources) // Cannot easily be cached as we allow changing backend
  4025. {
  4026. const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
  4027. loader_data_size += loader->FontBakedSrcLoaderDataSize;
  4028. }
  4029. baked->FontLoaderDatas = (loader_data_size > 0) ? IM_ALLOC(loader_data_size) : NULL;
  4030. char* loader_data_p = (char*)baked->FontLoaderDatas;
  4031. for (ImFontConfig* src : font->Sources)
  4032. {
  4033. const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
  4034. if (loader->FontBakedInit)
  4035. loader->FontBakedInit(atlas, src, baked, loader_data_p);
  4036. loader_data_p += loader->FontBakedSrcLoaderDataSize;
  4037. }
  4038. ImFontAtlasBuildSetupFontBakedBlanks(atlas, baked);
  4039. return baked;
  4040. }
  4041. // FIXME-OPT: This is not a fast query. Adding a BakedCount field in Font might allow to take a shortcut for the most common case.
  4042. ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density)
  4043. {
  4044. ImFontAtlasBuilder* builder = atlas->Builder;
  4045. for (int step_n = 0; step_n < 2; step_n++)
  4046. {
  4047. ImFontBaked* closest_larger_match = NULL;
  4048. ImFontBaked* closest_smaller_match = NULL;
  4049. for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++)
  4050. {
  4051. ImFontBaked* baked = &builder->BakedPool[baked_n];
  4052. if (baked->ContainerFont != font || baked->WantDestroy)
  4053. continue;
  4054. if (step_n == 0 && baked->RasterizerDensity != font_rasterizer_density) // First try with same density
  4055. continue;
  4056. if (baked->Size > font_size && (closest_larger_match == NULL || baked->Size < closest_larger_match->Size))
  4057. closest_larger_match = baked;
  4058. if (baked->Size < font_size && (closest_smaller_match == NULL || baked->Size > closest_smaller_match->Size))
  4059. closest_smaller_match = baked;
  4060. }
  4061. if (closest_larger_match)
  4062. if (closest_smaller_match == NULL || (closest_larger_match->Size >= font_size * 2.0f && closest_smaller_match->Size > font_size * 0.5f))
  4063. return closest_larger_match;
  4064. if (closest_smaller_match)
  4065. return closest_smaller_match;
  4066. }
  4067. return NULL;
  4068. }
  4069. void ImFontAtlasBakedDiscard(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked)
  4070. {
  4071. ImFontAtlasBuilder* builder = atlas->Builder;
  4072. IMGUI_DEBUG_LOG_FONT("[font] Discard baked %.2f for \"%s\"\n", baked->Size, font->GetDebugName());
  4073. for (ImFontGlyph& glyph : baked->Glyphs)
  4074. if (glyph.PackId != ImFontAtlasRectId_Invalid)
  4075. ImFontAtlasPackDiscardRect(atlas, glyph.PackId);
  4076. char* loader_data_p = (char*)baked->FontLoaderDatas;
  4077. for (ImFontConfig* src : font->Sources)
  4078. {
  4079. const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
  4080. if (loader->FontBakedDestroy)
  4081. loader->FontBakedDestroy(atlas, src, baked, loader_data_p);
  4082. loader_data_p += loader->FontBakedSrcLoaderDataSize;
  4083. }
  4084. if (baked->FontLoaderDatas)
  4085. {
  4086. IM_FREE(baked->FontLoaderDatas);
  4087. baked->FontLoaderDatas = NULL;
  4088. }
  4089. builder->BakedMap.SetVoidPtr(baked->BakedId, NULL);
  4090. builder->BakedDiscardedCount++;
  4091. baked->ClearOutputData();
  4092. baked->WantDestroy = true;
  4093. font->LastBaked = NULL;
  4094. }
  4095. // use unused_frames==0 to discard everything.
  4096. void ImFontAtlasFontDiscardBakes(ImFontAtlas* atlas, ImFont* font, int unused_frames)
  4097. {
  4098. if (ImFontAtlasBuilder* builder = atlas->Builder) // This can be called from font destructor
  4099. for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++)
  4100. {
  4101. ImFontBaked* baked = &builder->BakedPool[baked_n];
  4102. if (baked->LastUsedFrame + unused_frames > atlas->Builder->FrameCount)
  4103. continue;
  4104. if (baked->ContainerFont != font || baked->WantDestroy)
  4105. continue;
  4106. ImFontAtlasBakedDiscard(atlas, font, baked);
  4107. }
  4108. }
  4109. // use unused_frames==0 to discard everything.
  4110. void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames)
  4111. {
  4112. ImFontAtlasBuilder* builder = atlas->Builder;
  4113. for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++)
  4114. {
  4115. ImFontBaked* baked = &builder->BakedPool[baked_n];
  4116. if (baked->LastUsedFrame + unused_frames > atlas->Builder->FrameCount)
  4117. continue;
  4118. if (baked->WantDestroy || (baked->ContainerFont->Flags & ImFontFlags_LockBakedSizes))
  4119. continue;
  4120. ImFontAtlasBakedDiscard(atlas, baked->ContainerFont, baked);
  4121. }
  4122. }
  4123. // Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData*
  4124. void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data)
  4125. {
  4126. IM_ASSERT(!atlas->DrawListSharedDatas.contains(data));
  4127. atlas->DrawListSharedDatas.push_back(data);
  4128. }
  4129. void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data)
  4130. {
  4131. IM_ASSERT(atlas->DrawListSharedDatas.contains(data));
  4132. atlas->DrawListSharedDatas.find_erase(data);
  4133. }
  4134. // Update texture identifier in all active draw lists
  4135. void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex)
  4136. {
  4137. for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
  4138. for (ImDrawList* draw_list : shared_data->DrawLists)
  4139. {
  4140. // Replace in command-buffer
  4141. // (there is not need to replace in ImDrawListSplitter: current channel is in ImDrawList's CmdBuffer[],
  4142. // other channels will be on SetCurrentChannel() which already needs to compare CmdHeader anyhow)
  4143. if (draw_list->CmdBuffer.Size > 0 && draw_list->_CmdHeader.TexRef == old_tex)
  4144. draw_list->_SetTexture(new_tex);
  4145. // Replace in stack
  4146. for (ImTextureRef& stacked_tex : draw_list->_TextureStack)
  4147. if (stacked_tex == old_tex)
  4148. stacked_tex = new_tex;
  4149. }
  4150. }
  4151. // Update texture coordinates in all draw list shared context
  4152. // FIXME-NEWATLAS FIXME-OPT: Doesn't seem necessary to update for all, only one bound to current context?
  4153. void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas)
  4154. {
  4155. for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
  4156. if (shared_data->FontAtlas == atlas)
  4157. {
  4158. shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel;
  4159. shared_data->TexUvLines = atlas->TexUvLines;
  4160. }
  4161. }
  4162. // Set current texture. This is mostly called from AddTexture() + to handle a failed resize.
  4163. static void ImFontAtlasBuildSetTexture(ImFontAtlas* atlas, ImTextureData* tex)
  4164. {
  4165. ImTextureRef old_tex_ref = atlas->TexRef;
  4166. atlas->TexData = tex;
  4167. atlas->TexUvScale = ImVec2(1.0f / tex->Width, 1.0f / tex->Height);
  4168. atlas->TexRef._TexData = tex;
  4169. //atlas->TexRef._TexID = tex->TexID; // <-- We intentionally don't do that. It would be misleading and betray promise that both fields aren't set.
  4170. ImFontAtlasUpdateDrawListsTextures(atlas, old_tex_ref, atlas->TexRef);
  4171. }
  4172. // Create a new texture, discard previous one
  4173. ImTextureData* ImFontAtlasTextureAdd(ImFontAtlas* atlas, int w, int h)
  4174. {
  4175. ImTextureData* old_tex = atlas->TexData;
  4176. ImTextureData* new_tex;
  4177. // FIXME: Cannot reuse texture because old UV may have been used already (unless we remap UV).
  4178. /*if (old_tex != NULL && old_tex->Status == ImTextureStatus_WantCreate)
  4179. {
  4180. // Reuse texture not yet used by backend.
  4181. IM_ASSERT(old_tex->TexID == ImTextureID_Invalid && old_tex->BackendUserData == NULL);
  4182. old_tex->DestroyPixels();
  4183. old_tex->Updates.clear();
  4184. new_tex = old_tex;
  4185. old_tex = NULL;
  4186. }
  4187. else*/
  4188. {
  4189. // Add new
  4190. new_tex = IM_NEW(ImTextureData)();
  4191. new_tex->UniqueID = atlas->TexNextUniqueID++;
  4192. atlas->TexList.push_back(new_tex);
  4193. }
  4194. if (old_tex != NULL)
  4195. {
  4196. // Queue old as to destroy next frame
  4197. old_tex->WantDestroyNextFrame = true;
  4198. IM_ASSERT(old_tex->Status == ImTextureStatus_OK || old_tex->Status == ImTextureStatus_WantCreate || old_tex->Status == ImTextureStatus_WantUpdates);
  4199. }
  4200. new_tex->Create(atlas->TexDesiredFormat, w, h);
  4201. atlas->TexIsBuilt = false;
  4202. ImFontAtlasBuildSetTexture(atlas, new_tex);
  4203. return new_tex;
  4204. }
  4205. #if 0
  4206. #define STB_IMAGE_WRITE_IMPLEMENTATION
  4207. #include "../stb/stb_image_write.h"
  4208. static void ImFontAtlasDebugWriteTexToDisk(ImTextureData* tex, const char* description)
  4209. {
  4210. ImGuiContext& g = *GImGui;
  4211. char buf[128];
  4212. ImFormatString(buf, IM_ARRAYSIZE(buf), "[%05d] Texture #%03d - %s.png", g.FrameCount, tex->UniqueID, description);
  4213. stbi_write_png(buf, tex->Width, tex->Height, tex->BytesPerPixel, tex->Pixels, tex->GetPitch()); // tex->BytesPerPixel is technically not component, but ok for the formats we support.
  4214. }
  4215. #endif
  4216. void ImFontAtlasTextureRepack(ImFontAtlas* atlas, int w, int h)
  4217. {
  4218. ImFontAtlasBuilder* builder = atlas->Builder;
  4219. builder->LockDisableResize = true;
  4220. ImTextureData* old_tex = atlas->TexData;
  4221. ImTextureData* new_tex = ImFontAtlasTextureAdd(atlas, w, h);
  4222. new_tex->UseColors = old_tex->UseColors;
  4223. IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize+repack %dx%d => Texture #%03d: %dx%d\n", old_tex->UniqueID, old_tex->Width, old_tex->Height, new_tex->UniqueID, new_tex->Width, new_tex->Height);
  4224. //for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++)
  4225. // IMGUI_DEBUG_LOG_FONT("[font] - Baked %.2fpx, %d glyphs, want_destroy=%d\n", builder->BakedPool[baked_n].FontSize, builder->BakedPool[baked_n].Glyphs.Size, builder->BakedPool[baked_n].WantDestroy);
  4226. //IMGUI_DEBUG_LOG_FONT("[font] - Old packed rects: %d, area %d px\n", builder->RectsPackedCount, builder->RectsPackedSurface);
  4227. //ImFontAtlasDebugWriteTexToDisk(old_tex, "Before Pack");
  4228. // Repack, lose discarded rectangle, copy pixels
  4229. // FIXME-NEWATLAS: This is unstable because packing order is based on RectsIndex
  4230. // FIXME-NEWATLAS-V2: Repacking in batch would be beneficial to packing heuristic, and fix stability.
  4231. // FIXME-NEWATLAS-TESTS: Test calling RepackTexture with size too small to fits existing rects.
  4232. ImFontAtlasPackInit(atlas);
  4233. ImVector<ImTextureRect> old_rects;
  4234. ImVector<ImFontAtlasRectEntry> old_index = builder->RectsIndex;
  4235. old_rects.swap(builder->Rects);
  4236. for (ImFontAtlasRectEntry& index_entry : builder->RectsIndex)
  4237. {
  4238. if (index_entry.IsUsed == false)
  4239. continue;
  4240. ImTextureRect& old_r = old_rects[index_entry.TargetIndex];
  4241. if (old_r.w == 0 && old_r.h == 0)
  4242. continue;
  4243. ImFontAtlasRectId new_r_id = ImFontAtlasPackAddRect(atlas, old_r.w, old_r.h, &index_entry);
  4244. if (new_r_id == ImFontAtlasRectId_Invalid)
  4245. {
  4246. // Undo, grow texture and try repacking again.
  4247. // FIXME-NEWATLAS-TESTS: This is a very rarely exercised path! It needs to be automatically tested properly.
  4248. IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize failed. Will grow.\n", new_tex->UniqueID);
  4249. new_tex->WantDestroyNextFrame = true;
  4250. builder->Rects.swap(old_rects);
  4251. builder->RectsIndex = old_index;
  4252. ImFontAtlasBuildSetTexture(atlas, old_tex);
  4253. ImFontAtlasTextureGrow(atlas, w, h); // Recurse
  4254. return;
  4255. }
  4256. IM_ASSERT(ImFontAtlasRectId_GetIndex(new_r_id) == builder->RectsIndex.index_from_ptr(&index_entry));
  4257. ImTextureRect* new_r = ImFontAtlasPackGetRect(atlas, new_r_id);
  4258. ImFontAtlasTextureBlockCopy(old_tex, old_r.x, old_r.y, new_tex, new_r->x, new_r->y, new_r->w, new_r->h);
  4259. }
  4260. IM_ASSERT(old_rects.Size == builder->Rects.Size + builder->RectsDiscardedCount);
  4261. builder->RectsDiscardedCount = 0;
  4262. builder->RectsDiscardedSurface = 0;
  4263. // Patch glyphs UV
  4264. for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++)
  4265. for (ImFontGlyph& glyph : builder->BakedPool[baked_n].Glyphs)
  4266. if (glyph.PackId != ImFontAtlasRectId_Invalid)
  4267. {
  4268. ImTextureRect* r = ImFontAtlasPackGetRect(atlas, glyph.PackId);
  4269. glyph.U0 = (r->x) * atlas->TexUvScale.x;
  4270. glyph.V0 = (r->y) * atlas->TexUvScale.y;
  4271. glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x;
  4272. glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y;
  4273. }
  4274. // Update other cached UV
  4275. ImFontAtlasBuildUpdateLinesTexData(atlas);
  4276. ImFontAtlasBuildUpdateBasicTexData(atlas);
  4277. ImFontAtlasBuildUpdateShadowTexData(atlas);
  4278. builder->LockDisableResize = false;
  4279. ImFontAtlasUpdateDrawListsSharedData(atlas);
  4280. //ImFontAtlasDebugWriteTexToDisk(new_tex, "After Pack");
  4281. }
  4282. void ImFontAtlasTextureGrow(ImFontAtlas* atlas, int old_tex_w, int old_tex_h)
  4283. {
  4284. //ImFontAtlasDebugWriteTexToDisk(atlas->TexData, "Before Grow");
  4285. ImFontAtlasBuilder* builder = atlas->Builder;
  4286. if (old_tex_w == -1)
  4287. old_tex_w = atlas->TexData->Width;
  4288. if (old_tex_h == -1)
  4289. old_tex_h = atlas->TexData->Height;
  4290. // FIXME-NEWATLAS-V2: What to do when reaching limits exposed by backend?
  4291. // FIXME-NEWATLAS-V2: Does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' operations?
  4292. IM_ASSERT(ImIsPowerOfTwo(old_tex_w) && ImIsPowerOfTwo(old_tex_h));
  4293. IM_ASSERT(ImIsPowerOfTwo(atlas->TexMinWidth) && ImIsPowerOfTwo(atlas->TexMaxWidth) && ImIsPowerOfTwo(atlas->TexMinHeight) && ImIsPowerOfTwo(atlas->TexMaxHeight));
  4294. // Grow texture so it follows roughly a square.
  4295. // - Grow height before width, as width imply more packing nodes.
  4296. // - Caller should be taking account of RectsDiscardedSurface and may not need to grow.
  4297. int new_tex_w = (old_tex_h <= old_tex_w) ? old_tex_w : old_tex_w * 2;
  4298. int new_tex_h = (old_tex_h <= old_tex_w) ? old_tex_h * 2 : old_tex_h;
  4299. // Handle minimum size first (for pathologically large packed rects)
  4300. const int pack_padding = atlas->TexGlyphPadding;
  4301. new_tex_w = ImMax(new_tex_w, ImUpperPowerOfTwo(builder->MaxRectSize.x + pack_padding));
  4302. new_tex_h = ImMax(new_tex_h, ImUpperPowerOfTwo(builder->MaxRectSize.y + pack_padding));
  4303. new_tex_w = ImClamp(new_tex_w, atlas->TexMinWidth, atlas->TexMaxWidth);
  4304. new_tex_h = ImClamp(new_tex_h, atlas->TexMinHeight, atlas->TexMaxHeight);
  4305. if (new_tex_w == old_tex_w && new_tex_h == old_tex_h)
  4306. return;
  4307. ImFontAtlasTextureRepack(atlas, new_tex_w, new_tex_h);
  4308. }
  4309. void ImFontAtlasTextureMakeSpace(ImFontAtlas* atlas)
  4310. {
  4311. // Can some baked contents be ditched?
  4312. //IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlasBuildMakeSpace()\n");
  4313. ImFontAtlasBuilder* builder = atlas->Builder;
  4314. ImFontAtlasBuildDiscardBakes(atlas, 2);
  4315. // Currently using a heuristic for repack without growing.
  4316. if (builder->RectsDiscardedSurface < builder->RectsPackedSurface * 0.20f)
  4317. ImFontAtlasTextureGrow(atlas);
  4318. else
  4319. ImFontAtlasTextureRepack(atlas, atlas->TexData->Width, atlas->TexData->Height);
  4320. }
  4321. ImVec2i ImFontAtlasTextureGetSizeEstimate(ImFontAtlas* atlas)
  4322. {
  4323. int min_w = ImUpperPowerOfTwo(atlas->TexMinWidth);
  4324. int min_h = ImUpperPowerOfTwo(atlas->TexMinHeight);
  4325. if (atlas->Builder == NULL || atlas->TexData == NULL || atlas->TexData->Status == ImTextureStatus_WantDestroy)
  4326. return ImVec2i(min_w, min_h);
  4327. ImFontAtlasBuilder* builder = atlas->Builder;
  4328. min_w = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.x), min_w);
  4329. min_h = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.y), min_h);
  4330. const int surface_approx = builder->RectsPackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack
  4331. const int surface_sqrt = (int)sqrtf((float)surface_approx);
  4332. int new_tex_w;
  4333. int new_tex_h;
  4334. if (min_w >= min_h)
  4335. {
  4336. new_tex_w = ImMax(min_w, ImUpperPowerOfTwo(surface_sqrt));
  4337. new_tex_h = ImMax(min_h, (int)((surface_approx + new_tex_w - 1) / new_tex_w));
  4338. if ((atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) == 0)
  4339. new_tex_h = ImUpperPowerOfTwo(new_tex_h);
  4340. }
  4341. else
  4342. {
  4343. new_tex_h = ImMax(min_h, ImUpperPowerOfTwo(surface_sqrt));
  4344. if ((atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) == 0)
  4345. new_tex_h = ImUpperPowerOfTwo(new_tex_h);
  4346. new_tex_w = ImMax(min_w, (int)((surface_approx + new_tex_h - 1) / new_tex_h));
  4347. }
  4348. IM_ASSERT(ImIsPowerOfTwo(new_tex_w) && ImIsPowerOfTwo(new_tex_h));
  4349. return ImVec2i(new_tex_w, new_tex_h);
  4350. }
  4351. // Clear all output. Invalidates all AddCustomRect() return values!
  4352. void ImFontAtlasBuildClear(ImFontAtlas* atlas)
  4353. {
  4354. ImVec2i new_tex_size = ImFontAtlasTextureGetSizeEstimate(atlas);
  4355. ImFontAtlasBuildDestroy(atlas);
  4356. ImFontAtlasTextureAdd(atlas, new_tex_size.x, new_tex_size.y);
  4357. ImFontAtlasBuildInit(atlas);
  4358. for (ImFontConfig& src : atlas->Sources)
  4359. ImFontAtlasFontSourceInit(atlas, &src);
  4360. for (ImFont* font : atlas->Fonts)
  4361. for (ImFontConfig* src : font->Sources)
  4362. ImFontAtlasFontSourceAddToFont(atlas, font, src);
  4363. }
  4364. // You should not need to call this manually!
  4365. // If you think you do, let us know and we can advise about policies auto-compact.
  4366. void ImFontAtlasTextureCompact(ImFontAtlas* atlas)
  4367. {
  4368. ImFontAtlasBuilder* builder = atlas->Builder;
  4369. ImFontAtlasBuildDiscardBakes(atlas, 1);
  4370. ImTextureData* old_tex = atlas->TexData;
  4371. ImVec2i old_tex_size = ImVec2i(old_tex->Width, old_tex->Height);
  4372. ImVec2i new_tex_size = ImFontAtlasTextureGetSizeEstimate(atlas);
  4373. if (builder->RectsDiscardedCount == 0 && new_tex_size.x == old_tex_size.x && new_tex_size.y == old_tex_size.y)
  4374. return;
  4375. ImFontAtlasTextureRepack(atlas, new_tex_size.x, new_tex_size.y);
  4376. }
  4377. // Calculates the signed distance from sample_pos to the nearest point on the rectangle defined by rect_min->rect_max
  4378. static float DistanceFromRectangle(const ImVec2& sample_pos, const ImVec2& rect_min, const ImVec2& rect_max)
  4379. {
  4380. ImVec2 rect_centre = (rect_min + rect_max) * 0.5f;
  4381. ImVec2 rect_half_size = (rect_max - rect_min) * 0.5f;
  4382. ImVec2 local_sample_pos = sample_pos - rect_centre;
  4383. ImVec2 axis_dist = ImVec2(ImFabs(local_sample_pos.x), ImFabs(local_sample_pos.y)) - rect_half_size;
  4384. float out_dist = ImLength(ImVec2(ImMax(axis_dist.x, 0.0f), ImMax(axis_dist.y, 0.0f)), 0.00001f);
  4385. float in_dist = ImMin(ImMax(axis_dist.x, axis_dist.y), 0.0f);
  4386. return out_dist + in_dist;
  4387. }
  4388. // Calculates the signed distance from sample_pos to the point given
  4389. static float DistanceFromPoint(const ImVec2& sample_pos, const ImVec2& point)
  4390. {
  4391. return ImLength(sample_pos - point, 0.0f);
  4392. }
  4393. // Perform a single Gaussian blur pass with a fixed kernel size and sigma
  4394. static void GaussianBlurPass(float* src, float* dest, int size, bool horizontal)
  4395. {
  4396. // See http://dev.theomader.com/gaussian-kernel-calculator/
  4397. const float coefficients[] = { 0.0f, 0.0f, 0.000003f, 0.000229f, 0.005977f, 0.060598f, 0.24173f, 0.382925f, 0.24173f, 0.060598f, 0.005977f, 0.000229f, 0.000003f, 0.0f, 0.0f };
  4398. const int kernel_size = IM_ARRAYSIZE(coefficients);
  4399. const int sample_step = horizontal ? 1 : size;
  4400. float* read_ptr = src;
  4401. float* write_ptr = dest;
  4402. for (int y = 0; y < size; y++)
  4403. for (int x = 0; x < size; x++)
  4404. {
  4405. float result = 0.0f;
  4406. int current_offset = (horizontal ? x : y) - ((kernel_size - 1) >> 1);
  4407. float* sample_ptr = read_ptr - (((kernel_size - 1) >> 1) * sample_step);
  4408. for (int j = 0; j < kernel_size; j++)
  4409. {
  4410. if (current_offset >= 0 && current_offset < size)
  4411. result += (*sample_ptr) * coefficients[j];
  4412. current_offset++;
  4413. sample_ptr += sample_step;
  4414. }
  4415. read_ptr++;
  4416. *(write_ptr++) = result;
  4417. }
  4418. }
  4419. // Perform an in-place Gaussian blur of a square array of floats with a fixed kernel size and sigma
  4420. // Uses a stack allocation for the temporary data so potentially dangerous with large size values
  4421. static void GaussianBlur(float* data, int size)
  4422. {
  4423. // Do two passes, one from data into temp and then the second back to data again
  4424. float* temp = (float*)alloca(size * size * sizeof(float));
  4425. GaussianBlurPass(data, temp, size, true);
  4426. GaussianBlurPass(temp, data, size, false);
  4427. }
  4428. // Generate the actual pixel data for rounded corners in the atlas
  4429. static void ImFontAtlasBuildUpdateShadowTexData(ImFontAtlas* atlas)
  4430. {
  4431. // The actual size we want to reserve, including padding
  4432. const ImFontAtlasShadowTexConfig* shadow_cfg = &atlas->ShadowTexConfig;
  4433. const unsigned int effective_size = shadow_cfg->CalcRectTexSize() + shadow_cfg->GetRectTexPadding();
  4434. const int corner_size = shadow_cfg->TexCornerSize;
  4435. const int edge_size = shadow_cfg->TexEdgeSize;
  4436. // Because of the blur, we have to generate the full 3x3 texture here, and then we chop that down to just the 2x2 section we need later.
  4437. // 'size' correspond to the our 3x3 size, whereas 'shadow_tex_size' correspond to our 2x2 version where duplicate mirrored corners are not stored.
  4438. // The rectangular shadow texture
  4439. ImFontAtlasRect r;
  4440. bool add_and_draw = (atlas->GetCustomRect(atlas->ShadowRectIds[0], &r) == false);
  4441. if (add_and_draw)
  4442. {
  4443. atlas->ShadowRectIds[0] = atlas->AddCustomRect(effective_size, effective_size, &r);
  4444. IM_ASSERT(atlas->ShadowRectIds[0] != ImFontAtlasRectId_Invalid);
  4445. const int size = shadow_cfg->TexCornerSize + shadow_cfg->TexEdgeSize + shadow_cfg->TexCornerSize;
  4446. // The bounds of the rectangle we are generating the shadow from
  4447. const ImVec2 shadow_rect_min((float)corner_size, (float)corner_size);
  4448. const ImVec2 shadow_rect_max((float)(corner_size + edge_size), (float)(corner_size + edge_size));
  4449. // Remove the padding we added
  4450. const int padding = shadow_cfg->GetRectTexPadding();
  4451. r.x += (unsigned short)padding;
  4452. r.y += (unsigned short)padding;
  4453. r.w -= (unsigned short)padding * 2;
  4454. r.h -= (unsigned short)padding * 2;
  4455. // Generate distance field
  4456. // We draw the actual texture content by evaluating the distance field for the inner rectangle
  4457. float* tex_data = (float*)alloca(size * size * sizeof(float));
  4458. for (int y = 0; y < size; y++)
  4459. for (int x = 0; x < size; x++)
  4460. {
  4461. float dist = DistanceFromRectangle(ImVec2((float)x, (float)y), shadow_rect_min, shadow_rect_max);
  4462. float alpha = 1.0f - ImMin(ImMax(dist + shadow_cfg->TexDistanceFieldOffset, 0.0f) / ImMax(shadow_cfg->TexCornerSize + shadow_cfg->TexDistanceFieldOffset, 0.001f), 1.0f);
  4463. alpha = ImPow(alpha, shadow_cfg->TexFalloffPower); // Apply power curve to give a nicer falloff
  4464. tex_data[x + (y * size)] = alpha;
  4465. }
  4466. // Blur
  4467. if (shadow_cfg->TexBlur)
  4468. GaussianBlur(tex_data, size);
  4469. // Copy to texture, truncating to the actual required texture size (the bottom/right of the source data is chopped off, as we don't need it - see below). The truncated size is essentially the top 2x2 of our data, plus a little bit of padding for sampling.
  4470. ImTextureData* tex = atlas->TexData;
  4471. const int shadow_tex_size = shadow_cfg->CalcRectTexSize();
  4472. for (int y = 0; y < shadow_tex_size; y++)
  4473. for (int x = 0; x < shadow_tex_size; x++)
  4474. {
  4475. const float alpha_f = tex_data[x + (y * size)];
  4476. const unsigned char alpha_8 = (unsigned char)(0xFF * alpha_f);
  4477. // FIXME-SHADOWS: May be optimized.
  4478. switch (atlas->TexData->Format)
  4479. {
  4480. case ImTextureFormat_Alpha8:
  4481. {
  4482. ImU8* out_p = (ImU8*)(void*)tex->GetPixelsAt(r.x + x, r.y + y);
  4483. *out_p = alpha_8;
  4484. break;
  4485. }
  4486. case ImTextureFormat_RGBA32:
  4487. {
  4488. ImU32* out_p = (ImU32*)(void*)tex->GetPixelsAt(r.x + x, r.y + y);
  4489. *out_p = IM_COL32(255, 255, 255, alpha_8);;
  4490. break;
  4491. }
  4492. }
  4493. }
  4494. }
  4495. // Refresh UV coordinates
  4496. // Generate UVs for each of the nine sections, which are arranged in a 3x3 grid starting from 0 in the top-left and going across then down
  4497. if (atlas->GetCustomRect(atlas->ShadowRectIds[0], &r))
  4498. {
  4499. // Remove the padding we added
  4500. const int padding = shadow_cfg->GetRectTexPadding();
  4501. r.x += (unsigned short)padding;
  4502. r.y += (unsigned short)padding;
  4503. r.w -= (unsigned short)padding * 2;
  4504. r.h -= (unsigned short)padding * 2;
  4505. for (int i = 0; i < 9; i++)
  4506. {
  4507. // The third row/column of the 3x3 grid are generated by flipping the appropriate chunks of the upper 2x2 grid.
  4508. bool flip_h = false; // Do we need to flip the UVs horizontally?
  4509. bool flip_v = false; // Do we need to flip the UVs vertically?
  4510. ImFontAtlasRect sub_rect = r;
  4511. switch (i % 3)
  4512. {
  4513. case 0: sub_rect.w = (unsigned short)corner_size; break;
  4514. case 1: sub_rect.x += (unsigned short)corner_size; sub_rect.w = (unsigned short)edge_size; break;
  4515. case 2: sub_rect.w = (unsigned short)corner_size; flip_h = true; break;
  4516. }
  4517. switch (i / 3)
  4518. {
  4519. case 0: sub_rect.h = (unsigned short)corner_size; break;
  4520. case 1: sub_rect.y += (unsigned short)corner_size; sub_rect.h = (unsigned short)edge_size; break;
  4521. case 2: sub_rect.h = (unsigned short)corner_size; flip_v = true; break;
  4522. }
  4523. // FIXME-SHADOWS: caching UV !!
  4524. ImVec2 uv0 = ImVec2((float)(sub_rect.x), (float)(sub_rect.y)) * atlas->TexUvScale;
  4525. ImVec2 uv1 = ImVec2((float)(sub_rect.x + sub_rect.w), (float)(sub_rect.y + sub_rect.h)) * atlas->TexUvScale;
  4526. atlas->ShadowRectUvs[i] = ImVec4(flip_h ? uv1.x : uv0.x, flip_v ? uv1.y : uv0.y, flip_h ? uv0.x : uv1.x, flip_v ? uv0.y : uv1.y);
  4527. }
  4528. }
  4529. // The convex shape shadow texture
  4530. add_and_draw = (atlas->GetCustomRect(atlas->ShadowRectIds[1], &r) == false);
  4531. if (add_and_draw)
  4532. {
  4533. atlas->ShadowRectIds[1] = atlas->AddCustomRect(shadow_cfg->CalcConvexTexWidth() + shadow_cfg->GetConvexTexPadding(), shadow_cfg->CalcConvexTexHeight() + shadow_cfg->GetConvexTexPadding(), &r);
  4534. IM_ASSERT(atlas->ShadowRectIds[1] != ImFontAtlasRectId_Invalid);
  4535. const int size = shadow_cfg->TexCornerSize * 2;
  4536. const int padding = shadow_cfg->GetConvexTexPadding();
  4537. // Generate distance field
  4538. // We draw the actual texture content by evaluating the distance field for the distance from a center point
  4539. ImVec2 center_point(size * 0.5f, size * 0.5f);
  4540. float* tex_data = (float*)alloca(size * size * sizeof(float));
  4541. for (int y = 0; y < size; y++)
  4542. for (int x = 0; x < size; x++)
  4543. {
  4544. float dist = DistanceFromPoint(ImVec2((float)x, (float)y), center_point);
  4545. float alpha = 1.0f - ImMin(ImMax((float)dist + shadow_cfg->TexDistanceFieldOffset, 0.0f) / ImMax((float)shadow_cfg->TexCornerSize + shadow_cfg->TexDistanceFieldOffset, 0.001f), 1.0f);
  4546. alpha = ImPow(alpha, shadow_cfg->TexFalloffPower); // Apply power curve to give a nicer falloff
  4547. tex_data[x + (y * size)] = alpha;
  4548. }
  4549. // Blur
  4550. if (shadow_cfg->TexBlur)
  4551. GaussianBlur(tex_data, size);
  4552. // Copy to texture, truncating to the actual required texture size (the bottom/right of the source data is chopped off, as we don't need it - see below)
  4553. // We push the data down and right by the amount we padded the top of the texture (see CalcConvexTexWidth/CalcConvexTexHeight) for details
  4554. const int padded_size = (int)(shadow_cfg->TexCornerSize / ImCos(IM_PI * 0.25f));
  4555. const int src_x_offset = padding + (padded_size - shadow_cfg->TexCornerSize);
  4556. const int src_y_offset = padding + (padded_size - shadow_cfg->TexCornerSize);
  4557. const int tex_width = shadow_cfg->CalcConvexTexWidth();
  4558. const int tex_height = shadow_cfg->CalcConvexTexHeight();
  4559. ImTextureData* tex = atlas->TexData;
  4560. for (int y = 0; y < tex_height; y++)
  4561. for (int x = 0; x < tex_width; x++)
  4562. {
  4563. const int src_x = ImClamp(x - src_x_offset, 0, size - 1);
  4564. const int src_y = ImClamp(y - src_y_offset, 0, size - 1);
  4565. const float alpha_f = tex_data[src_x + (src_y * size)];
  4566. const unsigned char alpha_8 = (unsigned char)(0xFF * alpha_f);
  4567. // FIXME-SHADOWS: May be optimized.
  4568. switch (atlas->TexData->Format)
  4569. {
  4570. case ImTextureFormat_Alpha8:
  4571. {
  4572. ImU8* out_p = (ImU8*)(void*)tex->GetPixelsAt(r.x + x, r.y + y);
  4573. *out_p = alpha_8;
  4574. break;
  4575. }
  4576. case ImTextureFormat_RGBA32:
  4577. {
  4578. ImU32* out_p = (ImU32*)(void*)tex->GetPixelsAt(r.x + x, r.y + y);
  4579. *out_p = IM_COL32(255, 255, 255, alpha_8);;
  4580. break;
  4581. }
  4582. }
  4583. }
  4584. }
  4585. // Refresh UV coordinates
  4586. if (atlas->GetCustomRect(atlas->ShadowRectIds[1], &r))
  4587. {
  4588. // Remove the padding we added
  4589. const int padding = shadow_cfg->GetConvexTexPadding();
  4590. const int tex_width = shadow_cfg->CalcConvexTexWidth();
  4591. const int tex_height = shadow_cfg->CalcConvexTexHeight();
  4592. r.x += (unsigned short)padding;
  4593. r.y += (unsigned short)padding;
  4594. r.w = (unsigned short)(tex_width - (padding * 2));
  4595. r.h = (unsigned short)(tex_height - (padding * 2));
  4596. ImVec2 uv0 = ImVec2((float)(r.x), (float)(r.y)) * atlas->TexUvScale;
  4597. ImVec2 uv1 = ImVec2((float)(r.x + r.w), (float)(r.y + r.h)) * atlas->TexUvScale;
  4598. atlas->ShadowRectUvs[9] = ImVec4(uv0.x, uv0.y, uv1.x, uv1.y);
  4599. }
  4600. }
  4601. // Start packing over current empty texture
  4602. void ImFontAtlasBuildInit(ImFontAtlas* atlas)
  4603. {
  4604. // Select Backend
  4605. // - Note that we do not reassign to atlas->FontLoader, since it is likely to point to static data which
  4606. // may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are
  4607. // using a hot-reloading scheme that messes up static data, store your own instance of FontLoader somewhere
  4608. // and point to it instead of pointing directly to return value of the GetFontLoaderXXX functions.
  4609. if (atlas->FontLoader == NULL)
  4610. {
  4611. #ifdef IMGUI_ENABLE_FREETYPE
  4612. atlas->SetFontLoader(ImGuiFreeType::GetFontLoader());
  4613. #elif defined(IMGUI_ENABLE_STB_TRUETYPE)
  4614. atlas->SetFontLoader(ImFontAtlasGetFontLoaderForStbTruetype());
  4615. #else
  4616. IM_ASSERT(0); // Invalid Build function
  4617. #endif
  4618. }
  4619. // Create initial texture size
  4620. if (atlas->TexData == NULL || atlas->TexData->Pixels == NULL)
  4621. ImFontAtlasTextureAdd(atlas, ImUpperPowerOfTwo(atlas->TexMinWidth), ImUpperPowerOfTwo(atlas->TexMinHeight));
  4622. atlas->Builder = IM_NEW(ImFontAtlasBuilder)();
  4623. if (atlas->FontLoader->LoaderInit)
  4624. atlas->FontLoader->LoaderInit(atlas);
  4625. ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas);
  4626. ImFontAtlasPackInit(atlas);
  4627. // Add required texture data
  4628. ImFontAtlasBuildUpdateLinesTexData(atlas);
  4629. ImFontAtlasBuildUpdateBasicTexData(atlas);
  4630. ImFontAtlasBuildUpdateShadowTexData(atlas);
  4631. // Register fonts
  4632. ImFontAtlasBuildUpdatePointers(atlas);
  4633. // Update UV coordinates etc. stored in bound ImDrawListSharedData instance
  4634. ImFontAtlasUpdateDrawListsSharedData(atlas);
  4635. //atlas->TexIsBuilt = true;
  4636. }
  4637. // Destroy builder and all cached glyphs. Do not destroy actual fonts.
  4638. void ImFontAtlasBuildDestroy(ImFontAtlas* atlas)
  4639. {
  4640. for (ImFont* font : atlas->Fonts)
  4641. ImFontAtlasFontDestroyOutput(atlas, font);
  4642. if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderShutdown)
  4643. {
  4644. atlas->FontLoader->LoaderShutdown(atlas);
  4645. IM_ASSERT(atlas->FontLoaderData == NULL);
  4646. }
  4647. IM_DELETE(atlas->Builder);
  4648. atlas->Builder = NULL;
  4649. }
  4650. void ImFontAtlasPackInit(ImFontAtlas * atlas)
  4651. {
  4652. ImTextureData* tex = atlas->TexData;
  4653. ImFontAtlasBuilder* builder = atlas->Builder;
  4654. // In theory we could decide to reduce the number of nodes, e.g. halve them, and waste a little texture space, but it doesn't seem worth it.
  4655. const int pack_node_count = tex->Width / 2;
  4656. builder->PackNodes.resize(pack_node_count);
  4657. IM_STATIC_ASSERT(sizeof(stbrp_context) <= sizeof(stbrp_context_opaque));
  4658. stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width, tex->Height, builder->PackNodes.Data, builder->PackNodes.Size);
  4659. builder->RectsPackedSurface = builder->RectsPackedCount = 0;
  4660. builder->MaxRectSize = ImVec2i(0, 0);
  4661. builder->MaxRectBounds = ImVec2i(0, 0);
  4662. }
  4663. // This is essentially a free-list pattern, it may be nice to wrap it into a dedicated type.
  4664. static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas* atlas, int rect_idx)
  4665. {
  4666. ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
  4667. int index_idx;
  4668. ImFontAtlasRectEntry* index_entry;
  4669. if (builder->RectsIndexFreeListStart < 0)
  4670. {
  4671. builder->RectsIndex.resize(builder->RectsIndex.Size + 1);
  4672. index_idx = builder->RectsIndex.Size - 1;
  4673. index_entry = &builder->RectsIndex[index_idx];
  4674. memset(index_entry, 0, sizeof(*index_entry));
  4675. }
  4676. else
  4677. {
  4678. index_idx = builder->RectsIndexFreeListStart;
  4679. index_entry = &builder->RectsIndex[index_idx];
  4680. IM_ASSERT(index_entry->IsUsed == false && index_entry->Generation > 0); // Generation is incremented during DiscardRect
  4681. builder->RectsIndexFreeListStart = index_entry->TargetIndex;
  4682. }
  4683. index_entry->TargetIndex = rect_idx;
  4684. index_entry->IsUsed = 1;
  4685. return ImFontAtlasRectId_Make(index_idx, index_entry->Generation);
  4686. }
  4687. // Overwrite existing entry
  4688. static ImFontAtlasRectId ImFontAtlasPackReuseRectEntry(ImFontAtlas* atlas, ImFontAtlasRectEntry* index_entry)
  4689. {
  4690. IM_ASSERT(index_entry->IsUsed);
  4691. index_entry->TargetIndex = atlas->Builder->Rects.Size - 1;
  4692. int index_idx = atlas->Builder->RectsIndex.index_from_ptr(index_entry);
  4693. return ImFontAtlasRectId_Make(index_idx, index_entry->Generation);
  4694. }
  4695. // This is expected to be called in batches and followed by a repack
  4696. void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id)
  4697. {
  4698. IM_ASSERT(id != ImFontAtlasRectId_Invalid);
  4699. ImTextureRect* rect = ImFontAtlasPackGetRect(atlas, id);
  4700. if (rect == NULL)
  4701. return;
  4702. ImFontAtlasBuilder* builder = atlas->Builder;
  4703. int index_idx = ImFontAtlasRectId_GetIndex(id);
  4704. ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx];
  4705. IM_ASSERT(index_entry->IsUsed && index_entry->TargetIndex >= 0);
  4706. index_entry->IsUsed = false;
  4707. index_entry->TargetIndex = builder->RectsIndexFreeListStart;
  4708. index_entry->Generation++;
  4709. const int pack_padding = atlas->TexGlyphPadding;
  4710. builder->RectsIndexFreeListStart = index_idx;
  4711. builder->RectsDiscardedCount++;
  4712. builder->RectsDiscardedSurface += (rect->w + pack_padding) * (rect->h + pack_padding);
  4713. rect->w = rect->h = 0; // Clear rectangle so it won't be packed again
  4714. }
  4715. // Important: Calling this may recreate a new texture and therefore change atlas->TexData
  4716. // FIXME-NEWFONTS: Expose other glyph padding settings for custom alteration (e.g. drop shadows). See #7962
  4717. ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry)
  4718. {
  4719. IM_ASSERT(w > 0 && w <= 0xFFFF);
  4720. IM_ASSERT(h > 0 && h <= 0xFFFF);
  4721. ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
  4722. const int pack_padding = atlas->TexGlyphPadding;
  4723. builder->MaxRectSize.x = ImMax(builder->MaxRectSize.x, w);
  4724. builder->MaxRectSize.y = ImMax(builder->MaxRectSize.y, h);
  4725. // Pack
  4726. ImTextureRect r = { 0, 0, (unsigned short)w, (unsigned short)h };
  4727. for (int attempts_remaining = 3; attempts_remaining >= 0; attempts_remaining--)
  4728. {
  4729. // Try packing
  4730. stbrp_rect pack_r = {};
  4731. pack_r.w = w + pack_padding;
  4732. pack_r.h = h + pack_padding;
  4733. stbrp_pack_rects((stbrp_context*)(void*)&builder->PackContext, &pack_r, 1);
  4734. r.x = (unsigned short)pack_r.x;
  4735. r.y = (unsigned short)pack_r.y;
  4736. if (pack_r.was_packed)
  4737. break;
  4738. // If we ran out of attempts, return fallback
  4739. if (attempts_remaining == 0 || builder->LockDisableResize)
  4740. {
  4741. IMGUI_DEBUG_LOG_FONT("[font] Failed packing %dx%d rectangle. Returning fallback.\n", w, h);
  4742. return ImFontAtlasRectId_Invalid;
  4743. }
  4744. // Resize or repack atlas! (this should be a rare event)
  4745. ImFontAtlasTextureMakeSpace(atlas);
  4746. }
  4747. builder->MaxRectBounds.x = ImMax(builder->MaxRectBounds.x, r.x + r.w + pack_padding);
  4748. builder->MaxRectBounds.y = ImMax(builder->MaxRectBounds.y, r.y + r.h + pack_padding);
  4749. builder->RectsPackedCount++;
  4750. builder->RectsPackedSurface += (w + pack_padding) * (h + pack_padding);
  4751. builder->Rects.push_back(r);
  4752. if (overwrite_entry != NULL)
  4753. return ImFontAtlasPackReuseRectEntry(atlas, overwrite_entry); // Write into an existing entry instead of adding one (used during repack)
  4754. else
  4755. return ImFontAtlasPackAllocRectEntry(atlas, builder->Rects.Size - 1);
  4756. }
  4757. // Generally for non-user facing functions: assert on invalid ID.
  4758. ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id)
  4759. {
  4760. IM_ASSERT(id != ImFontAtlasRectId_Invalid);
  4761. int index_idx = ImFontAtlasRectId_GetIndex(id);
  4762. ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
  4763. ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx];
  4764. IM_ASSERT(index_entry->Generation == ImFontAtlasRectId_GetGeneration(id));
  4765. IM_ASSERT(index_entry->IsUsed);
  4766. return &builder->Rects[index_entry->TargetIndex];
  4767. }
  4768. // For user-facing functions: return NULL on invalid ID.
  4769. // Important: return pointer is valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers.
  4770. ImTextureRect* ImFontAtlasPackGetRectSafe(ImFontAtlas* atlas, ImFontAtlasRectId id)
  4771. {
  4772. if (id == ImFontAtlasRectId_Invalid)
  4773. return NULL;
  4774. int index_idx = ImFontAtlasRectId_GetIndex(id);
  4775. if (atlas->Builder == NULL)
  4776. ImFontAtlasBuildInit(atlas);
  4777. ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
  4778. IM_MSVC_WARNING_SUPPRESS(28182); // Static Analysis false positive "warning C28182: Dereferencing NULL pointer 'builder'"
  4779. if (index_idx >= builder->RectsIndex.Size)
  4780. return NULL;
  4781. ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx];
  4782. if (index_entry->Generation != ImFontAtlasRectId_GetGeneration(id) || !index_entry->IsUsed)
  4783. return NULL;
  4784. return &builder->Rects[index_entry->TargetIndex];
  4785. }
  4786. // Important! This assume by ImFontConfig::GlyphExcludeRanges[] is a SMALL ARRAY (e.g. <10 entries)
  4787. // Use "Input Glyphs Overlap Detection Tool" to display a list of glyphs provided by multiple sources in order to set this array up.
  4788. static bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar codepoint)
  4789. {
  4790. if (const ImWchar* exclude_list = src->GlyphExcludeRanges)
  4791. for (; exclude_list[0] != 0; exclude_list += 2)
  4792. if (codepoint >= exclude_list[0] && codepoint <= exclude_list[1])
  4793. return false;
  4794. return true;
  4795. }
  4796. static void ImFontBaked_BuildGrowIndex(ImFontBaked* baked, int new_size)
  4797. {
  4798. IM_ASSERT(baked->IndexAdvanceX.Size == baked->IndexLookup.Size);
  4799. if (new_size <= baked->IndexLookup.Size)
  4800. return;
  4801. baked->IndexAdvanceX.resize(new_size, -1.0f);
  4802. baked->IndexLookup.resize(new_size, IM_FONTGLYPH_INDEX_UNUSED);
  4803. }
  4804. static void ImFontAtlas_FontHookRemapCodepoint(ImFontAtlas* atlas, ImFont* font, ImWchar* c)
  4805. {
  4806. IM_UNUSED(atlas);
  4807. if (font->RemapPairs.Data.Size != 0)
  4808. *c = (ImWchar)font->RemapPairs.GetInt((ImGuiID)*c, (int)*c);
  4809. }
  4810. static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codepoint, float* only_load_advance_x)
  4811. {
  4812. ImFont* font = baked->ContainerFont;
  4813. ImFontAtlas* atlas = font->ContainerAtlas;
  4814. if (atlas->Locked || (font->Flags & ImFontFlags_NoLoadGlyphs))
  4815. {
  4816. // Lazily load fallback glyph
  4817. if (baked->FallbackGlyphIndex == -1 && baked->LoadNoFallback == 0)
  4818. ImFontAtlasBuildSetupFontBakedFallback(baked);
  4819. return NULL;
  4820. }
  4821. // User remapping hooks
  4822. ImWchar src_codepoint = codepoint;
  4823. ImFontAtlas_FontHookRemapCodepoint(atlas, font, &codepoint);
  4824. //char utf8_buf[5];
  4825. //IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint));
  4826. // Special hook
  4827. // FIXME-NEWATLAS: it would be nicer if this used a more standardized way of hooking
  4828. if (codepoint == font->EllipsisChar && font->EllipsisAutoBake)
  4829. if (ImFontGlyph* glyph = ImFontAtlasBuildSetupFontBakedEllipsis(atlas, baked))
  4830. return glyph;
  4831. // Call backend
  4832. char* loader_user_data_p = (char*)baked->FontLoaderDatas;
  4833. int src_n = 0;
  4834. for (ImFontConfig* src : font->Sources)
  4835. {
  4836. const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
  4837. if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint))
  4838. {
  4839. if (only_load_advance_x == NULL)
  4840. {
  4841. ImFontGlyph glyph_buf;
  4842. if (loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, &glyph_buf, NULL))
  4843. {
  4844. // FIXME: Add hooks for e.g. #7962
  4845. glyph_buf.Codepoint = src_codepoint;
  4846. glyph_buf.SourceIdx = src_n;
  4847. return ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph_buf);
  4848. }
  4849. }
  4850. else
  4851. {
  4852. // Special mode but only loading glyphs metrics. Will rasterize and pack later.
  4853. if (loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, NULL, only_load_advance_x))
  4854. {
  4855. ImFontAtlasBakedAddFontGlyphAdvancedX(atlas, baked, src, codepoint, *only_load_advance_x);
  4856. return NULL;
  4857. }
  4858. }
  4859. }
  4860. loader_user_data_p += loader->FontBakedSrcLoaderDataSize;
  4861. src_n++;
  4862. }
  4863. // Lazily load fallback glyph
  4864. if (baked->LoadNoFallback)
  4865. return NULL;
  4866. if (baked->FallbackGlyphIndex == -1)
  4867. ImFontAtlasBuildSetupFontBakedFallback(baked);
  4868. // Mark index as not found, so we don't attempt the search twice
  4869. ImFontBaked_BuildGrowIndex(baked, codepoint + 1);
  4870. baked->IndexAdvanceX[codepoint] = baked->FallbackAdvanceX;
  4871. baked->IndexLookup[codepoint] = IM_FONTGLYPH_INDEX_NOT_FOUND;
  4872. return NULL;
  4873. }
  4874. static float ImFontBaked_BuildLoadGlyphAdvanceX(ImFontBaked* baked, ImWchar codepoint)
  4875. {
  4876. if (baked->Size >= IMGUI_FONT_SIZE_THRESHOLD_FOR_LOADADVANCEXONLYMODE || baked->LoadNoRenderOnLayout)
  4877. {
  4878. // First load AdvanceX value used by CalcTextSize() API then load the rest when loaded by drawing API.
  4879. float only_advance_x = 0.0f;
  4880. ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(baked, (ImWchar)codepoint, &only_advance_x);
  4881. return glyph ? glyph->AdvanceX : only_advance_x;
  4882. }
  4883. else
  4884. {
  4885. ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(baked, (ImWchar)codepoint, NULL);
  4886. return glyph ? glyph->AdvanceX : baked->FallbackAdvanceX;
  4887. }
  4888. }
  4889. // The point of this indirection is to not be inlined in debug mode in order to not bloat inner loop.b
  4890. IM_MSVC_RUNTIME_CHECKS_OFF
  4891. static float BuildLoadGlyphGetAdvanceOrFallback(ImFontBaked* baked, unsigned int codepoint)
  4892. {
  4893. return ImFontBaked_BuildLoadGlyphAdvanceX(baked, (ImWchar)codepoint);
  4894. }
  4895. IM_MSVC_RUNTIME_CHECKS_RESTORE
  4896. #ifndef IMGUI_DISABLE_DEBUG_TOOLS
  4897. void ImFontAtlasDebugLogTextureRequests(ImFontAtlas* atlas)
  4898. {
  4899. // [DEBUG] Log texture update requests
  4900. ImGuiContext& g = *GImGui;
  4901. IM_UNUSED(g);
  4902. for (ImTextureData* tex : atlas->TexList)
  4903. {
  4904. if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0)
  4905. IM_ASSERT(tex->Updates.Size == 0);
  4906. if (tex->Status == ImTextureStatus_WantCreate)
  4907. IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: create %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
  4908. else if (tex->Status == ImTextureStatus_WantDestroy)
  4909. IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: destroy %dx%d, texid=0x%" IM_PRIX64 ", backend_data=%p\n", tex->UniqueID, tex->Width, tex->Height, tex->TexID, tex->BackendUserData);
  4910. else if (tex->Status == ImTextureStatus_WantUpdates)
  4911. {
  4912. IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: update %d regions, texid=0x%" IM_PRIX64 ", backend_data=0x%" IM_PRIX64 "\n", tex->UniqueID, tex->Updates.Size, tex->TexID, (ImU64)(intptr_t)tex->BackendUserData);
  4913. for (const ImTextureRect& r : tex->Updates)
  4914. {
  4915. IM_UNUSED(r);
  4916. IM_ASSERT(r.x >= 0 && r.y >= 0);
  4917. IM_ASSERT(r.x + r.w <= tex->Width && r.y + r.h <= tex->Height); // In theory should subtract PackPadding but it's currently part of atlas and mid-frame change would wreck assert.
  4918. //IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: update (% 4d..%-4d)->(% 4d..%-4d), texid=0x%" IM_PRIX64 ", backend_data=0x%" IM_PRIX64 "\n", tex->UniqueID, r.x, r.y, r.x + r.w, r.y + r.h, tex->TexID, (ImU64)(intptr_t)tex->BackendUserData);
  4919. }
  4920. }
  4921. }
  4922. }
  4923. #endif
  4924. //-------------------------------------------------------------------------
  4925. // [SECTION] ImFontAtlas: backend for stb_truetype
  4926. //-------------------------------------------------------------------------
  4927. // (imstb_truetype.h in included near the top of this file, when IMGUI_ENABLE_STB_TRUETYPE is set)
  4928. //-------------------------------------------------------------------------
  4929. #ifdef IMGUI_ENABLE_STB_TRUETYPE
  4930. // One for each ConfigData
  4931. struct ImGui_ImplStbTrueType_FontSrcData
  4932. {
  4933. stbtt_fontinfo FontInfo;
  4934. float ScaleFactor;
  4935. };
  4936. static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src)
  4937. {
  4938. IM_UNUSED(atlas);
  4939. ImGui_ImplStbTrueType_FontSrcData* bd_font_data = IM_NEW(ImGui_ImplStbTrueType_FontSrcData);
  4940. IM_ASSERT(src->FontLoaderData == NULL);
  4941. // Initialize helper structure for font loading and verify that the TTF/OTF data is correct
  4942. const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)src->FontData, src->FontNo);
  4943. if (font_offset < 0)
  4944. {
  4945. IM_DELETE(bd_font_data);
  4946. IM_ASSERT_USER_ERROR(0, "stbtt_GetFontOffsetForIndex(): FontData is incorrect, or FontNo cannot be found.");
  4947. return false;
  4948. }
  4949. if (!stbtt_InitFont(&bd_font_data->FontInfo, (unsigned char*)src->FontData, font_offset))
  4950. {
  4951. IM_DELETE(bd_font_data);
  4952. IM_ASSERT_USER_ERROR(0, "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize.");
  4953. return false;
  4954. }
  4955. src->FontLoaderData = bd_font_data;
  4956. const float ref_size = src->DstFont->Sources[0]->SizePixels;
  4957. if (src->MergeMode && src->SizePixels == 0.0f)
  4958. src->SizePixels = ref_size;
  4959. if (src->SizePixels >= 0.0f)
  4960. bd_font_data->ScaleFactor = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f);
  4961. else
  4962. bd_font_data->ScaleFactor = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f);
  4963. if (src->MergeMode && src->SizePixels != 0.0f && ref_size != 0.0f)
  4964. bd_font_data->ScaleFactor *= src->SizePixels / ref_size; // FIXME-NEWATLAS: Should tidy up that a bit
  4965. return true;
  4966. }
  4967. static void ImGui_ImplStbTrueType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src)
  4968. {
  4969. IM_UNUSED(atlas);
  4970. ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
  4971. IM_DELETE(bd_font_data);
  4972. src->FontLoaderData = NULL;
  4973. }
  4974. static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint)
  4975. {
  4976. IM_UNUSED(atlas);
  4977. ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
  4978. IM_ASSERT(bd_font_data != NULL);
  4979. int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint);
  4980. return glyph_index != 0;
  4981. }
  4982. static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*)
  4983. {
  4984. IM_UNUSED(atlas);
  4985. ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
  4986. if (src->MergeMode == false)
  4987. {
  4988. // FIXME-NEWFONTS: reevaluate how to use sizing metrics
  4989. // FIXME-NEWFONTS: make use of line gap value
  4990. float scale_for_layout = bd_font_data->ScaleFactor * baked->Size;
  4991. int unscaled_ascent, unscaled_descent, unscaled_line_gap;
  4992. stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
  4993. baked->Ascent = ImCeil(unscaled_ascent * scale_for_layout);
  4994. baked->Descent = ImFloor(unscaled_descent * scale_for_layout);
  4995. }
  4996. return true;
  4997. }
  4998. static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x)
  4999. {
  5000. // Search for first font which has the glyph
  5001. ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
  5002. IM_ASSERT(bd_font_data);
  5003. int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint);
  5004. if (glyph_index == 0)
  5005. return false;
  5006. // Fonts unit to pixels
  5007. int oversample_h, oversample_v;
  5008. ImFontAtlasBuildGetOversampleFactors(src, baked, &oversample_h, &oversample_v);
  5009. const float scale_for_layout = bd_font_data->ScaleFactor * baked->Size;
  5010. const float rasterizer_density = src->RasterizerDensity * baked->RasterizerDensity;
  5011. const float scale_for_raster_x = bd_font_data->ScaleFactor * baked->Size * rasterizer_density * oversample_h;
  5012. const float scale_for_raster_y = bd_font_data->ScaleFactor * baked->Size * rasterizer_density * oversample_v;
  5013. // Obtain size and advance
  5014. int x0, y0, x1, y1;
  5015. int advance, lsb;
  5016. stbtt_GetGlyphBitmapBoxSubpixel(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, 0, 0, &x0, &y0, &x1, &y1);
  5017. stbtt_GetGlyphHMetrics(&bd_font_data->FontInfo, glyph_index, &advance, &lsb);
  5018. // Load metrics only mode
  5019. if (out_advance_x != NULL)
  5020. {
  5021. IM_ASSERT(out_glyph == NULL);
  5022. *out_advance_x = advance * scale_for_layout;
  5023. return true;
  5024. }
  5025. // Prepare glyph
  5026. out_glyph->Codepoint = codepoint;
  5027. out_glyph->AdvanceX = advance * scale_for_layout;
  5028. // Pack and retrieve position inside texture atlas
  5029. // (generally based on stbtt_PackFontRangesRenderIntoRects)
  5030. const bool is_visible = (x0 != x1 && y0 != y1);
  5031. if (is_visible)
  5032. {
  5033. const int w = (x1 - x0 + oversample_h - 1);
  5034. const int h = (y1 - y0 + oversample_v - 1);
  5035. ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h);
  5036. if (pack_id == ImFontAtlasRectId_Invalid)
  5037. {
  5038. // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?)
  5039. IM_ASSERT(pack_id != ImFontAtlasRectId_Invalid && "Out of texture memory.");
  5040. return false;
  5041. }
  5042. ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
  5043. // Render
  5044. stbtt_GetGlyphBitmapBox(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, &x0, &y0, &x1, &y1);
  5045. ImFontAtlasBuilder* builder = atlas->Builder;
  5046. builder->TempBuffer.resize(w * h * 1);
  5047. unsigned char* bitmap_pixels = builder->TempBuffer.Data;
  5048. memset(bitmap_pixels, 0, w * h * 1);
  5049. // Render with oversampling
  5050. // (those functions conveniently assert if pixels are not cleared, which is another safety layer)
  5051. float sub_x, sub_y;
  5052. stbtt_MakeGlyphBitmapSubpixelPrefilter(&bd_font_data->FontInfo, bitmap_pixels, w, h, w,
  5053. scale_for_raster_x, scale_for_raster_y, 0, 0, oversample_h, oversample_v, &sub_x, &sub_y, glyph_index);
  5054. const float ref_size = baked->ContainerFont->Sources[0]->SizePixels;
  5055. const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f;
  5056. float font_off_x = (src->GlyphOffset.x * offsets_scale);
  5057. float font_off_y = (src->GlyphOffset.y * offsets_scale);
  5058. if (src->PixelSnapH) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, but a better design would be welcome.
  5059. font_off_x = IM_ROUND(font_off_x);
  5060. if (src->PixelSnapV)
  5061. font_off_y = IM_ROUND(font_off_y);
  5062. font_off_x += sub_x;
  5063. font_off_y += sub_y + IM_ROUND(baked->Ascent);
  5064. float recip_h = 1.0f / (oversample_h * rasterizer_density);
  5065. float recip_v = 1.0f / (oversample_v * rasterizer_density);
  5066. // Register glyph
  5067. // r->x r->y are coordinates inside texture (in pixels)
  5068. // glyph.X0, glyph.Y0 are drawing coordinates from base text position, and accounting for oversampling.
  5069. out_glyph->X0 = x0 * recip_h + font_off_x;
  5070. out_glyph->Y0 = y0 * recip_v + font_off_y;
  5071. out_glyph->X1 = (x0 + (int)r->w) * recip_h + font_off_x;
  5072. out_glyph->Y1 = (y0 + (int)r->h) * recip_v + font_off_y;
  5073. out_glyph->Visible = true;
  5074. out_glyph->PackId = pack_id;
  5075. ImFontAtlasBakedSetFontGlyphBitmap(atlas, baked, src, out_glyph, r, bitmap_pixels, ImTextureFormat_Alpha8, w);
  5076. }
  5077. return true;
  5078. }
  5079. const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype()
  5080. {
  5081. static ImFontLoader loader;
  5082. loader.Name = "stb_truetype";
  5083. loader.FontSrcInit = ImGui_ImplStbTrueType_FontSrcInit;
  5084. loader.FontSrcDestroy = ImGui_ImplStbTrueType_FontSrcDestroy;
  5085. loader.FontSrcContainsGlyph = ImGui_ImplStbTrueType_FontSrcContainsGlyph;
  5086. loader.FontBakedInit = ImGui_ImplStbTrueType_FontBakedInit;
  5087. loader.FontBakedDestroy = NULL;
  5088. loader.FontBakedLoadGlyph = ImGui_ImplStbTrueType_FontBakedLoadGlyph;
  5089. return &loader;
  5090. }
  5091. #endif // IMGUI_ENABLE_STB_TRUETYPE
  5092. //-------------------------------------------------------------------------
  5093. // [SECTION] ImFontAtlas: glyph ranges helpers
  5094. //-------------------------------------------------------------------------
  5095. // - GetGlyphRangesDefault()
  5096. // Obsolete functions since 1.92:
  5097. // - GetGlyphRangesGreek()
  5098. // - GetGlyphRangesKorean()
  5099. // - GetGlyphRangesChineseFull()
  5100. // - GetGlyphRangesChineseSimplifiedCommon()
  5101. // - GetGlyphRangesJapanese()
  5102. // - GetGlyphRangesCyrillic()
  5103. // - GetGlyphRangesThai()
  5104. // - GetGlyphRangesVietnamese()
  5105. //-----------------------------------------------------------------------------
  5106. // Retrieve list of range (2 int per range, values are inclusive)
  5107. const ImWchar* ImFontAtlas::GetGlyphRangesDefault()
  5108. {
  5109. static const ImWchar ranges[] =
  5110. {
  5111. 0x0020, 0x00FF, // Basic Latin + Latin Supplement
  5112. 0,
  5113. };
  5114. return &ranges[0];
  5115. }
  5116. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
  5117. const ImWchar* ImFontAtlas::GetGlyphRangesGreek()
  5118. {
  5119. static const ImWchar ranges[] =
  5120. {
  5121. 0x0020, 0x00FF, // Basic Latin + Latin Supplement
  5122. 0x0370, 0x03FF, // Greek and Coptic
  5123. 0,
  5124. };
  5125. return &ranges[0];
  5126. }
  5127. const ImWchar* ImFontAtlas::GetGlyphRangesKorean()
  5128. {
  5129. static const ImWchar ranges[] =
  5130. {
  5131. 0x0020, 0x00FF, // Basic Latin + Latin Supplement
  5132. 0x3131, 0x3163, // Korean alphabets
  5133. 0xAC00, 0xD7A3, // Korean characters
  5134. 0xFFFD, 0xFFFD, // Invalid
  5135. 0,
  5136. };
  5137. return &ranges[0];
  5138. }
  5139. const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull()
  5140. {
  5141. static const ImWchar ranges[] =
  5142. {
  5143. 0x0020, 0x00FF, // Basic Latin + Latin Supplement
  5144. 0x2000, 0x206F, // General Punctuation
  5145. 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
  5146. 0x31F0, 0x31FF, // Katakana Phonetic Extensions
  5147. 0xFF00, 0xFFEF, // Half-width characters
  5148. 0xFFFD, 0xFFFD, // Invalid
  5149. 0x4e00, 0x9FAF, // CJK Ideograms
  5150. 0,
  5151. };
  5152. return &ranges[0];
  5153. }
  5154. static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* accumulative_offsets, int accumulative_offsets_count, ImWchar* out_ranges)
  5155. {
  5156. for (int n = 0; n < accumulative_offsets_count; n++, out_ranges += 2)
  5157. {
  5158. out_ranges[0] = out_ranges[1] = (ImWchar)(base_codepoint + accumulative_offsets[n]);
  5159. base_codepoint += accumulative_offsets[n];
  5160. }
  5161. out_ranges[0] = 0;
  5162. }
  5163. const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
  5164. {
  5165. // Store 2500 regularly used characters for Simplified Chinese.
  5166. // Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8
  5167. // This table covers 97.97% of all characters used during the month in July, 1987.
  5168. // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
  5169. // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
  5170. static const short accumulative_offsets_from_0x4E00[] =
  5171. {
  5172. 0,1,2,4,1,1,1,1,2,1,3,2,1,2,2,1,1,1,1,1,5,2,1,2,3,3,3,2,2,4,1,1,1,2,1,5,2,3,1,2,1,2,1,1,2,1,1,2,2,1,4,1,1,1,1,5,10,1,2,19,2,1,2,1,2,1,2,1,2,
  5173. 1,5,1,6,3,2,1,2,2,1,1,1,4,8,5,1,1,4,1,1,3,1,2,1,5,1,2,1,1,1,10,1,1,5,2,4,6,1,4,2,2,2,12,2,1,1,6,1,1,1,4,1,1,4,6,5,1,4,2,2,4,10,7,1,1,4,2,4,
  5174. 2,1,4,3,6,10,12,5,7,2,14,2,9,1,1,6,7,10,4,7,13,1,5,4,8,4,1,1,2,28,5,6,1,1,5,2,5,20,2,2,9,8,11,2,9,17,1,8,6,8,27,4,6,9,20,11,27,6,68,2,2,1,1,
  5175. 1,2,1,2,2,7,6,11,3,3,1,1,3,1,2,1,1,1,1,1,3,1,1,8,3,4,1,5,7,2,1,4,4,8,4,2,1,2,1,1,4,5,6,3,6,2,12,3,1,3,9,2,4,3,4,1,5,3,3,1,3,7,1,5,1,1,1,1,2,
  5176. 3,4,5,2,3,2,6,1,1,2,1,7,1,7,3,4,5,15,2,2,1,5,3,22,19,2,1,1,1,1,2,5,1,1,1,6,1,1,12,8,2,9,18,22,4,1,1,5,1,16,1,2,7,10,15,1,1,6,2,4,1,2,4,1,6,
  5177. 1,1,3,2,4,1,6,4,5,1,2,1,1,2,1,10,3,1,3,2,1,9,3,2,5,7,2,19,4,3,6,1,1,1,1,1,4,3,2,1,1,1,2,5,3,1,1,1,2,2,1,1,2,1,1,2,1,3,1,1,1,3,7,1,4,1,1,2,1,
  5178. 1,2,1,2,4,4,3,8,1,1,1,2,1,3,5,1,3,1,3,4,6,2,2,14,4,6,6,11,9,1,15,3,1,28,5,2,5,5,3,1,3,4,5,4,6,14,3,2,3,5,21,2,7,20,10,1,2,19,2,4,28,28,2,3,
  5179. 2,1,14,4,1,26,28,42,12,40,3,52,79,5,14,17,3,2,2,11,3,4,6,3,1,8,2,23,4,5,8,10,4,2,7,3,5,1,1,6,3,1,2,2,2,5,28,1,1,7,7,20,5,3,29,3,17,26,1,8,4,
  5180. 27,3,6,11,23,5,3,4,6,13,24,16,6,5,10,25,35,7,3,2,3,3,14,3,6,2,6,1,4,2,3,8,2,1,1,3,3,3,4,1,1,13,2,2,4,5,2,1,14,14,1,2,2,1,4,5,2,3,1,14,3,12,
  5181. 3,17,2,16,5,1,2,1,8,9,3,19,4,2,2,4,17,25,21,20,28,75,1,10,29,103,4,1,2,1,1,4,2,4,1,2,3,24,2,2,2,1,1,2,1,3,8,1,1,1,2,1,1,3,1,1,1,6,1,5,3,1,1,
  5182. 1,3,4,1,1,5,2,1,5,6,13,9,16,1,1,1,1,3,2,3,2,4,5,2,5,2,2,3,7,13,7,2,2,1,1,1,1,2,3,3,2,1,6,4,9,2,1,14,2,14,2,1,18,3,4,14,4,11,41,15,23,15,23,
  5183. 176,1,3,4,1,1,1,1,5,3,1,2,3,7,3,1,1,2,1,2,4,4,6,2,4,1,9,7,1,10,5,8,16,29,1,1,2,2,3,1,3,5,2,4,5,4,1,1,2,2,3,3,7,1,6,10,1,17,1,44,4,6,2,1,1,6,
  5184. 5,4,2,10,1,6,9,2,8,1,24,1,2,13,7,8,8,2,1,4,1,3,1,3,3,5,2,5,10,9,4,9,12,2,1,6,1,10,1,1,7,7,4,10,8,3,1,13,4,3,1,6,1,3,5,2,1,2,17,16,5,2,16,6,
  5185. 1,4,2,1,3,3,6,8,5,11,11,1,3,3,2,4,6,10,9,5,7,4,7,4,7,1,1,4,2,1,3,6,8,7,1,6,11,5,5,3,24,9,4,2,7,13,5,1,8,82,16,61,1,1,1,4,2,2,16,10,3,8,1,1,
  5186. 6,4,2,1,3,1,1,1,4,3,8,4,2,2,1,1,1,1,1,6,3,5,1,1,4,6,9,2,1,1,1,2,1,7,2,1,6,1,5,4,4,3,1,8,1,3,3,1,3,2,2,2,2,3,1,6,1,2,1,2,1,3,7,1,8,2,1,2,1,5,
  5187. 2,5,3,5,10,1,2,1,1,3,2,5,11,3,9,3,5,1,1,5,9,1,2,1,5,7,9,9,8,1,3,3,3,6,8,2,3,2,1,1,32,6,1,2,15,9,3,7,13,1,3,10,13,2,14,1,13,10,2,1,3,10,4,15,
  5188. 2,15,15,10,1,3,9,6,9,32,25,26,47,7,3,2,3,1,6,3,4,3,2,8,5,4,1,9,4,2,2,19,10,6,2,3,8,1,2,2,4,2,1,9,4,4,4,6,4,8,9,2,3,1,1,1,1,3,5,5,1,3,8,4,6,
  5189. 2,1,4,12,1,5,3,7,13,2,5,8,1,6,1,2,5,14,6,1,5,2,4,8,15,5,1,23,6,62,2,10,1,1,8,1,2,2,10,4,2,2,9,2,1,1,3,2,3,1,5,3,3,2,1,3,8,1,1,1,11,3,1,1,4,
  5190. 3,7,1,14,1,2,3,12,5,2,5,1,6,7,5,7,14,11,1,3,1,8,9,12,2,1,11,8,4,4,2,6,10,9,13,1,1,3,1,5,1,3,2,4,4,1,18,2,3,14,11,4,29,4,2,7,1,3,13,9,2,2,5,
  5191. 3,5,20,7,16,8,5,72,34,6,4,22,12,12,28,45,36,9,7,39,9,191,1,1,1,4,11,8,4,9,2,3,22,1,1,1,1,4,17,1,7,7,1,11,31,10,2,4,8,2,3,2,1,4,2,16,4,32,2,
  5192. 3,19,13,4,9,1,5,2,14,8,1,1,3,6,19,6,5,1,16,6,2,10,8,5,1,2,3,1,5,5,1,11,6,6,1,3,3,2,6,3,8,1,1,4,10,7,5,7,7,5,8,9,2,1,3,4,1,1,3,1,3,3,2,6,16,
  5193. 1,4,6,3,1,10,6,1,3,15,2,9,2,10,25,13,9,16,6,2,2,10,11,4,3,9,1,2,6,6,5,4,30,40,1,10,7,12,14,33,6,3,6,7,3,1,3,1,11,14,4,9,5,12,11,49,18,51,31,
  5194. 140,31,2,2,1,5,1,8,1,10,1,4,4,3,24,1,10,1,3,6,6,16,3,4,5,2,1,4,2,57,10,6,22,2,22,3,7,22,6,10,11,36,18,16,33,36,2,5,5,1,1,1,4,10,1,4,13,2,7,
  5195. 5,2,9,3,4,1,7,43,3,7,3,9,14,7,9,1,11,1,1,3,7,4,18,13,1,14,1,3,6,10,73,2,2,30,6,1,11,18,19,13,22,3,46,42,37,89,7,3,16,34,2,2,3,9,1,7,1,1,1,2,
  5196. 2,4,10,7,3,10,3,9,5,28,9,2,6,13,7,3,1,3,10,2,7,2,11,3,6,21,54,85,2,1,4,2,2,1,39,3,21,2,2,5,1,1,1,4,1,1,3,4,15,1,3,2,4,4,2,3,8,2,20,1,8,7,13,
  5197. 4,1,26,6,2,9,34,4,21,52,10,4,4,1,5,12,2,11,1,7,2,30,12,44,2,30,1,1,3,6,16,9,17,39,82,2,2,24,7,1,7,3,16,9,14,44,2,1,2,1,2,3,5,2,4,1,6,7,5,3,
  5198. 2,6,1,11,5,11,2,1,18,19,8,1,3,24,29,2,1,3,5,2,2,1,13,6,5,1,46,11,3,5,1,1,5,8,2,10,6,12,6,3,7,11,2,4,16,13,2,5,1,1,2,2,5,2,28,5,2,23,10,8,4,
  5199. 4,22,39,95,38,8,14,9,5,1,13,5,4,3,13,12,11,1,9,1,27,37,2,5,4,4,63,211,95,2,2,2,1,3,5,2,1,1,2,2,1,1,1,3,2,4,1,2,1,1,5,2,2,1,1,2,3,1,3,1,1,1,
  5200. 3,1,4,2,1,3,6,1,1,3,7,15,5,3,2,5,3,9,11,4,2,22,1,6,3,8,7,1,4,28,4,16,3,3,25,4,4,27,27,1,4,1,2,2,7,1,3,5,2,28,8,2,14,1,8,6,16,25,3,3,3,14,3,
  5201. 3,1,1,2,1,4,6,3,8,4,1,1,1,2,3,6,10,6,2,3,18,3,2,5,5,4,3,1,5,2,5,4,23,7,6,12,6,4,17,11,9,5,1,1,10,5,12,1,1,11,26,33,7,3,6,1,17,7,1,5,12,1,11,
  5202. 2,4,1,8,14,17,23,1,2,1,7,8,16,11,9,6,5,2,6,4,16,2,8,14,1,11,8,9,1,1,1,9,25,4,11,19,7,2,15,2,12,8,52,7,5,19,2,16,4,36,8,1,16,8,24,26,4,6,2,9,
  5203. 5,4,36,3,28,12,25,15,37,27,17,12,59,38,5,32,127,1,2,9,17,14,4,1,2,1,1,8,11,50,4,14,2,19,16,4,17,5,4,5,26,12,45,2,23,45,104,30,12,8,3,10,2,2,
  5204. 3,3,1,4,20,7,2,9,6,15,2,20,1,3,16,4,11,15,6,134,2,5,59,1,2,2,2,1,9,17,3,26,137,10,211,59,1,2,4,1,4,1,1,1,2,6,2,3,1,1,2,3,2,3,1,3,4,4,2,3,3,
  5205. 1,4,3,1,7,2,2,3,1,2,1,3,3,3,2,2,3,2,1,3,14,6,1,3,2,9,6,15,27,9,34,145,1,1,2,1,1,1,1,2,1,1,1,1,2,2,2,3,1,2,1,1,1,2,3,5,8,3,5,2,4,1,3,2,2,2,12,
  5206. 4,1,1,1,10,4,5,1,20,4,16,1,15,9,5,12,2,9,2,5,4,2,26,19,7,1,26,4,30,12,15,42,1,6,8,172,1,1,4,2,1,1,11,2,2,4,2,1,2,1,10,8,1,2,1,4,5,1,2,5,1,8,
  5207. 4,1,3,4,2,1,6,2,1,3,4,1,2,1,1,1,1,12,5,7,2,4,3,1,1,1,3,3,6,1,2,2,3,3,3,2,1,2,12,14,11,6,6,4,12,2,8,1,7,10,1,35,7,4,13,15,4,3,23,21,28,52,5,
  5208. 26,5,6,1,7,10,2,7,53,3,2,1,1,1,2,163,532,1,10,11,1,3,3,4,8,2,8,6,2,2,23,22,4,2,2,4,2,1,3,1,3,3,5,9,8,2,1,2,8,1,10,2,12,21,20,15,105,2,3,1,1,
  5209. 3,2,3,1,1,2,5,1,4,15,11,19,1,1,1,1,5,4,5,1,1,2,5,3,5,12,1,2,5,1,11,1,1,15,9,1,4,5,3,26,8,2,1,3,1,1,15,19,2,12,1,2,5,2,7,2,19,2,20,6,26,7,5,
  5210. 2,2,7,34,21,13,70,2,128,1,1,2,1,1,2,1,1,3,2,2,2,15,1,4,1,3,4,42,10,6,1,49,85,8,1,2,1,1,4,4,2,3,6,1,5,7,4,3,211,4,1,2,1,2,5,1,2,4,2,2,6,5,6,
  5211. 10,3,4,48,100,6,2,16,296,5,27,387,2,2,3,7,16,8,5,38,15,39,21,9,10,3,7,59,13,27,21,47,5,21,6
  5212. };
  5213. static ImWchar base_ranges[] = // not zero-terminated
  5214. {
  5215. 0x0020, 0x00FF, // Basic Latin + Latin Supplement
  5216. 0x2000, 0x206F, // General Punctuation
  5217. 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
  5218. 0x31F0, 0x31FF, // Katakana Phonetic Extensions
  5219. 0xFF00, 0xFFEF, // Half-width characters
  5220. 0xFFFD, 0xFFFD // Invalid
  5221. };
  5222. static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 };
  5223. if (!full_ranges[0])
  5224. {
  5225. memcpy(full_ranges, base_ranges, sizeof(base_ranges));
  5226. UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges));
  5227. }
  5228. return &full_ranges[0];
  5229. }
  5230. const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
  5231. {
  5232. // 2999 ideograms code points for Japanese
  5233. // - 2136 Joyo (meaning "for regular use" or "for common use") Kanji code points
  5234. // - 863 Jinmeiyo (meaning "for personal name") Kanji code points
  5235. // - Sourced from official information provided by the government agencies of Japan:
  5236. // - List of Joyo Kanji by the Agency for Cultural Affairs
  5237. // - https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kijun/naikaku/kanji/
  5238. // - List of Jinmeiyo Kanji by the Ministry of Justice
  5239. // - http://www.moj.go.jp/MINJI/minji86.html
  5240. // - Available under the terms of the Creative Commons Attribution 4.0 International (CC BY 4.0).
  5241. // - https://creativecommons.org/licenses/by/4.0/legalcode
  5242. // - You can generate this code by the script at:
  5243. // - https://github.com/vaiorabbit/everyday_use_kanji
  5244. // - References:
  5245. // - List of Joyo Kanji
  5246. // - (Wikipedia) https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji
  5247. // - List of Jinmeiyo Kanji
  5248. // - (Wikipedia) https://en.wikipedia.org/wiki/Jinmeiy%C5%8D_kanji
  5249. // - Missing 1 Joyo Kanji: U+20B9F (Kun'yomi: Shikaru, On'yomi: Shitsu,shichi), see https://github.com/ocornut/imgui/pull/3627 for details.
  5250. // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
  5251. // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
  5252. static const short accumulative_offsets_from_0x4E00[] =
  5253. {
  5254. 0,1,2,4,1,1,1,1,2,1,3,3,2,2,1,5,3,5,7,5,6,1,2,1,7,2,6,3,1,8,1,1,4,1,1,18,2,11,2,6,2,1,2,1,5,1,2,1,3,1,2,1,2,3,3,1,1,2,3,1,1,1,12,7,9,1,4,5,1,
  5255. 1,2,1,10,1,1,9,2,2,4,5,6,9,3,1,1,1,1,9,3,18,5,2,2,2,2,1,6,3,7,1,1,1,1,2,2,4,2,1,23,2,10,4,3,5,2,4,10,2,4,13,1,6,1,9,3,1,1,6,6,7,6,3,1,2,11,3,
  5256. 2,2,3,2,15,2,2,5,4,3,6,4,1,2,5,2,12,16,6,13,9,13,2,1,1,7,16,4,7,1,19,1,5,1,2,2,7,7,8,2,6,5,4,9,18,7,4,5,9,13,11,8,15,2,1,1,1,2,1,2,2,1,2,2,8,
  5257. 2,9,3,3,1,1,4,4,1,1,1,4,9,1,4,3,5,5,2,7,5,3,4,8,2,1,13,2,3,3,1,14,1,1,4,5,1,3,6,1,5,2,1,1,3,3,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1,1,1,1,12,3,3,9,5,
  5258. 2,6,1,5,6,1,2,3,18,2,4,14,4,1,3,6,1,1,6,3,5,5,3,2,2,2,2,12,3,1,4,2,3,2,3,11,1,7,4,1,2,1,3,17,1,9,1,24,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,2,4,15,1,
  5259. 1,2,1,1,2,1,5,2,5,20,2,5,9,1,10,8,7,6,1,1,1,1,1,1,6,2,1,2,8,1,1,1,1,5,1,1,3,1,1,1,1,3,1,1,12,4,1,3,1,1,1,1,1,10,3,1,7,5,13,1,2,3,4,6,1,1,30,
  5260. 2,9,9,1,15,38,11,3,1,8,24,7,1,9,8,10,2,1,9,31,2,13,6,2,9,4,49,5,2,15,2,1,10,2,1,1,1,2,2,6,15,30,35,3,14,18,8,1,16,10,28,12,19,45,38,1,3,2,3,
  5261. 13,2,1,7,3,6,5,3,4,3,1,5,7,8,1,5,3,18,5,3,6,1,21,4,24,9,24,40,3,14,3,21,3,2,1,2,4,2,3,1,15,15,6,5,1,1,3,1,5,6,1,9,7,3,3,2,1,4,3,8,21,5,16,4,
  5262. 5,2,10,11,11,3,6,3,2,9,3,6,13,1,2,1,1,1,1,11,12,6,6,1,4,2,6,5,2,1,1,3,3,6,13,3,1,1,5,1,2,3,3,14,2,1,2,2,2,5,1,9,5,1,1,6,12,3,12,3,4,13,2,14,
  5263. 2,8,1,17,5,1,16,4,2,2,21,8,9,6,23,20,12,25,19,9,38,8,3,21,40,25,33,13,4,3,1,4,1,2,4,1,2,5,26,2,1,1,2,1,3,6,2,1,1,1,1,1,1,2,3,1,1,1,9,2,3,1,1,
  5264. 1,3,6,3,2,1,1,6,6,1,8,2,2,2,1,4,1,2,3,2,7,3,2,4,1,2,1,2,2,1,1,1,1,1,3,1,2,5,4,10,9,4,9,1,1,1,1,1,1,5,3,2,1,6,4,9,6,1,10,2,31,17,8,3,7,5,40,1,
  5265. 7,7,1,6,5,2,10,7,8,4,15,39,25,6,28,47,18,10,7,1,3,1,1,2,1,1,1,3,3,3,1,1,1,3,4,2,1,4,1,3,6,10,7,8,6,2,2,1,3,3,2,5,8,7,9,12,2,15,1,1,4,1,2,1,1,
  5266. 1,3,2,1,3,3,5,6,2,3,2,10,1,4,2,8,1,1,1,11,6,1,21,4,16,3,1,3,1,4,2,3,6,5,1,3,1,1,3,3,4,6,1,1,10,4,2,7,10,4,7,4,2,9,4,3,1,1,1,4,1,8,3,4,1,3,1,
  5267. 6,1,4,2,1,4,7,2,1,8,1,4,5,1,1,2,2,4,6,2,7,1,10,1,1,3,4,11,10,8,21,4,6,1,3,5,2,1,2,28,5,5,2,3,13,1,2,3,1,4,2,1,5,20,3,8,11,1,3,3,3,1,8,10,9,2,
  5268. 10,9,2,3,1,1,2,4,1,8,3,6,1,7,8,6,11,1,4,29,8,4,3,1,2,7,13,1,4,1,6,2,6,12,12,2,20,3,2,3,6,4,8,9,2,7,34,5,1,18,6,1,1,4,4,5,7,9,1,2,2,4,3,4,1,7,
  5269. 2,2,2,6,2,3,25,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,5,3,4,4,3,2,1,1,4,1,2,1,1,3,1,11,1,6,3,1,7,3,6,2,8,8,6,9,3,4,11,3,2,10,12,2,5,11,1,6,4,5,
  5270. 3,1,8,5,4,6,6,3,5,1,1,3,2,1,2,2,6,17,12,1,10,1,6,12,1,6,6,19,9,6,16,1,13,4,4,15,7,17,6,11,9,15,12,6,7,2,1,2,2,15,9,3,21,4,6,49,18,7,3,2,3,1,
  5271. 6,8,2,2,6,2,9,1,3,6,4,4,1,2,16,2,5,2,1,6,2,3,5,3,1,2,5,1,2,1,9,3,1,8,6,4,8,11,3,1,1,1,1,3,1,13,8,4,1,3,2,2,1,4,1,11,1,5,2,1,5,2,5,8,6,1,1,7,
  5272. 4,3,8,3,2,7,2,1,5,1,5,2,4,7,6,2,8,5,1,11,4,5,3,6,18,1,2,13,3,3,1,21,1,1,4,1,4,1,1,1,8,1,2,2,7,1,2,4,2,2,9,2,1,1,1,4,3,6,3,12,5,1,1,1,5,6,3,2,
  5273. 4,8,2,2,4,2,7,1,8,9,5,2,3,2,1,3,2,13,7,14,6,5,1,1,2,1,4,2,23,2,1,1,6,3,1,4,1,15,3,1,7,3,9,14,1,3,1,4,1,1,5,8,1,3,8,3,8,15,11,4,14,4,4,2,5,5,
  5274. 1,7,1,6,14,7,7,8,5,15,4,8,6,5,6,2,1,13,1,20,15,11,9,2,5,6,2,11,2,6,2,5,1,5,8,4,13,19,25,4,1,1,11,1,34,2,5,9,14,6,2,2,6,1,1,14,1,3,14,13,1,6,
  5275. 12,21,14,14,6,32,17,8,32,9,28,1,2,4,11,8,3,1,14,2,5,15,1,1,1,1,3,6,4,1,3,4,11,3,1,1,11,30,1,5,1,4,1,5,8,1,1,3,2,4,3,17,35,2,6,12,17,3,1,6,2,
  5276. 1,1,12,2,7,3,3,2,1,16,2,8,3,6,5,4,7,3,3,8,1,9,8,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,4,3,7,5,8,3,3,3,3,3,3,1,23,10,3,1,2,2,6,3,1,16,1,16,
  5277. 22,3,10,4,11,6,9,7,7,3,6,2,2,2,4,10,2,1,1,2,8,7,1,6,4,1,3,3,3,5,10,12,12,2,3,12,8,15,1,1,16,6,6,1,5,9,11,4,11,4,2,6,12,1,17,5,13,1,4,9,5,1,11,
  5278. 2,1,8,1,5,7,28,8,3,5,10,2,17,3,38,22,1,2,18,12,10,4,38,18,1,4,44,19,4,1,8,4,1,12,1,4,31,12,1,14,7,75,7,5,10,6,6,13,3,2,11,11,3,2,5,28,15,6,18,
  5279. 18,5,6,4,3,16,1,7,18,7,36,3,5,3,1,7,1,9,1,10,7,2,4,2,6,2,9,7,4,3,32,12,3,7,10,2,23,16,3,1,12,3,31,4,11,1,3,8,9,5,1,30,15,6,12,3,2,2,11,19,9,
  5280. 14,2,6,2,3,19,13,17,5,3,3,25,3,14,1,1,1,36,1,3,2,19,3,13,36,9,13,31,6,4,16,34,2,5,4,2,3,3,5,1,1,1,4,3,1,17,3,2,3,5,3,1,3,2,3,5,6,3,12,11,1,3,
  5281. 1,2,26,7,12,7,2,14,3,3,7,7,11,25,25,28,16,4,36,1,2,1,6,2,1,9,3,27,17,4,3,4,13,4,1,3,2,2,1,10,4,2,4,6,3,8,2,1,18,1,1,24,2,2,4,33,2,3,63,7,1,6,
  5282. 40,7,3,4,4,2,4,15,18,1,16,1,1,11,2,41,14,1,3,18,13,3,2,4,16,2,17,7,15,24,7,18,13,44,2,2,3,6,1,1,7,5,1,7,1,4,3,3,5,10,8,2,3,1,8,1,1,27,4,2,1,
  5283. 12,1,2,1,10,6,1,6,7,5,2,3,7,11,5,11,3,6,6,2,3,15,4,9,1,1,2,1,2,11,2,8,12,8,5,4,2,3,1,5,2,2,1,14,1,12,11,4,1,11,17,17,4,3,2,5,5,7,3,1,5,9,9,8,
  5284. 2,5,6,6,13,13,2,1,2,6,1,2,2,49,4,9,1,2,10,16,7,8,4,3,2,23,4,58,3,29,1,14,19,19,11,11,2,7,5,1,3,4,6,2,18,5,12,12,17,17,3,3,2,4,1,6,2,3,4,3,1,
  5285. 1,1,1,5,1,1,9,1,3,1,3,6,1,8,1,1,2,6,4,14,3,1,4,11,4,1,3,32,1,2,4,13,4,1,2,4,2,1,3,1,11,1,4,2,1,4,4,6,3,5,1,6,5,7,6,3,23,3,5,3,5,3,3,13,3,9,10,
  5286. 1,12,10,2,3,18,13,7,160,52,4,2,2,3,2,14,5,4,12,4,6,4,1,20,4,11,6,2,12,27,1,4,1,2,2,7,4,5,2,28,3,7,25,8,3,19,3,6,10,2,2,1,10,2,5,4,1,3,4,1,5,
  5287. 3,2,6,9,3,6,2,16,3,3,16,4,5,5,3,2,1,2,16,15,8,2,6,21,2,4,1,22,5,8,1,1,21,11,2,1,11,11,19,13,12,4,2,3,2,3,6,1,8,11,1,4,2,9,5,2,1,11,2,9,1,1,2,
  5288. 14,31,9,3,4,21,14,4,8,1,7,2,2,2,5,1,4,20,3,3,4,10,1,11,9,8,2,1,4,5,14,12,14,2,17,9,6,31,4,14,1,20,13,26,5,2,7,3,6,13,2,4,2,19,6,2,2,18,9,3,5,
  5289. 12,12,14,4,6,2,3,6,9,5,22,4,5,25,6,4,8,5,2,6,27,2,35,2,16,3,7,8,8,6,6,5,9,17,2,20,6,19,2,13,3,1,1,1,4,17,12,2,14,7,1,4,18,12,38,33,2,10,1,1,
  5290. 2,13,14,17,11,50,6,33,20,26,74,16,23,45,50,13,38,33,6,6,7,4,4,2,1,3,2,5,8,7,8,9,3,11,21,9,13,1,3,10,6,7,1,2,2,18,5,5,1,9,9,2,68,9,19,13,2,5,
  5291. 1,4,4,7,4,13,3,9,10,21,17,3,26,2,1,5,2,4,5,4,1,7,4,7,3,4,2,1,6,1,1,20,4,1,9,2,2,1,3,3,2,3,2,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,3,2,10,3,5,3,4,4,
  5292. 3,4,16,1,6,1,10,2,4,2,1,1,2,10,11,2,2,3,1,24,31,4,10,10,2,5,12,16,164,15,4,16,7,9,15,19,17,1,2,1,1,5,1,1,1,1,1,3,1,4,3,1,3,1,3,1,2,1,1,3,3,7,
  5293. 2,8,1,2,2,2,1,3,4,3,7,8,12,92,2,10,3,1,3,14,5,25,16,42,4,7,7,4,2,21,5,27,26,27,21,25,30,31,2,1,5,13,3,22,5,6,6,11,9,12,1,5,9,7,5,5,22,60,3,5,
  5294. 13,1,1,8,1,1,3,3,2,1,9,3,3,18,4,1,2,3,7,6,3,1,2,3,9,1,3,1,3,2,1,3,1,1,1,2,1,11,3,1,6,9,1,3,2,3,1,2,1,5,1,1,4,3,4,1,2,2,4,4,1,7,2,1,2,2,3,5,13,
  5295. 18,3,4,14,9,9,4,16,3,7,5,8,2,6,48,28,3,1,1,4,2,14,8,2,9,2,1,15,2,4,3,2,10,16,12,8,7,1,1,3,1,1,1,2,7,4,1,6,4,38,39,16,23,7,15,15,3,2,12,7,21,
  5296. 37,27,6,5,4,8,2,10,8,8,6,5,1,2,1,3,24,1,16,17,9,23,10,17,6,1,51,55,44,13,294,9,3,6,2,4,2,2,15,1,1,1,13,21,17,68,14,8,9,4,1,4,9,3,11,7,1,1,1,
  5297. 5,6,3,2,1,1,1,2,3,8,1,2,2,4,1,5,5,2,1,4,3,7,13,4,1,4,1,3,1,1,1,5,5,10,1,6,1,5,2,1,5,2,4,1,4,5,7,3,18,2,9,11,32,4,3,3,2,4,7,11,16,9,11,8,13,38,
  5298. 32,8,4,2,1,1,2,1,2,4,4,1,1,1,4,1,21,3,11,1,16,1,1,6,1,3,2,4,9,8,57,7,44,1,3,3,13,3,10,1,1,7,5,2,7,21,47,63,3,15,4,7,1,16,1,1,2,8,2,3,42,15,4,
  5299. 1,29,7,22,10,3,78,16,12,20,18,4,67,11,5,1,3,15,6,21,31,32,27,18,13,71,35,5,142,4,10,1,2,50,19,33,16,35,37,16,19,27,7,1,133,19,1,4,8,7,20,1,4,
  5300. 4,1,10,3,1,6,1,2,51,5,40,15,24,43,22928,11,1,13,154,70,3,1,1,7,4,10,1,2,1,1,2,1,2,1,2,2,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,
  5301. 3,2,1,1,1,1,2,1,1,
  5302. };
  5303. static ImWchar base_ranges[] = // not zero-terminated
  5304. {
  5305. 0x0020, 0x00FF, // Basic Latin + Latin Supplement
  5306. 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
  5307. 0x31F0, 0x31FF, // Katakana Phonetic Extensions
  5308. 0xFF00, 0xFFEF, // Half-width characters
  5309. 0xFFFD, 0xFFFD // Invalid
  5310. };
  5311. static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 };
  5312. if (!full_ranges[0])
  5313. {
  5314. memcpy(full_ranges, base_ranges, sizeof(base_ranges));
  5315. UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges));
  5316. }
  5317. return &full_ranges[0];
  5318. }
  5319. const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic()
  5320. {
  5321. static const ImWchar ranges[] =
  5322. {
  5323. 0x0020, 0x00FF, // Basic Latin + Latin Supplement
  5324. 0x0400, 0x052F, // Cyrillic + Cyrillic Supplement
  5325. 0x2DE0, 0x2DFF, // Cyrillic Extended-A
  5326. 0xA640, 0xA69F, // Cyrillic Extended-B
  5327. 0,
  5328. };
  5329. return &ranges[0];
  5330. }
  5331. const ImWchar* ImFontAtlas::GetGlyphRangesThai()
  5332. {
  5333. static const ImWchar ranges[] =
  5334. {
  5335. 0x0020, 0x00FF, // Basic Latin
  5336. 0x2010, 0x205E, // Punctuations
  5337. 0x0E00, 0x0E7F, // Thai
  5338. 0,
  5339. };
  5340. return &ranges[0];
  5341. }
  5342. const ImWchar* ImFontAtlas::GetGlyphRangesVietnamese()
  5343. {
  5344. static const ImWchar ranges[] =
  5345. {
  5346. 0x0020, 0x00FF, // Basic Latin
  5347. 0x0102, 0x0103,
  5348. 0x0110, 0x0111,
  5349. 0x0128, 0x0129,
  5350. 0x0168, 0x0169,
  5351. 0x01A0, 0x01A1,
  5352. 0x01AF, 0x01B0,
  5353. 0x1EA0, 0x1EF9,
  5354. 0,
  5355. };
  5356. return &ranges[0];
  5357. }
  5358. #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
  5359. //-----------------------------------------------------------------------------
  5360. // [SECTION] ImFontGlyphRangesBuilder
  5361. //-----------------------------------------------------------------------------
  5362. void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
  5363. {
  5364. while (text_end ? (text < text_end) : *text)
  5365. {
  5366. unsigned int c = 0;
  5367. int c_len = ImTextCharFromUtf8(&c, text, text_end);
  5368. text += c_len;
  5369. if (c_len == 0)
  5370. break;
  5371. AddChar((ImWchar)c);
  5372. }
  5373. }
  5374. void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)
  5375. {
  5376. for (; ranges[0]; ranges += 2)
  5377. for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560
  5378. AddChar((ImWchar)c);
  5379. }
  5380. void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
  5381. {
  5382. const int max_codepoint = IM_UNICODE_CODEPOINT_MAX;
  5383. for (int n = 0; n <= max_codepoint; n++)
  5384. if (GetBit(n))
  5385. {
  5386. out_ranges->push_back((ImWchar)n);
  5387. while (n < max_codepoint && GetBit(n + 1))
  5388. n++;
  5389. out_ranges->push_back((ImWchar)n);
  5390. }
  5391. out_ranges->push_back(0);
  5392. }
  5393. //-----------------------------------------------------------------------------
  5394. // [SECTION] ImFont
  5395. //-----------------------------------------------------------------------------
  5396. ImFontBaked::ImFontBaked()
  5397. {
  5398. memset(this, 0, sizeof(*this));
  5399. FallbackGlyphIndex = -1;
  5400. }
  5401. void ImFontBaked::ClearOutputData()
  5402. {
  5403. FallbackAdvanceX = 0.0f;
  5404. Glyphs.clear();
  5405. IndexAdvanceX.clear();
  5406. IndexLookup.clear();
  5407. FallbackGlyphIndex = -1;
  5408. Ascent = Descent = 0.0f;
  5409. MetricsTotalSurface = 0;
  5410. }
  5411. ImFont::ImFont()
  5412. {
  5413. memset(this, 0, sizeof(*this));
  5414. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
  5415. Scale = 1.0f;
  5416. #endif
  5417. }
  5418. ImFont::~ImFont()
  5419. {
  5420. ClearOutputData();
  5421. }
  5422. void ImFont::ClearOutputData()
  5423. {
  5424. if (ImFontAtlas* atlas = ContainerAtlas)
  5425. ImFontAtlasFontDiscardBakes(atlas, this, 0);
  5426. FallbackChar = EllipsisChar = 0;
  5427. memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap));
  5428. LastBaked = NULL;
  5429. }
  5430. // API is designed this way to avoid exposing the 8K page size
  5431. // e.g. use with IsGlyphRangeUnused(0, 255)
  5432. bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)
  5433. {
  5434. unsigned int page_begin = (c_begin / 8192);
  5435. unsigned int page_last = (c_last / 8192);
  5436. for (unsigned int page_n = page_begin; page_n <= page_last; page_n++)
  5437. if ((page_n >> 3) < sizeof(Used8kPagesMap))
  5438. if (Used8kPagesMap[page_n >> 3] & (1 << (page_n & 7)))
  5439. return false;
  5440. return true;
  5441. }
  5442. // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.
  5443. // Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis).
  5444. // - 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target font.
  5445. ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph)
  5446. {
  5447. int glyph_idx = baked->Glyphs.Size;
  5448. baked->Glyphs.push_back(*in_glyph);
  5449. ImFontGlyph* glyph = &baked->Glyphs[glyph_idx];
  5450. IM_ASSERT(baked->Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved.
  5451. // Set UV from packed rectangle
  5452. if (glyph->PackId != ImFontAtlasRectId_Invalid)
  5453. {
  5454. ImTextureRect* r = ImFontAtlasPackGetRect(atlas, glyph->PackId);
  5455. IM_ASSERT(glyph->U0 == 0.0f && glyph->V0 == 0.0f && glyph->U1 == 0.0f && glyph->V1 == 0.0f);
  5456. glyph->U0 = (r->x) * atlas->TexUvScale.x;
  5457. glyph->V0 = (r->y) * atlas->TexUvScale.y;
  5458. glyph->U1 = (r->x + r->w) * atlas->TexUvScale.x;
  5459. glyph->V1 = (r->y + r->h) * atlas->TexUvScale.y;
  5460. baked->MetricsTotalSurface += r->w * r->h;
  5461. }
  5462. if (src != NULL)
  5463. {
  5464. // Clamp & recenter if needed
  5465. const float ref_size = baked->ContainerFont->Sources[0]->SizePixels;
  5466. const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f;
  5467. float advance_x = ImClamp(glyph->AdvanceX, src->GlyphMinAdvanceX * offsets_scale, src->GlyphMaxAdvanceX * offsets_scale);
  5468. if (advance_x != glyph->AdvanceX)
  5469. {
  5470. float char_off_x = src->PixelSnapH ? ImTrunc((advance_x - glyph->AdvanceX) * 0.5f) : (advance_x - glyph->AdvanceX) * 0.5f;
  5471. glyph->X0 += char_off_x;
  5472. glyph->X1 += char_off_x;
  5473. }
  5474. // Snap to pixel
  5475. if (src->PixelSnapH)
  5476. advance_x = IM_ROUND(advance_x);
  5477. // Bake spacing
  5478. glyph->AdvanceX = advance_x + src->GlyphExtraAdvanceX;
  5479. }
  5480. if (glyph->Colored)
  5481. atlas->TexPixelsUseColors = atlas->TexData->UseColors = true;
  5482. // Update lookup tables
  5483. const int codepoint = glyph->Codepoint;
  5484. ImFontBaked_BuildGrowIndex(baked, codepoint + 1);
  5485. baked->IndexAdvanceX[codepoint] = glyph->AdvanceX;
  5486. baked->IndexLookup[codepoint] = (ImU16)glyph_idx;
  5487. const int page_n = codepoint / 8192;
  5488. baked->ContainerFont->Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7);
  5489. return glyph;
  5490. }
  5491. // FIXME: Code is duplicated with code above.
  5492. void ImFontAtlasBakedAddFontGlyphAdvancedX(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImWchar codepoint, float advance_x)
  5493. {
  5494. IM_UNUSED(atlas);
  5495. if (src != NULL)
  5496. {
  5497. // Clamp & recenter if needed
  5498. const float ref_size = baked->ContainerFont->Sources[0]->SizePixels;
  5499. const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f;
  5500. advance_x = ImClamp(advance_x, src->GlyphMinAdvanceX * offsets_scale, src->GlyphMaxAdvanceX * offsets_scale);
  5501. // Snap to pixel
  5502. if (src->PixelSnapH)
  5503. advance_x = IM_ROUND(advance_x);
  5504. // Bake spacing
  5505. advance_x += src->GlyphExtraAdvanceX;
  5506. }
  5507. ImFontBaked_BuildGrowIndex(baked, codepoint + 1);
  5508. baked->IndexAdvanceX[codepoint] = advance_x;
  5509. }
  5510. // Copy to texture, post-process and queue update for backend
  5511. void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImTextureRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch)
  5512. {
  5513. ImTextureData* tex = atlas->TexData;
  5514. IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height);
  5515. ImFontAtlasTextureBlockConvert(src_pixels, src_fmt, src_pitch, (unsigned char*)tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), r->w, r->h);
  5516. ImFontAtlasPostProcessData pp_data = { atlas, baked->ContainerFont, src, baked, glyph, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), r->w, r->h };
  5517. ImFontAtlasTextureBlockPostProcess(&pp_data);
  5518. ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h);
  5519. }
  5520. void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint)
  5521. {
  5522. RemapPairs.SetInt((ImGuiID)from_codepoint, (int)to_codepoint);
  5523. }
  5524. // Find glyph, load if necessary, return fallback if missing
  5525. ImFontGlyph* ImFontBaked::FindGlyph(ImWchar c)
  5526. {
  5527. if (c < (size_t)IndexLookup.Size) IM_LIKELY
  5528. {
  5529. const int i = (int)IndexLookup.Data[c];
  5530. if (i == IM_FONTGLYPH_INDEX_NOT_FOUND)
  5531. return &Glyphs.Data[FallbackGlyphIndex];
  5532. if (i != IM_FONTGLYPH_INDEX_UNUSED)
  5533. return &Glyphs.Data[i];
  5534. }
  5535. ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c, NULL);
  5536. return glyph ? glyph : &Glyphs.Data[FallbackGlyphIndex];
  5537. }
  5538. // Attempt to load but when missing, return NULL instead of FallbackGlyph
  5539. ImFontGlyph* ImFontBaked::FindGlyphNoFallback(ImWchar c)
  5540. {
  5541. if (c < (size_t)IndexLookup.Size) IM_LIKELY
  5542. {
  5543. const int i = (int)IndexLookup.Data[c];
  5544. if (i == IM_FONTGLYPH_INDEX_NOT_FOUND)
  5545. return NULL;
  5546. if (i != IM_FONTGLYPH_INDEX_UNUSED)
  5547. return &Glyphs.Data[i];
  5548. }
  5549. LoadNoFallback = true; // This is actually a rare call, not done in hot-loop, so we prioritize not adding extra cruft to ImFontBaked_BuildLoadGlyph() call sites.
  5550. ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c, NULL);
  5551. LoadNoFallback = false;
  5552. return glyph;
  5553. }
  5554. bool ImFontBaked::IsGlyphLoaded(ImWchar c)
  5555. {
  5556. if (c < (size_t)IndexLookup.Size) IM_LIKELY
  5557. {
  5558. const int i = (int)IndexLookup.Data[c];
  5559. if (i == IM_FONTGLYPH_INDEX_NOT_FOUND)
  5560. return false;
  5561. if (i != IM_FONTGLYPH_INDEX_UNUSED)
  5562. return true;
  5563. }
  5564. return false;
  5565. }
  5566. // This is not fast query
  5567. bool ImFont::IsGlyphInFont(ImWchar c)
  5568. {
  5569. ImFontAtlas* atlas = ContainerAtlas;
  5570. ImFontAtlas_FontHookRemapCodepoint(atlas, this, &c);
  5571. for (ImFontConfig* src : Sources)
  5572. {
  5573. const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
  5574. if (loader->FontSrcContainsGlyph != NULL && loader->FontSrcContainsGlyph(atlas, src, c))
  5575. return true;
  5576. }
  5577. return false;
  5578. }
  5579. // This is manually inlined in CalcTextSizeA() and CalcWordWrapPosition(), with a non-inline call to BuildLoadGlyphGetAdvanceOrFallback().
  5580. IM_MSVC_RUNTIME_CHECKS_OFF
  5581. float ImFontBaked::GetCharAdvance(ImWchar c)
  5582. {
  5583. if ((int)c < IndexAdvanceX.Size)
  5584. {
  5585. // Missing glyphs fitting inside index will have stored FallbackAdvanceX already.
  5586. const float x = IndexAdvanceX.Data[c];
  5587. if (x >= 0.0f)
  5588. return x;
  5589. }
  5590. return ImFontBaked_BuildLoadGlyphAdvanceX(this, c);
  5591. }
  5592. IM_MSVC_RUNTIME_CHECKS_RESTORE
  5593. ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size, float rasterizer_density)
  5594. {
  5595. struct { ImGuiID FontId; float BakedSize; float RasterizerDensity; } hashed_data;
  5596. hashed_data.FontId = font_id;
  5597. hashed_data.BakedSize = baked_size;
  5598. hashed_data.RasterizerDensity = rasterizer_density;
  5599. return ImHashData(&hashed_data, sizeof(hashed_data));
  5600. }
  5601. // ImFontBaked pointers are valid for the entire frame but shall never be kept between frames.
  5602. ImFontBaked* ImFont::GetFontBaked(float size, float density)
  5603. {
  5604. ImFontBaked* baked = LastBaked;
  5605. // Round font size
  5606. // - ImGui::PushFont() will already round, but other paths calling GetFontBaked() directly also needs it (e.g. ImFontAtlasBuildPreloadAllGlyphRanges)
  5607. size = ImGui::GetRoundedFontSize(size);
  5608. if (density < 0.0f)
  5609. density = CurrentRasterizerDensity;
  5610. if (baked && baked->Size == size && baked->RasterizerDensity == density)
  5611. return baked;
  5612. ImFontAtlas* atlas = ContainerAtlas;
  5613. ImFontAtlasBuilder* builder = atlas->Builder;
  5614. baked = ImFontAtlasBakedGetOrAdd(atlas, this, size, density);
  5615. if (baked == NULL)
  5616. return NULL;
  5617. baked->LastUsedFrame = builder->FrameCount;
  5618. LastBaked = baked;
  5619. return baked;
  5620. }
  5621. ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density)
  5622. {
  5623. // FIXME-NEWATLAS: Design for picking a nearest size based on some criteria?
  5624. // FIXME-NEWATLAS: Altering font density won't work right away.
  5625. IM_ASSERT(font_size > 0.0f && font_rasterizer_density > 0.0f);
  5626. ImGuiID baked_id = ImFontAtlasBakedGetId(font->FontId, font_size, font_rasterizer_density);
  5627. ImFontAtlasBuilder* builder = atlas->Builder;
  5628. ImFontBaked** p_baked_in_map = (ImFontBaked**)builder->BakedMap.GetVoidPtrRef(baked_id);
  5629. ImFontBaked* baked = *p_baked_in_map;
  5630. if (baked != NULL)
  5631. {
  5632. IM_ASSERT(baked->Size == font_size && baked->ContainerFont == font && baked->BakedId == baked_id);
  5633. return baked;
  5634. }
  5635. // If atlas is locked, find closest match
  5636. // FIXME-OPT: This is not an optimal query.
  5637. if ((font->Flags & ImFontFlags_LockBakedSizes) || atlas->Locked)
  5638. {
  5639. baked = ImFontAtlasBakedGetClosestMatch(atlas, font, font_size, font_rasterizer_density);
  5640. if (baked != NULL)
  5641. return baked;
  5642. if (atlas->Locked)
  5643. {
  5644. IM_ASSERT(!atlas->Locked && "Cannot use dynamic font size with a locked ImFontAtlas!"); // Locked because rendering backend does not support ImGuiBackendFlags_RendererHasTextures!
  5645. return NULL;
  5646. }
  5647. }
  5648. // Create new
  5649. baked = ImFontAtlasBakedAdd(atlas, font, font_size, font_rasterizer_density, baked_id);
  5650. *p_baked_in_map = baked; // To avoid 'builder->BakedMap.SetVoidPtr(baked_id, baked);' while we can.
  5651. return baked;
  5652. }
  5653. // Trim trailing space and find beginning of next line
  5654. static inline const char* CalcWordWrapNextLineStartA(const char* text, const char* text_end)
  5655. {
  5656. while (text < text_end && ImCharIsBlankA(*text))
  5657. text++;
  5658. if (*text == '\n')
  5659. text++;
  5660. return text;
  5661. }
  5662. // Simple word-wrapping for English, not full-featured. Please submit failing cases!
  5663. // This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end.
  5664. // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.)
  5665. const char* ImFont::CalcWordWrapPosition(float size, const char* text, const char* text_end, float wrap_width)
  5666. {
  5667. // For references, possible wrap point marked with ^
  5668. // "aaa bbb, ccc,ddd. eee fff. ggg!"
  5669. // ^ ^ ^ ^ ^__ ^ ^
  5670. // List of hardcoded separators: .,;!?'"
  5671. // Skip extra blanks after a line returns (that includes not counting them in width computation)
  5672. // e.g. "Hello world" --> "Hello" "World"
  5673. // Cut words that cannot possibly fit within one line.
  5674. // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
  5675. ImFontBaked* baked = GetFontBaked(size);
  5676. const float scale = size / baked->Size;
  5677. float line_width = 0.0f;
  5678. float word_width = 0.0f;
  5679. float blank_width = 0.0f;
  5680. wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
  5681. const char* word_end = text;
  5682. const char* prev_word_end = NULL;
  5683. bool inside_word = true;
  5684. const char* s = text;
  5685. IM_ASSERT(text_end != NULL);
  5686. while (s < text_end)
  5687. {
  5688. unsigned int c = (unsigned int)*s;
  5689. const char* next_s;
  5690. if (c < 0x80)
  5691. next_s = s + 1;
  5692. else
  5693. next_s = s + ImTextCharFromUtf8(&c, s, text_end);
  5694. if (c < 32)
  5695. {
  5696. if (c == '\n')
  5697. {
  5698. line_width = word_width = blank_width = 0.0f;
  5699. inside_word = true;
  5700. s = next_s;
  5701. continue;
  5702. }
  5703. if (c == '\r')
  5704. {
  5705. s = next_s;
  5706. continue;
  5707. }
  5708. }
  5709. // Optimized inline version of 'float char_width = GetCharAdvance((ImWchar)c);'
  5710. float char_width = (c < (unsigned int)baked->IndexAdvanceX.Size) ? baked->IndexAdvanceX.Data[c] : -1.0f;
  5711. if (char_width < 0.0f)
  5712. char_width = BuildLoadGlyphGetAdvanceOrFallback(baked, c);
  5713. if (ImCharIsBlankW(c))
  5714. {
  5715. if (inside_word)
  5716. {
  5717. line_width += blank_width;
  5718. blank_width = 0.0f;
  5719. word_end = s;
  5720. }
  5721. blank_width += char_width;
  5722. inside_word = false;
  5723. }
  5724. else
  5725. {
  5726. word_width += char_width;
  5727. if (inside_word)
  5728. {
  5729. word_end = next_s;
  5730. }
  5731. else
  5732. {
  5733. prev_word_end = word_end;
  5734. line_width += word_width + blank_width;
  5735. word_width = blank_width = 0.0f;
  5736. }
  5737. // Allow wrapping after punctuation.
  5738. inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"' && c != 0x3001 && c != 0x3002);
  5739. }
  5740. // We ignore blank width at the end of the line (they can be skipped)
  5741. if (line_width + word_width > wrap_width)
  5742. {
  5743. // Words that cannot possibly fit within an entire line will be cut anywhere.
  5744. if (word_width < wrap_width)
  5745. s = prev_word_end ? prev_word_end : word_end;
  5746. break;
  5747. }
  5748. s = next_s;
  5749. }
  5750. // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
  5751. // +1 may not be a character start point in UTF-8 but it's ok because caller loops use (text >= word_wrap_eol).
  5752. if (s == text && text < text_end)
  5753. return s + ImTextCountUtf8BytesFromChar(s, text_end);
  5754. return s;
  5755. }
  5756. ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining)
  5757. {
  5758. if (!text_end)
  5759. text_end = text_begin + ImStrlen(text_begin); // FIXME-OPT: Need to avoid this.
  5760. const float line_height = size;
  5761. ImFontBaked* baked = GetFontBaked(size);
  5762. const float scale = size / baked->Size;
  5763. ImVec2 text_size = ImVec2(0, 0);
  5764. float line_width = 0.0f;
  5765. const bool word_wrap_enabled = (wrap_width > 0.0f);
  5766. const char* word_wrap_eol = NULL;
  5767. const char* s = text_begin;
  5768. while (s < text_end)
  5769. {
  5770. if (word_wrap_enabled)
  5771. {
  5772. // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.
  5773. if (!word_wrap_eol)
  5774. word_wrap_eol = CalcWordWrapPosition(size, s, text_end, wrap_width - line_width);
  5775. if (s >= word_wrap_eol)
  5776. {
  5777. if (text_size.x < line_width)
  5778. text_size.x = line_width;
  5779. text_size.y += line_height;
  5780. line_width = 0.0f;
  5781. word_wrap_eol = NULL;
  5782. s = CalcWordWrapNextLineStartA(s, text_end); // Wrapping skips upcoming blanks
  5783. continue;
  5784. }
  5785. }
  5786. // Decode and advance source
  5787. const char* prev_s = s;
  5788. unsigned int c = (unsigned int)*s;
  5789. if (c < 0x80)
  5790. s += 1;
  5791. else
  5792. s += ImTextCharFromUtf8(&c, s, text_end);
  5793. if (c < 32)
  5794. {
  5795. if (c == '\n')
  5796. {
  5797. text_size.x = ImMax(text_size.x, line_width);
  5798. text_size.y += line_height;
  5799. line_width = 0.0f;
  5800. continue;
  5801. }
  5802. if (c == '\r')
  5803. continue;
  5804. }
  5805. // Optimized inline version of 'float char_width = GetCharAdvance((ImWchar)c);'
  5806. float char_width = (c < (unsigned int)baked->IndexAdvanceX.Size) ? baked->IndexAdvanceX.Data[c] : -1.0f;
  5807. if (char_width < 0.0f)
  5808. char_width = BuildLoadGlyphGetAdvanceOrFallback(baked, c);
  5809. char_width *= scale;
  5810. if (line_width + char_width >= max_width)
  5811. {
  5812. s = prev_s;
  5813. break;
  5814. }
  5815. line_width += char_width;
  5816. }
  5817. if (text_size.x < line_width)
  5818. text_size.x = line_width;
  5819. if (line_width > 0 || text_size.y == 0.0f)
  5820. text_size.y += line_height;
  5821. if (remaining)
  5822. *remaining = s;
  5823. return text_size;
  5824. }
  5825. // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
  5826. void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip)
  5827. {
  5828. ImFontBaked* baked = GetFontBaked(size);
  5829. const ImFontGlyph* glyph = baked->FindGlyph(c);
  5830. if (!glyph || !glyph->Visible)
  5831. return;
  5832. if (glyph->Colored)
  5833. col |= ~IM_COL32_A_MASK;
  5834. float scale = (size >= 0.0f) ? (size / baked->Size) : 1.0f;
  5835. float x = IM_TRUNC(pos.x);
  5836. float y = IM_TRUNC(pos.y);
  5837. float x1 = x + glyph->X0 * scale;
  5838. float x2 = x + glyph->X1 * scale;
  5839. if (cpu_fine_clip && (x1 > cpu_fine_clip->z || x2 < cpu_fine_clip->x))
  5840. return;
  5841. float y1 = y + glyph->Y0 * scale;
  5842. float y2 = y + glyph->Y1 * scale;
  5843. float u1 = glyph->U0;
  5844. float v1 = glyph->V0;
  5845. float u2 = glyph->U1;
  5846. float v2 = glyph->V1;
  5847. // Always CPU fine clip. Code extracted from RenderText().
  5848. // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
  5849. if (cpu_fine_clip != NULL)
  5850. {
  5851. if (x1 < cpu_fine_clip->x) { u1 = u1 + (1.0f - (x2 - cpu_fine_clip->x) / (x2 - x1)) * (u2 - u1); x1 = cpu_fine_clip->x; }
  5852. if (y1 < cpu_fine_clip->y) { v1 = v1 + (1.0f - (y2 - cpu_fine_clip->y) / (y2 - y1)) * (v2 - v1); y1 = cpu_fine_clip->y; }
  5853. if (x2 > cpu_fine_clip->z) { u2 = u1 + ((cpu_fine_clip->z - x1) / (x2 - x1)) * (u2 - u1); x2 = cpu_fine_clip->z; }
  5854. if (y2 > cpu_fine_clip->w) { v2 = v1 + ((cpu_fine_clip->w - y1) / (y2 - y1)) * (v2 - v1); y2 = cpu_fine_clip->w; }
  5855. if (y1 >= y2)
  5856. return;
  5857. }
  5858. draw_list->PrimReserve(6, 4);
  5859. draw_list->PrimRectUV(ImVec2(x1, y1), ImVec2(x2, y2), ImVec2(u1, v1), ImVec2(u2, v2), col);
  5860. }
  5861. // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
  5862. void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip)
  5863. {
  5864. // Align to be pixel perfect
  5865. begin:
  5866. float x = IM_TRUNC(pos.x);
  5867. float y = IM_TRUNC(pos.y);
  5868. if (y > clip_rect.w)
  5869. return;
  5870. if (!text_end)
  5871. text_end = text_begin + ImStrlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
  5872. const float line_height = size;
  5873. ImFontBaked* baked = GetFontBaked(size);
  5874. const float scale = size / baked->Size;
  5875. const float origin_x = x;
  5876. const bool word_wrap_enabled = (wrap_width > 0.0f);
  5877. // Fast-forward to first visible line
  5878. const char* s = text_begin;
  5879. if (y + line_height < clip_rect.y)
  5880. while (y + line_height < clip_rect.y && s < text_end)
  5881. {
  5882. const char* line_end = (const char*)ImMemchr(s, '\n', text_end - s);
  5883. if (word_wrap_enabled)
  5884. {
  5885. // FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPosition().
  5886. // If the specs for CalcWordWrapPosition() were reworked to optionally return on \n we could combine both.
  5887. // However it is still better than nothing performing the fast-forward!
  5888. s = CalcWordWrapPosition(size, s, line_end ? line_end : text_end, wrap_width);
  5889. s = CalcWordWrapNextLineStartA(s, text_end);
  5890. }
  5891. else
  5892. {
  5893. s = line_end ? line_end + 1 : text_end;
  5894. }
  5895. y += line_height;
  5896. }
  5897. // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve()
  5898. // Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer without a newline will likely crash atm)
  5899. if (text_end - s > 10000 && !word_wrap_enabled)
  5900. {
  5901. const char* s_end = s;
  5902. float y_end = y;
  5903. while (y_end < clip_rect.w && s_end < text_end)
  5904. {
  5905. s_end = (const char*)ImMemchr(s_end, '\n', text_end - s_end);
  5906. s_end = s_end ? s_end + 1 : text_end;
  5907. y_end += line_height;
  5908. }
  5909. text_end = s_end;
  5910. }
  5911. if (s == text_end)
  5912. return;
  5913. // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
  5914. const int vtx_count_max = (int)(text_end - s) * 4;
  5915. const int idx_count_max = (int)(text_end - s) * 6;
  5916. const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
  5917. draw_list->PrimReserve(idx_count_max, vtx_count_max);
  5918. ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
  5919. ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
  5920. unsigned int vtx_index = draw_list->_VtxCurrentIdx;
  5921. const int cmd_count = draw_list->CmdBuffer.Size;
  5922. const ImU32 col_untinted = col | ~IM_COL32_A_MASK;
  5923. const char* word_wrap_eol = NULL;
  5924. while (s < text_end)
  5925. {
  5926. if (word_wrap_enabled)
  5927. {
  5928. // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.
  5929. if (!word_wrap_eol)
  5930. word_wrap_eol = CalcWordWrapPosition(size, s, text_end, wrap_width - (x - origin_x));
  5931. if (s >= word_wrap_eol)
  5932. {
  5933. x = origin_x;
  5934. y += line_height;
  5935. if (y > clip_rect.w)
  5936. break; // break out of main loop
  5937. word_wrap_eol = NULL;
  5938. s = CalcWordWrapNextLineStartA(s, text_end); // Wrapping skips upcoming blanks
  5939. continue;
  5940. }
  5941. }
  5942. // Decode and advance source
  5943. unsigned int c = (unsigned int)*s;
  5944. if (c < 0x80)
  5945. s += 1;
  5946. else
  5947. s += ImTextCharFromUtf8(&c, s, text_end);
  5948. if (c < 32)
  5949. {
  5950. if (c == '\n')
  5951. {
  5952. x = origin_x;
  5953. y += line_height;
  5954. if (y > clip_rect.w)
  5955. break; // break out of main loop
  5956. continue;
  5957. }
  5958. if (c == '\r')
  5959. continue;
  5960. }
  5961. const ImFontGlyph* glyph = baked->FindGlyph((ImWchar)c);
  5962. //if (glyph == NULL)
  5963. // continue;
  5964. float char_width = glyph->AdvanceX * scale;
  5965. if (glyph->Visible)
  5966. {
  5967. // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w
  5968. float x1 = x + glyph->X0 * scale;
  5969. float x2 = x + glyph->X1 * scale;
  5970. float y1 = y + glyph->Y0 * scale;
  5971. float y2 = y + glyph->Y1 * scale;
  5972. if (x1 <= clip_rect.z && x2 >= clip_rect.x)
  5973. {
  5974. // Render a character
  5975. float u1 = glyph->U0;
  5976. float v1 = glyph->V0;
  5977. float u2 = glyph->U1;
  5978. float v2 = glyph->V1;
  5979. // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
  5980. if (cpu_fine_clip)
  5981. {
  5982. if (x1 < clip_rect.x)
  5983. {
  5984. u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1);
  5985. x1 = clip_rect.x;
  5986. }
  5987. if (y1 < clip_rect.y)
  5988. {
  5989. v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1);
  5990. y1 = clip_rect.y;
  5991. }
  5992. if (x2 > clip_rect.z)
  5993. {
  5994. u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);
  5995. x2 = clip_rect.z;
  5996. }
  5997. if (y2 > clip_rect.w)
  5998. {
  5999. v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1);
  6000. y2 = clip_rect.w;
  6001. }
  6002. if (y1 >= y2)
  6003. {
  6004. x += char_width;
  6005. continue;
  6006. }
  6007. }
  6008. // Support for untinted glyphs
  6009. ImU32 glyph_col = glyph->Colored ? col_untinted : col;
  6010. // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
  6011. {
  6012. vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1;
  6013. vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1;
  6014. vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2;
  6015. vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2;
  6016. idx_write[0] = (ImDrawIdx)(vtx_index); idx_write[1] = (ImDrawIdx)(vtx_index + 1); idx_write[2] = (ImDrawIdx)(vtx_index + 2);
  6017. idx_write[3] = (ImDrawIdx)(vtx_index); idx_write[4] = (ImDrawIdx)(vtx_index + 2); idx_write[5] = (ImDrawIdx)(vtx_index + 3);
  6018. vtx_write += 4;
  6019. vtx_index += 4;
  6020. idx_write += 6;
  6021. }
  6022. }
  6023. }
  6024. x += char_width;
  6025. }
  6026. // Edge case: calling RenderText() with unloaded glyphs triggering texture change. It doesn't happen via ImGui:: calls because CalcTextSize() is always used.
  6027. if (cmd_count != draw_list->CmdBuffer.Size) //-V547
  6028. {
  6029. IM_ASSERT(draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount == 0);
  6030. draw_list->CmdBuffer.pop_back();
  6031. draw_list->PrimUnreserve(idx_count_max, vtx_count_max);
  6032. draw_list->AddDrawCmd();
  6033. //IMGUI_DEBUG_LOG("RenderText: cancel and retry to missing glyphs.\n"); // [DEBUG]
  6034. //draw_list->AddRectFilled(pos, pos + ImVec2(10, 10), IM_COL32(255, 0, 0, 255)); // [DEBUG]
  6035. goto begin;
  6036. //RenderText(draw_list, size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip); // FIXME-OPT: Would a 'goto begin' be better for code-gen?
  6037. //return;
  6038. }
  6039. // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action.
  6040. draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink()
  6041. draw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data);
  6042. draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
  6043. draw_list->_VtxWritePtr = vtx_write;
  6044. draw_list->_IdxWritePtr = idx_write;
  6045. draw_list->_VtxCurrentIdx = vtx_index;
  6046. }
  6047. //-----------------------------------------------------------------------------
  6048. // [SECTION] ImGui Internal Render Helpers
  6049. //-----------------------------------------------------------------------------
  6050. // Vaguely redesigned to stop accessing ImGui global state:
  6051. // - RenderArrow()
  6052. // - RenderBullet()
  6053. // - RenderCheckMark()
  6054. // - RenderArrowPointingAt()
  6055. // - RenderRectFilledRangeH()
  6056. // - RenderRectFilledWithHole()
  6057. //-----------------------------------------------------------------------------
  6058. // Function in need of a redesign (legacy mess)
  6059. // - RenderColorRectWithAlphaCheckerboard()
  6060. //-----------------------------------------------------------------------------
  6061. // Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state
  6062. void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale)
  6063. {
  6064. const float h = draw_list->_Data->FontSize * 1.00f;
  6065. float r = h * 0.40f * scale;
  6066. ImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale);
  6067. ImVec2 a, b, c;
  6068. switch (dir)
  6069. {
  6070. case ImGuiDir_Up:
  6071. case ImGuiDir_Down:
  6072. if (dir == ImGuiDir_Up) r = -r;
  6073. a = ImVec2(+0.000f, +0.750f) * r;
  6074. b = ImVec2(-0.866f, -0.750f) * r;
  6075. c = ImVec2(+0.866f, -0.750f) * r;
  6076. break;
  6077. case ImGuiDir_Left:
  6078. case ImGuiDir_Right:
  6079. if (dir == ImGuiDir_Left) r = -r;
  6080. a = ImVec2(+0.750f, +0.000f) * r;
  6081. b = ImVec2(-0.750f, +0.866f) * r;
  6082. c = ImVec2(-0.750f, -0.866f) * r;
  6083. break;
  6084. case ImGuiDir_None:
  6085. case ImGuiDir_COUNT:
  6086. IM_ASSERT(0);
  6087. break;
  6088. }
  6089. draw_list->AddTriangleFilled(center + a, center + b, center + c, col);
  6090. }
  6091. void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col)
  6092. {
  6093. // FIXME-OPT: This should be baked in font.
  6094. draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8);
  6095. }
  6096. void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz)
  6097. {
  6098. float thickness = ImMax(sz / 5.0f, 1.0f);
  6099. sz -= thickness * 0.5f;
  6100. pos += ImVec2(thickness * 0.25f, thickness * 0.25f);
  6101. float third = sz / 3.0f;
  6102. float bx = pos.x + third;
  6103. float by = pos.y + sz - third * 0.5f;
  6104. draw_list->PathLineTo(ImVec2(bx - third, by - third));
  6105. draw_list->PathLineTo(ImVec2(bx, by));
  6106. draw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f));
  6107. draw_list->PathStroke(col, 0, thickness);
  6108. }
  6109. // Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side.
  6110. void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)
  6111. {
  6112. switch (direction)
  6113. {
  6114. case ImGuiDir_Left: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col); return;
  6115. case ImGuiDir_Right: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); return;
  6116. case ImGuiDir_Up: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); return;
  6117. case ImGuiDir_Down: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); return;
  6118. case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings
  6119. }
  6120. }
  6121. static inline float ImAcos01(float x)
  6122. {
  6123. if (x <= 0.0f) return IM_PI * 0.5f;
  6124. if (x >= 1.0f) return 0.0f;
  6125. return ImAcos(x);
  6126. //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do.
  6127. }
  6128. // FIXME: Cleanup and move code to ImDrawList.
  6129. void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding)
  6130. {
  6131. if (x_end_norm == x_start_norm)
  6132. return;
  6133. if (x_start_norm > x_end_norm)
  6134. ImSwap(x_start_norm, x_end_norm);
  6135. ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y);
  6136. ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y);
  6137. if (rounding == 0.0f)
  6138. {
  6139. draw_list->AddRectFilled(p0, p1, col, 0.0f);
  6140. return;
  6141. }
  6142. rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding);
  6143. const float inv_rounding = 1.0f / rounding;
  6144. const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding);
  6145. const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding);
  6146. const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return.
  6147. const float x0 = ImMax(p0.x, rect.Min.x + rounding);
  6148. if (arc0_b == arc0_e)
  6149. {
  6150. draw_list->PathLineTo(ImVec2(x0, p1.y));
  6151. draw_list->PathLineTo(ImVec2(x0, p0.y));
  6152. }
  6153. else if (arc0_b == 0.0f && arc0_e == half_pi)
  6154. {
  6155. draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL
  6156. draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR
  6157. }
  6158. else
  6159. {
  6160. draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b); // BL
  6161. draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e); // TR
  6162. }
  6163. if (p1.x > rect.Min.x + rounding)
  6164. {
  6165. const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding);
  6166. const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding);
  6167. const float x1 = ImMin(p1.x, rect.Max.x - rounding);
  6168. if (arc1_b == arc1_e)
  6169. {
  6170. draw_list->PathLineTo(ImVec2(x1, p0.y));
  6171. draw_list->PathLineTo(ImVec2(x1, p1.y));
  6172. }
  6173. else if (arc1_b == 0.0f && arc1_e == half_pi)
  6174. {
  6175. draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR
  6176. draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR
  6177. }
  6178. else
  6179. {
  6180. draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b); // TR
  6181. draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e); // BR
  6182. }
  6183. }
  6184. draw_list->PathFillConvex(col);
  6185. }
  6186. void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding)
  6187. {
  6188. const bool fill_L = (inner.Min.x > outer.Min.x);
  6189. const bool fill_R = (inner.Max.x < outer.Max.x);
  6190. const bool fill_U = (inner.Min.y > outer.Min.y);
  6191. const bool fill_D = (inner.Max.y < outer.Max.y);
  6192. if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft));
  6193. if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight));
  6194. if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight));
  6195. if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight));
  6196. if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft);
  6197. if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight);
  6198. if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft);
  6199. if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomRight);
  6200. }
  6201. // Helper for ColorPicker4()
  6202. // NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that.
  6203. // Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether.
  6204. // FIXME: uses ImGui::GetColorU32
  6205. void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, ImDrawFlags flags)
  6206. {
  6207. if ((flags & ImDrawFlags_RoundCornersMask_) == 0)
  6208. flags = ImDrawFlags_RoundCornersDefault_;
  6209. if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF)
  6210. {
  6211. ImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col));
  6212. ImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col));
  6213. draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, flags);
  6214. int yi = 0;
  6215. for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++)
  6216. {
  6217. float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y);
  6218. if (y2 <= y1)
  6219. continue;
  6220. for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f)
  6221. {
  6222. float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x);
  6223. if (x2 <= x1)
  6224. continue;
  6225. ImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone;
  6226. if (y1 <= p_min.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersTopLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersTopRight; }
  6227. if (y2 >= p_max.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersBottomLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersBottomRight; }
  6228. // Combine flags
  6229. cell_flags = (flags == ImDrawFlags_RoundCornersNone || cell_flags == ImDrawFlags_RoundCornersNone) ? ImDrawFlags_RoundCornersNone : (cell_flags & flags);
  6230. draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding, cell_flags);
  6231. }
  6232. }
  6233. }
  6234. else
  6235. {
  6236. draw_list->AddRectFilled(p_min, p_max, col, rounding, flags);
  6237. }
  6238. }
  6239. //-----------------------------------------------------------------------------
  6240. // [SECTION] Decompression code
  6241. //-----------------------------------------------------------------------------
  6242. // Compressed with stb_compress() then converted to a C array and encoded as base85.
  6243. // Use the program in misc/fonts/binary_to_compressed_c.cpp to create the array from a TTF file.
  6244. // The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size.
  6245. // Decompression from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h
  6246. //-----------------------------------------------------------------------------
  6247. static unsigned int stb_decompress_length(const unsigned char *input)
  6248. {
  6249. return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11];
  6250. }
  6251. static unsigned char *stb__barrier_out_e, *stb__barrier_out_b;
  6252. static const unsigned char *stb__barrier_in_b;
  6253. static unsigned char *stb__dout;
  6254. static void stb__match(const unsigned char *data, unsigned int length)
  6255. {
  6256. // INVERSE of memmove... write each byte before copying the next...
  6257. IM_ASSERT(stb__dout + length <= stb__barrier_out_e);
  6258. if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }
  6259. if (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e+1; return; }
  6260. while (length--) *stb__dout++ = *data++;
  6261. }
  6262. static void stb__lit(const unsigned char *data, unsigned int length)
  6263. {
  6264. IM_ASSERT(stb__dout + length <= stb__barrier_out_e);
  6265. if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }
  6266. if (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e+1; return; }
  6267. memcpy(stb__dout, data, length);
  6268. stb__dout += length;
  6269. }
  6270. #define stb__in2(x) ((i[x] << 8) + i[(x)+1])
  6271. #define stb__in3(x) ((i[x] << 16) + stb__in2((x)+1))
  6272. #define stb__in4(x) ((i[x] << 24) + stb__in3((x)+1))
  6273. static const unsigned char *stb_decompress_token(const unsigned char *i)
  6274. {
  6275. if (*i >= 0x20) { // use fewer if's for cases that expand small
  6276. if (*i >= 0x80) stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2;
  6277. else if (*i >= 0x40) stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3;
  6278. else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);
  6279. } else { // more ifs for cases that expand large, since overhead is amortized
  6280. if (*i >= 0x18) stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4;
  6281. else if (*i >= 0x10) stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5;
  6282. else if (*i >= 0x08) stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1);
  6283. else if (*i == 0x07) stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1);
  6284. else if (*i == 0x06) stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5;
  6285. else if (*i == 0x04) stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6;
  6286. }
  6287. return i;
  6288. }
  6289. static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)
  6290. {
  6291. const unsigned long ADLER_MOD = 65521;
  6292. unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
  6293. unsigned long blocklen = buflen % 5552;
  6294. unsigned long i;
  6295. while (buflen) {
  6296. for (i=0; i + 7 < blocklen; i += 8) {
  6297. s1 += buffer[0], s2 += s1;
  6298. s1 += buffer[1], s2 += s1;
  6299. s1 += buffer[2], s2 += s1;
  6300. s1 += buffer[3], s2 += s1;
  6301. s1 += buffer[4], s2 += s1;
  6302. s1 += buffer[5], s2 += s1;
  6303. s1 += buffer[6], s2 += s1;
  6304. s1 += buffer[7], s2 += s1;
  6305. buffer += 8;
  6306. }
  6307. for (; i < blocklen; ++i)
  6308. s1 += *buffer++, s2 += s1;
  6309. s1 %= ADLER_MOD, s2 %= ADLER_MOD;
  6310. buflen -= blocklen;
  6311. blocklen = 5552;
  6312. }
  6313. return (unsigned int)(s2 << 16) + (unsigned int)s1;
  6314. }
  6315. static unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/)
  6316. {
  6317. if (stb__in4(0) != 0x57bC0000) return 0;
  6318. if (stb__in4(4) != 0) return 0; // error! stream is > 4GB
  6319. const unsigned int olen = stb_decompress_length(i);
  6320. stb__barrier_in_b = i;
  6321. stb__barrier_out_e = output + olen;
  6322. stb__barrier_out_b = output;
  6323. i += 16;
  6324. stb__dout = output;
  6325. for (;;) {
  6326. const unsigned char *old_i = i;
  6327. i = stb_decompress_token(i);
  6328. if (i == old_i) {
  6329. if (*i == 0x05 && i[1] == 0xfa) {
  6330. IM_ASSERT(stb__dout == output + olen);
  6331. if (stb__dout != output + olen) return 0;
  6332. if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2))
  6333. return 0;
  6334. return olen;
  6335. } else {
  6336. IM_ASSERT(0); /* NOTREACHED */
  6337. return 0;
  6338. }
  6339. }
  6340. IM_ASSERT(stb__dout <= output + olen);
  6341. if (stb__dout > output + olen)
  6342. return 0;
  6343. }
  6344. }
  6345. //-----------------------------------------------------------------------------
  6346. // [SECTION] Default font data (ProggyClean.ttf)
  6347. //-----------------------------------------------------------------------------
  6348. // ProggyClean.ttf
  6349. // Copyright (c) 2004, 2005 Tristan Grimmer
  6350. // MIT license (see License.txt in http://www.proggyfonts.net/index.php?menu=download)
  6351. // Download and more information at http://www.proggyfonts.net or http://upperboundsinteractive.com/fonts.php
  6352. //-----------------------------------------------------------------------------
  6353. #ifndef IMGUI_DISABLE_DEFAULT_FONT
  6354. // File: 'ProggyClean.ttf' (41208 bytes)
  6355. // Exported using binary_to_compressed_c.exe -u8 "ProggyClean.ttf" proggy_clean_ttf
  6356. static const unsigned int proggy_clean_ttf_compressed_size = 9583;
  6357. static const unsigned char proggy_clean_ttf_compressed_data[9583] =
  6358. {
  6359. 87,188,0,0,0,0,0,0,0,0,160,248,0,4,0,0,55,0,1,0,0,0,12,0,128,0,3,0,64,79,83,47,50,136,235,116,144,0,0,1,72,130,21,44,78,99,109,97,112,2,18,35,117,0,0,3,160,130,19,36,82,99,118,116,
  6360. 32,130,23,130,2,33,4,252,130,4,56,2,103,108,121,102,18,175,137,86,0,0,7,4,0,0,146,128,104,101,97,100,215,145,102,211,130,27,32,204,130,3,33,54,104,130,16,39,8,66,1,195,0,0,1,4,130,
  6361. 15,59,36,104,109,116,120,138,0,126,128,0,0,1,152,0,0,2,6,108,111,99,97,140,115,176,216,0,0,5,130,30,41,2,4,109,97,120,112,1,174,0,218,130,31,32,40,130,16,44,32,110,97,109,101,37,89,
  6362. 187,150,0,0,153,132,130,19,44,158,112,111,115,116,166,172,131,239,0,0,155,36,130,51,44,210,112,114,101,112,105,2,1,18,0,0,4,244,130,47,32,8,132,203,46,1,0,0,60,85,233,213,95,15,60,
  6363. 245,0,3,8,0,131,0,34,183,103,119,130,63,43,0,0,189,146,166,215,0,0,254,128,3,128,131,111,130,241,33,2,0,133,0,32,1,130,65,38,192,254,64,0,0,3,128,131,16,130,5,32,1,131,7,138,3,33,2,
  6364. 0,130,17,36,1,1,0,144,0,130,121,130,23,38,2,0,8,0,64,0,10,130,9,32,118,130,9,130,6,32,0,130,59,33,1,144,131,200,35,2,188,2,138,130,16,32,143,133,7,37,1,197,0,50,2,0,131,0,33,4,9,131,
  6365. 5,145,3,43,65,108,116,115,0,64,0,0,32,172,8,0,131,0,35,5,0,1,128,131,77,131,3,33,3,128,191,1,33,1,128,130,184,35,0,0,128,0,130,3,131,11,32,1,130,7,33,0,128,131,1,32,1,136,9,32,0,132,
  6366. 15,135,5,32,1,131,13,135,27,144,35,32,1,149,25,131,21,32,0,130,0,32,128,132,103,130,35,132,39,32,0,136,45,136,97,133,17,130,5,33,0,0,136,19,34,0,128,1,133,13,133,5,32,128,130,15,132,
  6367. 131,32,3,130,5,32,3,132,27,144,71,32,0,133,27,130,29,130,31,136,29,131,63,131,3,65,63,5,132,5,132,205,130,9,33,0,0,131,9,137,119,32,3,132,19,138,243,130,55,32,1,132,35,135,19,131,201,
  6368. 136,11,132,143,137,13,130,41,32,0,131,3,144,35,33,128,0,135,1,131,223,131,3,141,17,134,13,136,63,134,15,136,53,143,15,130,96,33,0,3,131,4,130,3,34,28,0,1,130,5,34,0,0,76,130,17,131,
  6369. 9,36,28,0,4,0,48,130,17,46,8,0,8,0,2,0,0,0,127,0,255,32,172,255,255,130,9,34,0,0,129,132,9,130,102,33,223,213,134,53,132,22,33,1,6,132,6,64,4,215,32,129,165,216,39,177,0,1,141,184,
  6370. 1,255,133,134,45,33,198,0,193,1,8,190,244,1,28,1,158,2,20,2,136,2,252,3,20,3,88,3,156,3,222,4,20,4,50,4,80,4,98,4,162,5,22,5,102,5,188,6,18,6,116,6,214,7,56,7,126,7,236,8,78,8,108,
  6371. 8,150,8,208,9,16,9,74,9,136,10,22,10,128,11,4,11,86,11,200,12,46,12,130,12,234,13,94,13,164,13,234,14,80,14,150,15,40,15,176,16,18,16,116,16,224,17,82,17,182,18,4,18,110,18,196,19,
  6372. 76,19,172,19,246,20,88,20,174,20,234,21,64,21,128,21,166,21,184,22,18,22,126,22,198,23,52,23,142,23,224,24,86,24,186,24,238,25,54,25,150,25,212,26,72,26,156,26,240,27,92,27,200,28,
  6373. 4,28,76,28,150,28,234,29,42,29,146,29,210,30,64,30,142,30,224,31,36,31,118,31,166,31,166,32,16,130,1,52,46,32,138,32,178,32,200,33,20,33,116,33,152,33,238,34,98,34,134,35,12,130,1,
  6374. 33,128,35,131,1,60,152,35,176,35,216,36,0,36,74,36,104,36,144,36,174,37,6,37,96,37,130,37,248,37,248,38,88,38,170,130,1,8,190,216,39,64,39,154,40,10,40,104,40,168,41,14,41,32,41,184,
  6375. 41,248,42,54,42,96,42,96,43,2,43,42,43,94,43,172,43,230,44,32,44,52,44,154,45,40,45,92,45,120,45,170,45,232,46,38,46,166,47,38,47,182,47,244,48,94,48,200,49,62,49,180,50,30,50,158,
  6376. 51,30,51,130,51,238,52,92,52,206,53,58,53,134,53,212,54,38,54,114,54,230,55,118,55,216,56,58,56,166,57,18,57,116,57,174,58,46,58,154,59,6,59,124,59,232,60,58,60,150,61,34,61,134,61,
  6377. 236,62,86,62,198,63,42,63,154,64,18,64,106,64,208,65,54,65,162,66,8,66,64,66,122,66,184,66,240,67,98,67,204,68,42,68,138,68,238,69,88,69,182,69,226,70,84,70,180,71,20,71,122,71,218,
  6378. 72,84,72,198,73,64,0,36,70,21,8,8,77,3,0,7,0,11,0,15,0,19,0,23,0,27,0,31,0,35,0,39,0,43,0,47,0,51,0,55,0,59,0,63,0,67,0,71,0,75,0,79,0,83,0,87,0,91,0,95,0,99,0,103,0,107,0,111,0,115,
  6379. 0,119,0,123,0,127,0,131,0,135,0,139,0,143,0,0,17,53,51,21,49,150,3,32,5,130,23,32,33,130,3,211,7,151,115,32,128,133,0,37,252,128,128,2,128,128,190,5,133,74,32,4,133,6,206,5,42,0,7,
  6380. 1,128,0,0,2,0,4,0,0,65,139,13,37,0,1,53,51,21,7,146,3,32,3,130,19,32,1,141,133,32,3,141,14,131,13,38,255,0,128,128,0,6,1,130,84,35,2,128,4,128,140,91,132,89,32,51,65,143,6,139,7,33,
  6381. 1,0,130,57,32,254,130,3,32,128,132,4,32,4,131,14,138,89,35,0,0,24,0,130,0,33,3,128,144,171,66,55,33,148,115,65,187,19,32,5,130,151,143,155,163,39,32,1,136,182,32,253,134,178,132,7,
  6382. 132,200,145,17,32,3,65,48,17,165,17,39,0,0,21,0,128,255,128,3,65,175,17,65,3,27,132,253,131,217,139,201,155,233,155,27,131,67,131,31,130,241,33,255,0,131,181,137,232,132,15,132,4,138,
  6383. 247,34,255,0,128,179,238,32,0,130,0,32,20,65,239,48,33,0,19,67,235,10,32,51,65,203,14,65,215,11,32,7,154,27,135,39,32,33,130,35,33,128,128,130,231,32,253,132,231,32,128,132,232,34,
  6384. 128,128,254,133,13,136,8,32,253,65,186,5,130,36,130,42,176,234,133,231,34,128,0,0,66,215,44,33,0,1,68,235,6,68,211,19,32,49,68,239,14,139,207,139,47,66,13,7,32,51,130,47,33,1,0,130,
  6385. 207,35,128,128,1,0,131,222,131,5,130,212,130,6,131,212,32,0,130,10,133,220,130,233,130,226,32,254,133,255,178,233,39,3,1,128,3,0,2,0,4,68,15,7,68,99,12,130,89,130,104,33,128,4,133,
  6386. 93,130,10,38,0,0,11,1,0,255,0,68,63,16,70,39,9,66,215,8,32,7,68,77,6,68,175,14,32,29,68,195,6,132,7,35,2,0,128,255,131,91,132,4,65,178,5,141,111,67,129,23,165,135,140,107,142,135,33,
  6387. 21,5,69,71,6,131,7,33,1,0,140,104,132,142,130,4,137,247,140,30,68,255,12,39,11,0,128,0,128,3,0,3,69,171,15,67,251,7,65,15,8,66,249,11,65,229,7,67,211,7,66,13,7,35,1,128,128,254,133,
  6388. 93,32,254,131,145,132,4,132,18,32,2,151,128,130,23,34,0,0,9,154,131,65,207,8,68,107,15,68,51,7,32,7,70,59,7,135,121,130,82,32,128,151,111,41,0,0,4,0,128,255,0,1,128,1,137,239,33,0,
  6389. 37,70,145,10,65,77,10,65,212,14,37,0,0,0,5,0,128,66,109,5,70,123,10,33,0,19,72,33,18,133,237,70,209,11,33,0,2,130,113,137,119,136,115,33,1,0,133,43,130,5,34,0,0,10,69,135,6,70,219,
  6390. 13,66,155,7,65,9,12,66,157,11,66,9,11,32,7,130,141,132,252,66,151,9,137,9,66,15,30,36,0,20,0,128,0,130,218,71,11,42,68,51,8,65,141,7,73,19,15,69,47,23,143,39,66,81,7,32,1,66,55,6,34,
  6391. 1,128,128,68,25,5,69,32,6,137,6,136,25,32,254,131,42,32,3,66,88,26,148,26,32,0,130,0,32,14,164,231,70,225,12,66,233,7,67,133,19,71,203,15,130,161,32,255,130,155,32,254,139,127,134,
  6392. 12,164,174,33,0,15,164,159,33,59,0,65,125,20,66,25,7,32,5,68,191,6,66,29,7,144,165,65,105,9,35,128,128,255,0,137,2,133,182,164,169,33,128,128,197,171,130,155,68,235,7,32,21,70,77,19,
  6393. 66,21,10,68,97,8,66,30,5,66,4,43,34,0,17,0,71,19,41,65,253,20,71,25,23,65,91,15,65,115,7,34,2,128,128,66,9,8,130,169,33,1,0,66,212,13,132,28,72,201,43,35,0,0,0,18,66,27,38,76,231,5,
  6394. 68,157,20,135,157,32,7,68,185,13,65,129,28,66,20,5,32,253,66,210,11,65,128,49,133,61,32,0,65,135,6,74,111,37,72,149,12,66,203,19,65,147,19,68,93,7,68,85,8,76,4,5,33,255,0,133,129,34,
  6395. 254,0,128,68,69,8,181,197,34,0,0,12,65,135,32,65,123,20,69,183,27,133,156,66,50,5,72,87,10,67,137,32,33,0,19,160,139,78,251,13,68,55,20,67,119,19,65,91,36,69,177,15,32,254,143,16,65,
  6396. 98,53,32,128,130,0,32,0,66,43,54,70,141,23,66,23,15,131,39,69,47,11,131,15,70,129,19,74,161,9,36,128,255,0,128,254,130,153,65,148,32,67,41,9,34,0,0,4,79,15,5,73,99,10,71,203,8,32,3,
  6397. 72,123,6,72,43,8,32,2,133,56,131,99,130,9,34,0,0,6,72,175,5,73,159,14,144,63,135,197,132,189,133,66,33,255,0,73,6,7,70,137,12,35,0,0,0,10,130,3,73,243,25,67,113,12,65,73,7,69,161,7,
  6398. 138,7,37,21,2,0,128,128,254,134,3,73,116,27,33,128,128,130,111,39,12,0,128,1,0,3,128,2,72,219,21,35,43,0,47,0,67,47,20,130,111,33,21,1,68,167,13,81,147,8,133,230,32,128,77,73,6,32,
  6399. 128,131,142,134,18,130,6,32,255,75,18,12,131,243,37,128,0,128,3,128,3,74,231,21,135,123,32,29,134,107,135,7,32,21,74,117,7,135,7,134,96,135,246,74,103,23,132,242,33,0,10,67,151,28,
  6400. 67,133,20,66,141,11,131,11,32,3,77,71,6,32,128,130,113,32,1,81,4,6,134,218,66,130,24,131,31,34,0,26,0,130,0,77,255,44,83,15,11,148,155,68,13,7,32,49,78,231,18,79,7,11,73,243,11,32,
  6401. 33,65,187,10,130,63,65,87,8,73,239,19,35,0,128,1,0,131,226,32,252,65,100,6,32,128,139,8,33,1,0,130,21,32,253,72,155,44,73,255,20,32,128,71,67,8,81,243,39,67,15,20,74,191,23,68,121,
  6402. 27,32,1,66,150,6,32,254,79,19,11,131,214,32,128,130,215,37,2,0,128,253,0,128,136,5,65,220,24,147,212,130,210,33,0,24,72,219,42,84,255,13,67,119,16,69,245,19,72,225,19,65,3,15,69,93,
  6403. 19,131,55,132,178,71,115,14,81,228,6,142,245,33,253,0,132,43,172,252,65,16,11,75,219,8,65,219,31,66,223,24,75,223,10,33,29,1,80,243,10,66,175,8,131,110,134,203,133,172,130,16,70,30,
  6404. 7,164,183,130,163,32,20,65,171,48,65,163,36,65,143,23,65,151,19,65,147,13,65,134,17,133,17,130,216,67,114,5,164,217,65,137,12,72,147,48,79,71,19,74,169,22,80,251,8,65,173,7,66,157,
  6405. 15,74,173,15,32,254,65,170,8,71,186,45,72,131,6,77,143,40,187,195,152,179,65,123,38,68,215,57,68,179,15,65,85,7,69,187,14,32,21,66,95,15,67,19,25,32,1,83,223,6,32,2,76,240,7,77,166,
  6406. 43,65,8,5,130,206,32,0,67,39,54,143,167,66,255,19,82,193,11,151,47,85,171,5,67,27,17,132,160,69,172,11,69,184,56,66,95,6,33,12,1,130,237,32,2,68,179,27,68,175,16,80,135,15,72,55,7,
  6407. 71,87,12,73,3,12,132,12,66,75,32,76,215,5,169,139,147,135,148,139,81,12,12,81,185,36,75,251,7,65,23,27,76,215,9,87,165,12,65,209,15,72,157,7,65,245,31,32,128,71,128,6,32,1,82,125,5,
  6408. 34,0,128,254,131,169,32,254,131,187,71,180,9,132,27,32,2,88,129,44,32,0,78,47,40,65,79,23,79,171,14,32,21,71,87,8,72,15,14,65,224,33,130,139,74,27,62,93,23,7,68,31,7,75,27,7,139,15,
  6409. 74,3,7,74,23,27,65,165,11,65,177,15,67,123,5,32,1,130,221,32,252,71,96,5,74,12,12,133,244,130,25,34,1,0,128,130,2,139,8,93,26,8,65,9,32,65,57,14,140,14,32,0,73,79,67,68,119,11,135,
  6410. 11,32,51,90,75,14,139,247,65,43,7,131,19,139,11,69,159,11,65,247,6,36,1,128,128,253,0,90,71,9,33,1,0,132,14,32,128,89,93,14,69,133,6,130,44,131,30,131,6,65,20,56,33,0,16,72,179,40,
  6411. 75,47,12,65,215,19,74,95,19,65,43,11,131,168,67,110,5,75,23,17,69,106,6,75,65,5,71,204,43,32,0,80,75,47,71,203,15,159,181,68,91,11,67,197,7,73,101,13,68,85,6,33,128,128,130,214,130,
  6412. 25,32,254,74,236,48,130,194,37,0,18,0,128,255,128,77,215,40,65,139,64,32,51,80,159,10,65,147,39,130,219,84,212,43,130,46,75,19,97,74,33,11,65,201,23,65,173,31,33,1,0,79,133,6,66,150,
  6413. 5,67,75,48,85,187,6,70,207,37,32,71,87,221,13,73,163,14,80,167,15,132,15,83,193,19,82,209,8,78,99,9,72,190,11,77,110,49,89,63,5,80,91,35,99,63,32,70,235,23,81,99,10,69,148,10,65,110,
  6414. 36,32,0,65,99,47,95,219,11,68,171,51,66,87,7,72,57,7,74,45,17,143,17,65,114,50,33,14,0,65,111,40,159,195,98,135,15,35,7,53,51,21,100,78,9,95,146,16,32,254,82,114,6,32,128,67,208,37,
  6415. 130,166,99,79,58,32,17,96,99,14,72,31,19,72,87,31,82,155,7,67,47,14,32,21,131,75,134,231,72,51,17,72,78,8,133,8,80,133,6,33,253,128,88,37,9,66,124,36,72,65,12,134,12,71,55,43,66,139,
  6416. 27,85,135,10,91,33,12,65,35,11,66,131,11,71,32,8,90,127,6,130,244,71,76,11,168,207,33,0,12,66,123,32,32,0,65,183,15,68,135,11,66,111,7,67,235,11,66,111,15,32,254,97,66,12,160,154,67,
  6417. 227,52,80,33,15,87,249,15,93,45,31,75,111,12,93,45,11,77,99,9,160,184,81,31,12,32,15,98,135,30,104,175,7,77,249,36,69,73,15,78,5,12,32,254,66,151,19,34,128,128,4,87,32,12,149,35,133,
  6418. 21,96,151,31,32,19,72,35,5,98,173,15,143,15,32,21,143,99,158,129,33,0,0,65,35,52,65,11,15,147,15,98,75,11,33,1,0,143,151,132,15,32,254,99,200,37,132,43,130,4,39,0,10,0,128,1,128,3,
  6419. 0,104,151,14,97,187,20,69,131,15,67,195,11,87,227,7,33,128,128,132,128,33,254,0,68,131,9,65,46,26,42,0,0,0,7,0,0,255,128,3,128,0,88,223,15,33,0,21,89,61,22,66,209,12,65,2,12,37,0,2,
  6420. 1,0,3,128,101,83,8,36,0,1,53,51,29,130,3,34,21,1,0,66,53,8,32,0,68,215,6,100,55,25,107,111,9,66,193,11,72,167,8,73,143,31,139,31,33,1,0,131,158,32,254,132,5,33,253,128,65,16,9,133,
  6421. 17,89,130,25,141,212,33,0,0,93,39,8,90,131,25,93,39,14,66,217,6,106,179,8,159,181,71,125,15,139,47,138,141,87,11,14,76,23,14,65,231,26,140,209,66,122,8,81,179,5,101,195,26,32,47,74,
  6422. 75,13,69,159,11,83,235,11,67,21,16,136,167,131,106,130,165,130,15,32,128,101,90,24,134,142,32,0,65,103,51,108,23,11,101,231,15,75,173,23,74,237,23,66,15,6,66,46,17,66,58,17,65,105,
  6423. 49,66,247,55,71,179,12,70,139,15,86,229,7,84,167,15,32,1,95,72,12,89,49,6,33,128,128,65,136,38,66,30,9,32,0,100,239,7,66,247,29,70,105,20,65,141,19,69,81,15,130,144,32,128,83,41,5,
  6424. 32,255,131,177,68,185,5,133,126,65,97,37,32,0,130,0,33,21,0,130,55,66,195,28,67,155,13,34,79,0,83,66,213,13,73,241,19,66,59,19,65,125,11,135,201,66,249,16,32,128,66,44,11,66,56,17,
  6425. 68,143,8,68,124,38,67,183,12,96,211,9,65,143,29,112,171,5,32,0,68,131,63,34,33,53,51,71,121,11,32,254,98,251,16,32,253,74,231,10,65,175,37,133,206,37,0,0,8,1,0,0,107,123,11,113,115,
  6426. 9,33,0,1,130,117,131,3,73,103,7,66,51,18,66,44,5,133,75,70,88,5,32,254,65,39,12,68,80,9,34,12,0,128,107,179,28,68,223,6,155,111,86,147,15,32,2,131,82,141,110,33,254,0,130,15,32,4,103,
  6427. 184,15,141,35,87,176,5,83,11,5,71,235,23,114,107,11,65,189,16,70,33,15,86,153,31,135,126,86,145,30,65,183,41,32,0,130,0,32,10,65,183,24,34,35,0,39,67,85,9,65,179,15,143,15,33,1,0,65,
  6428. 28,17,157,136,130,123,32,20,130,3,32,0,97,135,24,115,167,19,80,71,12,32,51,110,163,14,78,35,19,131,19,155,23,77,229,8,78,9,17,151,17,67,231,46,94,135,8,73,31,31,93,215,56,82,171,25,
  6429. 72,77,8,162,179,169,167,99,131,11,69,85,19,66,215,15,76,129,13,68,115,22,72,79,35,67,113,5,34,0,0,19,70,31,46,65,89,52,73,223,15,85,199,33,95,33,8,132,203,73,29,32,67,48,16,177,215,
  6430. 101,13,15,65,141,43,69,141,15,75,89,5,70,0,11,70,235,21,178,215,36,10,0,128,0,0,71,207,24,33,0,19,100,67,6,80,215,11,66,67,7,80,43,12,71,106,7,80,192,5,65,63,5,66,217,26,33,0,13,156,
  6431. 119,68,95,5,72,233,12,134,129,85,81,11,76,165,20,65,43,8,73,136,8,75,10,31,38,128,128,0,0,0,13,1,130,4,32,3,106,235,29,114,179,12,66,131,23,32,7,77,133,6,67,89,12,131,139,116,60,9,
  6432. 89,15,37,32,0,74,15,7,103,11,22,65,35,5,33,55,0,93,81,28,67,239,23,78,85,5,107,93,14,66,84,17,65,193,26,74,183,10,66,67,34,143,135,79,91,15,32,7,117,111,8,75,56,9,84,212,9,154,134,
  6433. 32,0,130,0,32,18,130,3,70,171,41,83,7,16,70,131,19,84,191,15,84,175,19,84,167,30,84,158,12,154,193,68,107,15,33,0,0,65,79,42,65,71,7,73,55,7,118,191,16,83,180,9,32,255,76,166,9,154,
  6434. 141,32,0,130,0,69,195,52,65,225,15,151,15,75,215,31,80,56,10,68,240,17,100,32,9,70,147,39,65,93,12,71,71,41,92,85,15,84,135,23,78,35,15,110,27,10,84,125,8,107,115,29,136,160,38,0,0,
  6435. 14,0,128,255,0,82,155,24,67,239,8,119,255,11,69,131,11,77,29,6,112,31,8,134,27,105,203,8,32,2,75,51,11,75,195,12,74,13,29,136,161,37,128,0,0,0,11,1,130,163,82,115,8,125,191,17,69,35,
  6436. 12,74,137,15,143,15,32,1,65,157,12,136,12,161,142,65,43,40,65,199,6,65,19,24,102,185,11,76,123,11,99,6,12,135,12,32,254,130,8,161,155,101,23,9,39,8,0,0,1,128,3,128,2,78,63,17,72,245,
  6437. 12,67,41,11,90,167,9,32,128,97,49,9,32,128,109,51,14,132,97,81,191,8,130,97,125,99,12,121,35,9,127,75,15,71,79,12,81,151,23,87,97,7,70,223,15,80,245,16,105,97,15,32,254,113,17,6,32,
  6438. 128,130,8,105,105,8,76,122,18,65,243,21,74,63,7,38,4,1,0,255,0,2,0,119,247,28,133,65,32,255,141,91,35,0,0,0,16,67,63,36,34,59,0,63,77,59,9,119,147,11,143,241,66,173,15,66,31,11,67,
  6439. 75,8,81,74,16,32,128,131,255,87,181,42,127,43,5,34,255,128,2,120,235,11,37,19,0,23,0,0,37,109,191,14,118,219,7,127,43,14,65,79,14,35,0,0,0,3,73,91,5,130,5,38,3,0,7,0,11,0,0,70,205,
  6440. 11,88,221,12,32,0,73,135,7,87,15,22,73,135,10,79,153,15,97,71,19,65,49,11,32,1,131,104,121,235,11,80,65,11,142,179,144,14,81,123,46,32,1,88,217,5,112,5,8,65,201,15,83,29,15,122,147,
  6441. 11,135,179,142,175,143,185,67,247,39,66,199,7,35,5,0,128,3,69,203,15,123,163,12,67,127,7,130,119,71,153,10,141,102,70,175,8,32,128,121,235,30,136,89,100,191,11,116,195,11,111,235,15,
  6442. 72,39,7,32,2,97,43,5,132,5,94,67,8,131,8,125,253,10,32,3,65,158,16,146,16,130,170,40,0,21,0,128,0,0,3,128,5,88,219,15,24,64,159,32,135,141,65,167,15,68,163,10,97,73,49,32,255,82,58,
  6443. 7,93,80,8,97,81,16,24,67,87,52,34,0,0,5,130,231,33,128,2,80,51,13,65,129,8,113,61,6,132,175,65,219,5,130,136,77,152,17,32,0,95,131,61,70,215,6,33,21,51,90,53,10,78,97,23,105,77,31,
  6444. 65,117,7,139,75,24,68,195,9,24,64,22,9,33,0,128,130,11,33,128,128,66,25,5,121,38,5,134,5,134,45,66,40,36,66,59,18,34,128,0,0,66,59,81,135,245,123,103,19,120,159,19,77,175,12,33,255,
  6445. 0,87,29,10,94,70,21,66,59,54,39,3,1,128,3,0,2,128,4,24,65,7,15,66,47,7,72,98,12,37,0,0,0,3,1,0,24,65,55,21,131,195,32,1,67,178,6,33,4,0,77,141,8,32,6,131,47,74,67,16,24,69,3,20,24,
  6446. 65,251,7,133,234,130,229,94,108,17,35,0,0,6,0,141,175,86,59,5,162,79,85,166,8,70,112,13,32,13,24,64,67,26,24,71,255,7,123,211,12,80,121,11,69,215,15,66,217,11,69,71,10,131,113,132,
  6447. 126,119,90,9,66,117,19,132,19,32,0,130,0,24,64,47,59,33,7,0,73,227,5,68,243,15,85,13,12,76,37,22,74,254,15,130,138,33,0,4,65,111,6,137,79,65,107,16,32,1,77,200,6,34,128,128,3,75,154,
  6448. 12,37,0,16,0,0,2,0,104,115,36,140,157,68,67,19,68,51,15,106,243,15,134,120,70,37,10,68,27,10,140,152,65,121,24,32,128,94,155,7,67,11,8,24,74,11,25,65,3,12,83,89,18,82,21,37,67,200,
  6449. 5,130,144,24,64,172,12,33,4,0,134,162,74,80,14,145,184,32,0,130,0,69,251,20,32,19,81,243,5,82,143,8,33,5,53,89,203,5,133,112,79,109,15,33,0,21,130,71,80,175,41,36,75,0,79,0,83,121,
  6450. 117,9,87,89,27,66,103,11,70,13,15,75,191,11,135,67,87,97,20,109,203,5,69,246,8,108,171,5,78,195,38,65,51,13,107,203,11,77,3,17,24,75,239,17,65,229,28,79,129,39,130,175,32,128,123,253,
  6451. 7,132,142,24,65,51,15,65,239,41,36,128,128,0,0,13,65,171,5,66,163,28,136,183,118,137,11,80,255,15,67,65,7,74,111,8,32,0,130,157,32,253,24,76,35,10,103,212,5,81,175,9,69,141,7,66,150,
  6452. 29,131,158,24,75,199,28,124,185,7,76,205,15,68,124,14,32,3,123,139,16,130,16,33,128,128,108,199,6,33,0,3,65,191,35,107,11,6,73,197,11,24,70,121,15,83,247,15,24,70,173,23,69,205,14,
  6453. 32,253,131,140,32,254,136,4,94,198,9,32,3,78,4,13,66,127,13,143,13,32,0,130,0,33,16,0,24,69,59,39,109,147,12,76,253,19,24,69,207,15,69,229,15,130,195,71,90,10,139,10,130,152,73,43,
  6454. 40,91,139,10,65,131,37,35,75,0,79,0,84,227,12,143,151,68,25,15,80,9,23,95,169,11,34,128,2,128,112,186,5,130,6,83,161,19,76,50,6,130,37,65,145,44,110,83,5,32,16,67,99,6,71,67,15,76,
  6455. 55,17,140,215,67,97,23,76,69,15,77,237,11,104,211,23,77,238,11,65,154,43,33,0,10,83,15,28,83,13,20,67,145,19,67,141,14,97,149,21,68,9,15,86,251,5,66,207,5,66,27,37,82,1,23,127,71,12,
  6456. 94,235,10,110,175,24,98,243,15,132,154,132,4,24,66,69,10,32,4,67,156,43,130,198,35,2,1,0,4,75,27,9,69,85,9,95,240,7,32,128,130,35,32,28,66,43,40,24,82,63,23,83,123,12,72,231,15,127,
  6457. 59,23,116,23,19,117,71,7,24,77,99,15,67,111,15,71,101,8,36,2,128,128,252,128,127,60,11,32,1,132,16,130,18,141,24,67,107,9,32,3,68,194,15,175,15,38,0,11,0,128,1,128,2,80,63,25,32,0,
  6458. 24,65,73,11,69,185,15,83,243,16,32,0,24,81,165,8,130,86,77,35,6,155,163,88,203,5,24,66,195,30,70,19,19,24,80,133,15,32,1,75,211,8,32,254,108,133,8,79,87,20,65,32,9,41,0,0,7,0,128,0,
  6459. 0,2,128,2,68,87,15,66,1,16,92,201,16,24,76,24,17,133,17,34,128,0,30,66,127,64,34,115,0,119,73,205,9,66,43,11,109,143,15,24,79,203,11,90,143,15,131,15,155,31,65,185,15,86,87,11,35,128,
  6460. 128,253,0,69,7,6,130,213,33,1,0,119,178,15,142,17,66,141,74,83,28,6,36,7,0,0,4,128,82,39,18,76,149,12,67,69,21,32,128,79,118,15,32,0,130,0,32,8,131,206,32,2,79,83,9,100,223,14,102,
  6461. 113,23,115,115,7,24,65,231,12,130,162,32,4,68,182,19,130,102,93,143,8,69,107,29,24,77,255,12,143,197,72,51,7,76,195,15,132,139,85,49,15,130,152,131,18,71,81,23,70,14,11,36,0,10,0,128,
  6462. 2,69,59,9,89,151,15,66,241,11,76,165,12,71,43,15,75,49,13,65,12,23,132,37,32,0,179,115,130,231,95,181,16,132,77,32,254,67,224,8,65,126,20,79,171,8,32,2,89,81,5,75,143,6,80,41,8,34,
  6463. 2,0,128,24,81,72,9,32,0,130,0,35,17,0,0,255,77,99,39,95,65,36,67,109,15,24,69,93,11,77,239,5,95,77,23,35,128,1,0,128,24,86,7,8,132,167,32,2,69,198,41,130,202,33,0,26,120,75,44,24,89,
  6464. 51,15,71,243,12,70,239,11,24,84,3,11,66,7,11,71,255,10,32,21,69,155,35,88,151,12,32,128,74,38,10,65,210,8,74,251,5,65,226,5,75,201,13,32,3,65,9,41,146,41,40,0,0,0,9,1,0,1,0,2,91,99,
  6465. 19,32,35,106,119,13,70,219,15,83,239,12,137,154,32,2,67,252,19,36,128,0,0,4,1,130,196,32,2,130,8,91,107,8,32,0,135,81,24,73,211,8,132,161,73,164,13,36,0,8,0,128,2,105,123,26,139,67,
  6466. 76,99,15,34,1,0,128,135,76,83,156,20,92,104,8,67,251,30,24,86,47,27,123,207,12,24,86,7,15,71,227,8,32,4,65,20,20,131,127,32,0,130,123,32,0,71,223,26,32,19,90,195,22,71,223,15,84,200,
  6467. 6,32,128,133,241,24,84,149,9,67,41,25,36,0,0,0,22,0,88,111,49,32,87,66,21,5,77,3,27,123,75,7,71,143,19,135,183,71,183,19,130,171,74,252,5,131,5,89,87,17,32,1,132,18,130,232,68,11,10,
  6468. 33,1,128,70,208,16,66,230,18,147,18,130,254,223,255,75,27,23,65,59,15,135,39,155,255,34,128,128,254,104,92,8,33,0,128,65,32,11,65,1,58,33,26,0,130,0,72,71,18,78,55,17,76,11,19,86,101,
  6469. 12,75,223,11,89,15,11,24,76,87,15,75,235,15,131,15,72,95,7,85,71,11,72,115,11,73,64,6,34,1,128,128,66,215,9,34,128,254,128,134,14,33,128,255,67,102,5,32,0,130,16,70,38,11,66,26,57,
  6470. 88,11,8,24,76,215,34,78,139,7,95,245,7,32,7,24,73,75,23,32,128,131,167,130,170,101,158,9,82,49,22,118,139,6,32,18,67,155,44,116,187,9,108,55,14,80,155,23,66,131,15,93,77,10,131,168,
  6471. 32,128,73,211,12,24,75,187,22,32,4,96,71,20,67,108,19,132,19,120,207,8,32,5,76,79,15,66,111,21,66,95,8,32,3,190,211,111,3,8,211,212,32,20,65,167,44,34,75,0,79,97,59,13,32,33,112,63,
  6472. 10,65,147,19,69,39,19,143,39,24,66,71,9,130,224,65,185,43,94,176,12,65,183,24,71,38,8,24,72,167,7,65,191,38,136,235,24,96,167,12,65,203,62,115,131,13,65,208,42,175,235,67,127,6,32,
  6473. 4,76,171,29,114,187,5,32,71,65,211,5,65,203,68,72,51,8,164,219,32,0,172,214,71,239,58,78,3,27,66,143,15,77,19,15,147,31,35,33,53,51,21,66,183,10,173,245,66,170,30,150,30,34,0,0,23,
  6474. 80,123,54,76,1,16,73,125,15,82,245,11,167,253,24,76,85,12,70,184,5,32,254,131,185,37,254,0,128,1,0,128,133,16,117,158,18,92,27,38,65,3,17,130,251,35,17,0,128,254,24,69,83,39,140,243,
  6475. 121,73,19,109,167,7,81,41,15,24,95,175,12,102,227,15,121,96,11,24,95,189,7,32,3,145,171,154,17,24,77,47,9,33,0,5,70,71,37,68,135,7,32,29,117,171,11,69,87,15,24,79,97,19,24,79,149,23,
  6476. 131,59,32,1,75,235,5,72,115,11,72,143,7,132,188,71,27,46,131,51,32,0,69,95,6,175,215,32,21,131,167,81,15,19,151,191,151,23,131,215,71,43,5,32,254,24,79,164,24,74,109,8,77,166,13,65,
  6477. 176,26,88,162,5,98,159,6,171,219,120,247,6,79,29,8,99,169,10,103,59,19,65,209,35,131,35,91,25,19,112,94,15,83,36,8,173,229,33,20,0,88,75,43,71,31,12,65,191,71,33,1,0,130,203,32,254,
  6478. 131,4,68,66,7,67,130,6,104,61,13,173,215,38,13,1,0,0,0,2,128,67,111,28,74,129,16,104,35,19,79,161,16,87,14,7,138,143,132,10,67,62,36,114,115,5,162,151,67,33,16,108,181,15,143,151,67,
  6479. 5,5,24,100,242,15,170,153,34,0,0,14,65,51,34,32,55,79,75,9,32,51,74,7,10,65,57,38,132,142,32,254,72,0,14,139,163,32,128,80,254,8,67,158,21,65,63,7,32,4,72,227,27,95,155,12,67,119,19,
  6480. 124,91,24,149,154,72,177,34,97,223,8,155,151,24,108,227,15,88,147,16,72,117,19,68,35,11,92,253,15,70,199,15,24,87,209,17,32,2,87,233,7,32,1,24,88,195,10,119,24,8,32,3,81,227,24,65,
  6481. 125,21,35,128,128,0,25,76,59,48,24,90,187,9,97,235,12,66,61,11,91,105,19,24,79,141,11,24,79,117,15,24,79,129,27,90,53,13,130,13,32,253,131,228,24,79,133,40,69,70,8,66,137,31,65,33,
  6482. 19,96,107,8,68,119,29,66,7,5,68,125,16,65,253,19,65,241,27,24,90,179,13,24,79,143,18,33,128,128,130,246,32,254,130,168,68,154,36,77,51,9,97,47,5,167,195,32,21,131,183,78,239,27,155,
  6483. 195,78,231,14,201,196,77,11,6,32,5,73,111,37,97,247,12,77,19,31,155,207,78,215,19,162,212,69,17,14,66,91,19,80,143,57,78,203,39,159,215,32,128,93,134,8,24,80,109,24,66,113,15,169,215,
  6484. 66,115,6,32,4,69,63,33,32,0,101,113,7,86,227,35,143,211,36,49,53,51,21,1,77,185,14,65,159,28,69,251,34,67,56,8,33,9,0,24,107,175,25,90,111,12,110,251,11,119,189,24,119,187,34,87,15,
  6485. 9,32,4,66,231,37,90,39,7,66,239,8,84,219,15,69,105,23,24,85,27,27,87,31,11,33,1,128,76,94,6,32,1,85,241,7,33,128,128,106,48,10,33,128,128,69,136,11,133,13,24,79,116,49,84,236,8,24,
  6486. 91,87,9,32,5,165,255,69,115,12,66,27,15,159,15,24,72,247,12,74,178,5,24,80,64,15,33,0,128,143,17,77,89,51,130,214,24,81,43,7,170,215,74,49,8,159,199,143,31,139,215,69,143,5,32,254,
  6487. 24,81,50,35,181,217,84,123,70,143,195,159,15,65,187,16,66,123,7,65,175,15,65,193,29,68,207,39,79,27,5,70,131,6,32,4,68,211,33,33,67,0,83,143,14,159,207,143,31,140,223,33,0,128,24,80,
  6488. 82,14,24,93,16,23,32,253,65,195,5,68,227,40,133,214,107,31,7,32,5,67,115,27,87,9,8,107,31,43,66,125,6,32,0,103,177,23,131,127,72,203,36,32,0,110,103,8,155,163,73,135,6,32,19,24,112,
  6489. 99,10,65,71,11,73,143,19,143,31,126,195,5,24,85,21,9,24,76,47,14,32,254,24,93,77,36,68,207,11,39,25,0,0,255,128,3,128,4,66,51,37,95,247,13,82,255,24,76,39,19,147,221,66,85,27,24,118,
  6490. 7,8,24,74,249,12,76,74,8,91,234,8,67,80,17,131,222,33,253,0,121,30,44,73,0,16,69,15,6,32,0,65,23,38,69,231,12,65,179,6,98,131,16,86,31,27,24,108,157,14,80,160,8,24,65,46,17,33,4,0,
  6491. 96,2,18,144,191,65,226,8,68,19,5,171,199,80,9,15,180,199,67,89,5,32,255,24,79,173,28,174,201,24,79,179,50,32,1,24,122,5,10,82,61,10,180,209,83,19,8,32,128,24,80,129,27,111,248,43,131,
  6492. 71,24,115,103,8,67,127,41,78,213,24,100,247,19,66,115,39,75,107,5,32,254,165,219,78,170,40,24,112,163,49,32,1,97,203,6,65,173,64,32,0,83,54,7,133,217,88,37,12,32,254,131,28,33,128,
  6493. 3,67,71,44,84,183,6,32,5,69,223,33,96,7,7,123,137,16,192,211,24,112,14,9,32,255,67,88,29,68,14,10,84,197,38,33,0,22,116,47,50,32,87,106,99,9,116,49,15,89,225,15,97,231,23,70,41,19,
  6494. 82,85,8,93,167,6,32,253,132,236,108,190,7,89,251,5,116,49,58,33,128,128,131,234,32,15,24,74,67,38,70,227,24,24,83,45,23,89,219,12,70,187,12,89,216,19,32,2,69,185,24,141,24,70,143,66,
  6495. 24,82,119,56,78,24,10,32,253,133,149,132,6,24,106,233,7,69,198,48,178,203,81,243,12,68,211,15,106,255,23,66,91,15,69,193,7,100,39,10,24,83,72,16,176,204,33,19,0,88,207,45,68,21,12,
  6496. 68,17,10,65,157,53,68,17,6,32,254,92,67,10,65,161,25,69,182,43,24,118,91,47,69,183,18,181,209,111,253,12,89,159,8,66,112,12,69,184,45,35,0,0,0,9,24,80,227,26,73,185,16,118,195,15,131,
  6497. 15,33,1,0,65,59,15,66,39,27,160,111,66,205,12,148,111,143,110,33,128,128,156,112,24,81,199,8,75,199,23,66,117,20,155,121,32,254,68,126,12,72,213,29,134,239,149,123,89,27,16,148,117,
  6498. 65,245,8,24,71,159,14,141,134,134,28,73,51,55,109,77,15,105,131,11,68,67,11,76,169,27,107,209,12,102,174,8,32,128,72,100,18,116,163,56,79,203,11,75,183,44,85,119,19,71,119,23,151,227,
  6499. 32,1,93,27,8,65,122,5,77,102,8,110,120,20,66,23,8,66,175,17,66,63,12,133,12,79,35,8,74,235,33,67,149,16,69,243,15,78,57,15,69,235,16,67,177,7,151,192,130,23,67,84,29,141,192,174,187,
  6500. 77,67,15,69,11,12,159,187,77,59,10,199,189,24,70,235,50,96,83,19,66,53,23,105,65,19,77,47,12,163,199,66,67,37,78,207,50,67,23,23,174,205,67,228,6,71,107,13,67,22,14,66,85,11,83,187,
  6501. 38,124,47,49,95,7,19,66,83,23,67,23,19,24,96,78,17,80,101,16,71,98,40,33,0,7,88,131,22,24,89,245,12,84,45,12,102,213,5,123,12,9,32,2,126,21,14,43,255,0,128,128,0,0,20,0,128,255,128,
  6502. 3,126,19,39,32,75,106,51,7,113,129,15,24,110,135,19,126,47,15,115,117,11,69,47,11,32,2,109,76,9,102,109,9,32,128,75,2,10,130,21,32,254,69,47,6,32,3,94,217,47,32,0,65,247,10,69,15,46,
  6503. 65,235,31,65,243,15,101,139,10,66,174,14,65,247,16,72,102,28,69,17,14,84,243,9,165,191,88,47,48,66,53,12,32,128,71,108,6,203,193,32,17,75,187,42,73,65,16,65,133,52,114,123,9,167,199,
  6504. 69,21,37,86,127,44,75,171,11,180,197,78,213,12,148,200,81,97,46,24,95,243,9,32,4,66,75,33,113,103,9,87,243,36,143,225,24,84,27,31,90,145,8,148,216,67,49,5,24,84,34,14,75,155,27,67,
  6505. 52,13,140,13,36,0,20,0,128,255,24,135,99,46,88,59,43,155,249,80,165,7,136,144,71,161,23,32,253,132,33,32,254,88,87,44,136,84,35,128,0,0,21,81,103,5,94,47,44,76,51,12,143,197,151,15,
  6506. 65,215,31,24,64,77,13,65,220,20,65,214,14,71,4,40,65,213,13,32,0,130,0,35,21,1,2,0,135,0,34,36,0,72,134,10,36,1,0,26,0,130,134,11,36,2,0,14,0,108,134,11,32,3,138,23,32,4,138,11,34,
  6507. 5,0,20,134,33,34,0,0,6,132,23,32,1,134,15,32,18,130,25,133,11,37,1,0,13,0,49,0,133,11,36,2,0,7,0,38,134,11,36,3,0,17,0,45,134,11,32,4,138,35,36,5,0,10,0,62,134,23,32,6,132,23,36,3,
  6508. 0,1,4,9,130,87,131,167,133,11,133,167,133,11,133,167,133,11,37,3,0,34,0,122,0,133,11,133,167,133,11,133,167,133,11,133,167,34,50,0,48,130,1,34,52,0,47,134,5,8,49,49,0,53,98,121,32,
  6509. 84,114,105,115,116,97,110,32,71,114,105,109,109,101,114,82,101,103,117,108,97,114,84,84,88,32,80,114,111,103,103,121,67,108,101,97,110,84,84,50,48,48,52,47,130,2,53,49,53,0,98,0,121,
  6510. 0,32,0,84,0,114,0,105,0,115,0,116,0,97,0,110,130,15,32,71,132,15,36,109,0,109,0,101,130,9,32,82,130,5,36,103,0,117,0,108,130,29,32,114,130,43,34,84,0,88,130,35,32,80,130,25,34,111,
  6511. 0,103,130,1,34,121,0,67,130,27,32,101,132,59,32,84,130,31,33,0,0,65,155,9,34,20,0,0,65,11,6,130,8,135,2,33,1,1,130,9,8,120,1,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,1,11,1,12,1,13,1,14,
  6512. 1,15,1,16,1,17,1,18,1,19,1,20,1,21,1,22,1,23,1,24,1,25,1,26,1,27,1,28,1,29,1,30,1,31,1,32,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,16,0,17,0,18,0,19,0,20,0,21,0,
  6513. 22,0,23,0,24,0,25,0,26,0,27,0,28,0,29,0,30,0,31,130,187,8,66,33,0,34,0,35,0,36,0,37,0,38,0,39,0,40,0,41,0,42,0,43,0,44,0,45,0,46,0,47,0,48,0,49,0,50,0,51,0,52,0,53,0,54,0,55,0,56,0,
  6514. 57,0,58,0,59,0,60,0,61,0,62,0,63,0,64,0,65,0,66,130,243,9,75,68,0,69,0,70,0,71,0,72,0,73,0,74,0,75,0,76,0,77,0,78,0,79,0,80,0,81,0,82,0,83,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,91,0,
  6515. 92,0,93,0,94,0,95,0,96,0,97,1,33,1,34,1,35,1,36,1,37,1,38,1,39,1,40,1,41,1,42,1,43,1,44,1,45,1,46,1,47,1,48,1,49,1,50,1,51,1,52,1,53,1,54,1,55,1,56,1,57,1,58,1,59,1,60,1,61,1,62,1,
  6516. 63,1,64,1,65,0,172,0,163,0,132,0,133,0,189,0,150,0,232,0,134,0,142,0,139,0,157,0,169,0,164,0,239,0,138,0,218,0,131,0,147,0,242,0,243,0,141,0,151,0,136,0,195,0,222,0,241,0,158,0,170,
  6517. 0,245,0,244,0,246,0,162,0,173,0,201,0,199,0,174,0,98,0,99,0,144,0,100,0,203,0,101,0,200,0,202,0,207,0,204,0,205,0,206,0,233,0,102,0,211,0,208,0,209,0,175,0,103,0,240,0,145,0,214,0,
  6518. 212,0,213,0,104,0,235,0,237,0,137,0,106,0,105,0,107,0,109,0,108,0,110,0,160,0,111,0,113,0,112,0,114,0,115,0,117,0,116,0,118,0,119,0,234,0,120,0,122,0,121,0,123,0,125,0,124,0,184,0,
  6519. 161,0,127,0,126,0,128,0,129,0,236,0,238,0,186,14,117,110,105,99,111,100,101,35,48,120,48,48,48,49,141,14,32,50,141,14,32,51,141,14,32,52,141,14,32,53,141,14,32,54,141,14,32,55,141,
  6520. 14,32,56,141,14,32,57,141,14,32,97,141,14,32,98,141,14,32,99,141,14,32,100,141,14,32,101,141,14,32,102,140,14,33,49,48,141,14,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,
  6521. 141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,45,49,102,6,100,101,108,101,116,101,4,69,117,114,
  6522. 111,140,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,
  6523. 32,56,141,236,32,56,141,236,32,56,65,220,13,32,57,65,220,13,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,
  6524. 239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,35,57,102,0,0,5,250,72,249,98,247,
  6525. };
  6526. static const char* GetDefaultCompressedFontDataTTF(int* out_size)
  6527. {
  6528. *out_size = proggy_clean_ttf_compressed_size;
  6529. return (const char*)proggy_clean_ttf_compressed_data;
  6530. }
  6531. #endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT
  6532. #endif // #ifndef IMGUI_DISABLE