| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373 |
- /*==============================================================================================================
- * Copyright (c) 2020 John Jackson
- * Gunslinger: A simple, header-only c99 multi-media framework
- * File: gs.h
- * Github: https://github.com/MrFrenik/gunslinger
- * All Rights Reserved
- * MIT License
- * May all those that this source may reach be blessed by the LORD and find peace and joy in life.
- * Everyone who drinks of this water will be thirsty again; but whoever drinks of the water
- * that I will give him shall never thirst; John 4:13-14
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
- * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
- * TO THE WARRANTIES OF MECHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
-
- =================================================================================================================*/
- #ifndef GS_H
- #define GS_H
- /*═█═════════════════════════════════════════════════════════════════════════════════════█═╗
- ████ ██████╗ ██╗ ██╗███╗ ██╗███████╗██╗ ██╗███╗ ██╗ ██████╗ ███████╗██████╗ ██████═█
- █║█ ██╔════╝ ██║ ██║████╗ ██║██╔════╝██║ ██║████╗ ██║██╔════╝ ██╔════╝██╔══██╗ ██═████
- ███ ██║ ███╗██║ ██║██╔██╗ ██║███████╗██║ ██║██╔██╗ ██║██║ ███╗█████╗ ██████╔╝ █████═██
- ╚██ ██║ ██║██║ ██║██║╚██╗██║╚════██║██║ ██║██║╚██╗██║██║ ██║██╔══╝ ██╔══██╗ ███ █╝█
- █║█ ╚██████╔╝╚██████╔╝██║ ╚████║███████║███████╗██║██║ ╚████║╚██████╔╝███████╗██║ ██║ ██═████
- ████ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ █═█═██
- ╚═██════════════════════════════════════════════════════════════════════════════════════██═╝*/
- /*
- Gunslinger is a header-only, c99 framework for multi-media applications and tools.
- USAGE: (IMPORTANT)
- =================================================================================================================
- Before including, define the gunslinger implementation like this:
- #define GS_IMPL
- in EXACTLY ONE C or C++ file that includes this header, BEFORE the
- include, like this:
- #define GS_IMPL
- #include "gs.h"
- All other files should just #include "gs.h" without the #define.
- (Thanks to SB for the template for this instructional message. I was too lazy to come up with my own wording.)
- NOTE:
- All main interface stuff in here, then system implementations can be in separate header files
- All provided implementations will be in impl/xxx.h
- This is just to keep everything from being in one huge file
- ================================================================================================================
- Contained within (Contents):
- * GS_APPLICATION
- * GS_UTIL
- * GS_CONTAINERS
- * GS_ASSET_TYPES
- * GS_MATH
- * GS_LEXER
- * GS_PLATFORM
- * GS_GRAPHICS
- * GS_AUDIO
- ================================================================================================================
- GS_APPLICATION:
- Gunslinger is a framework that expects to take flow control over your app and calls into your code
- at certain sync points. These points are 'init', 'update', and 'shutdown'. When creating your application,
- you provide certain information to the framework via a `gs_app_desc_t` descriptor object. Gunslinger acts as the
- main entry point to your application, so instead of defining "main" as you typically would for a c/c++ program,
- you instead implement the `gs_main` function that will be called by gunslinger. This last bit is optional and
- a different method for entry is covered, however this is the most convenient way to use the framework.
- Basic Example Application:
- #define GS_IMPL
- #include "gs.h"
- void my_init(void* app) {
- // Do your initialization
- }
- void my_update(void* app) {
- // Do your updates
- }
- void my_shutdown(void* app) {
- // Do your shutdown
- }
- gs_app_desc_t gs_main(int32_t argc, char** argv) {
- return (gs_app_desc_t) {
- .init = my_init, // Function pointer to call into your init code
- .update = my_update, // Function pointer to call into your update code
- .shutdown = my_shutdown // Function pointer to call into your shutdown code
- };
- }
- If you do not provide information for any of this information, defaults will be provided by the framework.
- Therefore, it is possible to return a completely empty app descriptor back to the framework to run:
- gs_app_desc_t gs_main(int32_t argc, char** argv) {
- return (gs_app_desc_t){0};
- }
- NOTE:
- In addition to function callbacks, there are quite a few options available to provide for this descriptor,
- such as window width, window height, window flags, window title, etc. Refer to the section for gs_app_desc_t
- further in the code for all provided options.
- It's also possible to define GS_NO_HIJACK_MAIN for your application. This will make it so gunslinger will not be
- the main entry point to your application. You will instead be responsible for creating a gunslinger instance and
- passing in your application description to it.
- #define GS_NO_HIJACK_MAIN
- int32_t main(int32_t argv, char** argc)
- {
- gs_app_desc_t app = {0}; // Fill this with whatever your app needs
- gs_create(app); // Create instance of framework and run
- while (gs_app()->is_running) {
- gs_frame();
- }
- return 0;
- }
- NOTE:
- Lastly, while it is possible to use gunslinger without it controlling the main application loop, this isn't recommended.
- Internally, gunslinger does its best to handle the boiler plate drudge work of implementing (in correct order)
- the various layers required for a basic hardware accelerated multi-media application program to work. This involves allocating
- memory for internal data structures for these layers as well initializing them in a particular order so they can inter-operate
- as expected. If you're interested in taking care of this yourself, look at the `gs_frame()` function to get a feeling
- for how this is being handled.
- GS_MATH:
- Gunslinger includes utilities for common graphics/game related math structures. These aren't required to be used, however they are
- used internally for certain function calls in various APIs. Where possible, I've tried to add as much redundancy as possible to
- the APIs so that these structures are not required if you prefer.
- * common utils:
- - interpolation
- * Vectors:
- - gs_vec2: float[2]
- - gs_vec3: float[3]
- - gs_vec4: float[4]
- * vector ops:
- - dot product
- - normalize
- - add/subtract (component wise)
- - multiply
- - cross product
- - length
-
- *Quaternions:
- - gs_quat: float[4]
- * quaternion ops:
- - add/subtract/multiply
- - inverse
- - conjugate
- - angle/axis | axis/angle
- - to euler | from euler
- - to mat4
- *Mat4x4:
- - gs_mat4: float[16]
- * mat4 ops:
- - add/subtract/multiply
- - transpose
- - inverse
- - homogenous transformations:
- - rotation
- - scale
- - translate
- - view:
- - lookat
- - projection:
- - orthographic
- - perspective
- *VQS:
- - gs_vqs: gs_vec3, gs_quat, gs_vec3
- (SPECIAL NOTE):
- `gs_vqs` is a transform structure that's commonly used in games/physics sims, especially with complex child/parent hierarchies. It stands for
- `Vector-Quaternion-Scalar` to denote its internal components. Typically this encodes position, rotation (in quaternion), and a uniform scale
- for transformation. Gunslinger uses non-uniform scale in the form of a gs_vec3.
- gs_vqs xform = {0};
- xform.position = gs_v3(...);
- xform.rotation = gs_quat(...);
- xform.scale = gs_v3(...);
- This structure can then be converted into a final form float[16] mat4x4 for any typical homogenous graphics transformations:
- gs_mat4 model = gs_vqs_to_mat4(&xform);
- The real power in VQS transforms is the ability to easily encode parent/child hierarchies. This is done using the two functions
- `gs_vqs_absolute_transform` and `gs_vqs_relative_transform`:
- gs_vqs parent = ...;
- gs_vqs child = ...; {
- gs_vqs relative = gs_vqs_relative_transform(&child, &parent); // Get relative transform with respect to parent
- gs_vqs absolute = gs_vqs_absolute_transform(&local, &parent); // Get absolute transform with respect to local
- GS_UTIL:
-
- memory allocation
- hashing(32/64 bit)
- siphash (hash generic bytes)
- string utils
- file utils
- GS_CONTAINERS:
- gs_dyn_array:
- Inspired GREATLY from Shawn Barret's "stretchy buffer" implementation. A generic, dynamic array of type T,
- which is defined by the user:
- gs_dyn_array(float) arr = NULL; // Dynamic array of type float
- This works by using the macro `gs_dyn_array(T)`, which evaluates to `T*`. The dynamic array stores a bit of header information
- right before the actual array in memory for a table to describe properties of the array:
- [header][actual array data]
- The header is a structure of uint32_t[2]:
- typedef struct gs_array_header_t {
- uint32_t size;
- uint32_t capacity;
- } gs_array_header_t;
- The array can be randomly accessed using the [] operator, just like any regular c array. There are also provided functions for accessing
- information using this provided table. This dynamic structure is the baseline for all other containers provided in gunslinger.
- Array Usage:
- gs_dyn_array(float) arr = NULL; // Create dynamic array of type float.
- gs_dyn_array_push(arr, 10.f); // Push value into back of array. Will dynamically grow/initialize on demand.
- float v = arr[0]; // Gets value of array data at index 0;
- float* vp = &arr[0]; // Gets pointer reference of array data at index 0;
- uint32_t sz = gs_dyn_array_size(arr); // Gets size of array. Return 0 if NULL.
- uint32_t cap = gs_dyn_array_capacity(arr); // Gets capacity of array. Return 0 if NULL.
- bool is_empty = gs_dyn_array_empty(arr); // Returns whether array is empty. Return true if NULL.
- gs_dyn_array_reserve(arr, 10); // Reserves internal space in the array for N, non-initialized elements.
- gs_dyn_array_clear(arr); // Clears all elements. Simply sets array size to 0.
- gs_dyn_array_free(arr); // Frees array data calling `gs_free` internally.
- gs_hash_table: generic hash table of key:K and val:V
- Inspired GREATLY from Shawn Barret's "stb_ds.h" implementation. A generic hash table of K,V which is defined
- by the user:
- gs_hash_table(uint32_t, float) ht = NULL; // Creates a hash table with K = uint32_t, V = float
- Internally, the hash table uses a 64-bit siphash to hash generic byte data to an unsigned 64-bit key. This means it's possible to pass up
- arbitrary data to the hash table and it will hash accordingly, such as structures:
- typedef struct key_t {
- uint32_t id0;
- uint64_t id1;
- } key_t;
- gs_hash_table(key_t, float) ht = NULL; // Create hash table with K = key_t, V = float
- Inserting into the array with "complex" types is as simple as:
- key_t k = {.ido0 = 5, .id1 = 32}; // Create structure for "key"
- gs_hash_table_insert(ht, k, 5.f); // Insert into hash table using key
- float v = gs_hash_table_get(ht, k); // Get data at key
- It is possible to return a reference to the data using `gs_hash_table_getp()`. However, keep in mind that this comes with the
- danger that the reference could be lost IF the internal data array grows or shrinks in between you caching the pointer
- and using it.
- float* val = gs_hash_table_getp(ht, k); // Cache pointer to internal data. Dangerous game.
- gs_hash_table_insert(ht, new_key); // At this point, your pointer could be invalidated due to growing internal array.
- Hash tables provide iterators to iterate the data:
- for (
- gs_hash_table_iter it = 0;
- gs_hash_table_iter_valid(ht, it);
- gs_hash_table_iter_advance(ht, it)
- ) {
- float v = gs_hash_table_iter_get(ht, it); // Get value using iterator
- float* vp = gs_hash_table_iter_getp(ht, it); // Get value pointer using iterator
- key_t k = gs_hash_table_iter_getk(ht, it); // Get key using iterator
- key_t* kp = gs_hash_table_iter_getkp(ht, it); // Get key pointer using iterator
- }
- Hash Table Usage:
- gs_hash_table(uint32_t, float) ht = NULL; // Create hash table with key = uint32_t, val = float
- gs_hash_table_insert(ht, 64, 3.145f); // Insert key/val pair {64, 3.145f} into hash table. Will dynamically grow/init on demand.
- bool exists = gs_hash_table_key_exists(ht, 64); // Use to query whether or not a key exists in the table.
- float v = gs_hash_table_get(ht, 64); // Get value at key = 64. Will crash if not available.
- float* vp = gs_hash_table_get(ht, 64); // Get pointer reference to data at key = 64. Will crash if not available.
- bool is_empty = gs_hash_table_empty(ht); // Returns whether hash table is empty. Returns true if NULL.
- uint32_t sz = gs_hash_table_size(ht); // Get size of hash table. Returns 0 if NULL.
- uint32_t cap = gs_hash_table_capacity(ht); // Get capacity of hash table. Returns 0 if NULL.
- gs_hash_table_clear(ht); // Clears all elements. Sets size to 0.
- gs_hash_table_free(ht); // Frees hash table internal data calling `gs_free` internally.
- gs_slot_array:
- Slot arrays are internally just dynamic arrays but alleviate the issue with losing references to internal
- data when the arrays grow. Slot arrays therefore hold two internals arrays:
- gs_dyn_array(T) your_data;
- gs_dyn_array(uint32_t) indirection_array;
- The indirection array takes an opaque uint32_t handle and then dereferences it to find the actual index
- for the data you're interested in. Just like dynamic arrays, they are NULL initialized and then
- allocated/initialized internally upon use:
- gs_slot_array(float) arr = NULL; // Slot array with internal 'float' data
- uint32_t hndl = gs_slot_array_insert(arr, 3.145f); // Inserts your data into the slot array, returns handle to you
- float val = gs_slot_array_get(arr, hndl); // Returns copy of data to you using handle as lookup
- It is possible to return a reference to the data using `gs_slot_array_getp()`. However, keep in mind that this comes with the
- danger that the reference could be lost IF the internal data array grows or shrinks in between you caching the pointer
- and using it.
- float* val = gs_slot_array_getp(arr, hndl); // Cache pointer to internal data. Dangerous game.
- gs_slot_array_insert(arr, 5.f); // At this point, your pointer could be invalidated due to growing internal array.
- Slot arrays provide iterators to iterate the data:
- for (
- gs_slot_array_iter it = 0;
- gs_slot_array_iter_valid(sa, it);
- gs_slot_array_iter_advance(sa, it)
- ) {
- float v = gs_slot_array_iter_get(sa, it); // Get value using iterator
- float* vp = gs_slot_array_iter_getp(sa, it); // Get value pointer using iterator
- }
- Slot Array Usage:
- gs_slot_array(float) sa = NULL; // Create slot array with internal 'float' data
- uint32_t hndl = gs_slot_array_insert(sa, 3.145); // Insert data into slot array. Returns uint32_t handle. Init/Grow on demand.
- float v = gs_slot_array_get(sa, hndl); // Get data at hndl.
- float* vp = gs_slot_array_getp(sa, hndl); // Get pointer reference at hndl. Dangerous.
- uint32_t sz = gs_slot_array_size(sa); // Size of slot array. Returns 0 if NULL.
- uint32_t cap = gs_slot_array_capacity(sa); // Capacity of slot array. Returns 0 if NULL.
- gs_slot_array_empty(sa); // Returns whether slot array is empty. Returns true if NULL.
- gs_slot_array_clear(sa); // Clears array. Sets size to 0.
- gs_slot_array_free(sa); // Frees array memory. Calls `gs_free` internally.
- gs_slot_map:
- Works exactly the same, functionally, as gs_slot_array, however allows the user to use one more layer of indirection by
- hashing any data as a key type. Also worth note, the slot map does not return a handle to the user. Instead, the user is
- expected to use the key to access data.
- gs_slot_map(float, uint64_t) sm = NULL; // Slot map with key = float, val = uint64_t
- gs_slot_map_insert(sm, 1.f, 32); // Insert data into slot map.
- uint64_t v = gs_slot_map_get(sm, 1.f); // Returns copy of data to you at key `1.f`
- Like the slot array, it is possible to return a reference via pointer using `gs_slot_map_getp()`. Again, this comes with the same
- danger of losing references if not careful about growing the internal data.
- uint64_t* v = gs_slot_map_getp(sm, 1.f); // Cache pointer to data
- gs_slot_map_insert(sm, 2.f, 10); // Possibly have just invalidated your previous pointer
- Slot maps provide iterators to iterate the data:
- for (
- gs_slot_map_iter it = 0;
- gs_slot_map_iter_valid(sm, it);
- gs_slot_map_iter_advance(sm, it)
- ) {
- uint64_t v = gs_slot_map_iter_get(sm, it); // Get value using iterator
- uint64_t* vp = gs_slot_map_iter_getp(sm, it); // Get value pointer using iterator
- float k = gs_slot_map_iter_get_key(sm, it); // Get key using iterator
- float* kp = gs_slot_map_iter_get_keyp(sm, it); // Get key pointer using iterator
- }
- Slot Map Usage:
- gs_slot_map(float, uint64_t) sm = NULL; // Create slot map with K = float, V = uint64_t
- uint32_t hndl = gs_slot_map_insert(sm, 3.145f, 32); // Insert data into slot map. Init/Grow on demand.
- uint64_t v = gs_slot_map_get(sm, 3.145f); // Get data at key.
- uint64_t* vp = gs_slot_map_getp(sm, 3.145f); // Get pointer reference at hndl. Dangerous.
- uint32_t sz = gs_slot_map_size(sm); // Size of slot map. Returns 0 if NULL.
- uint32_t cap = gs_slot_map_capacity(sm); // Capacity of slot map. Returns 0 if NULL.
- gs_slot_map_empty(sm); // Returns whether slot map is empty. Returns true if NULL.
- gs_slot_map_clear(sm); // Clears map. Sets size to 0.
- gs_slot_map_free(sm); // Frees map memory. Calls `gs_free` internally.
- GS_PLATFORM:
- By default, Gunslinger supports (via included GLFW) the following platforms:
- - Win32
- - OSX
- - Linux
- To define your own custom implementation and not use the included glfw implementation, define GS_PLATFORM_IMPL_CUSTOM in your
- project. Gunslinger will see this and leave the implementation of the platform API up to you:
- // For custom platform implementation
- #define GS_PLATFORM_IMPL_CUSTOM
- Internally, the platform interface holds the following data:
- gs_platform_settings_t settings; // Settings for platform, including video driver settings
- gs_platform_time_t time; // Time structure, used to query frame time, delta time, render time
- gs_platform_input_t input; // Input struture, used to query input state for mouse, keyboard, controllers
- gs_slot_array(void*) windows; // Slot array of raw platform window data and handles
- void* cursors[GS_PLATFORM_CURSOR_COUNT]; // Raw platform cursors
- void* user_data; // Specific user data (for custom implementations)
- Upon creation, the framework will create a main window for you and then store its handle with slot id 0. All platform related window
- query functions require passing in an opaque uint32_t handle to get the actual data internally. There is a convenience function available for
- querying the main window handle created for you:
- uint32_t main_window_hndl = gs_platform_main_window();
- Internally, the platform layer queries the platform backend and updates its exposed gs_platform_input_t data structure for you to use. Several
- utility functions exist:
- gs_platform_key_down(gs_platform_keycode) // Checks to see if a key is held down (pressed last frame and this frame)
- gs_platform_key_released(gs_platform_keycode) // Checks to see if a key was released this frame
- gs_platform_key_pressed(gs_platform_keycode) // Checks to see if a key was pressed this frame (not pressed last frame)
- gs_platform_mouse_down(gs_platform_mouse_button_code) // Checks to see if mouse button is held down
- gs_platform_mouse_pressed(gs_platform_mouse_button_code) // Checks to see if mouse button was pressed this frame (not pressed last frame)
- gs_platform_mouse_released(gs_platform_mouse_button_code) // Checks to see if mouse button was released this frame
- GS_AUDIO:
- By default, Gunslinger includes and uses miniaudio for its audio backend.
- To define your own custom implementation and not use the included miniaudio implementation, define GS_AUDIO_IMPL_CUSTOM in your
- project. Gunslinger will see this and leave the implementation of the audio API up to you:
- // For custom audio implementation
- #define GS_AUDIO_IMPL_CUSTOM
- GS_GRAPHICS:
- // For custom graphics implementation
- #define GS_GRAPHICS_IMPL_CUSTOM
- */
- /*===== Gunslinger Include ======*/
- // #ifdef __cplusplus
- // extern "C" {
- // #endif
- /*========================
- // Defines
- ========================*/
- #include <stdarg.h> // valist
- #include <stddef.h> // ptrdiff_t
- #include <stdlib.h> // malloc, realloc, free
- #include <stdint.h> // standard types
- #include <limits.h> // INT32_MAX, UINT32_MAX
- #include <string.h> // memset
- #include <float.h> // FLT_MAX
- #include <stdio.h> // FILE
- #include <time.h> // time
- #include <ctype.h> // tolower
- #include <math.h> // floor, acos, sin, sqrt, tan
- #include <assert.h> // assert
- #include <malloc.h> // alloca/_alloca
- /*===========================================================
- // gs_inline, gs_global, gs_local_persist, gs_force_inline
- ===========================================================*/
- #ifndef gs_inline
- #define gs_inline static inline
- #endif
- #ifndef gs_local_persist
- #define gs_local_persist static
- #endif
- #ifndef gs_global
- #define gs_global static
- #endif
- #if (defined _WIN32 || defined _WIN64)
- #define gs_force_inline gs_inline
- #elif (defined __APPLE__ || defined _APPLE)
- #define gs_force_inline static __attribute__((always_inline))
- #else
- #define gs_force_inline gs_inline
- #endif
- #define GS_INLINE gs_force_inline
- #define GS_GLOBAL gs_global
- #define GS_LOCAL_PERSIST gs_local_persist
- #ifdef __cplusplus
- #pragma warning(disable:4996)
- #endif
- /*===================
- // GS_API_DECL
- ===================*/
- #ifdef GS_API_DLL_EXPORT
- #ifdef __cplusplus
- #define GS_API_EXTERN extern "C" __declspec(dllexport)
- #else
- #define GS_API_EXTERN extern __declspec(dllexport)
- #endif
- #else
- #ifdef __cplusplus
- #define GS_API_EXTERN extern "C"
- #else
- #define GS_API_EXTERN extern
- #endif
- #endif
- #define GS_API_DECL GS_API_EXTERN
- #define GS_API_PRIVATE GS_API_EXTERN
- /*===================
- // PLATFORM DEFINES
- ===================*/
- /* Platform Android */
- #if (defined __ANDROID__)
- #define GS_PLATFORM_ANDROID
- /* Platform Apple */
- #elif (defined __APPLE__ || defined _APPLE)
- #define GS_PLATFORM_APPLE
- /* Platform Windows */
- #elif (defined _WIN32 || defined _WIN64)
- #define __USE_MINGW_ANSI_STDIO 1
- // Necessary windows defines before including windows.h, because it's retarded.
- #define OEMRESOURCE
- #define GS_PLATFORM_WIN
- #define GS_PLATFORM_WINDOWS
- #include <windows.h>
- #define WIN32_LEAN_AND_MEAN
- /* Platform Linux */
- #elif (defined linux || defined _linux || defined __linux__)
- #define GS_PLATFORM_LINUX
- /* Platform Emscripten */
- #elif (defined __EMSCRIPTEN__)
- #define GS_PLATFORM_WEB
- /* Else - Platform Undefined and Unsupported or custom */
- #endif
- /*============================================================
- // C primitive types
- ============================================================*/
- #ifndef __cplusplus
- #define false 0
- #define true 1
- #endif
- #ifdef __cplusplus
- typedef bool b8;
- #else
- #ifndef __bool_true_false_are_defined
- typedef _Bool bool;
- #endif
- typedef bool b8;
- #endif
- typedef size_t usize;
- typedef uint8_t u8;
- typedef int8_t s8;
- typedef uint16_t u16;
- typedef int16_t s16;
- typedef uint32_t u32;
- typedef int32_t s32;
- typedef s32 b32;
- typedef uint64_t u64;
- typedef int64_t s64;
- typedef float f32;
- typedef double f64;
- typedef const char* const_str;
- typedef int32_t bool32_t;
- typedef float float32_t;
- typedef double float64_t;
- typedef bool32_t bool32;
- #define uint16_max UINT16_MAX
- #define uint32_max UINT32_MAX
- #define int32_max INT32_MAX
- #define float_max FLT_MAX
- #define float_min FLT_MIN
- /*============================================================
- // gs utils
- ============================================================*/
- /** @defgroup gs_util Common Utils
- * Gunslinger Common Utils
- * @{
- */
- // Helper macro for compiling to nothing
- #define gs_empty_instruction(...)
- #define gs_array_size(__ARR) sizeof(__ARR) / sizeof(__ARR[0])
- #ifndef gs_assert
- #define gs_assert assert
- #endif
-
- #if defined (__cplusplus)
- #define gs_default_val() {}
- #else
- #define gs_default_val() {0}
- #endif
- // Helper macro for an in place for-range loop
- #define gs_for_range_i(__COUNT)\
- for (uint32_t i = 0; i < __COUNT; ++i)
- // Helper macro for an in place for-range loop
- #define gs_for_range_j(__COUNT)\
- for (uint32_t j = 0; j < __COUNT; ++j)
- #define gs_for_range(__COUNT)\
- for(uint32_t gs_macro_token_paste(__T, __LINE__) = 0;\
- gs_macro_token_paste(__T, __LINE__) < __COUNT;\
- ++(gs_macro_token_paste(__T, __LINE__)))
- #define gs_max(A, B) ((A) > (B) ? (A) : (B))
- #define gs_min(A, B) ((A) < (B) ? (A) : (B))
- #define gs_clamp(V, MIN, MAX) ((V) > (MAX) ? (MAX) : (V) < (MIN) ? (MIN) : (V))
- #define gs_is_nan(V) ((V) != (V))
- // Helpful macro for casting one type to another
- #define gs_cast(A, B) ((A*)(B))
- #ifdef __cplusplus
- #define gs_ctor(TYPE, ...) (TYPE {__VA_ARGS__})
- #else
- #define gs_ctor(TYPE, ...) ((TYPE){__VA_ARGS__})
- #endif
- // Helpful marco for calculating offset (in bytes) of an element from a given structure type
- #define gs_offset(TYPE, ELEMENT) ((size_t)(&(((TYPE*)(0))->ELEMENT)))
- // macro for turning any given type into a const char* of itself
- #define gs_to_str(TYPE) ((const char*)#TYPE)
- #define gs_macro_token_paste(X, Y) X##Y
- #define gs_macro_cat(X, Y) gs_macro_token_paste(X, Y)
- #define gs_timed_action(INTERVAL, ...)\
- do {\
- static uint32_t gs_macro_cat(gs_macro_cat(__T, __LINE__), t) = 0;\
- if (gs_macro_cat(gs_macro_cat(__T, __LINE__), t)++ > INTERVAL) {\
- gs_macro_cat(gs_macro_cat(__T, __LINE__), t) = 0;\
- __VA_ARGS__\
- }\
- } while (0)
- #define gs_int2voidp(I) (void*)(uintptr_t)(I)
- #define gs_if(INIT, CHECK, ...)\
- do {\
- INIT;\
- if (CHECK)\
- {\
- __VA_ARGS__\
- }\
- } while (0)
- //=== Logging ===//
- #define gs_log_info(MESSAGE, ...) gs_println("LOG::%s::%s(%zu)::" MESSAGE, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
- #define gs_log_success(MESSAGE, ...) gs_println("SUCCESS::%s::%s(%zu)::" MESSAGE, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
- #define gs_log_warning(MESSAGE, ...) gs_println("WARNING::%s::%s(%zu)::" MESSAGE, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
- #define gs_log_error(MESSAGE, ...) do {gs_println("ERROR::%s::%s(%zu)::" MESSAGE, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);\
- gs_assert(false);\
- } while (0)
- /*===================================
- // Memory Allocation Utils
- ===================================*/
- // Operating system function pointer
- typedef struct gs_os_api_s
- {
- void* (* malloc)(size_t sz);
- void (* free)(void* ptr);
- void* (* realloc)(void* ptr, size_t sz);
- void* (* calloc)(size_t num, size_t sz);
- void* (* alloca)(size_t sz);
- void* (* malloc_init)(size_t sz);
- char* (* strdup)(const char* str);
- } gs_os_api_t;
- // TODO(john): Check if all defaults need to be set, in case gs context will not be used
- GS_API_DECL
- void* _gs_malloc_init_impl(size_t sz);
- // Default memory allocations
- #ifndef GS_NO_OS_MEMORY_ALLOC_DEFAULT
- #define gs_malloc malloc
- #define gs_free free
- #define gs_realloc realloc
- #define gs_calloc calloc
- #define gs_alloca malloc
- #define gs_malloc_init(__T) (__T*)_gs_malloc_init_impl(sizeof(__T))
- #endif
- GS_API_DECL gs_os_api_t
- gs_os_api_new_default();
- #ifndef gs_os_api_new
- #define gs_os_api_new gs_os_api_new_default
- #endif
- #ifndef gs_malloc
- #define gs_malloc(__SZ) (gs_ctx()->os.malloc(__SZ))
- #endif
- #ifndef gs_malloc_init
- #define gs_malloc_init(__T) ((__T*)gs_ctx()->os.malloc_init(sizeof(__T)))
- #endif
- #ifndef gs_free
- #define gs_free(__MEM) (gs_ctx()->os.free(__MEM))
- #endif
- #ifndef gs_realloc
- #define gs_realloc(__MEM, __AZ) (gs_ctx()->os.realloc(__MEM, __AZ))
- #endif
- #ifndef gs_calloc
- #define gs_calloc(__NUM, __SZ) (gs_ctx()->os.calloc(__NUM, __SZ))
- #endif
- #ifndef gs_alloca
- #define gs_alloca(__SZ) (gs_ctx()->os.alloca(__SZ))
- #endif
- #ifndef gs_strdup
- #define gs_strdup(__STR) (gs_ctx()->os.strdup(__STR))
- #endif
- // Modified from: https://stackoverflow.com/questions/11815894/how-to-read-write-arbitrary-bits-in-c-c
- #define gs_bit_mask(INDEX, SIZE)\
- (((1u << (SIZE)) - 1u) << (INDEX))
- #define gs_write_bits(DATA, INDEX, SIZE, VAL)\
- ((DATA) = (((DATA) & (~BIT_MASK((INDEX), (SIZE)))) | (((VAL) << (INDEX)) & (BIT_MASK((INDEX), (SIZE))))))
- #define gs_read_bits(DATA, INDEX, SIZE)\
- (((DATA) & BIT_MASK((INDEX), (SIZE))) >> (INDEX))
- /*============================================================
- // Result
- ============================================================*/
- typedef enum gs_result
- {
- GS_RESULT_SUCCESS,
- GS_RESULT_IN_PROGRESS,
- GS_RESULT_INCOMPLETE,
- GS_RESULT_FAILURE
- } gs_result;
- /*===================================
- // Resource Handles
- ===================================*/
- // Useful typedefs for typesafe, internal resource handles
- #define gs_handle(TYPE)\
- gs_handle_##TYPE
- #define gs_handle_decl(TYPE)\
- typedef struct {uint32_t id;} gs_handle(TYPE);\
- gs_inline\
- gs_handle(TYPE) gs_handle_invalid_##TYPE()\
- {\
- gs_handle(TYPE) h;\
- h.id = UINT32_MAX;\
- return h;\
- }\
- \
- gs_inline\
- gs_handle(TYPE) gs_handle_create_##TYPE(uint32_t id)\
- {\
- gs_handle(TYPE) h;\
- h.id = id;\
- return h;\
- }
- #define gs_handle_invalid(__TYPE)\
- gs_handle_invalid_##__TYPE()
- #define gs_handle_create(__TYPE, __ID)\
- gs_handle_create_##__TYPE(__ID)
- #define gs_handle_is_valid(HNDL)\
- ((HNDL.id) != UINT32_MAX)
- /*===================================
- // Color
- ===================================*/
- #define gs_hsv(...) gs_hsv_ctor(__VA_ARGS__)
- #define gs_color(...) gs_color_ctor(__VA_ARGS__)
- typedef struct gs_hsv_t
- {
- union
- {
- float hsv[3];
- struct
- {
- float h, s, v;
- };
- };
- } gs_hsv_t;
- gs_force_inline
- gs_hsv_t gs_hsv_ctor(float h, float s, float v)
- {
- gs_hsv_t hsv;
- hsv.h = h;
- hsv.s = s;
- hsv.v = v;
- return hsv;
- }
- typedef struct gs_color_t
- {
- union
- {
- uint8_t rgba[4];
- struct
- {
- uint8_t r, g, b, a;
- };
- };
- } gs_color_t;
- gs_force_inline
- gs_color_t gs_color_ctor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
- {
- gs_color_t color;
- color.r = r;
- color.g = g;
- color.b = b;
- color.a = a;
- return color;
- }
- #define GS_COLOR_BLACK gs_color(0, 0, 0, 255)
- #define GS_COLOR_WHITE gs_color(255, 255, 255, 255)
- #define GS_COLOR_RED gs_color(255, 0, 0, 255)
- #define GS_COLOR_GREEN gs_color(0, 255, 0, 255)
- #define GS_COLOR_BLUE gs_color(0, 0, 255, 255)
- #define GS_COLOR_ORANGE gs_color(255, 100, 0, 255)
- #define GS_COLOR_YELLOW gs_color(255, 255, 0, 255)
- #define GS_COLOR_PURPLE gs_color(128, 0, 128, 255)
- #define GS_COLOR_MAROON gs_color(128, 0, 0, 255)
- #define GS_COLOR_BROWN gs_color(165, 42, 42, 255)
- #define GS_COLOR_MAGENTA gs_color(255, 0, 255, 255)
- gs_force_inline
- gs_color_t gs_color_alpha(gs_color_t c, uint8_t a)
- {
- return gs_color(c.r, c.g, c.b, a);
- }
- gs_force_inline gs_hsv_t
- gs_rgb2hsv(gs_color_t in)
- {
- float ir = (float)in.r / 255.f;
- float ig = (float)in.g / 255.f;
- float ib = (float)in.b / 255.f;
- float ia = (float)in.a / 255.f;
- gs_hsv_t out = gs_default_val();
- double min, max, delta;
- min = ir < ig ? ir : ig;
- min = min < ib ? min : ib;
- max = ir > ig ? ir : ig;
- max = max > ib ? max : ib;
- out.v = max; // v
- delta = max - min;
- if (delta < 0.00001)
- {
- out.s = 0;
- out.h = 0; // undefined, maybe nan?
- return out;
- }
- if(max > 0.0)
- { // NOTE: if Max is == 0, this divide would cause a crash
- out.s = (delta / max); // s
- }
- else
- {
- // if max is 0, then r = g = b = 0
- // s = 0, h is undefined
- out.s = 0.0;
- out.h = NAN; // its now undefined
- return out;
- }
- if(ir >= max) // > is bogus, just keeps compilor happy
- out.h = (ig - ib) / delta; // between yellow & magenta
- else
- if( ig >= max )
- out.h = 2.0 + ( ib - ir ) / delta; // between cyan & yellow
- else
- out.h = 4.0 + ( ir - ig ) / delta; // between magenta & cyan
- out.h *= 60.0; // degrees
- if( out.h < 0.0 )
- out.h += 360.0;
- return out;
- }
- gs_force_inline gs_color_t
- gs_hsv2rgb(gs_hsv_t in)
- {
- double hh, p, q, t, ff;
- long i;
- gs_color_t out;
- if(in.s <= 0.0) { // < is bogus, just shuts up warnings
- out.r = in.v * 255;
- out.g = in.v * 255;
- out.b = in.v * 255;
- out.a = 255;
- return out;
- }
- hh = in.h;
- if(hh >= 360.0) hh = 0.0;
- hh /= 60.0;
- i = (long)hh;
- ff = hh - i;
- p = in.v * (1.0 - in.s);
- q = in.v * (1.0 - (in.s * ff));
- t = in.v * (1.0 - (in.s * (1.0 - ff)));
- uint8_t iv = in.v * 255;
- uint8_t it = t * 255;
- uint8_t ip = p * 255;
- uint8_t iq = q * 255;
- switch(i)
- {
- case 0:
- out.r = iv;
- out.g = it;
- out.b = ip;
- break;
- case 1:
- out.r = iq;
- out.g = iv;
- out.b = ip;
- break;
- case 2:
- out.r = ip;
- out.g = iv;
- out.b = it;
- break;
- case 3:
- out.r = ip;
- out.g = iq;
- out.b = iv;
- break;
- case 4:
- out.r = it;
- out.g = ip;
- out.b = iv;
- break;
- case 5:
- default:
- out.r = iv;
- out.g = ip;
- out.b = iq;
- break;
- }
- return out;
- }
- /*===================================
- // String Utils
- ===================================*/
- gs_force_inline uint32_t
- gs_string_length(const char* txt)
- {
- uint32_t sz = 0;
- while (txt != NULL && txt[ sz ] != '\0')
- {
- sz++;
- }
- return sz;
- }
- #define gs_strlen gs_string_length
- // Expects null terminated strings
- gs_force_inline b32
- gs_string_compare_equal
- (
- const char* txt,
- const char* cmp
- )
- {
- // Grab sizes of both strings
- uint32_t a_sz = gs_string_length(txt);
- uint32_t b_sz = gs_string_length(cmp);
- // Return false if sizes do not match
- if (a_sz != b_sz)
- {
- return false;
- }
- for(uint32_t i = 0; i < a_sz; ++i)
- {
- if (*txt++ != *cmp++)
- {
- return false;
- }
- };
- return true;
- }
- gs_force_inline b32
- gs_string_compare_equal_n
- (
- const char* txt,
- const char* cmp,
- uint32_t n
- )
- {
- uint32_t a_sz = gs_string_length(txt);
- uint32_t b_sz = gs_string_length(cmp);
- // Not enough characters to do operation
- if (a_sz < n || b_sz < n)
- {
- return false;
- }
- for (uint32_t i = 0; i < n; ++i)
- {
- if (*txt++ != *cmp++)
- {
- return false;
- }
- };
- return true;
- }
- gs_force_inline void
- gs_util_str_to_lower
- (
- const char* src,
- char* buffer,
- size_t buffer_sz
- )
- {
- size_t src_sz = gs_string_length(src);
- size_t len = gs_min(src_sz, buffer_sz-1);
- for (uint32_t i = 0; i < len; ++i) {
- buffer[i] = tolower(src[i]);
- }
- if (len) buffer[len] = '\0';
- }
- gs_force_inline b32
- gs_util_str_is_numeric(const char* str)
- {
- const char* at = str;
- while (at && *at)
- {
- while (*at == '\n' || *at == '\t' || *at == ' ' || *at == '\r') at++;;
- char c = *at++;
- if (c < '0' || c > '9')
- {
- return false;
- }
- }
- return true;
- }
- // Will return a null buffer if file does not exist or allocation fails
- GS_API_DECL char*
- gs_read_file_contents_into_string_null_term (const char* file_path, const char* mode, size_t* _sz);
- gs_force_inline
- b32 gs_util_file_exists(const char* file_path)
- {
- FILE* fp = fopen(file_path, "r");
- if (fp)
- {
- fclose(fp);
- return true;
- }
- return false;
- }
- gs_force_inline
- void gs_util_get_file_extension
- (
- char* buffer,
- uint32_t buffer_size,
- const char* file_path
- )
- {
- // assumes that buffer and buffer_size is non-zero
- const char* extension = strrchr(file_path, '.');
- if (extension) {
- uint32_t extension_len = strlen(extension+1);
- uint32_t len = (extension_len >= buffer_size) ? buffer_size - 1 : extension_len;
- memcpy(buffer, extension+1, len);
- buffer[len] = '\0';
- } else {
- buffer[0] = '\0';
- }
- }
- gs_force_inline
- void gs_util_get_dir_from_file
- (
- char* buffer,
- uint32_t buffer_size,
- const char* file_path
- )
- {
- uint32_t str_len = gs_string_length(file_path);
- const char* end = (file_path + str_len);
- for (uint32_t i = 0; i < str_len; ++i)
- {
- if (file_path[i] == '/' || file_path[i] == '\\')
- {
- end = &file_path[i];
- }
- }
- size_t dir_len = end - file_path;
- memcpy(buffer, file_path, gs_min(buffer_size, dir_len + 1));
- if (dir_len + 1 <= buffer_size) {
- buffer[dir_len] = '\0';
- }
- }
- gs_force_inline
- void gs_util_get_file_name
- (
- char* buffer,
- uint32_t buffer_size,
- const char* file_path
- )
- {
- uint32_t str_len = gs_string_length(file_path);
- const char* file_start = file_path;
- const char* file_end = (file_path + str_len);
- for (uint32_t i = 0; i < str_len; ++i)
- {
- if (file_path[i] == '/' || file_path[i] == '\\')
- {
- file_start = &file_path[i + 1];
- }
- else if (file_path[i] == '.')
- {
- file_end = &file_path[i];
- }
- }
- size_t dir_len = file_end - file_start;
- memcpy(buffer, file_start, gs_min(buffer_size, dir_len + 1));
- if (dir_len + 1 <= buffer_size) {
- buffer[dir_len] = '\0';
- }
- }
- gs_force_inline
- void gs_util_string_substring
- (
- const char* src,
- char* dst,
- size_t sz,
- uint32_t start,
- uint32_t end
- )
- {
- uint32_t str_len = gs_string_length(src);
- if (end > str_len) {
- end = str_len;
- }
- if (start > str_len) {
- start = str_len;
- }
- const char* at = src + start;
- const char* e = src + end;
- uint32_t ct = 0;
- while (at && *at != '\0' && at != e)
- {
- dst[ ct ] = *at;
- at++;
- ct++;
- }
- }
- gs_force_inline
- void gs_util_string_remove_character
- (
- const char* src,
- char* buffer,
- uint32_t buffer_size,
- char delimiter
- )
- {
- uint32_t ct = 0;
- uint32_t str_len = gs_string_length(src);
- const char* at = src;
- while (at && *at != '\0' && ct < buffer_size)
- {
- char c = *at;
- if (c != delimiter) {
- buffer[ ct ] = c;
- ct++;
- }
- at++;
- }
- }
- gs_force_inline
- void gs_util_string_replace(
- char* buffer,
- size_t buffer_sz,
- const char* replace,
- char fallback
- )
- {
- // Replace all characters with characters of keyword, then the rest replace with spaces
- size_t len = gs_string_length(replace);
- for (uint32_t c = 0; c < buffer_sz; ++c)
- {
- if (c < len)
- {
- buffer[c] = replace[c];
- }
- else
- {
- buffer[c] = fallback;
- }
- }
- }
- gs_force_inline
- void gs_util_string_replace_delim
- (
- const char* source_str,
- char* buffer,
- uint32_t buffer_size,
- char delimiter,
- char replace
- )
- {
- uint32_t str_len = gs_string_length(source_str);
- const char* at = source_str;
- while (at && *at != '\0')
- {
- char c = *at;
- if (c == delimiter) {
- c = replace;
- }
- buffer[(at - source_str)] = c;
- at++;
- }
- }
- GS_API_DECL char*
- gs_util_string_concat(char* s1, const char* s2);
- gs_force_inline
- void gs_util_normalize_path
- (
- const char* path,
- char* buffer,
- uint32_t buffer_size
- )
- {
- // Normalize the path somehow...
- }
- // Custom printf defines
- #ifndef gs_printf
- #ifdef __MINGW32__
- #define gs_printf(__FMT, ...) __mingw_printf(__FMT, ##__VA_ARGS__)
- #elif (defined GS_PLATFORM_ANDROID)
- #include <android/log.h>
- #define gs_printf(__FMT, ...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __FMT, ## __VA_ARGS__))
- #else
- gs_force_inline void
- gs_printf
- (
- const char* fmt,
- ...
- )
- {
- va_list args;
- va_start (args, fmt);
- vprintf(fmt, args);
- va_end(args);
- }
- #endif
- #endif
- #define gs_println(__FMT, ...)\
- do {\
- gs_printf(__FMT, ## __VA_ARGS__);\
- gs_printf("\n");\
- } while (0)
- #ifndef gs_fprintf
- gs_force_inline
- void gs_fprintf
- (
- FILE* fp,
- const char* fmt,
- ...
- )
- {
- va_list args;
- va_start (args, fmt);
- vfprintf(fp, fmt, args);
- va_end(args);
- }
- #endif
- gs_force_inline
- void gs_fprintln
- (
- FILE* fp,
- const char* fmt,
- ...
- )
- {
- va_list args;
- va_start(args, fmt);
- vfprintf(fp, fmt, args);
- va_end(args);
- gs_fprintf(fp, "\n");
- }
- gs_force_inline
- void gs_fprintln_t
- (
- FILE* fp,
- uint32_t tabs,
- const char* fmt,
- ...
- )
- {
- va_list args;
- va_start(args, fmt);
- for (uint32_t i = 0; i < tabs; ++i)
- {
- gs_fprintf(fp, "\t");
- }
- vfprintf(fp, fmt, args);
- va_end(args);
- gs_fprintf(fp, "\n");
- }
- #ifdef __MINGW32__
- #define gs_snprintf(__NAME, __SZ, __FMT, ...) __mingw_snprintf(__NAME, __SZ, __FMT, ## __VA_ARGS__)
- #else
- gs_force_inline
- void gs_snprintf
- (
- char* buffer,
- size_t buffer_size,
- const char* fmt,
- ...
- )
- {
- va_list args;
- va_start(args, fmt);
- vsnprintf(buffer, buffer_size, fmt, args);
- va_end(args);
- }
- #endif
- #define gs_transient_buffer(__N, __SZ)\
- char __N[__SZ] = gs_default_val();\
- memset(__N, 0, __SZ);
- #define gs_snprintfc(__NAME, __SZ, __FMT, ...)\
- char __NAME[__SZ] = gs_default_val();\
- gs_snprintf(__NAME, __SZ, __FMT, ## __VA_ARGS__);
- gs_force_inline
- uint32_t gs_util_safe_truncate_u64(uint64_t value)
- {
- gs_assert(value <= 0xFFFFFFFF);
- uint32_t result = (uint32_t)value;
- return result;
- }
- gs_force_inline
- uint32_t gs_hash_uint32_t(uint32_t x)
- {
- x = ((x >> 16) ^ x) * 0x45d9f3b;
- x = ((x >> 16) ^ x) * 0x45d9f3b;
- x = (x >> 16) ^ x;
- return x;
- }
- #define gs_hash_u32_ip(__X, __OUT)\
- do {\
- __OUT = ((__X >> 16) ^ __X) * 0x45d9f3b;\
- __OUT = ((__OUT >> 16) ^ __OUT) * 0x45d9f3b;\
- __OUT = (__OUT >> 16) ^ __OUT;\
- } while (0)
- gs_force_inline
- uint32_t gs_hash_u64(uint64_t x)
- {
- x = (x ^ (x >> 31) ^ (x >> 62)) * UINT64_C(0x319642b2d24d8ec3);
- x = (x ^ (x >> 27) ^ (x >> 54)) * UINT64_C(0x96de1b173f119089);
- x = x ^ (x >> 30) ^ (x >> 60);
- return (uint32_t)x;
- }
- // Note(john): source: http://www.cse.yorku.ca/~oz/hash.html
- // djb2 hash by dan bernstein
- gs_force_inline
- uint32_t gs_hash_str(const char* str)
- {
- uint32_t hash = 5381;
- s32 c;
- while ((c = *str++))
- {
- hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
- }
- return hash;
- }
- gs_force_inline
- uint64_t gs_hash_str64(const char* str)
- {
- uint32_t hash1 = 5381;
- uint32_t hash2 = 52711;
- uint32_t i = gs_string_length(str);
- while(i--)
- {
- char c = str[ i ];
- hash1 = (hash1 * 33) ^ c;
- hash2 = (hash2 * 33) ^ c;
- }
- return (hash1 >> 0) * 4096 + (hash2 >> 0);
- }
- gs_force_inline
- bool gs_compare_bytes(void* b0, void* b1, size_t len)
- {
- return 0 == memcmp(b0, b1, len);
- }
- // Hash generic bytes using (ripped directly from Sean Barret's stb_ds.h)
- #define GS_SIZE_T_BITS ((sizeof(size_t)) * 8)
- #define GS_SIPHASH_C_ROUNDS 1
- #define GS_SIPHASH_D_ROUNDS 1
- #define gs_rotate_left(__V, __N) (((__V) << (__N)) | ((__V) >> (GS_SIZE_T_BITS - (__N))))
- #define gs_rotate_right(__V, __N) (((__V) >> (__N)) | ((__V) << (GS_SIZE_T_BITS - (__N))))
- #ifdef _MSC_VER
- #pragma warning(push)
- #pragma warning(disable:4127) // conditional expression is constant, for do..while(0) and sizeof()==
- #endif
- gs_force_inline
- size_t gs_hash_siphash_bytes(void *p, size_t len, size_t seed)
- {
- unsigned char *d = (unsigned char *) p;
- size_t i,j;
- size_t v0,v1,v2,v3, data;
- // hash that works on 32- or 64-bit registers without knowing which we have
- // (computes different results on 32-bit and 64-bit platform)
- // derived from siphash, but on 32-bit platforms very different as it uses 4 32-bit state not 4 64-bit
- v0 = ((((size_t) 0x736f6d65 << 16) << 16) + 0x70736575) ^ seed;
- v1 = ((((size_t) 0x646f7261 << 16) << 16) + 0x6e646f6d) ^ ~seed;
- v2 = ((((size_t) 0x6c796765 << 16) << 16) + 0x6e657261) ^ seed;
- v3 = ((((size_t) 0x74656462 << 16) << 16) + 0x79746573) ^ ~seed;
- #ifdef STBDS_TEST_SIPHASH_2_4
- // hardcoded with key material in the siphash test vectors
- v0 ^= 0x0706050403020100ull ^ seed;
- v1 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed;
- v2 ^= 0x0706050403020100ull ^ seed;
- v3 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed;
- #endif
- #define gs_sipround() \
- do { \
- v0 += v1; v1 = gs_rotate_left(v1, 13); v1 ^= v0; v0 = gs_rotate_left(v0,GS_SIZE_T_BITS/2); \
- v2 += v3; v3 = gs_rotate_left(v3, 16); v3 ^= v2; \
- v2 += v1; v1 = gs_rotate_left(v1, 17); v1 ^= v2; v2 = gs_rotate_left(v2,GS_SIZE_T_BITS/2); \
- v0 += v3; v3 = gs_rotate_left(v3, 21); v3 ^= v0; \
- } while (0)
- for (i=0; i+sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) {
- data = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
- data |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // discarded if size_t == 4
- v3 ^= data;
- for (j=0; j < GS_SIPHASH_C_ROUNDS; ++j)
- gs_sipround();
- v0 ^= data;
- }
- data = len << (GS_SIZE_T_BITS-8);
- switch (len - i) {
- case 7: data |= ((size_t) d[6] << 24) << 24; // fall through
- case 6: data |= ((size_t) d[5] << 20) << 20; // fall through
- case 5: data |= ((size_t) d[4] << 16) << 16; // fall through
- case 4: data |= (d[3] << 24); // fall through
- case 3: data |= (d[2] << 16); // fall through
- case 2: data |= (d[1] << 8); // fall through
- case 1: data |= d[0]; // fall through
- case 0: break;
- }
- v3 ^= data;
- for (j=0; j < GS_SIPHASH_C_ROUNDS; ++j)
- gs_sipround();
- v0 ^= data;
- v2 ^= 0xff;
- for (j=0; j < GS_SIPHASH_D_ROUNDS; ++j)
- gs_sipround();
- #if 0
- return v0^v1^v2^v3;
- #else
- return v1^v2^v3; // slightly stronger since v0^v3 in above cancels out final round operation? I tweeted at the authors of SipHash about this but they didn't reply
- #endif
- }
- gs_force_inline
- size_t gs_hash_murmur3(void *p, size_t len, size_t seed)
- {
- const uint8_t* data = (const uint8_t*)p;
- size_t h = seed ^ len;
- for (uint32_t i = 0; i < len / 4; ++i) {
- uint32_t k = *(uint32_t*)(data + i * 4);
- k *= 0xcc9e2d51;
- k = (k << 15) | (k >> (32 - 15));
- k *= 0x1b873593;
- h ^= k;
- h = (h << 13) | (h >> (32 - 13));
- h = h * 5 + 0xe6546b64;
- }
- // Handle remaining bytes
- const uint8_t* tail = data + (len & ~3);
- uint32_t k1 = 0;
- switch (len & 3) {
- case 3: k1 ^= tail[2] << 16;
- case 2: k1 ^= tail[1] << 8;
- case 1: k1 ^= tail[0];
- k1 *= 0xcc9e2d51;
- k1 = (k1 << 15) | (k1 >> (32 - 15));
- k1 *= 0x1b873593;
- h ^= k1;
- }
-
- h ^= h >> 16;
- h *= 0x85ebca6b;
- h ^= h >> 13;
- h *= 0xc2b2ae35;
- h ^= h >> 16;
- return h;
- }
- gs_force_inline
- size_t gs_hash_bytes(void *p, size_t len, size_t seed)
- {
- #if 1
- return gs_hash_siphash_bytes(p, len, seed);
- #else
- return gs_hash_murmur3(p, len, seed);
- #endif
- }
- #ifdef _MSC_VER
- #pragma warning(pop)
- #endif
- /* Resource Loading Util */
- GS_API_DECL bool32_t gs_util_load_texture_data_from_file(const char* file_path, int32_t* width, int32_t* height, uint32_t* num_comps, void** data, bool32_t flip_vertically_on_load);
- GS_API_DECL bool32_t gs_util_load_texture_data_from_memory(const void* memory, size_t sz, int32_t* width, int32_t* height, uint32_t* num_comps, void** data, bool32_t flip_vertically_on_load);
- /** @} */ // end of gs_util
- /*========================
- // GS_CONTAINERS
- ========================*/
- /** @defgroup gs_containers Containers
- * Gunslinger Containers
- * @{
- */
- /*========================
- // Byte Buffer
- ========================*/
- /** @defgroup gs_byte_buffer Byte Buffer
- * @ingroup gs_containers
- * Byte Buffer
- */
- #define GS_BYTE_BUFFER_DEFAULT_CAPCITY 1024
- /** @addtogroup gs_byte_buffer
- */
- typedef struct gs_byte_buffer_t
- {
- uint8_t* data; // Buffer that actually holds all relevant byte data
- uint32_t size; // Current size of the stored buffer data
- uint32_t position; // Current read/write position in the buffer
- uint32_t capacity; // Current max capacity for the buffer
- } gs_byte_buffer_t;
- // Generic "write" function for a byte buffer
- #define gs_byte_buffer_write(__BB, __T, __VAL)\
- do {\
- gs_byte_buffer_t* __BUFFER = __BB;\
- if (!__BUFFER || !__BUFFER->data) break;\
- usize __SZ = sizeof(__T);\
- usize __TWS = __BUFFER->position + __SZ;\
- if (__TWS >= (usize)__BUFFER->capacity)\
- {\
- usize __CAP = __BUFFER->capacity * 2;\
- while(__CAP < __TWS)\
- {\
- __CAP *= 2;\
- }\
- uint8_t* __OLD_DATA = __BUFFER->data;\
- uint32_t __OLD_POS = __BUFFER->position;\
- uint32_t __OLD_SIZE = __BUFFER->size;\
- gs_byte_buffer_resize(__BUFFER, __CAP);\
- if (__BUFFER->data == NULL) {\
- __BUFFER->data = __OLD_DATA;\
- __BUFFER->position = __OLD_POS;\
- __BUFFER->size = __OLD_SIZE;\
- break;\
- }\
- }\
- if (!__BUFFER || !__BUFFER->data || __BUFFER->position + sizeof(__T) > __BUFFER->capacity) break;\
- *(__T*)(__BUFFER->data + __BUFFER->position) = __VAL;\
- __BUFFER->position += (uint32_t)__SZ;\
- __BUFFER->size += (uint32_t)__SZ;\
- } while (0)
- // Generic "read" function
- #define gs_byte_buffer_read(__BUFFER, __T, __VAL_P)\
- do {\
- __T* __V = (__T*)(__VAL_P);\
- gs_byte_buffer_t* __BB = (__BUFFER);\
- *(__V) = *(__T*)(__BB->data + __BB->position);\
- __BB->position += sizeof(__T);\
- } while (0)
- // Defines variable and sets value from buffer in place
- // Use to construct a new variable
- #define gs_byte_buffer_readc(__BUFFER, __T, __NAME)\
- __T __NAME = gs_default_val();\
- gs_byte_buffer_read((__BUFFER), __T, &__NAME);
- #define gs_byte_buffer_read_bulkc(__BUFFER, __T, __NAME, __SZ)\
- __T __NAME = gs_default_val();\
- __T* gs_macro_cat(__NAME, __LINE__) = &(__NAME);\
- gs_byte_buffer_read_bulk(__BUFFER, (void**)&gs_macro_cat(__NAME, __LINE__), __SZ);
- GS_API_DECL void gs_byte_buffer_init(gs_byte_buffer_t* buffer);
- GS_API_DECL gs_byte_buffer_t gs_byte_buffer_new();
- GS_API_DECL void gs_byte_buffer_free(gs_byte_buffer_t* buffer);
- GS_API_DECL void gs_byte_buffer_clear(gs_byte_buffer_t* buffer);
- GS_API_DECL bool gs_byte_buffer_empty(gs_byte_buffer_t* buffer);
- GS_API_DECL size_t gs_byte_buffer_size(gs_byte_buffer_t* buffer);
- GS_API_DECL void gs_byte_buffer_resize(gs_byte_buffer_t* buffer, size_t sz);
- GS_API_DECL void gs_byte_buffer_seek_to_beg(gs_byte_buffer_t* buffer);
- GS_API_DECL void gs_byte_buffer_seek_to_end(gs_byte_buffer_t* buffer);
- GS_API_DECL void gs_byte_buffer_advance_position(gs_byte_buffer_t* buffer, size_t sz);
- GS_API_DECL void gs_byte_buffer_write_str(gs_byte_buffer_t* buffer, const char* str); // Expects a null terminated string
- GS_API_DECL void gs_byte_buffer_read_str(gs_byte_buffer_t* buffer, char* str); // Expects an allocated string
- GS_API_DECL void gs_byte_buffer_write_bulk(gs_byte_buffer_t* buffer, void* src, size_t sz);
- GS_API_DECL void gs_byte_buffer_read_bulk(gs_byte_buffer_t* buffer, void** dst, size_t sz);
- GS_API_DECL gs_result gs_byte_buffer_write_to_file(gs_byte_buffer_t* buffer, const char* output_path); // Assumes that the output directory exists
- GS_API_DECL gs_result gs_byte_buffer_read_from_file(gs_byte_buffer_t* buffer, const char* file_path); // Assumes an allocated byte buffer
- GS_API_DECL void gs_byte_buffer_memset(gs_byte_buffer_t* buffer, uint8_t val);
- /*====================//
- //=== Static Array ===//
- ======================*/
- #define gs_array(__T, __N)\
- struct {\
- __T data[__N];\
- size_t size;\
- }
- #define gs_array_capacity(__Q) (sizeof((__Q).data) / sizeof((__Q).data[0]))
- #define gs_array_push(__Q, __V)\
- do {\
- const size_t cap = gs_array_capacity((__Q));\
- if ((__Q).size < cap) {\
- (__Q).data[(__Q).size++] = (__V);\
- }\
- } while (0)
- #define gs_array_pop(__Q)\
- do {\
- if ((__Q).size) {\
- const size_t cap = gs_array_capacity((__Q));\
- (__Q).size--;\
- }\
- } while (0)
- #define gs_array_empty(__Q) (__Q).size ? false : true
- #define gs_array_clear(__Q) do {(__Q).size = 0;} while (0)
- #define gs_array_back(__Q)\
- !gs_array_empty(__Q) ? &__Q.data[__Q.size - 1] : NULL
- /*=============================//
- //=== Static Circular Queue ===//
- ===============================*/
- #define gs_cqueue(__T, __N)\
- struct {\
- __T data[__N];\
- size_t size;\
- size_t head;\
- }
- #define gs_cqueue_size(__Q) ((__Q).size)
- #define gs_cqueue_capacity(__Q) (sizeof((__Q).data) / sizeof((__Q).data[0]))
- #define gs_cqueue_push(__Q, __V)\
- do {\
- const size_t cap = gs_cqueue_capacity((__Q));\
- if ((__Q).size < cap) {\
- (__Q).data[((__Q).head + (__Q).size++) % cap] = (__V);\
- }\
- } while (0)
- #define gs_cqueue_pop(__Q)\
- do {\
- if ((__Q).size) {\
- const size_t cap = gs_cqueue_capacity((__Q));\
- (__Q).size--;\
- (__Q).head = ((__Q).head + 1) % cap;\
- }\
- else {\
- (__Q).head = 0;\
- }\
- } while (0)
- #define gs_cqueue_peek(__Q) (__Q).size ? &(__Q).data[(__Q).head] : NULL
- #define gs_cqueue_empty(__Q) (__Q).size ? false : true
- #define gs_cqueue_clear(__Q)\
- do {\
- (__Q).size = 0;\
- (__Q).head = 0;\
- } while (0)
- /*===================================
- // Dynamic Array
- ===================================*/
- /** @defgroup gs_dyn_array Dynamic Array
- * @ingroup gs_containers
- * Dynamic Array
- */
- /** @addtogroup gs_dyn_array
- */
- typedef struct gs_dyn_array
- {
- int32_t size;
- int32_t capacity;
- } gs_dyn_array;
- #define gs_dyn_array_head(__ARR)\
- ((gs_dyn_array*)((uint8_t*)(__ARR) - sizeof(gs_dyn_array)))
- #define gs_dyn_array_size(__ARR)\
- (__ARR == NULL ? 0 : gs_dyn_array_head((__ARR))->size)
- #define gs_dyn_array_capacity(__ARR)\
- (__ARR == NULL ? 0 : gs_dyn_array_head((__ARR))->capacity)
- #define gs_dyn_array_full(__ARR)\
- ((gs_dyn_array_size((__ARR)) == gs_dyn_array_capacity((__ARR))))
- #define gs_dyn_array_byte_size(__ARR)\
- (gs_dyn_array_size((__ARR)) * sizeof(*__ARR))
- GS_API_DECL void*
- gs_dyn_array_resize_impl(void* arr, size_t sz, size_t amount);
- #define gs_dyn_array_need_grow(__ARR, __N)\
- ((__ARR) == 0 || gs_dyn_array_size(__ARR) + (__N) >= gs_dyn_array_capacity(__ARR))
- #define gs_dyn_array_grow(__ARR)\
- gs_dyn_array_resize_impl((__ARR), sizeof(*(__ARR)), gs_dyn_array_capacity(__ARR) ? gs_dyn_array_capacity(__ARR) * 2 : 1)
- #define gs_dyn_array_grow_size(__ARR, __SZ )\
- gs_dyn_array_resize_impl((__ARR), (__SZ ), gs_dyn_array_capacity(__ARR) ? gs_dyn_array_capacity(__ARR) * 2 : 1)
- GS_API_DECL void**
- gs_dyn_array_init(void** arr, size_t val_len);
- GS_API_DECL void
- gs_dyn_array_push_data(void** arr, void* val, size_t val_len);
- gs_force_inline
- void gs_dyn_array_set_data_i(void** arr, void* val, size_t val_len, uint32_t offset)
- {
- memcpy(((char*)(*arr)) + offset * val_len, val, val_len);
- }
- #define gs_dyn_array_push(__ARR, __ARRVAL)\
- do {\
- gs_dyn_array_init((void**)&(__ARR), sizeof(*(__ARR)));\
- if (!(__ARR) || ((__ARR) && gs_dyn_array_need_grow(__ARR, 1))) {\
- *((void **)&(__ARR)) = gs_dyn_array_grow(__ARR); \
- }\
- (__ARR)[gs_dyn_array_size(__ARR)] = (__ARRVAL);\
- gs_dyn_array_head(__ARR)->size++;\
- } while(0)
- #define gs_dyn_array_reserve(__ARR, __AMOUNT)\
- do {\
- if ((!__ARR)) gs_dyn_array_init((void**)&(__ARR), sizeof(*(__ARR)));\
- if ((!__ARR) || (size_t)__AMOUNT > gs_dyn_array_capacity(__ARR)) {\
- *((void **)&(__ARR)) = gs_dyn_array_resize_impl(__ARR, sizeof(*__ARR), __AMOUNT);\
- }\
- } while(0)
- #define gs_dyn_array_empty(__ARR)\
- (gs_dyn_array_init((void**)&(__ARR), sizeof(*(__ARR))), (gs_dyn_array_size(__ARR) == 0))
- #define gs_dyn_array_pop(__ARR)\
- do {\
- if (__ARR && !gs_dyn_array_empty(__ARR)) {\
- gs_dyn_array_head(__ARR)->size -= 1;\
- }\
- } while (0)
- #define gs_dyn_array_back(__ARR)\
- *(__ARR + (gs_dyn_array_size(__ARR) ? gs_dyn_array_size(__ARR) - 1 : 0))
- #define gs_dyn_array_for(__ARR, __T, __IT_NAME)\
- for (__T* __IT_NAME = __ARR; __IT_NAME != gs_dyn_array_back(__ARR); ++__IT_NAME)
- #define gs_dyn_array_new(__T)\
- ((__T*)gs_dyn_array_resize_impl(NULL, sizeof(__T), 0))
- #define gs_dyn_array_clear(__ARR)\
- do {\
- if (__ARR) {\
- gs_dyn_array_head(__ARR)->size = 0;\
- }\
- } while (0)
- #define gs_dyn_array(__T) __T*
- #define gs_dyn_array_free(__ARR)\
- do {\
- if (__ARR) {\
- gs_free(gs_dyn_array_head(__ARR));\
- (__ARR) = NULL;\
- }\
- } while (0)
- /*===================================
- // Static Array
- ===================================*/
- /*===================================
- // Hash Table
- ===================================*/
- /*
- If using struct for keys, requires struct to be word-aligned.
- */
- #define GS_HASH_TABLE_HASH_SEED 0x31415296
- #define GS_HASH_TABLE_INVALID_INDEX UINT32_MAX
- typedef enum gs_hash_table_entry_state {
- GS_HASH_TABLE_ENTRY_INACTIVE = 0x00,
- GS_HASH_TABLE_ENTRY_ACTIVE = 0x01
- } gs_hash_table_entry_state;
- typedef size_t (*gs_hash_func_t)(void*, size_t, size_t);
- #define __gs_hash_table_entry(__HMK, __HMV)\
- struct {\
- __HMK key;\
- __HMV val;\
- size_t hash;\
- gs_hash_table_entry_state state;\
- }
- #define gs_hash_table(__HMK, __HMV)\
- struct {\
- __gs_hash_table_entry(__HMK, __HMV)* data;\
- __HMK tmp_key;\
- __HMV tmp_val;\
- size_t stride;\
- size_t klpvl;\
- size_t tmp_idx;\
- gs_hash_func_t hash_func;\
- }*
- // Need a way to create a temporary key so I can take the address of it
- #define gs_hash_table_new(__K, __V)\
- NULL
- GS_API_DECL void
- __gs_hash_table_init_impl(void** ht, size_t sz);
- #define gs_hash_table_init_ex(__HT, __K, __V, __HFUNC)\
- do {\
- size_t entry_sz = sizeof(*__HT->data);\
- size_t ht_sz = sizeof(*__HT);\
- __gs_hash_table_init_impl((void**)&(__HT), ht_sz);\
- memset((__HT), 0, ht_sz);\
- gs_dyn_array_reserve(__HT->data, 2);\
- __HT->data[0].state = GS_HASH_TABLE_ENTRY_INACTIVE;\
- __HT->data[1].state = GS_HASH_TABLE_ENTRY_INACTIVE;\
- uintptr_t d0 = (uintptr_t)&((__HT)->data[0]);\
- uintptr_t d1 = (uintptr_t)&((__HT)->data[1]);\
- ptrdiff_t diff = (d1 - d0);\
- ptrdiff_t klpvl = (uintptr_t)&(__HT->data[0].state) - (uintptr_t)(&__HT->data[0]);\
- (__HT)->stride = (size_t)(diff);\
- (__HT)->klpvl = (size_t)(klpvl);\
- (__HT)->hash_func = (__HFUNC);\
- } while (0)
- // Internal helper to compute hash with optional custom function
- gs_force_inline
- size_t __gs_hash_table_compute_hash(gs_hash_func_t hash_func, void* key, size_t key_len, size_t seed)
- {
- if (hash_func) {
- return hash_func(key, key_len, seed);
- }
- return gs_hash_bytes(key, key_len, seed);
- }
- #define gs_hash_table_init(__HT, __K, __V)\
- gs_hash_table_init_ex(__HT, __K, __V, gs_hash_bytes)
- #define gs_hash_table_reserve(_HT, _KT, _VT, _CT)\
- do {\
- if ((_HT) == NULL) {\
- gs_hash_table_init((_HT), _KT, _VT);\
- }\
- gs_dyn_array_reserve((_HT)->data, _CT);\
- } while (0)
- #define gs_hash_table_size(__HT)\
- ((__HT) != NULL ? gs_dyn_array_size((__HT)->data) : 0)
- #define gs_hash_table_capacity(__HT)\
- ((__HT) != NULL ? gs_dyn_array_capacity((__HT)->data) : 0)
- #define gs_hash_table_load_factor(__HT)\
- (gs_hash_table_capacity(__HT) ? (float)(gs_hash_table_size(__HT)) / (float)(gs_hash_table_capacity(__HT)) : 0.f)
- #define gs_hash_table_grow(__HT, __C)\
- ((__HT)->data = gs_dyn_array_resize_impl((__HT)->data, sizeof(*((__HT)->data)), (__C)))
- #define gs_hash_table_empty(__HT)\
- ((__HT) != NULL ? gs_dyn_array_size((__HT)->data) == 0 : true)
- #define gs_hash_table_clear(__HT)\
- do {\
- if ((__HT) != NULL) {\
- uint32_t capacity = gs_dyn_array_capacity((__HT)->data);\
- for (uint32_t i = 0; i < capacity; ++i) {\
- (__HT)->data[i].state = GS_HASH_TABLE_ENTRY_INACTIVE;\
- }\
- /*memset((__HT)->data, 0, gs_dyn_array_capacity((__HT)->data) * );*/\
- gs_dyn_array_clear((__HT)->data);\
- }\
- } while (0)
- #define gs_hash_table_free(__HT)\
- do {\
- if ((__HT) != NULL) {\
- gs_dyn_array_free((__HT)->data);\
- (__HT)->data = NULL;\
- gs_free(__HT);\
- (__HT) = NULL;\
- }\
- } while (0)
- // Find available slot to insert k/v pair into
- #define gs_hash_table_insert(__HT, __HMK, __HMV)\
- do {\
- /* Check for null hash table, init if necessary */\
- if ((__HT) == NULL) {\
- gs_hash_table_init((__HT), (__HMK), (__HMV));\
- }\
- \
- /* Grow table if necessary */\
- uint32_t __CAP = gs_hash_table_capacity(__HT);\
- float __LF = gs_hash_table_load_factor(__HT);\
- if (__LF >= 0.5f || !__CAP)\
- {\
- uint32_t NEW_CAP = __CAP ? __CAP * 2 : 2;\
- size_t ENTRY_SZ = sizeof((__HT)->tmp_key) + sizeof((__HT)->tmp_val) + sizeof(size_t) + sizeof(gs_hash_table_entry_state);\
- gs_dyn_array_reserve((__HT)->data, NEW_CAP);\
- /**((void **)&(__HT->data)) = gs_dyn_array_resize_impl(__HT->data, ENTRY_SZ, NEW_CAP);*/\
- /* Iterate through data and set state to null, from __CAP -> __CAP * 2 */\
- /* Memset here instead */\
- for (uint32_t __I = __CAP; __I < NEW_CAP; ++__I) {\
- (__HT)->data[__I].state = GS_HASH_TABLE_ENTRY_INACTIVE;\
- }\
- __CAP = gs_hash_table_capacity(__HT);\
- }\
- \
- /* Get hash of key */\
- (__HT)->tmp_key = (__HMK);\
- size_t __HSH = __gs_hash_table_compute_hash((__HT)->hash_func, (void*)&((__HT)->tmp_key), sizeof((__HT)->tmp_key), GS_HASH_TABLE_HASH_SEED);\
- size_t __HSH_IDX = __HSH % __CAP;\
- (__HT)->tmp_key = (__HT)->data[__HSH_IDX].key;\
- uint32_t c = 0;\
- \
- /* Find valid idx and place data */\
- while (\
- c < __CAP\
- && __HSH != __gs_hash_table_compute_hash((__HT)->hash_func, (void*)&(__HT)->tmp_key, sizeof((__HT)->tmp_key), GS_HASH_TABLE_HASH_SEED)\
- && (__HT)->data[__HSH_IDX].state == GS_HASH_TABLE_ENTRY_ACTIVE)\
- {\
- __HSH_IDX = ((__HSH_IDX + 1) % __CAP);\
- (__HT)->tmp_key = (__HT)->data[__HSH_IDX].key;\
- ++c;\
- }\
- (__HT)->data[__HSH_IDX].key = (__HMK);\
- (__HT)->data[__HSH_IDX].val = (__HMV);\
- (__HT)->data[__HSH_IDX].hash = __HSH;\
- (__HT)->data[__HSH_IDX].state = GS_HASH_TABLE_ENTRY_ACTIVE;\
- (__HT)->tmp_idx = __HSH_IDX;\
- gs_dyn_array_head((__HT)->data)->size++;\
- } while (0)
- // Need size difference between two entries
- // Need size of key + val
- gs_force_inline
- uint32_t gs_hash_table_get_key_index_func(void** data, void* key, size_t key_len,
- size_t val_len, size_t stride, size_t klpvl, gs_hash_func_t hash_func)
- {
- if (!data || !key) return GS_HASH_TABLE_INVALID_INDEX;
- // Need a better way to handle this. Can't do it like this anymore.
- // Need to fix this. Seriously messing me up.
- uint32_t capacity = gs_dyn_array_capacity(*data);
- uint32_t size = gs_dyn_array_size(*data);
- if (!capacity || !size) return (size_t)GS_HASH_TABLE_INVALID_INDEX;
- size_t idx = (size_t)GS_HASH_TABLE_INVALID_INDEX;
- // size_t hash = (size_t)gs_hash_bytes(key, key_len, GS_HASH_TABLE_HASH_SEED);
- size_t hash = (size_t)hash_func(key, key_len, GS_HASH_TABLE_HASH_SEED);
- size_t hash_idx = (hash % capacity);
- // Iterate through data
- for (size_t i = hash_idx, c = 0; c < capacity; ++c, i = ((i + 1) % capacity)) {
- size_t offset = (i * stride);
- gs_hash_table_entry_state state = *(gs_hash_table_entry_state*)((char*)(*data) + offset + (klpvl));
- // Early out inactive slots immediately
- if (state != GS_HASH_TABLE_ENTRY_ACTIVE) continue;
- size_t stored_hash = *(size_t*)((char*)(*data) + offset + (klpvl) - sizeof(size_t));
- // Quick hash comparison first
- if (hash != stored_hash) continue;
- // Byte comparison
- void* k = ((char*)(*data) + (offset));
- if (gs_compare_bytes(k, key, key_len)) {
- idx = i;
- break;
- }
- }
- return (uint32_t)idx;
- }
- // Get key at index
- #define gs_hash_table_getk(__HT, __I)\
- (((__HT))->data[(__I)].key)
- // Get val at index
- #define gs_hash_table_geti(__HT, __I)\
- ((__HT)->data[(__I)].val)
- // Could search for the index in the macro instead now. Does this help me?
- #define gs_hash_table_get(__HT, __HTK)\
- ((__HT)->tmp_key = (__HTK),\
- (gs_hash_table_geti((__HT),\
- gs_hash_table_get_key_index_func((void**)&(__HT)->data, (void*)&((__HT)->tmp_key),\
- sizeof((__HT)->tmp_key), sizeof((__HT)->tmp_val), (__HT)->stride, (__HT)->klpvl, (__HT)->hash_func))))
- #define gs_hash_table_getp(__HT, __HTK)\
- (\
- (__HT)->tmp_key = (__HTK),\
- ((__HT)->tmp_idx = (uint32_t)gs_hash_table_get_key_index_func((void**)&(__HT->data), (void*)&(__HT->tmp_key), sizeof(__HT->tmp_key),\
- sizeof(__HT->tmp_val), __HT->stride, __HT->klpvl, __HT->hash_func)),\
- ((__HT)->tmp_idx != GS_HASH_TABLE_INVALID_INDEX ? &gs_hash_table_geti((__HT), (__HT)->tmp_idx) : NULL)\
- )
- #define _gs_hash_table_key_exists_internal(__HT, __HTK)\
- ((__HT)->tmp_key = (__HTK),\
- (__HT)->tmp_idx = gs_hash_table_get_key_index_func((void**)&(__HT->data), (void*)&(__HT->tmp_key), sizeof(__HT->tmp_key),\
- sizeof(__HT->tmp_val), __HT->stride, __HT->klpvl, __HT->hash_func), ((__HT->tmp_idx) != GS_HASH_TABLE_INVALID_INDEX))
- // uint32_t gs_hash_table_get_key_index_func(void** data, void* key, size_t key_len, size_t val_len, size_t stride, size_t klpvl)
- #define gs_hash_table_exists(__HT, __HTK)\
- (__HT && _gs_hash_table_key_exists_internal((__HT), (__HTK)))
- #define gs_hash_table_key_exists(__HT, __HTK)\
- (gs_hash_table_exists((__HT), (__HTK)))
- #define gs_hash_table_erase(__HT, __HTK)\
- do {\
- if ((__HT))\
- {\
- /* Get idx for key */\
- (__HT)->tmp_key = (__HTK);\
- uint32_t __IDX = gs_hash_table_get_key_index_func((void**)&(__HT)->data, (void*)&((__HT)->tmp_key), sizeof((__HT)->tmp_key), sizeof((__HT)->tmp_val), (__HT)->stride, (__HT)->klpvl, (__HT)->hash_func);\
- if (__IDX != GS_HASH_TABLE_INVALID_INDEX) {\
- (__HT)->data[__IDX].state = GS_HASH_TABLE_ENTRY_INACTIVE;\
- if (gs_dyn_array_head((__HT)->data)->size) gs_dyn_array_head((__HT)->data)->size--;\
- }\
- }\
- } while (0)
- /*===== Hash Table Iterator ====*/
- typedef uint32_t gs_hash_table_iter;
- typedef gs_hash_table_iter gs_hash_table_iter_t;
- gs_force_inline
- uint32_t __gs_find_first_valid_iterator(void* data, size_t key_len, size_t val_len, uint32_t idx, size_t stride, size_t klpvl)
- {
- uint32_t it = (uint32_t)idx;
- for (; it < (uint32_t)gs_dyn_array_capacity(data); ++it)
- {
- size_t offset = (it * stride);
- gs_hash_table_entry_state state = *(gs_hash_table_entry_state*)((uint8_t*)data + offset + (klpvl));
- if (state == GS_HASH_TABLE_ENTRY_ACTIVE)
- {
- break;
- }
- }
- return it;
- }
- /* Find first valid iterator idx */
- #define gs_hash_table_iter_new(__HT)\
- (__HT ? __gs_find_first_valid_iterator((__HT)->data, sizeof((__HT)->tmp_key), sizeof((__HT)->tmp_val), 0, (__HT)->stride, (__HT)->klpvl) : 0)
- #define gs_hash_table_iter_valid(__HT, __IT)\
- ((__IT) < gs_hash_table_capacity((__HT)))
- // Have to be able to do this for hash table...
- gs_force_inline
- void __gs_hash_table_iter_advance_func(void** data, size_t key_len, size_t val_len, uint32_t* it, size_t stride, size_t klpvl)
- {
- (*it)++;
- for (; *it < (uint32_t)gs_dyn_array_capacity(*data); ++*it)
- {
- size_t offset = (size_t)(*it * stride);
- gs_hash_table_entry_state state = *(gs_hash_table_entry_state*)((uint8_t*)*data + offset + (klpvl));
- if (state == GS_HASH_TABLE_ENTRY_ACTIVE)
- {
- break;
- }
- }
- }
- #define gs_hash_table_find_valid_iter(__HT, __IT)\
- ((__IT) = __gs_find_first_valid_iterator((void**)&(__HT)->data, sizeof((__HT)->tmp_key), sizeof((__HT)->tmp_val), (__IT), (__HT)->stride, (__HT)->klpvl))
- #define gs_hash_table_iter_advance(__HT, __IT)\
- (__gs_hash_table_iter_advance_func((void**)&(__HT)->data, sizeof((__HT)->tmp_key), sizeof((__HT)->tmp_val), &(__IT), (__HT)->stride, (__HT)->klpvl))
- #define gs_hash_table_iter_get(__HT, __IT)\
- gs_hash_table_geti(__HT, __IT)
- #define gs_hash_table_iter_getp(__HT, __IT)\
- (&(gs_hash_table_geti(__HT, __IT)))
- #define gs_hash_table_iter_getk(__HT, __IT)\
- (gs_hash_table_getk(__HT, __IT))
- #define gs_hash_table_iter_getkp(__HT, __IT)\
- (&(gs_hash_table_getk(__HT, __IT)))
- /*==================
- //=== Hash Set ===//
- ==================*/
- #define GS_HASH_SET_HASH_SEED 0x31415296
- #define GS_HASH_SET_INVALID_INDEX UINT32_MAX
- #define GS_HASH_SET_MAX_PROBE 64
- #define GS_HASH_SET_MAX_LOAD_FACTOR 0.75f
- typedef enum gs_hash_set_entry_state
- {
- GS_HASH_SET_ENTRY_INACTIVE = 0x00,
- GS_HASH_SET_ENTRY_ACTIVE = 0x01
- } gs_hash_set_entry_state;
- #define __gs_hash_set_entry(__T)\
- struct\
- {\
- __T val;\
- gs_hash_set_entry_state state;\
- }
- #define gs_hash_set(__T)\
- struct {\
- __gs_hash_set_entry(__T)* data;\
- __T tmp_val;\
- size_t stride;\
- size_t klpvl;\
- size_t tmp_idx;\
- gs_hash_func_t hash_func;\
- }*
- #define gs_hash_set_new(T)\
- NULL
- GS_API_DECL void
- __gs_hash_set_init_impl( void** ht, size_t sz );
- #define gs_hash_set_init_ex(__S, __T, __HFUNC)\
- do {\
- size_t entry_sz = sizeof(*__S->data);\
- size_t ht_sz = sizeof(*__S);\
- __gs_hash_set_init_impl((void**)&(__S), ht_sz);\
- memset((__S), 0, ht_sz);\
- gs_dyn_array_reserve(__S->data, 2);\
- __S->data[0].state = GS_HASH_SET_ENTRY_INACTIVE;\
- __S->data[1].state = GS_HASH_SET_ENTRY_INACTIVE;\
- uintptr_t d0 = (uintptr_t)&((__S)->data[0]);\
- uintptr_t d1 = (uintptr_t)&((__S)->data[1]);\
- ptrdiff_t diff = (d1 - d0);\
- ptrdiff_t klpvl = (uintptr_t)&(__S->data[0].state) - (uintptr_t)(&__S->data[0]);\
- (__S)->hash_func = __HFUNC;\
- (__S)->stride = (size_t)(diff);\
- (__S)->klpvl = (size_t)(klpvl);\
- } while (0)
- #define gs_hash_set_init(__S, __T)\
- gs_hash_set_init_ex(__S, __T, gs_hash_bytes)
- #define gs_hash_set_reserve(__S, __T, __CT)\
- do {\
- if ((__S) == NULL) {\
- gs_hash_set_init((__S), __T);\
- }\
- gs_dyn_array_reserve((__S)->data, __CT);\
- } while (0)
- #define gs_hash_set_size(__S)\
- ((__S) != NULL ? gs_dyn_array_size((__S)->data) : 0)
- #define gs_hash_set_capacity(__S)\
- ((__S) != NULL ? gs_dyn_array_capacity((__S)->data) : 0)
- #define gs_hash_set_load_factor(__S)\
- (gs_hash_set_capacity(__S) ? (float)(gs_hash_set_size(__S)) / (float)(gs_hash_set_capacity(__S)) : 0.f)
- #define gs_hash_set_grow(__S, __C)\
- ((__S)->data = gs_dyn_array_resize_impl((__S)->data, sizeof(*((__S)->data)), (__C)))
- #define gs_hash_set_empty(__S)\
- ((__S) != NULL ? gs_dyn_array_size((__S)->data) == 0 : true)
- #define gs_hash_set_clear(__S)\
- do {\
- if ((__S) != NULL) {\
- uint32_t capacity = gs_dyn_array_capacity((__S)->data);\
- memset((__S)->data, 0, gs_dyn_array_capacity((__S)->data) * sizeof(*(__S)->data));\
- gs_dyn_array_clear((__S)->data);\
- }\
- } while (0)
- #define gs_hash_set_free(__S)\
- do {\
- if ((__S) != NULL) {\
- gs_dyn_array_free((__S)->data);\
- (__S)->data = NULL;\
- gs_free(__S);\
- (__S) = NULL;\
- }\
- } while (0)
- #define gs_hash_set_hash_idx(_I, _C, _CAP)\
- ((_I + _C) % _CAP)
- gs_force_inline
- uint32_t gs_hash_set_get_key_index_func(void** data, void* key, size_t key_len, size_t stride, size_t klpvl, gs_hash_func_t hfunc)
- {
- if (!data || !key) return GS_HASH_SET_INVALID_INDEX;
- uint32_t capacity = gs_dyn_array_capacity(*data);
- uint32_t size = gs_dyn_array_size(*data);
- if (!capacity || !size) return (size_t)GS_HASH_SET_INVALID_INDEX;
- size_t idx = (size_t)GS_HASH_SET_INVALID_INDEX;
- size_t hash = (size_t)hfunc(key, key_len, GS_HASH_SET_HASH_SEED);
- size_t hash_idx = (hash % capacity);
- size_t c = 0;
- size_t max_probe = GS_HASH_SET_MAX_PROBE;
- // Iterate through data
- for (size_t i = hash_idx; c < max_probe; ++c, i = ((i + c) % capacity)) {
- size_t offset = (i * stride);
- void* k = ((char*)(*data) + (offset));
- size_t kh = hfunc(k, key_len, GS_HASH_SET_HASH_SEED);
- bool comp = gs_compare_bytes(k, key, key_len);
- gs_hash_set_entry_state state = *(gs_hash_set_entry_state*)((char*)(*data) + offset + (klpvl));
- if (comp && hash == kh && state == GS_HASH_SET_ENTRY_ACTIVE) {
- idx = i;
- break;
- }
- }
- return (uint32_t)idx;
- }
- gs_force_inline
- void gs_hash_set_rehash(void** data, void** new_data, size_t new_cap, size_t key_len, size_t stride, size_t klpvl, gs_hash_func_t hfunc)
- {
- if (!data | !new_data) return;
- uint32_t capacity = gs_dyn_array_capacity(*data);
- if (new_cap <= capacity) return;
- for (uint32_t i = 0; i < capacity; ++i) {
- // Get original data
- size_t offset = (i * stride);
- // If this entry is inactive, then continue
- if (*((gs_hash_set_entry_state*)((char*)(*data) + offset + (klpvl))) == GS_HASH_SET_ENTRY_INACTIVE) {
- continue;
- }
- void* k = ((char*)(*data) + offset);
- size_t kh = hfunc(k, key_len, GS_HASH_SET_HASH_SEED);
- // Hash idx into new data with new capacity
- uint32_t c = 0;
- size_t hash_idx = (kh % new_cap);
- /* Find valid idx and place data */
- while (
- c < new_cap
- && *((gs_hash_set_entry_state*)((char*)(*new_data) + (hash_idx * stride) + (klpvl))) == GS_HASH_SET_ENTRY_ACTIVE
- ) {
- ++c;
- hash_idx = ((hash_idx + c)) % new_cap;
- }
- // Set new data in new array
- size_t noff = hash_idx * stride;
- uint32_t tmp = 20;
- memcpy((void*)(((uint8_t*)(*new_data)) + noff), k, key_len);
- *((gs_hash_set_entry_state*)((char*)(*new_data) + (hash_idx * stride) + klpvl)) = GS_HASH_SET_ENTRY_ACTIVE;
- }
- }
- // Find available slot to insert k/v pair into
- #define gs_hash_set_insert(__S, __T)\
- do {\
- /* Check for null hash table, init if necessary */\
- if ((__S) == NULL) {\
- gs_hash_set_init((__S), (__T));\
- }\
- \
- /* Grow table if necessary */\
- uint32_t __CAP = gs_hash_set_capacity(__S);\
- float __LF = gs_hash_set_load_factor(__S);\
- if (__LF >= GS_HASH_SET_MAX_LOAD_FACTOR || !__CAP)\
- {\
- uint32_t NEW_CAP = __CAP ? __CAP * 2 : 2;\
- size_t ENTRY_SZ = sizeof((__S)->tmp_val) + sizeof(gs_hash_set_entry_state);\
- void* new_data = gs_calloc(NEW_CAP * 2, ENTRY_SZ);\
- /*Rehash data, reserve, copy, free*/\
- gs_hash_set_rehash((void**)&(__S)->data, (void**)&new_data, NEW_CAP, sizeof((__S)->tmp_val), (__S)->stride, (__S)->klpvl, (__S)->hash_func);\
- gs_dyn_array_reserve((__S)->data, NEW_CAP);\
- memcpy((__S)->data, new_data, NEW_CAP * ENTRY_SZ);\
- __CAP = gs_hash_set_capacity(__S);\
- gs_free(new_data);\
- }\
- \
- /* Get hash of key */\
- (__S)->tmp_val = (__T);\
- size_t __HSH = (__S)->hash_func((void*)&((__S)->tmp_val), sizeof((__S)->tmp_val), GS_HASH_SET_HASH_SEED);\
- size_t __HSH_IDX = __HSH % __CAP;\
- uint32_t c = 0;\
- bool exists = false;\
- \
- /* Find valid idx and place data */\
- while (c < __CAP) {\
- /*If active entry*/\
- if (__S->data[__HSH_IDX].state == GS_HASH_SET_ENTRY_ACTIVE) {\
- if (gs_compare_bytes((void*)&(__S->tmp_val), (void*)&((__S)->data[__HSH_IDX].val), sizeof((__S)->tmp_val))) {\
- exists = true;\
- break;\
- }\
- ++c;\
- __HSH_IDX = ((__HSH_IDX + c) % __CAP);\
- }\
- /*Inactive entry, so break*/\
- else {\
- break;\
- }\
- }\
- if (!exists) {\
- (__S)->data[__HSH_IDX].val = (__T);\
- (__S)->data[__HSH_IDX].state = GS_HASH_SET_ENTRY_ACTIVE;\
- gs_dyn_array_head((__S)->data)->size++;\
- }\
- } while (0)
- // Get val at index
- #define gs_hash_set_geti(__S, __I)\
- ((__S)->data[(__I)].val)
- // Could search for the index in the macro instead now. Does this help me?
- #define gs_hash_set_get(__S, __SK)\
- ((__S)->tmp_val = (__SK),\
- (gs_hash_set_geti((__S),\
- gs_hash_set_get_key_index_func((void**)&(__S)->data, (void*)&((__S)->tmp_val),\
- sizeof((__S)->tmp_val), (__S)->stride, (__S)->klpvl, (__S)->hash_func))))
- #define gs_hash_set_getp(__S, __SK)\
- (\
- (__S)->tmp_val = (__SK),\
- ((__S)->tmp_idx = (uint32_t)gs_hash_set_get_key_index_func((void**)&(__S->data), (void*)&(__S->tmp_val), sizeof(__S->tmp_val),\
- __S->stride, __S->klpvl, __S->hash_func)),\
- ((__S)->tmp_idx != GS_HASH_SET_INVALID_INDEX ? &gs_hash_set_geti((__S), (__S)->tmp_idx) : NULL)\
- )
- #define _gs_hash_set_key_exists_internal(__S, __SK)\
- ((__S)->tmp_val = (__SK),\
- (gs_hash_set_get_key_index_func((void**)&(__S->data), (void*)&(__S->tmp_val), sizeof(__S->tmp_val),\
- __S->stride, __S->klpvl, __S->hash_func) != GS_HASH_SET_INVALID_INDEX))
- #define gs_hash_set_exists(__S, __SK)\
- (__S && _gs_hash_set_key_exists_internal((__S), (__SK)))
- #define gs_hash_set_key_exists(__S, __SK)\
- (gs_hash_set_exists((__S), (__SK)))
- #define gs_hash_set_erase(__S, __SK)\
- do {\
- if ((__S))\
- {\
- /* Get idx for key */\
- (__S)->tmp_val = (__SK);\
- uint32_t __IDX = gs_hash_set_get_key_index_func((void**)&(__S)->data, (void*)&((__S)->tmp_val), sizeof((__S)->tmp_val), (__S)->stride, (__S)->klpvl, (__S)->hash_func);\
- if (__IDX != GS_HASH_SET_INVALID_INDEX) {\
- (__S)->data[__IDX].state = GS_HASH_SET_ENTRY_INACTIVE;\
- if (gs_dyn_array_head((__S)->data)->size) gs_dyn_array_head((__S)->data)->size--;\
- }\
- }\
- } while (0)
- gs_force_inline
- bool _gs_hash_set_is_subset_of_internal(void** s0, void** s1, size_t key_len, size_t stride, size_t klpvl, gs_hash_func_t hfunc)
- {
- // If sz0 > sz1, then cannot be subset
- uint32_t sz0 = gs_dyn_array_size(*s0);
- uint32_t sz1 = gs_dyn_array_size(*s1);
- if (sz0 > sz1) return false;
- // If there exists an element in s0 not in s1, then not a subset
- uint32_t c0 = gs_dyn_array_capacity(*s0);
- uint32_t c1 = gs_dyn_array_capacity(*s1);
- for (uint32_t i = 0; i < c0; ++i) {
- // Continue past invalid entry
- size_t offset = (i * stride);
- gs_hash_set_entry_state state = *(gs_hash_set_entry_state*)((char*)(*s0) + offset + (klpvl));
- if (state == GS_HASH_SET_ENTRY_INACTIVE) {
- continue;
- }
- // Valid entry, check against s1
- void* k0 = ((char*)(*s0) + (offset));
- size_t kh = hfunc(k0, key_len, GS_HASH_SET_HASH_SEED);
- uint32_t hidx = (kh % c1); // Hash idx into super set
- uint32_t cc = 0;
- bool found = false;
- while (
- !found &&
- cc < GS_HASH_SET_MAX_PROBE
- ) {
- // Not active entry
- size_t o1 = hidx * stride; // New offset
- gs_hash_set_entry_state es = *((gs_hash_set_entry_state*)((char*)(*s1) + (hidx * stride) + (klpvl)));
- void* k1 = ((char*)(*s1) + (o1));
- // Found
- if (es == GS_HASH_SET_ENTRY_ACTIVE && gs_compare_bytes(k0, k1, key_len)) {
- found = true;
- break;
- }
- // Continue
- ++cc;
- hidx = ((hidx + cc)) % c1;
- }
- if (!found) return false;
- }
- return true;
- }
- #define gs_hash_set_is_subset_of(__S0, __S1)\
- (__S0 && __S1 &&\
- sizeof((__S0)->tmp_val) == sizeof((__S1)->tmp_val) &&\
- (__S0)->stride == (__S1)->stride &&\
- (__S0)->klpvl == (__S1)->klpvl &&\
- _gs_hash_set_is_subset_of_internal((void**)&(__S0)->data, (void**)&(__S1)->data,\
- sizeof((__S0)->tmp_val), (__S0)->stride, (__S0)->klpvl, (__S0)->hfunc))
- /*===== Set Iterator ====*/
- typedef uint32_t gs_hash_set_iter;
- typedef gs_hash_set_iter gs_hash_set_iter_t;
- gs_force_inline
- uint32_t __gs_hash_set_find_first_valid_iterator(void* data, uint32_t idx, size_t stride, size_t klpvl)
- {
- uint32_t it = (uint32_t)idx;
- for (; it < (uint32_t)gs_dyn_array_capacity(data); ++it) {
- size_t offset = (it * stride);
- gs_hash_set_entry_state state = *(gs_hash_set_entry_state*)((uint8_t*)data + offset + (klpvl));
- if (state == GS_HASH_SET_ENTRY_ACTIVE) {
- break;
- }
- }
- return it;
- }
- /* Find first valid iterator idx */
- #define gs_hash_set_iter_new(__S)\
- (__S ? __gs_hash_set_find_first_valid_iterator((__S)->data, 0, (__S)->stride, (__S)->klpvl) : 0)
- #define gs_hash_set_iter_valid(__S, __IT)\
- ((__IT) < gs_hash_set_capacity((__S)))
- gs_force_inline
- void __gs_hash_set_iter_advance_func(void** data, uint32_t* it, size_t stride, size_t klpvl)
- {
- (*it)++;
- for (; *it < (uint32_t)gs_dyn_array_capacity(*data); ++*it) {
- size_t offset = (size_t)(*it * stride);
- gs_hash_set_entry_state state = *(gs_hash_set_entry_state*)((uint8_t*)*data + offset + (klpvl));
- if (state == GS_HASH_SET_ENTRY_ACTIVE) {
- break;
- }
- }
- }
- #define gs_hash_set_find_valid_iter(__S, __IT)\
- ((__IT) = __gs_hash_set_find_first_valid_iterator((void**)&(__S)->data, (__IT), (__S)->stride, (__S)->klpvl))
- #define gs_hash_set_iter_advance(__S, __IT)\
- (__gs_hash_set_iter_advance_func((void**)&(__S)->data, &(__IT), (__S)->stride, (__S)->klpvl))
- #define gs_hash_set_iter_get(__S, __IT)\
- gs_hash_set_geti(__S, __IT)
- #define gs_hash_set_iter_getp(__S, __IT)\
- (&(gs_hash_set_geti(__S, __IT)))
- #define gs_hash_set_iter_getk(__S, __IT)\
- (gs_hash_set_getk(__S, __IT))
- #define gs_hash_set_iter_getkp(__S, __IT)\
- (&(gs_hash_set_getk(__S, __IT)))
- /*===================================
- // Slot Array
- ===================================*/
- #define GS_SLOT_ARRAY_INVALID_HANDLE UINT32_MAX
- #define gs_slot_array_handle_valid(__SA, __ID)\
- ((__SA) && __ID < gs_dyn_array_size((__SA)->indices) && (__SA)->indices[__ID] != GS_SLOT_ARRAY_INVALID_HANDLE)
- typedef struct __gs_slot_array_dummy_header {
- gs_dyn_array(uint32_t) indices;
- gs_dyn_array(uint32_t) data;
- } __gs_slot_array_dummy_header;
- #define gs_slot_array(__T)\
- struct\
- {\
- gs_dyn_array(uint32_t) indices;\
- gs_dyn_array(__T) data;\
- __T tmp;\
- }*
- #define gs_slot_array_new(__T)\
- NULL
- gs_force_inline
- uint32_t __gs_slot_array_find_next_available_index(gs_dyn_array(uint32_t) indices)
- {
- uint32_t idx = GS_SLOT_ARRAY_INVALID_HANDLE;
- for (uint32_t i = 0; i < (uint32_t)gs_dyn_array_size(indices); ++i)
- {
- uint32_t handle = indices[i];
- if (handle == GS_SLOT_ARRAY_INVALID_HANDLE)
- {
- idx = i;
- break;
- }
- }
- if (idx == GS_SLOT_ARRAY_INVALID_HANDLE)
- {
- idx = gs_dyn_array_size(indices);
- }
- return idx;
- }
- GS_API_DECL void**
- gs_slot_array_init(void** sa, size_t sz);
- #define gs_slot_array_init_all(__SA)\
- (gs_slot_array_init((void**)&(__SA), sizeof(*(__SA))), gs_dyn_array_init((void**)&((__SA)->indices), sizeof(uint32_t)),\
- gs_dyn_array_init((void**)&((__SA)->data), sizeof((__SA)->tmp)))
- gs_force_inline
- uint32_t gs_slot_array_insert_func(void** indices, void** data, void* val, size_t val_len, uint32_t* ip)
- {
- // Find next available index
- u32 idx = __gs_slot_array_find_next_available_index((uint32_t*)*indices);
- if (idx == gs_dyn_array_size(*indices)) {
- uint32_t v = 0;
- gs_dyn_array_push_data(indices, &v, sizeof(uint32_t));
- idx = gs_dyn_array_size(*indices) - 1;
- }
- // Push data to array
- gs_dyn_array_push_data(data, val, val_len);
- // Set data in indices
- uint32_t bi = gs_dyn_array_size(*data) - 1;
- gs_dyn_array_set_data_i(indices, &bi, sizeof(uint32_t), idx);
- if (ip){
- *ip = idx;
- }
- return idx;
- }
- #define gs_slot_array_reserve(__SA, __NUM)\
- do {\
- gs_slot_array_init_all(__SA);\
- gs_dyn_array_reserve((__SA)->data, __NUM);\
- gs_dyn_array_reserve((__SA)->indices, __NUM);\
- } while (0)
- #define gs_slot_array_insert(__SA, __VAL)\
- (gs_slot_array_init_all(__SA), (__SA)->tmp = (__VAL),\
- gs_slot_array_insert_func((void**)&((__SA)->indices), (void**)&((__SA)->data), (void*)&((__SA)->tmp), sizeof(((__SA)->tmp)), NULL))
- #define gs_slot_array_insert_hp(__SA, __VAL, __hp)\
- (gs_slot_array_init_all(__SA), (__SA)->tmp = (__VAL),\
- gs_slot_array_insert_func((void**)&((__SA)->indices), (void**)&((__SA)->data), &((__SA)->tmp), sizeof(((__SA)->tmp)), (__hp)))
- #define gs_slot_array_insert_no_init(__SA, __VAL)\
- ((__SA)->tmp = (__VAL), gs_slot_array_insert_func((void**)&((__SA)->indices), (void**)&((__SA)->data), &((__SA)->tmp), sizeof(((__SA)->tmp)), NULL))
- #define gs_slot_array_size(__SA)\
- ((__SA) == NULL ? 0 : gs_dyn_array_size((__SA)->data))
- #define gs_slot_array_empty(__SA)\
- (gs_slot_array_size(__SA) == 0)
- #define gs_slot_array_clear(__SA)\
- do {\
- if ((__SA) != NULL) {\
- gs_dyn_array_clear((__SA)->data);\
- gs_dyn_array_clear((__SA)->indices);\
- }\
- } while (0)
- #define gs_slot_array_exists(__SA, __SID)\
- ((__SA) && (__SID) < (uint32_t)gs_dyn_array_size((__SA)->indices) && (__SA)->indices[__SID] != GS_SLOT_ARRAY_INVALID_HANDLE)
- #define gs_slot_array_get(__SA, __SID)\
- ((__SA)->data[(__SA)->indices[(__SID) % gs_dyn_array_size(((__SA)->indices))]])
- #define gs_slot_array_getp(__SA, __SID)\
- (&(gs_slot_array_get(__SA, (__SID))))
- #define gs_slot_array_free(__SA)\
- do {\
- if ((__SA) != NULL) {\
- gs_dyn_array_free((__SA)->data);\
- gs_dyn_array_free((__SA)->indices);\
- (__SA)->indices = NULL;\
- (__SA)->data = NULL;\
- gs_free((__SA));\
- (__SA) = NULL;\
- }\
- } while (0)
- #define gs_slot_array_erase(__SA, __id)\
- do {\
- uint32_t __H0 = (__id) /*% gs_dyn_array_size((__SA)->indices)*/;\
- if (gs_slot_array_size(__SA) == 1) {\
- gs_slot_array_clear(__SA);\
- }\
- else if (!gs_slot_array_handle_valid(__SA, __H0)) {\
- gs_println("Warning: Attempting to erase invalid slot array handle (%zu)", __H0);\
- }\
- else {\
- uint32_t __OG_DATA_IDX = (__SA)->indices[__H0];\
- /* Iterate through handles until last index of data found */\
- uint32_t __H = 0;\
- for (uint32_t __I = 0; __I < gs_dyn_array_size((__SA)->indices); ++__I)\
- {\
- if ((__SA)->indices[__I] == gs_dyn_array_size((__SA)->data) - 1)\
- {\
- __H = __I;\
- break;\
- }\
- }\
- \
- /* Swap and pop data */\
- (__SA)->data[__OG_DATA_IDX] = gs_dyn_array_back((__SA)->data);\
- gs_dyn_array_pop((__SA)->data);\
- \
- /* Point new handle, Set og handle to invalid */\
- (__SA)->indices[__H] = __OG_DATA_IDX;\
- (__SA)->indices[__H0] = GS_SLOT_ARRAY_INVALID_HANDLE;\
- }\
- } while (0)
- /*=== Slot Array Iterator ===*/
- // Slot array iterator new
- typedef uint32_t gs_slot_array_iter;
- typedef gs_slot_array_iter gs_slot_array_iter_t;
- #define gs_slot_array_iter_valid(__SA, __IT)\
- (__SA && gs_slot_array_exists(__SA, __IT))
- gs_force_inline
- void _gs_slot_array_iter_advance_func(gs_dyn_array(uint32_t) indices, uint32_t* it)
- {
- if (!indices) {
- *it = GS_SLOT_ARRAY_INVALID_HANDLE;
- return;
- }
- (*it)++;
- for (; *it < (uint32_t)gs_dyn_array_size(indices); ++*it)
- {\
- if (indices[*it] != GS_SLOT_ARRAY_INVALID_HANDLE)\
- {\
- break;\
- }\
- }\
- }
- gs_force_inline
- uint32_t _gs_slot_array_iter_find_first_valid_index(gs_dyn_array(uint32_t) indices)
- {
- if (!indices) return GS_SLOT_ARRAY_INVALID_HANDLE;
- for (uint32_t i = 0; i < (uint32_t)gs_dyn_array_size(indices); ++i)
- {
- if (indices[i] != GS_SLOT_ARRAY_INVALID_HANDLE)
- {
- return i;
- }
- }
- return GS_SLOT_ARRAY_INVALID_HANDLE;
- }
- #define gs_slot_array_iter_new(__SA) (_gs_slot_array_iter_find_first_valid_index((__SA) ? (__SA)->indices : 0))
- #define gs_slot_array_iter_advance(__SA, __IT)\
- _gs_slot_array_iter_advance_func((__SA) ? (__SA)->indices : NULL, &(__IT))
- #define gs_slot_array_iter_get(__SA, __IT)\
- gs_slot_array_get(__SA, __IT)
- #define gs_slot_array_iter_getp(__SA, __IT)\
- gs_slot_array_getp(__SA, __IT)
- /*===================================
- // Slot Map
- ===================================*/
- #define gs_slot_map(__SMK, __SMV)\
- struct {\
- gs_hash_table(__SMK, uint32_t) ht;\
- gs_slot_array(__SMV) sa;\
- }*
- #define gs_slot_map_new(__SMK, __SMV)\
- NULL
- GS_API_DECL void**
- gs_slot_map_init(void** sm);
- // Could return something, I believe?
- #define gs_slot_map_insert(__SM, __SMK, __SMV)\
- do {\
- gs_slot_map_init((void**)&(__SM));\
- uint32_t __H = gs_slot_array_insert((__SM)->sa, ((__SMV)));\
- gs_hash_table_insert((__SM)->ht, (__SMK), __H);\
- } while (0)
- #define gs_slot_map_get(__SM, __SMK)\
- (gs_slot_array_get((__SM)->sa, gs_hash_table_get((__SM)->ht, (__SMK))))
- #define gs_slot_map_getp(__SM, __SMK)\
- (gs_slot_array_getp((__SM)->sa, gs_hash_table_get((__SM)->ht, (__SMK))))
- #define gs_slot_map_size(__SM)\
- (gs_slot_array_size((__SM)->sa))
- #define gs_slot_map_clear(__SM)\
- do {\
- if ((__SM) != NULL) {\
- gs_hash_table_clear((__SM)->ht);\
- gs_slot_array_clear((__SM)->sa);\
- }\
- } while (0)
- #define gs_slot_map_erase(__SM, __SMK)\
- do {\
- uint32_t __K = gs_hash_table_get((__SM)->ht, (__SMK));\
- gs_hash_table_erase((__SM)->ht, (__SMK));\
- gs_slot_array_erase((__SM)->sa, __K);\
- } while (0)
- #define gs_slot_map_free(__SM)\
- do {\
- if (__SM != NULL) {\
- gs_hash_table_free((__SM)->ht);\
- gs_slot_array_free((__SM)->sa);\
- gs_free((__SM));\
- (__SM) = NULL;\
- }\
- } while (0)
- #define gs_slot_map_capacity(__SM)\
- (gs_hash_table_capacity((__SM)->ht))
- /*=== Slot Map Iterator ===*/
- typedef uint32_t gs_slot_map_iter;
- /* Find first valid iterator idx */
- #define gs_slot_map_iter_new(__SM)\
- gs_hash_table_iter_new((__SM)->ht)
- #define gs_slot_map_iter_valid(__SM, __IT)\
- ((__IT) < gs_hash_table_capacity((__SM)->ht))
- #define gs_slot_map_iter_advance(__SM, __IT)\
- __gs_hash_table_iter_advance_func((void**)&((__SM)->ht->data), sizeof((__SM)->ht->tmp_key), sizeof((__SM)->ht->tmp_val), &(__IT), (__SM)->ht->stride, (__SM)->ht->klpvl)
- #define gs_slot_map_iter_getk(__SM, __IT)\
- gs_hash_table_iter_getk((__SM)->ht, (__IT))
- //(gs_hash_table_find_valid_iter(__SM->ht, __IT), gs_hash_table_geti((__SM)->ht, (__IT)))
- #define gs_slot_map_iter_getkp(__SM, __IT)\
- (gs_hash_table_find_valid_iter(__SM->ht, __IT), &(gs_hash_table_geti((__SM)->ht, (__IT))))
- #define gs_slot_map_iter_get(__SM, __IT)\
- ((__SM)->sa->data[gs_hash_table_iter_get((__SM)->ht, (__IT))])
- // ((__SM)->sa->data[gs_hash_table_geti((__SM)->ht, (__IT))])
- // (gs_hash_table_find_valid_iter(__SM->ht, __IT), (__SM)->sa->data[gs_hash_table_geti((__SM)->ht, (__IT))])
- #define gs_slot_map_iter_getp(__SM, __IT)\
- (&((__SM)->sa->data[gs_hash_table_geti((__SM)->ht, (__IT))]))
- // (gs_hash_table_find_valid_iter(__SM->ht, __IT), &((__SM)->sa->data[gs_hash_table_geti((__SM)->ht, (__IT))]))
- /*===================================
- // Priority Queue
- ===================================*/
- // Min heap
- #define gs_pqueue(__T)\
- struct\
- {\
- gs_dyn_array(__T) data;\
- gs_dyn_array(int32_t) priority;\
- __T tmp;\
- }*
- #define gs_pqueue_parent_idx(I) gs_max((uint32_t)(ceil(((float)I / 2.f) - 1)), 0)
- #define gs_pqueue_child_left_idx(I) ((I * 2) + 1)
- #define gs_pqueue_child_right_idx(I) ((I * 2) + 2)
- GS_API_DECL void**
- gs_pqueue_init(void** pq, size_t sz);
- #define gs_pqueue_init_all(__PQ, __V)\
- (gs_pqueue_init((void**)&(__PQ), sizeof(*(__PQ))), gs_dyn_array_init((void**)&((__PQ)->priority), sizeof(int32_t)),\
- gs_dyn_array_init((void**)&((__PQ)->data), sizeof(__V)))
- #define gs_pqueue_size(__PQ)\
- gs_dyn_array_size((__PQ)->data)
- #define gs_pqueue_capacity(__PQ)\
- gs_dyn_array_capacity((__PQ)->data)
- #define gs_pqueue_clear(__PQ)\
- do {\
- gs_dyn_array_clear((__PQ)->data);\
- gs_dyn_array_clear((__PQ)->priority);\
- } while (0)
- #define gs_pqueue_empty(__PQ)\
- (!(__PQ) || !gs_pqueue_size(__PQ))
- #define __gs_pqueue_swp(__PQ, __I0, __I1, __SZ)\
- do {\
- /* Move data */\
- {\
- const size_t sz = (__SZ);\
- memmove(&((__PQ)->tmp), &((__PQ)->data[__I0]), sz);\
- memmove(&((__PQ)->data[__I0]), &((__PQ)->data[__I1]), sz);\
- memmove(&((__PQ)->data[__I1]), &((__PQ)->tmp), sz);\
- }\
- /* Move priority */\
- {\
- int32_t tmp = 0;\
- const size_t sz = sizeof(int32_t);\
- memmove(&tmp, &((__PQ)->priority[__I0]), sz);\
- memmove(&((__PQ)->priority[__I0]), &((__PQ)->priority[__I1]), sz);\
- memmove(&((__PQ)->priority[__I1]), &tmp, sz);\
- }\
- } while (0)
- #define gs_pqueue_push(__PQ, __V, __PRI)\
- do {\
- /*Init*/\
- gs_pqueue_init_all((__PQ), (__V));\
- /*Push to end of array*/\
- gs_dyn_array_push((__PQ)->data, (__V));\
- gs_dyn_array_push((__PQ)->priority, (__PRI));\
- /*Compare and sort up*/\
- const size_t dsize = sizeof(__V);\
- int32_t i = gs_max(gs_pqueue_size((__PQ)) - 1, 0);\
- while (i)\
- {\
- /* Look at parent, compare, then swap indices with parent */\
- int32_t pidx = gs_pqueue_parent_idx(i);\
- if ((__PQ)->priority[pidx] > __PRI) {\
- __gs_pqueue_swp(__PQ, i, pidx, dsize);\
- }\
- else {\
- break;\
- }\
- i = pidx;\
- }\
- } while (0)
- #if 0
- /*
- Need to call into another function to return what I need... Not sure how to do this, since I need to know what TYPE to return...
- */
- #define gs_pqueue_pop(__PQ)\
- (\
- __gs_pqueue_pop_internal(\
- (void**)&(__PQ),\
- &(__PQ)->tmp,\
- (void**)(&(__PQ)->data),\
- (__PQ)->priority,\
- gs_pqueue_size((__PQ)),\
- sizeof((__PQ)->tmp)\
- ),\
- (__PQ)->tmp = (__PQ)->data[gs_pqueue_size((__PQ)) - 1],\
- (gs_dyn_array_head((__PQ)->data))->size--,\
- (gs_dyn_array_head((__PQ)->priority))->size--,\
- (__PQ)->tmp\
- )
- #endif
- #if 1
- /*
- No return.
- */
- #define gs_pqueue_pop(__PQ)\
- do {\
- /* Swap elements */\
- if (gs_pqueue_empty((__PQ))) break;\
- __gs_pqueue_swp(__PQ, 0, gs_pqueue_size((__PQ)) - 1, sizeof((__PQ)->tmp));\
- \
- int32_t i = 0;\
- int32_t c = 0;\
- int32_t psz = gs_dyn_array_size((__PQ)->priority) - 1;\
- for (int32_t i = 0; gs_pqueue_child_left_idx(i) < psz; i = c)\
- {\
- /* Set child to smaller of two */\
- c = gs_pqueue_child_left_idx(i);\
- \
- /* Set to right child if valid and less priority */\
- if ((c + 1) < psz && (__PQ)->priority[c + 1] < (__PQ)->priority[c]) {\
- c++;\
- }\
- \
- /* Check to swp, if necessary */\
- if ((__PQ)->priority[i] > (__PQ)->priority[c]) {\
- __gs_pqueue_swp((__PQ), i, c, sizeof((__PQ)->tmp));\
- }\
- /* Otherwise, we're done */\
- else\
- {\
- break;\
- }\
- }\
- (gs_dyn_array_head((__PQ)->data))->size--;\
- (gs_dyn_array_head((__PQ)->priority))->size--;\
- } while (0)
- #endif
- #if 1
- /*
- */
- GS_API_PRIVATE void
- __gs_pqueue_pop_internal(void** pqueue, void* tmp, void** data, int32_t* priority, int32_t pq_sz, size_t d_sz);
- #endif
- #define gs_pqueue_peek(__PQ)\
- (__PQ)->data[0]
- #define gs_pqueue_peekp(__PQ)\
- &((__PQ)->data[0])
- #define gs_pqueue_peek_pri(__PQ)\
- (__PQ)->priority[0]
- #define gs_pqueue_free(__PQ)\
- do {\
- if ((__PQ) && (__PQ)->data) gs_dyn_array_free((__PQ)->data);\
- if ((__PQ) && (__PQ)->priority) gs_dyn_array_free((__PQ)->priority);\
- if ((__PQ)) gs_free((__PQ));\
- } while (0)
- /*=== Priority Queue Iterator ===*/
- typedef uint32_t gs_pqueue_iter;
- typedef gs_pqueue_iter gs_pqueue_iter_t;
- #define gs_pqueue_iter_new(__PQ) 0
- #define gs_pqueue_iter_valid(__PQ, __IT)\
- ((__IT) < gs_pqueue_size((__PQ)))
- #define gs_pqueue_iter_advance(__PQ, __IT) ++(__IT)
- #define gs_pqueue_iter_get(__PQ, __IT)\
- (__PQ)->data[(__IT)]
- #define gs_pqueue_iter_getp(__PQ, __IT)\
- &(__PQ)->data[(__IT)]
- #define gs_pqueue_iter_get_pri(__PQ, __IT)\
- (__PQ)->priority[(__IT)]
- #define gs_pqueue_iter_get_prip(__PQ, __IT)\
- &(__PQ)->priority[(__IT)]
- /*===================================
- // Command Buffer
- ===================================*/
- typedef struct gs_command_buffer_t
- {
- uint32_t num_commands;
- gs_byte_buffer_t commands;
- } gs_command_buffer_t;
- gs_force_inline
- gs_command_buffer_t gs_command_buffer_new()
- {
- gs_command_buffer_t cb = gs_default_val();
- cb.commands = gs_byte_buffer_new();
- return cb;
- }
- #define gs_command_buffer_write(__CB, __CT, __C, __T, __VAL)\
- do {\
- gs_command_buffer_t* __cb = (__CB);\
- __cb->num_commands++;\
- gs_byte_buffer_write(&__cb->commands, __CT, (__C));\
- gs_byte_buffer_write(&__cb->commands, __T, (__VAL));\
- } while (0)
- gs_force_inline
- void gs_command_buffer_clear(gs_command_buffer_t* cb)
- {
- cb->num_commands = 0;
- gs_byte_buffer_clear(&cb->commands);
- }
- gs_force_inline
- void gs_command_buffer_free(gs_command_buffer_t* cb)
- {
- gs_byte_buffer_free(&cb->commands);
- }
- #define gs_command_buffer_readc(__CB, __T, __NAME)\
- __T __NAME = gs_default_val();\
- gs_byte_buffer_read(&(__CB)->commands, __T, &__NAME);
- #ifndef GS_NO_SHORT_NAME
- typedef gs_command_buffer_t gs_cmdbuf;
- #endif
- /** @} */ // end of gs_containers
- /*========================
- // GS_MEMORY
- ========================*/
- /** @defgroup gs_memory Memory
- * Gunslinger Memory
- * @{
- */
- #define gs_ptr_add(P, BYTES) \
- (((uint8_t*)P + (BYTES)))
- typedef struct gs_memory_block_t {
- uint8_t* data;
- size_t size;
- } gs_memory_block_t;
-
- GS_API_DECL gs_memory_block_t gs_memory_block_new(size_t sz);
- GS_API_DECL void gs_memory_block_free(gs_memory_block_t* mem);
- GS_API_DECL size_t gs_memory_calc_padding(size_t base_address, size_t alignment);
- GS_API_DECL size_t gs_memory_calc_padding_w_header(size_t base_address, size_t alignment, size_t header_sz);
- /*================================================================================
- // Linear Allocator
- ================================================================================*/
- typedef struct gs_linear_allocator_t {
- uint8_t* memory;
- size_t total_size;
- size_t offset;
- } gs_linear_allocator_t;
- GS_API_DECL gs_linear_allocator_t gs_linear_allocator_new(size_t sz);
- GS_API_DECL void gs_linear_allocator_free(gs_linear_allocator_t* la);
- GS_API_DECL void* gs_linear_allocator_allocate(gs_linear_allocator_t* la, size_t sz, size_t alignment);
- GS_API_DECL void gs_linear_allocator_clear(gs_linear_allocator_t* la);
- /*================================================================================
- // Stack Allocator
- ================================================================================*/
- typedef struct gs_stack_allocator_header_t {
- uint32_t size;
- } gs_stack_allocator_header_t;
- typedef struct gs_stack_allocator_t {
- gs_memory_block_t memory;
- size_t offset;
- } gs_stack_allocator_t;
- GS_API_DECL gs_stack_allocator_t gs_stack_allocator_new(size_t sz);
- GS_API_DECL void gs_stack_allocator_free(gs_stack_allocator_t* sa);
- GS_API_DECL void* gs_stack_allocator_allocate(gs_stack_allocator_t* sa, size_t sz);
- GS_API_DECL void* gs_stack_allocator_peek(gs_stack_allocator_t* sa);
- GS_API_DECL void* gs_stack_allocator_pop(gs_stack_allocator_t* sa);
- GS_API_DECL void gs_stack_allocator_clear(gs_stack_allocator_t* sa);
- /*================================================================================
- // Heap Allocator
- ================================================================================*/
- #ifndef GS_HEAP_ALLOC_DEFAULT_SIZE
- #define GS_HEAP_ALLOC_DEFAULT_SIZE 1024 * 1024 * 20
- #endif
- #ifndef GS_HEAP_ALLOC_DEFAULT_CAPCITY
- #define GS_HEAP_ALLOC_DEFAULT_CAPCITY 1024
- #endif
- typedef struct gs_heap_allocator_header_t {
- struct gs_heap_allocator_header_t* next;
- struct gs_heap_allocator_header_t* prev;
- size_t size;
- } gs_heap_allocator_header_t;
- typedef struct gs_heap_allocator_free_block_t {
- gs_heap_allocator_header_t* header;
- size_t size;
- } gs_heap_allocator_free_block_t;
- typedef struct gs_heap_allocator_t {
- gs_heap_allocator_header_t* memory;
- gs_heap_allocator_free_block_t* free_blocks;
- uint32_t free_block_count;
- uint32_t free_block_capacity;
- } gs_heap_allocator_t;
- GS_API_DECL gs_heap_allocator_t gs_heap_allocate_new();
- GS_API_DECL void gs_heap_allocator_free(gs_heap_allocator_t* ha);
- GS_API_DECL void* gs_heap_allocator_allocate(gs_heap_allocator_t* ha, size_t sz);
- GS_API_DECL void gs_heap_allocator_deallocate(gs_heap_allocator_t* ha, void* memory);
- /*================================================================================
- // Pool Allocator
- ================================================================================*/
- /*================================================================================
- // Paged Allocator
- ================================================================================*/
- typedef struct gs_paged_allocator_block_t {
- struct gs_paged_allocator_block_t* next;
- } gs_paged_allocator_block_t;
- typedef struct gs_paged_allocator_page_t {
- struct gs_paged_allocator_page_t* next;
- struct gs_paged_allocator_block_t* data;
- } gs_paged_allocator_page_t;
- typedef struct gs_paged_allocator_t {
- uint32_t block_size;
- uint32_t blocks_per_page;
- gs_paged_allocator_page_t* pages;
- uint32_t page_count;
- gs_paged_allocator_block_t* free_list;
- } gs_paged_allocator_t;
- GS_API_DECL gs_paged_allocator_t gs_paged_allocator_new(size_t element_size, size_t elements_per_page);
- GS_API_DECL void gs_paged_allocator_free(gs_paged_allocator_t* pa);
- GS_API_DECL void* gs_paged_allocator_allocate(gs_paged_allocator_t* pa);
- GS_API_DECL void gs_paged_allocator_deallocate(gs_paged_allocator_t* pa, void* data);
- GS_API_DECL void gs_paged_allocator_clear(gs_paged_allocator_t* pa);
- /** @} */ // end of gs_memory
- /*========================
- // GS_MATH
- ========================*/
- /** @defgroup gs_math Math
- * Gunslinger Math
- * @{
- */
- // Defines
- #define GS_EPSILON (1e-6)
- #define GS_PI 3.1415926535897932
- #define GS_TAU 2.0 * GS_PI
- // Useful Utility
- #define gs_v2(...) gs_vec2_ctor(__VA_ARGS__)
- #define gs_v3(...) gs_vec3_ctor(__VA_ARGS__)
- #define gs_v4(...) gs_vec4_ctor(__VA_ARGS__)
- #define gs_quat(...) gs_quat_ctor(__VA_ARGS__)
- #define gs_v2s(__S) gs_vec2_ctor((__S), (__S))
- #define gs_v3s(__S) gs_vec3_ctor((__S), (__S), (__S))
- #define gs_v4s(__S) gs_vec4_ctor((__S), (__S), (__S), (__S))
- #define gs_v4_xy_v(__X, __Y, __V) gs_vec4_ctor((__X), (__Y), (__V).x, (__V).y)
- #define gs_v4_xyz_s(__XYZ, __S) gs_vec4_ctor((__XYZ).x, (__XYZ).y, (__XYZ).z, (__S))
- #define GS_XAXIS gs_v3(1.f, 0.f, 0.f)
- #define GS_YAXIS gs_v3(0.f, 1.f, 0.f)
- #define GS_ZAXIS gs_v3(0.f, 0.f, 1.f)
- /*================================================================================
- // Useful Common Math Functions
- ================================================================================*/
- #define gs_rad2deg(__R)\
- (float)((__R * 180.0f) / GS_PI)
- #define gs_deg2rad(__D)\
- (float)((__D * GS_PI) / 180.0f)
- // Interpolation
- // Source: https://codeplea.com/simple-interpolation
- // Returns v based on t
- gs_inline float
- gs_interp_linear(float a, float b, float t)
- {
- return (a + t * (b - a));
- }
- // Returns t based on v
- gs_inline float
- gs_interp_linear_inv(float a, float b, float v)
- {
- return (v - a) / (b - a);
- }
- gs_inline float
- gs_interp_smoothstep(float a, float b, float t)
- {
- return gs_interp_linear(a, b, t * t * (3.0f - 2.0f * t));
- }
- gs_inline float
- gs_interp_cosine(float a, float b, float t)
- {
- return gs_interp_linear(a, b, (float)-cos(GS_PI * t) * 0.5f + 0.5f);
- }
- gs_inline float
- gs_interp_acceleration(float a, float b, float t)
- {
- return gs_interp_linear(a, b, t * t);
- }
- gs_inline float
- gs_interp_deceleration(float a, float b, float t)
- {
- return gs_interp_linear(a, b, 1.0f - (1.0f - t) * (1.0f - t));
- }
- gs_inline float
- gs_round(float val)
- {
- return (float)floor(val + 0.5f);
- }
- gs_inline float
- gs_map_range(float input_start, float input_end, float output_start, float output_end, float val)
- {
- float slope = (output_end - output_start) / (input_end - input_start);
- return (output_start + (slope * (val - input_start)));
- }
- // Easings from: https://github.com/raysan5/raylib/blob/ea0f6c7a26f3a61f3be542aa8f066ce033766a9f/examples/others/easings.h
- gs_inline
- float gs_ease_cubic_in(float t, float b, float c, float d)
- {
- t /= d;
- return (c*t*t*t + b);
- }
- gs_inline
- float gs_ease_cubic_out(float t, float b, float c, float d)
- {
- t = t/d - 1.0f;
- return (c*(t*t*t + 1.0f) + b);
- }
- gs_inline
- float gs_ease_cubic_in_out(float t, float b, float c, float d)
- {
- if ((t/=d/2.0f) < 1.0f)
- {
- return (c/2.0f*t*t*t + b);
- }
- t -= 2.0f;
- return (c/2.0f*(t*t*t + 2.0f) + b);
- }
- /*================================================================================
- // Vec2
- ================================================================================*/
- /** @brief struct gs_vec2 in gs math */
- typedef struct
- {
- union
- {
- f32 xy[2];
- struct
- {
- f32 x, y;
- };
- };
- } gs_vec2_t;
- typedef gs_vec2_t gs_vec2;
- gs_inline gs_vec2
- gs_vec2_ctor(f32 _x, f32 _y)
- {
- gs_vec2 v;
- v.x = _x;
- v.y = _y;
- return v;
- }
- gs_inline bool
- gs_vec2_nan(gs_vec2 v)
- {
- if (v.x != v.x || v.y != v.y) return true;
- return false;
- }
- gs_inline gs_vec2
- gs_vec2_add(gs_vec2 v0, gs_vec2 v1)
- {
- return gs_vec2_ctor(v0.x + v1.x, v0.y + v1.y);
- }
- gs_inline gs_vec2
- gs_vec2_sub(gs_vec2 v0, gs_vec2 v1)
- {
- return gs_vec2_ctor(v0.x - v1.x, v0.y - v1.y);
- }
- gs_inline gs_vec2
- gs_vec2_mul(gs_vec2 v0, gs_vec2 v1)
- {
- return gs_vec2_ctor(v0.x * v1.x, v0.y * v1.y);
- }
- gs_inline gs_vec2
- gs_vec2_div(gs_vec2 v0, gs_vec2 v1)
- {
- return gs_vec2_ctor(v0.x / v1.x, v0.y / v1.y);
- }
- gs_inline bool
- gs_vec2_equals(gs_vec2 v0, gs_vec2 v1)
- {
- return (v0.x == v1.x && v0.y == v1.y);
- }
- gs_inline gs_vec2
- gs_vec2_scale(gs_vec2 v, f32 s)
- {
- return gs_vec2_ctor(v.x * s, v.y * s);
- }
- gs_inline f32
- gs_vec2_dot(gs_vec2 v0, gs_vec2 v1)
- {
- return (f32)(v0.x * v1.x + v0.y * v1.y);
- }
- gs_inline f32
- gs_vec2_len(gs_vec2 v)
- {
- return (f32)sqrt(gs_vec2_dot(v, v));
- }
- gs_inline gs_vec2
- gs_vec2_project_onto(gs_vec2 v0, gs_vec2 v1)
- {
- f32 dot = gs_vec2_dot(v0, v1);
- f32 len = gs_vec2_dot(v1, v1);
- // Orthogonal, so return v1
- if (len == 0.f) return v1;
- return gs_vec2_scale(v1, dot / len);
- }
- gs_inline gs_vec2 gs_vec2_norm(gs_vec2 v)
- {
- f32 len = gs_vec2_len(v);
- return gs_vec2_scale(v, len != 0.f ? 1.0f / gs_vec2_len(v) : 1.f);
- }
- gs_inline
- f32 gs_vec2_dist(gs_vec2 a, gs_vec2 b)
- {
- f32 dx = (a.x - b.x);
- f32 dy = (a.y - b.y);
- return (float)(sqrt(dx * dx + dy * dy));
- }
- gs_inline
- f32 gs_vec2_dist2(gs_vec2 a, gs_vec2 b)
- {
- f32 dx = (a.x - b.x);
- f32 dy = (a.y - b.y);
- return (float)(dx * dx + dy * dy);
- }
- gs_inline
- f32 gs_vec2_cross(gs_vec2 a, gs_vec2 b)
- {
- return a.x * b.y - a.y * b.x;
- }
- gs_inline
- f32 gs_vec2_angle(gs_vec2 a, gs_vec2 b)
- {
- return (float)acos(gs_vec2_dot(a, b) / (gs_vec2_len(a) * gs_vec2_len(b)));
- }
- gs_inline
- b32 gs_vec2_equal(gs_vec2 a, gs_vec2 b)
- {
- return (a.x == b.x && a.y == b.y);
- }
- /*================================================================================
- // Vec3
- ================================================================================*/
- typedef struct
- {
- union
- {
- f32 xyz[3];
- struct
- {
- f32 x, y, z;
- };
- };
- } gs_vec3_t;
- typedef gs_vec3_t gs_vec3;
- gs_inline gs_vec3
- gs_vec3_ctor(f32 _x, f32 _y, f32 _z)
- {
- gs_vec3 v;
- v.x = _x;
- v.y = _y;
- v.z = _z;
- return v;
- }
- gs_inline bool
- gs_vec3_eq(gs_vec3 v0, gs_vec3 v1)
- {
- return (v0.x == v1.x && v0.y == v1.y && v0.z == v1.z);
- }
- gs_inline gs_vec3
- gs_vec3_add(gs_vec3 v0, gs_vec3 v1)
- {
- return gs_vec3_ctor(v0.x + v1.x, v0.y + v1.y, v0.z + v1.z);
- }
- gs_inline gs_vec3
- gs_vec3_sub(gs_vec3 v0, gs_vec3 v1)
- {
- return gs_vec3_ctor(v0.x - v1.x, v0.y - v1.y, v0.z - v1.z);
- }
- gs_inline gs_vec3
- gs_vec3_mul(gs_vec3 v0, gs_vec3 v1)
- {
- return gs_vec3_ctor(v0.x * v1.x, v0.y * v1.y, v0.z * v1.z);
- }
- gs_inline gs_vec3
- gs_vec3_div(gs_vec3 v0, gs_vec3 v1)
- {
- return gs_vec3_ctor(v0.x / v1.x, v0.y / v1.y, v0.z / v1.z);
- }
- gs_inline gs_vec3
- gs_vec3_scale(gs_vec3 v, f32 s)
- {
- return gs_vec3_ctor(v.x * s, v.y * s, v.z * s);
- }
- gs_inline gs_vec3
- gs_vec3_neg(gs_vec3 v)
- {
- return gs_vec3_scale(v, -1.f);
- }
- gs_inline f32
- gs_vec3_dot(gs_vec3 v0, gs_vec3 v1)
- {
- f32 dot = (f32)((v0.x * v1.x) + (v0.y * v1.y) + v0.z * v1.z);
- return dot;
- }
- gs_inline bool
- gs_vec3_same_dir(gs_vec3 v0, gs_vec3 v1)
- {
- return (gs_vec3_dot(v0, v1) > 0.f);
- }
- gs_inline gs_vec3
- gs_vec3_sign(gs_vec3 v)
- {
- return (gs_vec3_ctor(
- v.x < 0.f ? -1.f : v.x > 0.f ? 1.f : 0.f,
- v.y < 0.f ? -1.f : v.y > 0.f ? 1.f : 0.f,
- v.z < 0.f ? -1.f : v.z > 0.f ? 1.f : 0.f
- ));
- }
- gs_inline float
- gs_vec3_signX(gs_vec3 v)
- {
- return (v.x < 0.f ? -1.f : v.x > 0.f ? 1.f : 0.f);
- }
- gs_inline float
- gs_vec3_signY(gs_vec3 v)
- {
- return (v.y < 0.f ? -1.f : v.y > 0.f ? 1.f : 0.f);
- }
- gs_inline float
- gs_vec3_signZ(gs_vec3 v)
- {
- return (v.z < 0.f ? -1.f : v.z > 0.f ? 1.f : 0.f);
- }
- gs_inline f32
- gs_vec3_len(gs_vec3 v)
- {
- return (f32)sqrt(gs_vec3_dot(v, v));
- }
- gs_inline f32
- gs_vec3_len2(gs_vec3 v)
- {
- return (f32)(gs_vec3_dot(v, v));
- }
- gs_inline gs_vec3
- gs_vec3_project_onto(gs_vec3 v0, gs_vec3 v1)
- {
- f32 dot = gs_vec3_dot(v0, v1);
- f32 len = gs_vec3_dot(v1, v1);
- // Orthogonal, so return v1
- if (len == 0.f) return v1;
- return gs_vec3_scale(v1, dot / len);
- }
- gs_inline bool
- gs_vec3_nan(gs_vec3 v)
- {
- if (v.x != v.x || v.y != v.y || v.z != v.z) return true;
- return false;
- }
- gs_inline
- f32 gs_vec3_dist2(gs_vec3 a, gs_vec3 b)
- {
- f32 dx = (a.x - b.x);
- f32 dy = (a.y - b.y);
- f32 dz = (a.z - b.z);
- return (dx * dx + dy * dy + dz * dz);
- }
- gs_inline
- f32 gs_vec3_dist(gs_vec3 a, gs_vec3 b)
- {
- return sqrt(gs_vec3_dist2(a, b));
- }
- gs_inline gs_vec3
- gs_vec3_norm(gs_vec3 v)
- {
- f32 len = gs_vec3_len(v);
- return len == 0.f ? v : gs_vec3_scale(v, 1.f / len);
- }
- gs_inline gs_vec3
- gs_vec3_cross(gs_vec3 v0, gs_vec3 v1)
- {
- return gs_vec3_ctor
- (
- v0.y * v1.z - v0.z * v1.y,
- v0.z * v1.x - v0.x * v1.z,
- v0.x * v1.y - v0.y * v1.x
- );
- }
- gs_inline void gs_vec3_scale_ip(gs_vec3* vp, f32 s)
- {
- vp->x *= s;
- vp->y *= s;
- vp->z *= s;
- }
- gs_inline float gs_vec3_angle_between(gs_vec3 v0, gs_vec3 v1)
- {
- return acosf(gs_vec3_dot(v0, v1));
- }
- gs_inline float gs_vec3_angle_between_signed(gs_vec3 v0, gs_vec3 v1)
- {
- return asinf(gs_vec3_len(gs_vec3_cross(v0, v1)));
- }
- gs_inline gs_vec3 gs_vec3_triple_cross_product(gs_vec3 a, gs_vec3 b, gs_vec3 c)
- {
- return gs_vec3_sub((gs_vec3_scale(b, gs_vec3_dot(c, a))), (gs_vec3_scale(a, gs_vec3_dot(c, b))));
- }
- /*================================================================================
- // Vec4
- ================================================================================*/
- typedef struct
- {
- union
- {
- f32 xyzw[4];
- struct
- {
- f32 x, y, z, w;
- };
- };
- } gs_vec4_t;
- typedef gs_vec4_t gs_vec4;
- gs_inline gs_vec4
- gs_vec4_ctor(f32 _x, f32 _y, f32 _z, f32 _w)
- {
- gs_vec4 v;
- v.x = _x;
- v.y = _y;
- v.z = _z;
- v.w = _w;
- return v;
- }
- gs_inline gs_vec4
- gs_vec4_add(gs_vec4 v0, gs_vec4 v1)
- {
- return gs_vec4_ctor(v0.x + v1.x, v0.y + v1.y, v0.z + v1.z, v0.w + v1.w);
- }
- gs_inline gs_vec4
- gs_vec4_sub(gs_vec4 v0, gs_vec4 v1)
- {
- return gs_vec4_ctor(v0.x - v1.x, v0.y - v1.y, v0.z - v1.z, v0.w - v1.w);
- }
- gs_inline gs_vec4
- gs_vec4_mul(gs_vec4 v0, gs_vec4 v1)
- {
- return gs_vec4_ctor(v0.x * v1.x, v0.y * v1.y, v0.z * v1.z, v0.w * v1.w);
- }
- gs_inline gs_vec4
- gs_vec4_div(gs_vec4 v0, gs_vec4 v1)
- {
- return gs_vec4_ctor(v0.x / v1.x, v0.y / v1.y, v0.z / v1.z, v0.w / v1.w);
- }
- gs_inline gs_vec4
- gs_vec4_scale(gs_vec4 v, f32 s)
- {
- return gs_vec4_ctor(v.x * s, v.y * s, v.z * s, v.w * s);
- }
- gs_inline f32
- gs_vec4_dot(gs_vec4 v0, gs_vec4 v1)
- {
- return (f32)(v0.x * v1.x + v0.y * v1.y + v0.z * v1.z + v0.w * v1.w);
- }
- gs_inline f32
- gs_vec4_len(gs_vec4 v)
- {
- return (f32)sqrt(gs_vec4_dot(v, v));
- }
- gs_inline gs_vec4
- gs_vec4_project_onto(gs_vec4 v0, gs_vec4 v1)
- {
- f32 dot = gs_vec4_dot(v0, v1);
- f32 len = gs_vec4_dot(v1, v1);
- // Orthogonal, so return v1
- if (len == 0.f) return v1;
- return gs_vec4_scale(v1, dot / len);
- }
- gs_inline gs_vec4
- gs_vec4_norm(gs_vec4 v)
- {
- return gs_vec4_scale(v, 1.0f / gs_vec4_len(v));
- }
- gs_inline f32
- gs_vec4_dist(gs_vec4 v0, gs_vec4 v1)
- {
- f32 dx = (v0.x - v1.x);
- f32 dy = (v0.y - v1.y);
- f32 dz = (v0.z - v1.z);
- f32 dw = (v0.w - v1.w);
- return (float)(sqrt(dx * dx + dy * dy + dz * dz + dw * dw));
- }
- /*================================================================================
- // Useful Vector Functions
- ================================================================================*/
- gs_inline
- gs_vec3 gs_v4tov3(gs_vec4 v)
- {
- return gs_v3(v.x, v.y, v.z);
- }
- gs_inline
- gs_vec2 gs_v3tov2(gs_vec3 v)
- {
- return gs_v2(v.x, v.y);
- }
- gs_inline
- gs_vec3 gs_v2tov3(gs_vec2 v)
- {
- return gs_v3(v.x, v.y, 0.f);
- }
- /*================================================================================
- // Mat3x3
- ================================================================================*/
- /*
- Matrices are stored in linear, contiguous memory and assume a column-major ordering.
- */
- typedef struct gs_mat3 {
- f32 m[9];
- } gs_mat3;
- gs_inline gs_mat3 gs_mat3_diag(float val)
- {
- gs_mat3 m = gs_default_val();
- m.m[0 + 0 * 3] = val;
- m.m[1 + 1 * 3] = val;
- m.m[2 + 2 * 3] = val;
- return m;
- }
- #define gs_mat3_identity()\
- gs_mat3_diag(1.f)
- gs_inline gs_mat3
- gs_mat3_mul(gs_mat3 m0, gs_mat3 m1)
- {
- gs_mat3 m = gs_default_val();
- for (u32 y = 0; y < 3; ++y)
- {
- for (u32 x = 0; x < 3; ++x)
- {
- f32 sum = 0.0f;
- for (u32 e = 0; e < 3; ++e)
- {
- sum += m0.m[x + e * 3] * m1.m[e + y * 3];
- }
- m.m[x + y * 3] = sum;
- }
- }
- return m;
- }
- gs_inline gs_vec3
- gs_mat3_mul_vec3(gs_mat3 m, gs_vec3 v)
- {
- return gs_vec3_ctor(
- m.m[0] * v.x + m.m[1] * v.y + m.m[2] * v.z,
- m.m[3] * v.x + m.m[4] * v.y + m.m[5] * v.z,
- m.m[6] * v.x + m.m[7] * v.y + m.m[8] * v.z
- );
- }
- gs_inline gs_mat3
- gs_mat3_scale(float x, float y, float z)
- {
- gs_mat3 m = gs_default_val();
- m.m[0] = x;
- m.m[4] = y;
- m.m[8] = z;
- return m;
- }
- gs_inline gs_mat3
- gs_mat3_rotate(float radians, float x, float y, float z)
- {
- gs_mat3 m = gs_default_val();
- float s = sinf(radians), c = cosf(radians), c1 = 1.f - c;
- float xy = x * y;
- float yz = y * z;
- float zx = z * x;
- float xs = x * s;
- float ys = y * s;
- float zs = z * s;
- m.m[0] = c1 * x * x + c; m.m[1] = c1 * xy - zs; m.m[2] = c1 * zx + ys;
- m.m[3] = c1 * xy + zs; m.m[4] = c1 * y * y + c; m.m[5] = c1 * yz - xs;
- m.m[6] = c1 * zx - ys; m.m[7] = c1 * yz + xs; m.m[8] = c1 * z * z + c;
- return m;
- }
- gs_inline gs_mat3
- gs_mat3_rotatev(float radians, gs_vec3 axis)
- {
- return gs_mat3_rotate(radians, axis.x, axis.y, axis.z);
- }
- // Turn quaternion into mat3
- gs_inline gs_mat3
- gs_mat3_rotateq(gs_vec4 q)
- {
- gs_mat3 m = gs_default_val();
- float x2 = q.x * q.x, y2 = q.y * q.y, z2 = q.z * q.z, w2 = q.w * q.w;
- float xz = q.x *q.z, xy = q.x * q.y, yz = q.y * q.z, wz = q.w * q.z, wy = q.w * q.y, wx = q.w * q.x;
- m.m[0] = 1 - 2 * (y2 + z2); m.m[1] = 2 * (xy + wz); m.m[2] = 2 * (xz - wy);
- m.m[3] = 2 * (xy - wz); m.m[4] = 1 - 2 * (x2 + z2); m.m[5] = 2 * (yz + wx);
- m.m[6] = 2 * (xz + wy); m.m[7] = 2 * (yz - wx); m.m[8] = 1 - 2 * (x2 + y2);
- return m;
- }
- gs_inline gs_mat3
- gs_mat3_rsq(gs_vec4 q, gs_vec3 s)
- {
- gs_mat3 mr = gs_mat3_rotateq(q);
- gs_mat3 ms = gs_mat3_scale(s.x, s.y, s.z);
- return gs_mat3_mul(mr, ms);
- }
- gs_inline gs_mat3
- gs_mat3_inverse(gs_mat3 m)
- {
- gs_mat3 r = gs_default_val();
- double det = (double)(m.m[0 * 3 + 0] * (m.m[1 * 3 + 1] * m.m[2 * 3 + 2] - m.m[2 * 3 + 1] * m.m[1 * 3 + 2]) -
- m.m[0 * 3 + 1] * (m.m[1 * 3 + 0] * m.m[2 * 3 + 2] - m.m[1 * 3 + 2] * m.m[2 * 3 + 0]) +
- m.m[0 * 3 + 2] * (m.m[1 * 3 + 0] * m.m[2 * 3 + 1] - m.m[1 * 3 + 1] * m.m[2 * 3 + 0]));
- double inv_det = det ? 1.0 / det : 0.0;
- r.m[0 * 3 + 0] = (m.m[1 * 3 + 1] * m.m[2 * 3 + 2] - m.m[2 * 3 + 1] * m.m[1 * 3 + 2]) * inv_det;
- r.m[0 * 3 + 1] = (m.m[0 * 3 + 2] * m.m[2 * 3 + 1] - m.m[0 * 3 + 1] * m.m[2 * 3 + 2]) * inv_det;
- r.m[0 * 3 + 2] = (m.m[0 * 3 + 1] * m.m[1 * 3 + 2] - m.m[0 * 3 + 2] * m.m[1 * 3 + 1]) * inv_det;
- r.m[1 * 3 + 0] = (m.m[1 * 3 + 2] * m.m[2 * 3 + 0] - m.m[1 * 3 + 0] * m.m[2 * 3 + 2]) * inv_det;
- r.m[1 * 3 + 1] = (m.m[0 * 3 + 0] * m.m[2 * 3 + 2] - m.m[0 * 3 + 2] * m.m[2 * 3 + 0]) * inv_det;
- r.m[1 * 3 + 2] = (m.m[1 * 3 + 0] * m.m[0 * 3 + 2] - m.m[0 * 3 + 0] * m.m[1 * 3 + 2]) * inv_det;
- r.m[2 * 3 + 0] = (m.m[1 * 3 + 0] * m.m[2 * 3 + 1] - m.m[2 * 3 + 0] * m.m[1 * 3 + 1]) * inv_det;
- r.m[2 * 3 + 1] = (m.m[2 * 3 + 0] * m.m[0 * 3 + 1] - m.m[0 * 3 + 0] * m.m[2 * 3 + 1]) * inv_det;
- r.m[2 * 3 + 2] = (m.m[0 * 3 + 0] * m.m[1 * 3 + 1] - m.m[1 * 3 + 0] * m.m[0 * 3 + 1]) * inv_det;
- return r;
- }
- /*================================================================================
- // Mat4x4
- ================================================================================*/
- /*
- Matrices are stored in linear, contiguous memory and assume a column-major ordering.
- */
- typedef struct gs_mat4
- {
- union {
- gs_vec4 rows[4];
- float m[4][4];
- float elements[16];
- struct {
- gs_vec4 right, up, dir, position;
- } v;
- };
- } gs_mat4_t;
- typedef gs_mat4_t gs_mat4;
- gs_inline gs_mat4
- gs_mat4_diag(f32 val)
- {
- gs_mat4 m;
- memset(m.elements, 0, sizeof(m.elements));
- m.elements[0 + 0 * 4] = val;
- m.elements[1 + 1 * 4] = val;
- m.elements[2 + 2 * 4] = val;
- m.elements[3 + 3 * 4] = val;
- return m;
- }
- #define gs_mat4_identity()\
- gs_mat4_diag(1.0f)
- gs_inline gs_mat4
- gs_mat4_ctor() {
- gs_mat4 mat = gs_default_val();
- return mat;
- }
- gs_inline
- gs_mat4 gs_mat4_elem(const float* elements)
- {
- gs_mat4 mat = gs_mat4_ctor();
- memcpy(mat.elements, elements, sizeof(f32) * 16);
- return mat;
- }
- gs_inline gs_mat4
- gs_mat4_mul(gs_mat4 m0, gs_mat4 m1)
- {
- gs_mat4 m_res = gs_mat4_ctor();
- for (u32 y = 0; y < 4; ++y)
- {
- for (u32 x = 0; x < 4; ++x)
- {
- f32 sum = 0.0f;
- for (u32 e = 0; e < 4; ++e)
- {
- sum += m0.elements[x + e * 4] * m1.elements[e + y * 4];
- }
- m_res.elements[x + y * 4] = sum;
- }
- }
- return m_res;
- }
- gs_inline
- gs_mat4 gs_mat4_mul_list(uint32_t count, ...)
- {
- va_list ap;
- gs_mat4 m = gs_mat4_identity();
- va_start(ap, count);
- for (uint32_t i = 0; i < count; ++i) {
- m = gs_mat4_mul(m, va_arg(ap, gs_mat4));
- }
- va_end(ap);
- return m;
- }
- gs_inline
- void gs_mat4_set_elements(gs_mat4* m, float* elements, uint32_t count)
- {
- for (u32 i = 0; i < count; ++i)
- {
- m->elements[i] = elements[i];
- }
- }
- gs_inline
- gs_mat4 gs_mat4_ortho_norm(const gs_mat4* m)
- {
- gs_mat4 r = *m;
- r.v.right = gs_vec4_norm(r.v.right);
- r.v.up = gs_vec4_norm(r.v.up);
- r.v.dir = gs_vec4_norm(r.v.dir);
- return r;
- }
- gs_inline
- gs_mat4 gs_mat4_transpose(gs_mat4 m)
- {
- gs_mat4 t = gs_mat4_identity();
- // First row
- t.elements[0 * 4 + 0] = m.elements[0 * 4 + 0];
- t.elements[1 * 4 + 0] = m.elements[0 * 4 + 1];
- t.elements[2 * 4 + 0] = m.elements[0 * 4 + 2];
- t.elements[3 * 4 + 0] = m.elements[0 * 4 + 3];
- // Second row
- t.elements[0 * 4 + 1] = m.elements[1 * 4 + 0];
- t.elements[1 * 4 + 1] = m.elements[1 * 4 + 1];
- t.elements[2 * 4 + 1] = m.elements[1 * 4 + 2];
- t.elements[3 * 4 + 1] = m.elements[1 * 4 + 3];
- // Third row
- t.elements[0 * 4 + 2] = m.elements[2 * 4 + 0];
- t.elements[1 * 4 + 2] = m.elements[2 * 4 + 1];
- t.elements[2 * 4 + 2] = m.elements[2 * 4 + 2];
- t.elements[3 * 4 + 2] = m.elements[2 * 4 + 3];
- // Fourth row
- t.elements[0 * 4 + 3] = m.elements[3 * 4 + 0];
- t.elements[1 * 4 + 3] = m.elements[3 * 4 + 1];
- t.elements[2 * 4 + 3] = m.elements[3 * 4 + 2];
- t.elements[3 * 4 + 3] = m.elements[3 * 4 + 3];
- return t;
- }
- gs_inline
- gs_mat4 gs_mat4_inverse(gs_mat4 m)
- {
- gs_mat4 res = gs_mat4_identity();
- f32 temp[16];
- temp[0] = m.elements[5] * m.elements[10] * m.elements[15] -
- m.elements[5] * m.elements[11] * m.elements[14] -
- m.elements[9] * m.elements[6] * m.elements[15] +
- m.elements[9] * m.elements[7] * m.elements[14] +
- m.elements[13] * m.elements[6] * m.elements[11] -
- m.elements[13] * m.elements[7] * m.elements[10];
- temp[4] = -m.elements[4] * m.elements[10] * m.elements[15] +
- m.elements[4] * m.elements[11] * m.elements[14] +
- m.elements[8] * m.elements[6] * m.elements[15] -
- m.elements[8] * m.elements[7] * m.elements[14] -
- m.elements[12] * m.elements[6] * m.elements[11] +
- m.elements[12] * m.elements[7] * m.elements[10];
- temp[8] = m.elements[4] * m.elements[9] * m.elements[15] -
- m.elements[4] * m.elements[11] * m.elements[13] -
- m.elements[8] * m.elements[5] * m.elements[15] +
- m.elements[8] * m.elements[7] * m.elements[13] +
- m.elements[12] * m.elements[5] * m.elements[11] -
- m.elements[12] * m.elements[7] * m.elements[9];
- temp[12] = -m.elements[4] * m.elements[9] * m.elements[14] +
- m.elements[4] * m.elements[10] * m.elements[13] +
- m.elements[8] * m.elements[5] * m.elements[14] -
- m.elements[8] * m.elements[6] * m.elements[13] -
- m.elements[12] * m.elements[5] * m.elements[10] +
- m.elements[12] * m.elements[6] * m.elements[9];
- temp[1] = -m.elements[1] * m.elements[10] * m.elements[15] +
- m.elements[1] * m.elements[11] * m.elements[14] +
- m.elements[9] * m.elements[2] * m.elements[15] -
- m.elements[9] * m.elements[3] * m.elements[14] -
- m.elements[13] * m.elements[2] * m.elements[11] +
- m.elements[13] * m.elements[3] * m.elements[10];
- temp[5] = m.elements[0] * m.elements[10] * m.elements[15] -
- m.elements[0] * m.elements[11] * m.elements[14] -
- m.elements[8] * m.elements[2] * m.elements[15] +
- m.elements[8] * m.elements[3] * m.elements[14] +
- m.elements[12] * m.elements[2] * m.elements[11] -
- m.elements[12] * m.elements[3] * m.elements[10];
- temp[9] = -m.elements[0] * m.elements[9] * m.elements[15] +
- m.elements[0] * m.elements[11] * m.elements[13] +
- m.elements[8] * m.elements[1] * m.elements[15] -
- m.elements[8] * m.elements[3] * m.elements[13] -
- m.elements[12] * m.elements[1] * m.elements[11] +
- m.elements[12] * m.elements[3] * m.elements[9];
- temp[13] = m.elements[0] * m.elements[9] * m.elements[14] -
- m.elements[0] * m.elements[10] * m.elements[13] -
- m.elements[8] * m.elements[1] * m.elements[14] +
- m.elements[8] * m.elements[2] * m.elements[13] +
- m.elements[12] * m.elements[1] * m.elements[10] -
- m.elements[12] * m.elements[2] * m.elements[9];
- temp[2] = m.elements[1] * m.elements[6] * m.elements[15] -
- m.elements[1] * m.elements[7] * m.elements[14] -
- m.elements[5] * m.elements[2] * m.elements[15] +
- m.elements[5] * m.elements[3] * m.elements[14] +
- m.elements[13] * m.elements[2] * m.elements[7] -
- m.elements[13] * m.elements[3] * m.elements[6];
- temp[6] = -m.elements[0] * m.elements[6] * m.elements[15] +
- m.elements[0] * m.elements[7] * m.elements[14] +
- m.elements[4] * m.elements[2] * m.elements[15] -
- m.elements[4] * m.elements[3] * m.elements[14] -
- m.elements[12] * m.elements[2] * m.elements[7] +
- m.elements[12] * m.elements[3] * m.elements[6];
- temp[10] = m.elements[0] * m.elements[5] * m.elements[15] -
- m.elements[0] * m.elements[7] * m.elements[13] -
- m.elements[4] * m.elements[1] * m.elements[15] +
- m.elements[4] * m.elements[3] * m.elements[13] +
- m.elements[12] * m.elements[1] * m.elements[7] -
- m.elements[12] * m.elements[3] * m.elements[5];
- temp[14] = -m.elements[0] * m.elements[5] * m.elements[14] +
- m.elements[0] * m.elements[6] * m.elements[13] +
- m.elements[4] * m.elements[1] * m.elements[14] -
- m.elements[4] * m.elements[2] * m.elements[13] -
- m.elements[12] * m.elements[1] * m.elements[6] +
- m.elements[12] * m.elements[2] * m.elements[5];
- temp[3] = -m.elements[1] * m.elements[6] * m.elements[11] +
- m.elements[1] * m.elements[7] * m.elements[10] +
- m.elements[5] * m.elements[2] * m.elements[11] -
- m.elements[5] * m.elements[3] * m.elements[10] -
- m.elements[9] * m.elements[2] * m.elements[7] +
- m.elements[9] * m.elements[3] * m.elements[6];
- temp[7] = m.elements[0] * m.elements[6] * m.elements[11] -
- m.elements[0] * m.elements[7] * m.elements[10] -
- m.elements[4] * m.elements[2] * m.elements[11] +
- m.elements[4] * m.elements[3] * m.elements[10] +
- m.elements[8] * m.elements[2] * m.elements[7] -
- m.elements[8] * m.elements[3] * m.elements[6];
- temp[11] = -m.elements[0] * m.elements[5] * m.elements[11] +
- m.elements[0] * m.elements[7] * m.elements[9] +
- m.elements[4] * m.elements[1] * m.elements[11] -
- m.elements[4] * m.elements[3] * m.elements[9] -
- m.elements[8] * m.elements[1] * m.elements[7] +
- m.elements[8] * m.elements[3] * m.elements[5];
- temp[15] = m.elements[0] * m.elements[5] * m.elements[10] -
- m.elements[0] * m.elements[6] * m.elements[9] -
- m.elements[4] * m.elements[1] * m.elements[10] +
- m.elements[4] * m.elements[2] * m.elements[9] +
- m.elements[8] * m.elements[1] * m.elements[6] -
- m.elements[8] * m.elements[2] * m.elements[5];
- float determinant = m.elements[0] * temp[0] + m.elements[1] * temp[4] + m.elements[2] * temp[8] + m.elements[3] * temp[12];
- determinant = 1.0f / determinant;
- for (int i = 0; i < 4 * 4; i++)
- res.elements[i] = (float)(temp[i] * (float)determinant);
- return res;
- }
- /*
- f32 l : left
- f32 r : right
- f32 b : bottom
- f32 t : top
- f32 n : near
- f32 f : far
- */
- gs_inline gs_mat4
- gs_mat4_ortho(f32 l, f32 r, f32 b, f32 t, f32 n, f32 f)
- {
- gs_mat4 m_res = gs_mat4_identity();
- // Main diagonal
- m_res.elements[0 + 0 * 4] = 2.0f / (r - l);
- m_res.elements[1 + 1 * 4] = 2.0f / (t - b);
- m_res.elements[2 + 2 * 4] = -2.0f / (f - n);
- // Last column
- m_res.elements[0 + 3 * 4] = -(r + l) / (r - l);
- m_res.elements[1 + 3 * 4] = -(t + b) / (t - b);
- m_res.elements[2 + 3 * 4] = -(f + n) / (f - n);
- return m_res;
- }
- gs_inline gs_mat4
- gs_mat4_perspective(f32 fov, f32 asp_ratio, f32 n, f32 f)
- {
- // Zero matrix
- gs_mat4 m_res = gs_mat4_ctor();
- f32 q = 1.0f / (float)tan(gs_deg2rad(0.5f * fov));
- f32 a = q / asp_ratio;
- f32 b = (n + f) / (n - f);
- f32 c = (2.0f * n * f) / (n - f);
- m_res.elements[0 + 0 * 4] = a;
- m_res.elements[1 + 1 * 4] = q;
- m_res.elements[2 + 2 * 4] = b;
- m_res.elements[2 + 3 * 4] = c;
- m_res.elements[3 + 2 * 4] = -1.0f;
- return m_res;
- }
- gs_inline gs_mat4
- gs_mat4_translatev(const gs_vec3 v)
- {
- gs_mat4 m_res = gs_mat4_identity();
- m_res.elements[0 + 4 * 3] = v.x;
- m_res.elements[1 + 4 * 3] = v.y;
- m_res.elements[2 + 4 * 3] = v.z;
- return m_res;
- }
- gs_inline gs_mat4
- gs_mat4_translate(float x, float y, float z)
- {
- return gs_mat4_translatev(gs_v3(x, y, z));
- }
- gs_inline gs_mat4
- gs_mat4_scalev(const gs_vec3 v)
- {
- gs_mat4 m_res = gs_mat4_identity();
- m_res.elements[0 + 0 * 4] = v.x;
- m_res.elements[1 + 1 * 4] = v.y;
- m_res.elements[2 + 2 * 4] = v.z;
- return m_res;
- }
- gs_inline gs_mat4
- gs_mat4_scale(float x, float y, float z)
- {
- return (gs_mat4_scalev(gs_v3(x, y, z)));
- }
- // Assumes normalized axis
- gs_inline gs_mat4
- gs_mat4_rotatev(float angle, gs_vec3 axis)
- {
- gs_mat4 m_res = gs_mat4_identity();
- float a = angle;
- float c = (float)cos(a);
- float s = (float)sin(a);
- gs_vec3 naxis = gs_vec3_norm(axis);
- float x = naxis.x;
- float y = naxis.y;
- float z = naxis.z;
- //First column
- m_res.elements[0 + 0 * 4] = x * x * (1 - c) + c;
- m_res.elements[1 + 0 * 4] = x * y * (1 - c) + z * s;
- m_res.elements[2 + 0 * 4] = x * z * (1 - c) - y * s;
-
- //Second column
- m_res.elements[0 + 1 * 4] = x * y * (1 - c) - z * s;
- m_res.elements[1 + 1 * 4] = y * y * (1 - c) + c;
- m_res.elements[2 + 1 * 4] = y * z * (1 - c) + x * s;
-
- //Third column
- m_res.elements[0 + 2 * 4] = x * z * (1 - c) + y * s;
- m_res.elements[1 + 2 * 4] = y * z * (1 - c) - x * s;
- m_res.elements[2 + 2 * 4] = z * z * (1 - c) + c;
- return m_res;
- }
- gs_inline gs_mat4
- gs_mat4_rotate(float angle, float x, float y, float z)
- {
- return gs_mat4_rotatev(angle, gs_v3(x, y, z));
- }
- gs_inline gs_mat4
- gs_mat4_look_at(gs_vec3 position, gs_vec3 target, gs_vec3 up)
- {
- gs_vec3 f = gs_vec3_norm(gs_vec3_sub(target, position));
- gs_vec3 s = gs_vec3_norm(gs_vec3_cross(f, up));
- gs_vec3 u = gs_vec3_cross(s, f);
- gs_mat4 m_res = gs_mat4_identity();
- m_res.elements[0 * 4 + 0] = s.x;
- m_res.elements[1 * 4 + 0] = s.y;
- m_res.elements[2 * 4 + 0] = s.z;
- m_res.elements[0 * 4 + 1] = u.x;
- m_res.elements[1 * 4 + 1] = u.y;
- m_res.elements[2 * 4 + 1] = u.z;
- m_res.elements[0 * 4 + 2] = -f.x;
- m_res.elements[1 * 4 + 2] = -f.y;
- m_res.elements[2 * 4 + 2] = -f.z;
- m_res.elements[3 * 4 + 0] = -gs_vec3_dot(s, position);;
- m_res.elements[3 * 4 + 1] = -gs_vec3_dot(u, position);
- m_res.elements[3 * 4 + 2] = gs_vec3_dot(f, position);
- return m_res;
- }
- // Modified from github.com/CedricGuillemet/ImGuizmo/blob/master/ImGuizmo.cpp
- gs_inline
- void gs_mat4_decompose(const gs_mat4* m, float* translation, float* rotation, float* scale)
- {
- gs_mat4 mat = *m;
- scale[0] = gs_vec4_len(mat.v.right);
- scale[1] = gs_vec4_len(mat.v.up);
- scale[2] = gs_vec4_len(mat.v.dir);
- mat = gs_mat4_ortho_norm(&mat);
- rotation[0] = gs_rad2deg(atan2f(mat.m[1][2], mat.m[2][2]));
- rotation[1] = gs_rad2deg(atan2f(-mat.m[0][2], sqrtf(mat.m[1][2] * mat.m[1][2] +
- mat.m[2][2] * mat.m[2][2])));
- rotation[2] = gs_rad2deg(atan2f(mat.m[0][1], mat.m[0][0]));
- translation[0] = mat.v.position.x;
- translation[1] = mat.v.position.y;
- translation[2] = mat.v.position.z;
- }
- // Modified from github.com/CedricGuillemet/ImGuizmo/blob/master/ImGuizmo.cpp
- gs_inline
- gs_mat4 gs_mat4_recompose(const float* translation, const float* rotation, const float* scale)
- {
- gs_mat4 mat = gs_mat4_identity();
- gs_vec3 direction_unary[3] = {
- GS_XAXIS,
- GS_YAXIS,
- GS_ZAXIS
- };
- gs_mat4 rot[3] = {gs_mat4_identity(), gs_mat4_identity(), gs_mat4_identity()};
- for (uint32_t i = 0; i < 3; ++i) {
- rot[i] = gs_mat4_rotatev(gs_deg2rad(rotation[i]), direction_unary[i]);
- }
- mat = gs_mat4_mul_list(3, rot[2], rot[1], rot[0]);
- float valid_scale[3] = gs_default_val();
- for (uint32_t i = 0; i < 3; ++i) {
- valid_scale[i] = fabsf(scale[i]) < GS_EPSILON ? 0.001f : scale[i];
- }
- mat.v.right = gs_vec4_scale(mat.v.right, valid_scale[0]);
- mat.v.up = gs_vec4_scale(mat.v.up, valid_scale[1]);
- mat.v.dir = gs_vec4_scale(mat.v.dir, valid_scale[2]);
- mat.v.position = gs_v4(translation[0], translation[1], translation[2], 1.f);
- return mat;
- }
- gs_inline
- gs_vec4 gs_mat4_mul_vec4(gs_mat4 m, gs_vec4 v)
- {
- return gs_vec4_ctor
- (
- m.elements[0 + 4 * 0] * v.x + m.elements[0 + 4 * 1] * v.y + m.elements[0 + 4 * 2] * v.z + m.elements[0 + 4 * 3] * v.w,
- m.elements[1 + 4 * 0] * v.x + m.elements[1 + 4 * 1] * v.y + m.elements[1 + 4 * 2] * v.z + m.elements[1 + 4 * 3] * v.w,
- m.elements[2 + 4 * 0] * v.x + m.elements[2 + 4 * 1] * v.y + m.elements[2 + 4 * 2] * v.z + m.elements[2 + 4 * 3] * v.w,
- m.elements[3 + 4 * 0] * v.x + m.elements[3 + 4 * 1] * v.y + m.elements[3 + 4 * 2] * v.z + m.elements[3 + 4 * 3] * v.w
- );
- }
- gs_inline
- gs_vec3 gs_mat4_mul_vec3(gs_mat4 m, gs_vec3 v)
- {
- return gs_v4tov3(gs_mat4_mul_vec4(m, gs_v4_xyz_s(v, 1.f)));
- }
-
- /*================================================================================
- // Quaternion
- ================================================================================*/
- typedef struct
- {
- union
- {
- struct {
- union {
- gs_vec3 xyz;
- gs_vec3 axis;
- } axis;
- float a;
- } aa;
- gs_vec4 v;
- f32 xyzw[4];
- struct
- {
- f32 x, y, z, w;
- };
- };
- } gs_quat_t;
- typedef gs_quat_t gs_quat;
- gs_inline
- gs_quat gs_quat_default()
- {
- gs_quat q;
- q.x = 0.f;
- q.y = 0.f;
- q.z = 0.f;
- q.w = 1.f;
- return q;
- }
- gs_inline
- gs_quat gs_quat_ctor(f32 _x, f32 _y, f32 _z, f32 _w)
- {
- gs_quat q;
- q.x = _x;
- q.y = _y;
- q.z = _z;
- q.w = _w;
- return q;
- }
- gs_inline gs_quat
- gs_quat_add(gs_quat q0, gs_quat q1)
- {
- return gs_quat_ctor(q0.x + q1.x, q0.y + q1.y, q0.z + q1.z, q0.w + q1.w);
- }
- gs_inline gs_quat
- gs_quat_sub(gs_quat q0, gs_quat q1)
- {
- return gs_quat_ctor(q0.x - q1.x, q0.y - q1.y, q0.z - q1.z, q0.w - q1.w);
- }
- gs_inline gs_quat
- gs_quat_mul(gs_quat q0, gs_quat q1)
- {
- return gs_quat_ctor(
- q0.w * q1.x + q1.w * q0.x + q0.y * q1.z - q1.y * q0.z,
- q0.w * q1.y + q1.w * q0.y + q0.z * q1.x - q1.z * q0.x,
- q0.w * q1.z + q1.w * q0.z + q0.x * q1.y - q1.x * q0.y,
- q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z
- );
- }
- gs_inline
- gs_quat gs_quat_mul_list(u32 count, ...)
- {
- va_list ap;
- gs_quat q = gs_quat_default();
- va_start(ap, count);
- for (u32 i = 0; i < count; ++i)
- {
- q = gs_quat_mul(q, va_arg(ap, gs_quat));
- }
- va_end(ap);
- return q;
- }
- gs_inline gs_quat
- gs_quat_mul_quat(gs_quat q0, gs_quat q1)
- {
- return gs_quat_ctor(
- q0.w * q1.x + q1.w * q0.x + q0.y * q1.z - q1.y * q0.z,
- q0.w * q1.y + q1.w * q0.y + q0.z * q1.x - q1.z * q0.x,
- q0.w * q1.z + q1.w * q0.z + q0.x * q1.y - q1.x * q0.y,
- q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z
- );
- }
- gs_inline
- gs_quat gs_quat_scale(gs_quat q, f32 s)
- {
- return gs_quat_ctor(q.x * s, q.y * s, q.z * s, q.w * s);
- }
- gs_inline f32
- gs_quat_dot(gs_quat q0, gs_quat q1)
- {
- return (f32)(q0.x * q1.x + q0.y * q1.y + q0.z * q1.z + q0.w * q1.w);
- }
- gs_inline
- gs_quat gs_quat_conjugate(gs_quat q)
- {
- return (gs_quat_ctor(-q.x, -q.y, -q.z, q.w));
- }
- gs_inline f32
- gs_quat_len(gs_quat q)
- {
- return (f32)sqrt(gs_quat_dot(q, q));
- }
- gs_inline gs_quat
- gs_quat_norm(gs_quat q)
- {
- return gs_quat_scale(q, 1.0f / gs_quat_len(q));
- }
- gs_inline gs_quat
- gs_quat_cross(gs_quat q0, gs_quat q1)
- {
- return gs_quat_ctor (
- q0.x * q1.x + q0.x * q1.w + q0.y * q1.z - q0.z * q1.y,
- q0.w * q1.y + q0.y * q1.w + q0.z * q1.x - q0.x * q1.z,
- q0.w * q1.z + q0.z * q1.w + q0.x * q1.y - q0.y * q1.x,
- q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z
- );
- }
- // Inverse := Conjugate / Dot;
- gs_inline
- gs_quat gs_quat_inverse(gs_quat q)
- {
- return (gs_quat_scale(gs_quat_conjugate(q), 1.0f / gs_quat_dot(q, q)));
- }
- gs_inline gs_quat
- gs_quat_angle_axis(f32 rad, gs_vec3 axis)
- {
- // Normalize axis
- gs_vec3 a = gs_vec3_norm(axis);
- // Get scalar
- f32 half_angle = 0.5f * rad;
- f32 s = (float)sin(half_angle);
- return gs_quat_ctor(a.x * s, a.y * s, a.z * s, (float)cos(half_angle));
- }
- gs_inline gs_vec3
- gs_quat_rotate(gs_quat q, gs_vec3 v)
- {
- // nVidia SDK implementation
- gs_vec3 qvec = gs_vec3_ctor(q.x, q.y, q.z);
- gs_vec3 uv = gs_vec3_cross(qvec, v);
- gs_vec3 uuv = gs_vec3_cross(qvec, uv);
- uv = gs_vec3_scale(uv, 2.f * q.w);
- uuv = gs_vec3_scale(uuv, 2.f);
- return (gs_vec3_add(v, gs_vec3_add(uv, uuv)));
- }
- gs_inline gs_vec3
- gs_quat_forward(gs_quat q)
- {
- return gs_quat_rotate(q, gs_v3(0.f, 0.f, -1.f));
- }
- gs_inline gs_vec3
- gs_quat_backward(gs_quat q)
- {
- return gs_quat_rotate(q, gs_v3(0.f, 0.f, 1.f));
- }
- gs_inline gs_vec3
- gs_quat_left(gs_quat q)
- {
- return gs_quat_rotate(q, gs_v3(-1.f, 0.f, 0.f));
- }
- gs_inline gs_vec3
- gs_quat_right(gs_quat q)
- {
- return gs_quat_rotate(q, gs_v3(1.f, 0.f, 0.f));
- }
- gs_inline gs_vec3
- gs_quat_up(gs_quat q)
- {
- return gs_quat_rotate(q, gs_v3(0.f, 1.f, 0.f));
- }
- gs_inline gs_vec3
- gs_quat_down(gs_quat q)
- {
- return gs_quat_rotate(q, gs_v3(0.f, -1.f, 0.f));
- }
- gs_inline gs_quat
- gs_quat_from_to_rotation(gs_vec3 src, gs_vec3 dst)
- {
- src = gs_vec3_norm(src);
- dst = gs_vec3_norm(dst);
- const float d = gs_vec3_dot(src, dst);
- if (d >= 1.f)
- {
- return gs_quat_default();
- }
- else if (d <= -1.f)
- {
- // Orthonormalize, find axis of rotation
- gs_vec3 axis = gs_vec3_cross(src, GS_XAXIS);
- if (gs_vec3_len2(axis) < 1e-6)
- {
- axis = gs_vec3_cross(src, GS_YAXIS);
- }
- return gs_quat_angle_axis((float)GS_PI, gs_vec3_norm(axis));
- }
- else
- {
- const float s = sqrtf(gs_vec3_len2(src) * gs_vec3_len2(dst)) +
- gs_vec3_dot(src, dst);
- gs_vec3 axis = gs_vec3_cross(src, dst);
- return gs_quat_norm(gs_quat_ctor(axis.x, axis.y, axis.z, s));
- }
- }
- gs_inline
- gs_quat gs_quat_look_rotation(gs_vec3 position, gs_vec3 target, gs_vec3 up)
- {
- const gs_vec3 forward = gs_vec3_norm(gs_vec3_sub(position, target));
- const gs_quat q0 = gs_quat_from_to_rotation(GS_ZAXIS, forward);
- if (gs_vec3_len2(gs_vec3_cross(forward, up)) < 1e-6)
- {
- return q0;
- }
- const gs_vec3 new_up = gs_quat_rotate(q0, up);
- const gs_quat q1 = gs_quat_from_to_rotation(new_up, up);
- return gs_quat_mul(q1, q0);
- }
- gs_inline
- gs_quat gs_quat_slerp(gs_quat a, gs_quat b, f32 t)
- {
- f32 c = gs_quat_dot(a, b);
- gs_quat end = b;
- if (c < 0.0f)
- {
- // Reverse all signs
- c *= -1.0f;
- end.x *= -1.0f;
- end.y *= -1.0f;
- end.z *= -1.0f;
- end.w *= -1.0f;
- }
- // Calculate coefficients
- f32 sclp, sclq;
- if ((1.0f - c) > 0.0001f)
- {
- f32 omega = (float)acosf(c);
- f32 s = (float)sinf(omega);
- sclp = (float)sinf((1.0f - t) * omega) / s;
- sclq = (float)sinf(t * omega) / s;
- }
- else
- {
- sclp = 1.0f - t;
- sclq = t;
- }
- gs_quat q;
- q.x = sclp * a.x + sclq * end.x;
- q.y = sclp * a.y + sclq * end.y;
- q.z = sclp * a.z + sclq * end.z;
- q.w = sclp * a.w + sclq * end.w;
- return q;
- }
- #define quat_axis_angle(__AXS, __ANG)\
- gs_quat_angle_axis(__ANG, __AXS)
- /*
- * @brief Convert given quaternion param into equivalent 4x4 rotation matrix
- * @note: From http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.htm
- */
- gs_inline gs_mat4 gs_quat_to_mat4(gs_quat _q)
- {
- gs_mat4 mat = gs_mat4_identity();
- gs_quat q = gs_quat_norm(_q);
- f32 xx = q.x * q.x;
- f32 yy = q.y * q.y;
- f32 zz = q.z * q.z;
- f32 xy = q.x * q.y;
- f32 xz = q.x * q.z;
- f32 yz = q.y * q.z;
- f32 wx = q.w * q.x;
- f32 wy = q.w * q.y;
- f32 wz = q.w * q.z;
- mat.elements[0 * 4 + 0] = 1.0f - 2.0f * (yy + zz);
- mat.elements[1 * 4 + 0] = 2.0f * (xy - wz);
- mat.elements[2 * 4 + 0] = 2.0f * (xz + wy);
- mat.elements[0 * 4 + 1] = 2.0f * (xy + wz);
- mat.elements[1 * 4 + 1] = 1.0f - 2.0f * (xx + zz);
- mat.elements[2 * 4 + 1] = 2.0f * (yz - wx);
- mat.elements[0 * 4 + 2] = 2.0f * (xz - wy);
- mat.elements[1 * 4 + 2] = 2.0f * (yz + wx);
- mat.elements[2 * 4 + 2] = 1.0f - 2.0f * (xx + yy);
- return mat;
- }
- gs_inline
- gs_quat gs_quat_from_euler(f32 yaw_deg, f32 pitch_deg, f32 roll_deg)
- {
- f32 yaw = gs_deg2rad(yaw_deg);
- f32 pitch = gs_deg2rad(pitch_deg);
- f32 roll = gs_deg2rad(roll_deg);
- gs_quat q;
- f32 cy = (float)cos(yaw * 0.5f);
- f32 sy = (float)sin(yaw * 0.5f);
- f32 cr = (float)cos(roll * 0.5f);
- f32 sr = (float)sin(roll * 0.5f);
- f32 cp = (float)cos(pitch * 0.5f);
- f32 sp = (float)sin(pitch * 0.5f);
- q.x = cy * sr * cp - sy * cr * sp;
- q.y = cy * cr * sp + sy * sr * cp;
- q.z = sy * cr * cp - cy * sr * sp;
- q.w = cy * cr * cp + sy * sr * sp;
- return q;
- }
- gs_inline
- float gs_quat_pitch(gs_quat* q)
- {
- return atan2(2.0f * q->y * q->z + q->w * q->x, q->w * q->w - q->x * q->x - q->y * q->y + q->z * q->z);
- }
- gs_inline
- float gs_quat_yaw(gs_quat* q)
- {
- return asin(-2.0f * (q->x * q->z - q->w * q->y));
- }
- gs_inline
- float gs_quat_roll(gs_quat* q)
- {
- return atan2(2.0f * q->x * q->y + q->z * q->w, q->x * q->x + q->w * q->w - q->y * q->y - q->z * q->z);
- }
- gs_inline
- gs_vec3 gs_quat_to_euler(gs_quat* q)
- {
- return gs_v3(gs_quat_yaw(q), gs_quat_pitch(q), gs_quat_roll(q));
- }
- /*================================================================================
- // Transform (Non-Uniform Scalar VQS)
- ================================================================================*/
- /*
- - This follows a traditional 'VQS' structure for complex object transformations,
- however it differs from the standard in that it allows for non-uniform
- scaling in the form of a vec3.
- */
- // Source: https://www.eurosis.org/cms/files/conf/gameon-asia/gameon-asia2007/R-SESSION/G1.pdf
- typedef struct
- {
- union {
- gs_vec3 position;
- gs_vec3 translation;
- };
- gs_quat rotation;
- gs_vec3 scale;
- } gs_vqs_t;
- typedef gs_vqs_t gs_vqs;
- gs_inline gs_vqs
- gs_vqs_ctor(gs_vec3 tns, gs_quat rot, gs_vec3 scl)
- {
- gs_vqs t;
- t.position = tns;
- t.rotation = rot;
- t.scale = scl;
- return t;
- }
- gs_inline gs_vqs
- gs_vqs_default()
- {
- gs_vqs t = gs_vqs_ctor
- (
- gs_vec3_ctor(0.0f, 0.0f, 0.0f),
- gs_quat_ctor(0.0f, 0.0f, 0.0f, 1.0f),
- gs_vec3_ctor(1.0f, 1.0f, 1.0f)
- );
- return t;
- }
- // AbsScale = ParentScale * LocalScale
- // AbsRot = LocalRot * ParentRot
- // AbsTrans = ParentPos + [ParentRot * (ParentScale * LocalPos)]
- gs_inline gs_vqs
- gs_vqs_absolute_transform(const gs_vqs* local, const gs_vqs* parent)
- {
- if (!local || !parent) {
- return gs_vqs_default();
- }
- // Normalized rotations
- gs_quat p_rot_norm = gs_quat_norm(parent->rotation);
- gs_quat l_rot_norm = gs_quat_norm(local->rotation);
- // Scale
- gs_vec3 scl = gs_vec3_mul(local->scale, parent->scale);
- // Rotation
- gs_quat rot = gs_quat_norm(gs_quat_mul(p_rot_norm, l_rot_norm));
- // position
- gs_vec3 tns = gs_vec3_add(parent->position, gs_quat_rotate(p_rot_norm, gs_vec3_mul(parent->scale, local->position)));
- return gs_vqs_ctor(tns, rot, scl);
- }
- // RelScale = AbsScale / ParentScale
- // RelRot = Inverse(ParentRot) * AbsRot
- // RelTrans = [Inverse(ParentRot) * (AbsPos - ParentPosition)] / ParentScale;
- gs_inline gs_vqs
- gs_vqs_relative_transform(const gs_vqs* absolute, const gs_vqs* parent)
- {
- if (!absolute || !parent) {
- return gs_vqs_default();
- }
- // Get inverse rotation normalized
- gs_quat p_rot_inv = gs_quat_norm(gs_quat_inverse(parent->rotation));
- // Normalized abs rotation
- gs_quat a_rot_norm = gs_quat_norm(absolute->rotation);
- // Scale
- gs_vec3 scl = gs_vec3_div(absolute->scale, parent->scale);
- // Rotation
- gs_quat rot = gs_quat_norm(gs_quat_mul(p_rot_inv, a_rot_norm));
- // position
- gs_vec3 tns = gs_vec3_div(gs_quat_rotate(p_rot_inv, gs_vec3_sub(absolute->position, parent->position)), parent->scale);
- return gs_vqs_ctor(tns, rot, scl);
- }
- gs_inline gs_mat4
- gs_vqs_to_mat4(const gs_vqs* transform)
- {
- gs_mat4 mat = gs_mat4_identity();
- gs_mat4 trans = gs_mat4_translatev(transform->position);
- gs_mat4 rot = gs_quat_to_mat4(transform->rotation);
- gs_mat4 scl = gs_mat4_scalev(transform->scale);
- mat = gs_mat4_mul(mat, trans);
- mat = gs_mat4_mul(mat, rot);
- mat = gs_mat4_mul(mat, scl);
- return mat;
- }
- gs_inline gs_vqs
- gs_vqs_from_mat4(const gs_mat4* m)
- {
- gs_vec3 translation = gs_v3s(0.f), rotation = gs_v3s(0.f), scale = gs_v3s(1.f);
- gs_mat4_decompose(m, (float*)&translation, (float*)&rotation, (float*)&scale);
- return gs_vqs_ctor(
- translation,
- gs_quat_from_euler(rotation.x, rotation.y, rotation.z),
- scale
- );
- }
- gs_inline gs_vec3
- gs_vqs_forward(const gs_vqs* transform)
- {
- return (gs_quat_rotate(transform->rotation, gs_v3(0.0f, 0.0f, -1.0f)));
- }
- gs_inline gs_vec3
- gs_vqs_backward(const gs_vqs* transform)
- {
- return (gs_quat_rotate(transform->rotation, gs_v3(0.0f, 0.0f, 1.0f)));
- }
- gs_inline gs_vec3
- gs_vqs_left(const gs_vqs* transform)
- {
- return (gs_quat_rotate(transform->rotation, gs_v3(-1.0f, 0.0f, 0.0f)));
- }
- gs_inline gs_vec3
- gs_vqs_right(const gs_vqs* transform)
- {
- return (gs_quat_rotate(transform->rotation, gs_v3(1.0f, 0.0f, 0.0f)));
- }
- gs_inline gs_vec3
- gs_vqs_up(const gs_vqs* transform)
- {
- return (gs_quat_rotate(transform->rotation, gs_v3(0.0f, 1.0f, 0.0f)));
- }
- gs_inline gs_vec3
- gs_vqs_down(const gs_vqs* transform)
- {
- return (gs_quat_rotate(transform->rotation, gs_v3(0.0f, -1.0f, 0.0f)));
- }
- /*================================================================================
- // Random
- ================================================================================*/
- // From: https://github.com/ESultanik/mtwister
- #define GS_STATE_VECTOR_LENGTH 624
- #define GS_STATE_VECTOR_M 397 /* changes to STATE_VECTOR_LENGTH also require changes to this */
- typedef struct gs_mt_rand_t
- {
- uint64_t mt[GS_STATE_VECTOR_LENGTH];
- int32_t index;
- } gs_mt_rand_t;
- GS_API_DECL gs_mt_rand_t gs_rand_seed(uint64_t seed);
- GS_API_DECL int64_t gs_rand_gen_long(gs_mt_rand_t* rand);
- GS_API_DECL double gs_rand_gen(gs_mt_rand_t* rand);
- GS_API_DECL double gs_rand_gen_range(gs_mt_rand_t* rand, double min, double max);
- GS_API_DECL int64_t gs_rand_gen_range_long(gs_mt_rand_t* rand, int32_t min, int32_t max);
- GS_API_DECL gs_color_t gs_rand_gen_color(gs_mt_rand_t* rand);
- #ifndef GS_NO_SHORT_NAME
- typedef gs_mt_rand_t gs_rand;
- #endif
- /*================================================================================
- // Coroutine (Light wrapper around Minicoro)
- ================================================================================*/
- #define MCO_MALLOC gs_malloc
- #define MCO_FREE gs_free
- #include "external/minicoro/minicoro.h"
- typedef mco_coro gs_coro_t;
- typedef mco_desc gs_coro_desc_t;
- typedef mco_result gs_coro_result;
- // Result
- #define GS_CORO_SUCCESS MCO_SUCCESS
- #define GS_CORO_GENERIC_ERROR MCO_GENERIC_ERROR
- #define GS_CORO_INVALID_POINTER MCO_INVALID_POINTER
- #define GS_CORO_INVALID_COROUTINE MCO_INVALID_COROUTINE
- #define GS_CORO_NOT_SUSPENDED MCO_NOT_SUSPENDED
- #define GS_CORO_NOT_RUNNING MCO_NOT_RUNNING
- #define GS_CORO_MAKE_CONTEXT_ERROR MCO_MAKE_CONTEXT_ERROR
- #define GS_CORO_SWITCH_CONTEXT_ERROR MCO_SWITCH_CONTEXT_ERROR
- #define GS_CORO_NOT_ENOUGH_SPACE MCO_NOT_ENOUGH_SPACE
- #define GS_CORO_OUT_OF_MEMORY MCO_OUT_OF_MEMORY
- #define GS_CORO_INVALID_ARGUMENTS MCO_INVALID_ARGUMENTS
- #define GS_CORO_INVALID_OPERATION MCO_INVALID_OPERATION
- #define GS_CORO_STACK_OVERFLOW MCO_STACK_OVERFLOW
- // State
- #define GS_CORO_DEAD MCO_DEAD // The coroutine has finished normally or was uninitialized before finishing.
- #define GS_CORO_NORMAL MCO_NORMAL // The coroutine is active but not running (that is, it has resumed another coroutine).
- #define GS_CORO_RUNNING MCO_RUNNING // The coroutine is active and running
- #define GS_CORO_SUSPENDED MCO_SUSPENDED // The coroutine is suspended (in a call to yield, or it has not started running yet).
- // Functions
- #define gs_coro_desc_init(DESC, V) mco_desc_init((DESC), (V))
- #define gs_coro_init(CO, DESC) mco_init((CO), (DESC))
- #define gs_coro_uninit(CO) mco_uninit((CO))
- #define gs_coro_create(CO, DESC) mco_create((CO), (DESC))
- #define gs_coro_destroy(CO) mco_destroy((CO))
- #define gs_coro_yield(CO) mco_yield((CO))
- #define gs_coro_resume(CO) mco_resume((CO))
- #define gs_coro_result_description(RES) mco_result_description((RES))
- #define gs_coro_status(CO) mco_status((CO))
- /*================================================================================
- // Scheduler
- ================================================================================*/
- #include "external/sched/sched.h"
- #ifdef GS_PLATFORM_WINDOWS
- #define gs_thread_local __declspec(thread)
- #else
- #define gs_thread_local __thread
- #endif
- #define GS_SCHED_DEFAULT SCHED_DEFAULT
- #define gs_sched_fp_t sched_run
- #define gs_sched_task_t struct sched_task
- #define gs_sched_task_partition_t struct sched_task_partition
- #define gs_scheduler_t struct scheduler
- #define gs_sched_profiling_t struct sched_profiling
- #define gs_scheduler_init scheduler_init
- #define gs_scheduler_start scheduler_start
- #define gs_scheduler_add scheduler_add
- #define gs_scheduler_join scheduler_join
- #define gs_scheduler_wait scheduler_wait
- #define gs_scheduler_stop scheduler_stop
- #define gs_sched_task_done sched_task_done
- #define gs_atomic_int_t int32_t
- GS_API_DECL uint32_t
- gs_atomic_cmp_swp(volatile uint32_t *dst, uint32_t swap, uint32_t cmp);
- GS_API_DECL int32_t
- gs_atomic_add(volatile int32_t *dst, int32_t value);
- /*================================================================================
- // Noise
- ================================================================================*/
- // Perlin noise
- GS_API_DECL float gs_perlin1(float x);
- GS_API_DECL float gs_perlin2(float x, float y);
- GS_API_DECL float gs_perlin3(float x, float y, float z);
- GS_API_DECL float gs_perlin4(float x, float y, float z, float w);
- // Perlin periodic noise
- GS_API_DECL float gs_perlin1p(float x, int32_t px);
- GS_API_DECL float gs_perlin2p(float x, float y, int32_t px, int32_t py);
- GS_API_DECL float gs_perlin3p(float x, float y, float z, int32_t px, int32_t py, int32_t pz);
- GS_API_DECL float gs_perlin4p(float x, float y, float z, float w, int32_t px, int32_t py, int32_t pz, int32_t pw);
- /*================================================================================
- // Camera
- ================================================================================*/
- typedef enum gs_projection_type
- {
- GS_PROJECTION_TYPE_ORTHOGRAPHIC,
- GS_PROJECTION_TYPE_PERSPECTIVE
- } gs_projection_type;
- typedef struct gs_camera_t
- {
- gs_vqs transform;
- float fov;
- float aspect_ratio;
- float near_plane;
- float far_plane;
- float ortho_scale;
- gs_projection_type proj_type;
- } gs_camera_t;
- GS_API_DECL gs_camera_t gs_camera_default();
- GS_API_DECL gs_camera_t gs_camera_perspective();
- GS_API_DECL gs_mat4 gs_camera_get_view(const gs_camera_t* cam);
- GS_API_DECL gs_mat4 gs_camera_get_proj(const gs_camera_t* cam, int32_t view_width, int32_t view_height);
- GS_API_DECL gs_mat4 gs_camera_get_view_projection(const gs_camera_t* cam, int32_t view_width, int32_t view_height);
- GS_API_DECL gs_vec3 gs_camera_forward(const gs_camera_t* cam);
- GS_API_DECL gs_vec3 gs_camera_backward(const gs_camera_t* cam);
- GS_API_DECL gs_vec3 gs_camera_up(const gs_camera_t* cam);
- GS_API_DECL gs_vec3 gs_camera_down(const gs_camera_t* cam);
- GS_API_DECL gs_vec3 gs_camera_right(const gs_camera_t* cam);
- GS_API_DECL gs_vec3 gs_camera_left(const gs_camera_t* cam);
- GS_API_DECL gs_vec3 gs_camera_screen_to_world(const gs_camera_t* cam, gs_vec3 coords, int32_t view_x, int32_t view_y, int32_t view_width, int32_t view_height);
- GS_API_DECL gs_vec3 gs_camera_world_to_screen(const gs_camera_t* cam, gs_vec3 coords, int32_t view_width, int32_t view_height);
- GS_API_DECL void gs_camera_offset_orientation(gs_camera_t* cam, float yaw, float picth);
- /*================================================================================
- // Utils
- ================================================================================*/
- // AABBs
- /*
- min is top left of rect,
- max is bottom right
- */
- /*
- typedef struct gs_aabb_t
- {
- gs_vec2 min;
- gs_vec2 max;
- } gs_aabb_t;
- // Collision Resolution: Minimum Translation Vector
- gs_force_inline
- gs_vec2 gs_aabb_aabb_mtv(gs_aabb_t* a0, gs_aabb_t* a1)
- {
- gs_vec2 diff = gs_v2(a0->min.x - a1->min.x, a0->min.y - a1->min.y);
- f32 l, r, b, t;
- gs_vec2 mtv = gs_v2(0.f, 0.f);
- l = a1->min.x - a0->max.x;
- r = a1->max.x - a0->min.x;
- b = a1->min.y - a0->max.y;
- t = a1->max.y - a0->min.y;
- mtv.x = fabsf(l) > r ? r : l;
- mtv.y = fabsf(b) > t ? t : b;
- if ( fabsf(mtv.x) <= fabsf(mtv.y)) {
- mtv.y = 0.f;
- } else {
- mtv.x = 0.f;
- }
-
- return mtv;
- }
- // 2D AABB collision detection (rect. vs. rect.)
- gs_force_inline
- b32 gs_aabb_vs_aabb(gs_aabb_t* a, gs_aabb_t* b)
- {
- if (a->max.x > b->min.x &&
- a->max.y > b->min.y &&
- a->min.x < b->max.x &&
- a->min.y < b->max.y)
- {
- return true;
- }
- return false;
- }
- gs_force_inline
- gs_vec4 gs_aabb_window_coords(gs_aabb_t* aabb, gs_camera_t* camera, gs_vec2 window_size)
- {
- // AABB of the player
- gs_vec4 bounds = gs_default_val();
- gs_vec4 tl = gs_v4(aabb->min.x, aabb->min.y, 0.f, 1.f);
- gs_vec4 br = gs_v4(aabb->max.x, aabb->max.y, 0.f, 1.f);
- gs_mat4 view_mtx = gs_camera_get_view(camera);
- gs_mat4 proj_mtx = gs_camera_get_proj(camera, (int32_t)window_size.x, (int32_t)window_size.y);
- gs_mat4 vp = gs_mat4_mul(proj_mtx, view_mtx);
- // Transform verts
- tl = gs_mat4_mul_vec4(vp, tl);
- br = gs_mat4_mul_vec4(vp, br);
- // Perspective divide
- tl = gs_vec4_scale(tl, 1.f / tl.w);
- br = gs_vec4_scale(br, 1.f / br.w);
- // NDC [0.f, 1.f] and NDC
- tl.x = (tl.x * 0.5f + 0.5f);
- tl.y = (tl.y * 0.5f + 0.5f);
- br.x = (br.x * 0.5f + 0.5f);
- br.y = (br.y * 0.5f + 0.5f);
- // Window Space
- tl.x = tl.x * window_size.x;
- tl.y = gs_map_range(1.f, 0.f, 0.f, 1.f, tl.y) * window_size.y;
- br.x = br.x * window_size.x;
- br.y = gs_map_range(1.f, 0.f, 0.f, 1.f, br.y) * window_size.y;
- bounds = gs_v4(tl.x, tl.y, br.x, br.y);
- return bounds;
- }
- */
- /** @} */ // end of gs_math
- /*========================
- // GS_LEXER
- ========================*/
- //==== [ Token ] ============================================================//
- typedef enum gs_token_type
- {
- GS_TOKEN_UNKNOWN = 0x00,
- GS_TOKEN_LPAREN,
- GS_TOKEN_RPAREN,
- GS_TOKEN_LTHAN,
- GS_TOKEN_GTHAN,
- GS_TOKEN_SEMICOLON,
- GS_TOKEN_COLON,
- GS_TOKEN_COMMA,
- GS_TOKEN_EQUAL,
- GS_TOKEN_EEQUAL,
- GS_TOKEN_NEQUAL,
- GS_TOKEN_LEQUAL,
- GS_TOKEN_GEQUAL,
- GS_TOKEN_NOT,
- GS_TOKEN_HASH,
- GS_TOKEN_PIPE,
- GS_TOKEN_AMPERSAND,
- GS_TOKEN_AND,
- GS_TOKEN_OR,
- GS_TOKEN_XOR,
- GS_TOKEN_NEGATE,
- GS_TOKEN_LBRACE,
- GS_TOKEN_RBRACE,
- GS_TOKEN_LBRACKET,
- GS_TOKEN_RBRACKET,
- GS_TOKEN_MINUS,
- GS_TOKEN_PLUS,
- GS_TOKEN_ASTERISK,
- GS_TOKEN_BSLASH,
- GS_TOKEN_FSLASH,
- GS_TOKEN_QMARK,
- GS_TOKEN_SPACE,
- GS_TOKEN_PERCENT,
- GS_TOKEN_DOLLAR,
- GS_TOKEN_NEWLINE,
- GS_TOKEN_TAB,
- GS_TOKEN_UNDERSCORE,
- GS_TOKEN_SINGLE_LINE_COMMENT,
- GS_TOKEN_MULTI_LINE_COMMENT,
- GS_TOKEN_IDENTIFIER,
- GS_TOKEN_SINGLE_QUOTE,
- GS_TOKEN_DOUBLE_QUOTE,
- GS_TOKEN_STRING,
- GS_TOKEN_PERIOD,
- GS_TOKEN_NUMBER,
- GS_TOKEN_KEYWORD,
- GS_TOKEN_COUNT // Max tokens accounted for
- } gs_token_type;
- typedef struct gs_token_t
- {
- const char* text;
- gs_token_type type;
- uint32_t len;
- uint32_t line;
- } gs_token_t;
- GS_API_DECL gs_token_t gs_token_invalid_token();
- GS_API_DECL bool gs_token_compare_type(const gs_token_t* t, gs_token_type type);
- GS_API_DECL bool gs_token_compare_text(const gs_token_t* t, const char* match);
- GS_API_DECL void gs_token_print_text(const gs_token_t* t);
- GS_API_DECL void gs_token_debug_print(const gs_token_t* t);
- GS_API_DECL const char* gs_token_type_to_str(gs_token_type type);
- GS_API_DECL bool gs_char_is_end_of_line(char c);
- GS_API_DECL bool gs_char_is_white_space(char c);
- GS_API_DECL bool gs_char_is_alpha(char c);
- GS_API_DECL bool gs_char_is_numeric(char c);
- //==== [ Lexer ] ============================================================//
- typedef struct gs_lexer_t
- {
- const char* at;
- const char* contents;
- gs_token_t current_token;
- bool (* can_lex)(struct gs_lexer_t* lex);
- void (* eat_white_space)(struct gs_lexer_t* lex);
- gs_token_t (* next_token)(struct gs_lexer_t*);
- bool32 skip_white_space;
- size_t size; // Optional
- size_t contents_size; // Optional
- uint32_t line; // Line number
- } gs_lexer_t;
- GS_API_DECL void gs_lexer_set_contents(gs_lexer_t* lex, const char* contents);
- GS_API_DECL gs_token_t gs_lexer_next_token(gs_lexer_t* lex);
- GS_API_DECL bool gs_lexer_can_lex(gs_lexer_t* lex);
- GS_API_DECL gs_token_t gs_lexer_current_token(const gs_lexer_t* lex);
- GS_API_DECL bool gs_lexer_require_token_text(gs_lexer_t* lex, const char* match);
- GS_API_DECL bool gs_lexer_require_token_type(gs_lexer_t* lex, gs_token_type type);
- GS_API_DECL bool gs_lexer_current_token_compare_type(const gs_lexer_t* lex, gs_token_type type);
- GS_API_DECL gs_token_t gs_lexer_peek(gs_lexer_t* lex);
- GS_API_DECL bool gs_lexer_find_next_token_type(gs_lexer_t* lex, gs_token_type type);
- GS_API_DECL gs_token_t gs_lexer_advance_before_next_token_type(gs_lexer_t* lex, gs_token_type type);
- // C specific functions for lexing
- GS_API_DECL gs_lexer_t gs_lexer_c_ctor(const char* contents);
- GS_API_DECL bool gs_lexer_c_can_lex(gs_lexer_t* lex);
- GS_API_DECL void gs_lexer_c_eat_white_space(gs_lexer_t* lex);
- GS_API_DECL gs_token_t gs_lexer_c_next_token(gs_lexer_t* lex);
- /*========================
- // GS_PLATFORM
- ========================*/
- /** @defgroup gs_platform Platform
- * Gunslinger Platform
- * @{
- */
- /*============================================================
- // Platform Time
- ============================================================*/
- typedef struct gs_platform_time_t
- {
- float max_fps;
- float elapsed;
- float previous;
- float update;
- float render;
- float delta;
- float frame;
- } gs_platform_time_t;
- /*============================================================
- // Platform UUID
- ============================================================*/
- #define GS_UUID_STR_SIZE_CONSTANT 32
- // 33 characters, all set to 0
- #define gs_uuid_temp_str_buffer()\
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- typedef struct gs_uuid_t
- {
- uint8_t bytes[16];
- } gs_uuid_t;
- /*============================================================
- // Platform Window
- ============================================================*/
- #define GS_WINDOW_FLAGS_NO_RESIZE 0x01
- #define GS_WINDOW_FLAGS_FULLSCREEN 0x02
- #define GS_WINDOW_FLAGS_INVISIBLE 0x03
- // Should have an internal resource cache of window handles (controlled by the platform api)
- typedef struct gs_platform_window_desc_t
- {
- const char* title;
- uint32_t width;
- uint32_t height;
- uint32_t flags;
- uint32_t num_samples; // Multisamples (if 0, then disabled)
- uint32_t monitor_index;
- bool32 vsync;
- float frame_rate;
- } gs_platform_window_desc_t;
- typedef struct gs_platform_window_s
- {
- void* hndl;
- gs_vec2 framebuffer_size;
- gs_vec2 window_size;
- gs_vec2 window_position;
- } gs_platform_window_t;
- typedef enum gs_platform_cursor
- {
- GS_PLATFORM_CURSOR_ARROW,
- GS_PLATFORM_CURSOR_IBEAM,
- GS_PLATFORM_CURSOR_SIZE_NW_SE,
- GS_PLATFORM_CURSOR_SIZE_NE_SW,
- GS_PLATFORM_CURSOR_SIZE_NS,
- GS_PLATFORM_CURSOR_SIZE_WE,
- GS_PLATFORM_CURSOR_SIZE_ALL,
- GS_PLATFORM_CURSOR_HAND,
- GS_PLATFORM_CURSOR_NO,
- GS_PLATFORM_CURSOR_COUNT
- } gs_platform_cursor;
- typedef enum gs_platform_keycode
- {
- GS_KEYCODE_INVALID,
- GS_KEYCODE_SPACE,
- GS_KEYCODE_APOSTROPHE, /* ' */
- GS_KEYCODE_COMMA, /* , */
- GS_KEYCODE_MINUS, /* - */
- GS_KEYCODE_PERIOD, /* . */
- GS_KEYCODE_SLASH, /* / */
- GS_KEYCODE_0,
- GS_KEYCODE_1,
- GS_KEYCODE_2,
- GS_KEYCODE_3,
- GS_KEYCODE_4,
- GS_KEYCODE_5,
- GS_KEYCODE_6,
- GS_KEYCODE_7,
- GS_KEYCODE_8,
- GS_KEYCODE_9,
- GS_KEYCODE_SEMICOLON, /* ; */
- GS_KEYCODE_EQUAL, /* = */
- GS_KEYCODE_A,
- GS_KEYCODE_B,
- GS_KEYCODE_C,
- GS_KEYCODE_D,
- GS_KEYCODE_E,
- GS_KEYCODE_F,
- GS_KEYCODE_G,
- GS_KEYCODE_H,
- GS_KEYCODE_I,
- GS_KEYCODE_J,
- GS_KEYCODE_K,
- GS_KEYCODE_L,
- GS_KEYCODE_M,
- GS_KEYCODE_N,
- GS_KEYCODE_O,
- GS_KEYCODE_P,
- GS_KEYCODE_Q,
- GS_KEYCODE_R,
- GS_KEYCODE_S,
- GS_KEYCODE_T,
- GS_KEYCODE_U,
- GS_KEYCODE_V,
- GS_KEYCODE_W,
- GS_KEYCODE_X,
- GS_KEYCODE_Y,
- GS_KEYCODE_Z,
- GS_KEYCODE_LEFT_BRACKET, /* [ */
- GS_KEYCODE_BACKSLASH, /* \ */
- GS_KEYCODE_RIGHT_BRACKET, /* ] */
- GS_KEYCODE_GRAVE_ACCENT, /* ` */
- GS_KEYCODE_WORLD_1, /* non-US #1 */
- GS_KEYCODE_WORLD_2, /* non-US #2 */
- GS_KEYCODE_ESC,
- GS_KEYCODE_ENTER,
- GS_KEYCODE_TAB,
- GS_KEYCODE_BACKSPACE,
- GS_KEYCODE_INSERT,
- GS_KEYCODE_DELETE,
- GS_KEYCODE_RIGHT,
- GS_KEYCODE_LEFT,
- GS_KEYCODE_DOWN,
- GS_KEYCODE_UP,
- GS_KEYCODE_PAGE_UP,
- GS_KEYCODE_PAGE_DOWN,
- GS_KEYCODE_HOME,
- GS_KEYCODE_END,
- GS_KEYCODE_CAPS_LOCK,
- GS_KEYCODE_SCROLL_LOCK,
- GS_KEYCODE_NUM_LOCK,
- GS_KEYCODE_PRINT_SCREEN,
- GS_KEYCODE_PAUSE,
- GS_KEYCODE_F1,
- GS_KEYCODE_F2,
- GS_KEYCODE_F3,
- GS_KEYCODE_F4,
- GS_KEYCODE_F5,
- GS_KEYCODE_F6,
- GS_KEYCODE_F7,
- GS_KEYCODE_F8,
- GS_KEYCODE_F9,
- GS_KEYCODE_F10,
- GS_KEYCODE_F11,
- GS_KEYCODE_F12,
- GS_KEYCODE_F13,
- GS_KEYCODE_F14,
- GS_KEYCODE_F15,
- GS_KEYCODE_F16,
- GS_KEYCODE_F17,
- GS_KEYCODE_F18,
- GS_KEYCODE_F19,
- GS_KEYCODE_F20,
- GS_KEYCODE_F21,
- GS_KEYCODE_F22,
- GS_KEYCODE_F23,
- GS_KEYCODE_F24,
- GS_KEYCODE_F25,
- GS_KEYCODE_KP_0,
- GS_KEYCODE_KP_1,
- GS_KEYCODE_KP_2,
- GS_KEYCODE_KP_3,
- GS_KEYCODE_KP_4,
- GS_KEYCODE_KP_5,
- GS_KEYCODE_KP_6,
- GS_KEYCODE_KP_7,
- GS_KEYCODE_KP_8,
- GS_KEYCODE_KP_9,
- GS_KEYCODE_KP_DECIMAL,
- GS_KEYCODE_KP_DIVIDE,
- GS_KEYCODE_KP_MULTIPLY,
- GS_KEYCODE_KP_SUBTRACT,
- GS_KEYCODE_KP_ADD,
- GS_KEYCODE_KP_ENTER,
- GS_KEYCODE_KP_EQUAL,
- GS_KEYCODE_LEFT_SHIFT,
- GS_KEYCODE_LEFT_CONTROL,
- GS_KEYCODE_LEFT_ALT,
- GS_KEYCODE_LEFT_SUPER,
- GS_KEYCODE_RIGHT_SHIFT,
- GS_KEYCODE_RIGHT_CONTROL,
- GS_KEYCODE_RIGHT_ALT,
- GS_KEYCODE_RIGHT_SUPER,
- GS_KEYCODE_MENU,
- GS_KEYCODE_COUNT
- } gs_platform_keycode;
- #define GS_KEYCODE_LCTRL GS_KEYCODE_LEFT_CONTROL
- #define GS_KEYCODE_RCTRL GS_KEYCODE_RIGHT_CONTROL
- #define GS_KEYCODE_LSHIFT GS_KEYCODE_LEFT_SHIFT
- #define GS_KEYCODE_RSHIFT GS_KEYCODE_RIGHT_SHIFT
- #define GS_KEYCODE_LALT GS_KEYCODE_LEFT_ALT
- #define GS_KEYCODE_RALT GS_KEYCODE_RIGHT_ALT
- typedef enum gs_platform_mouse_button_code
- {
- GS_MOUSE_LBUTTON,
- GS_MOUSE_RBUTTON,
- GS_MOUSE_MBUTTON,
- GS_MOUSE_BUTTON_CODE_COUNT
- } gs_platform_mouse_button_code;
- typedef struct gs_platform_mouse_t
- {
- b32 button_map[GS_MOUSE_BUTTON_CODE_COUNT];
- b32 prev_button_map[GS_MOUSE_BUTTON_CODE_COUNT];
- gs_vec2 position;
- gs_vec2 delta;
- gs_vec2 wheel;
- b32 moved_this_frame;
- b32 locked;
- } gs_platform_mouse_t;
- enum
- {
- GS_PLATFORM_GAMEPAD_BUTTON_A = 0x00,
- GS_PLATFORM_GAMEPAD_BUTTON_B,
- GS_PLATFORM_GAMEPAD_BUTTON_X,
- GS_PLATFORM_GAMEPAD_BUTTON_Y,
- GS_PLATFORM_GAMEPAD_BUTTON_LBUMPER,
- GS_PLATFORM_GAMEPAD_BUTTON_RBUMPER,
- GS_PLATFORM_GAMEPAD_BUTTON_BACK,
- GS_PLATFORM_GAMEPAD_BUTTON_START,
- GS_PLATFORM_GAMEPAD_BUTTON_GUIDE,
- GS_PLATFORM_GAMEPAD_BUTTON_LTHUMB,
- GS_PLATFORM_GAMEPAD_BUTTON_RTHUMB,
- GS_PLATFORM_GAMEPAD_BUTTON_DPUP,
- GS_PLATFORM_GAMEPAD_BUTTON_DPRIGHT,
- GS_PLATFORM_GAMEPAD_BUTTON_DPDOWN,
- GS_PLATFORM_GAMEPAD_BUTTON_DPLEFT,
- GS_PLATFORM_GAMEPAD_BUTTON_COUNT
- };
- #define GS_PLATFORM_GAMEPAD_BUTTON_LAST GS_PLATFORM_GAMEPAD_BUTTON_DPLEFT
- #define GS_PLATFORM_GAMEPAD_BUTTON_CROSS GS_PLATFORM_GAMEPAD_BUTTON_A
- #define GS_PLATFORM_GAMEPAD_BUTTON_CIRCLE GS_PLATFORM_GAMEPAD_BUTTON_B
- #define GS_PLATFORM_GAMEPAD_BUTTON_SQUARE GS_PLATFORM_GAMEPAD_BUTTON_X
- #define GS_PLATFORM_GAMEPAD_BUTTON_TRIANGLE GS_PLATFORM_GAMEPAD_BUTTON_Y
- enum
- {
- GS_PLATFORM_JOYSTICK_AXIS_LEFT_X = 0x00,
- GS_PLATFORM_JOYSTICK_AXIS_LEFT_Y,
- GS_PLATFORM_JOYSTICK_AXIS_RIGHT_X,
- GS_PLATFORM_JOYSTICK_AXIS_RIGHT_Y,
- GS_PLATFORM_JOYSTICK_AXIS_LTRIGGER,
- GS_PLATFORM_JOYSTICK_AXIS_RTRIGGER,
- GS_PLATFORM_JOYSTICK_AXIS_COUNT
- };
- #define GS_PLATFORM_GAMEPAD_MAX 16
- typedef struct gs_platform_gamepad_t
- {
- int16_t buttons[GS_PLATFORM_GAMEPAD_BUTTON_COUNT];
- float axes[GS_PLATFORM_JOYSTICK_AXIS_COUNT];
- int16_t present;
- } gs_platform_gamepad_t;
- #define GS_PLATFORM_MAX_TOUCH 5
- typedef struct gs_platform_touchpoint_t
- {
- size_t id;
- gs_vec2 position;
- gs_vec2 delta;
- uint16_t changed;
- uint16_t pressed;
- uint16_t down;
- } gs_platform_touchpoint_t;
- typedef struct gs_platform_touch_t
- {
- gs_platform_touchpoint_t points[GS_PLATFORM_MAX_TOUCH];
- uint16_t size; // Current number of touches active
- } gs_platform_touch_t;
- typedef struct gs_platform_input_t
- {
- b32 key_map[GS_KEYCODE_COUNT];
- b32 prev_key_map[GS_KEYCODE_COUNT];
- gs_platform_mouse_t mouse;
- gs_platform_touch_t touch;
- gs_platform_gamepad_t gamepads[GS_PLATFORM_GAMEPAD_MAX];
- } gs_platform_input_t;
- // Enumeration of all platform types
- typedef enum gs_platform_type
- {
- GS_PLATFORM_TYPE_UNKNOWN = 0,
- GS_PLATFORM_TYPE_WINDOWS,
- GS_PLATFORM_TYPE_LINUX,
- GS_PLATFORM_TYPE_MAC,
- GS_PLATFORM_TYPE_ANDROID,
- GS_PLATFORM_TYPE_IOS,
- GS_PLATFORM_TYPE_HTML5,
- GS_PLATFORM_TYPE_RPI
- } gs_platform_type;
- typedef enum gs_platform_video_driver_type
- {
- GS_PLATFORM_VIDEO_DRIVER_TYPE_NONE = 0,
- GS_PLATFORM_VIDEO_DRIVER_TYPE_OPENGL,
- GS_PLATFORM_VIDEO_DRIVER_TYPE_OPENGLES,
- GS_PLATFORM_VIDEO_DRIVER_TYPE_DIRECTX,
- GS_PLATFORM_VIDEO_DRIVER_TYPE_VULKAN,
- GS_PLATFORM_VIDEO_DRIVER_TYPE_METAL,
- GS_PLATFORM_VIDEO_DRIVER_TYPE_SOFTWARE
- } gs_platform_video_driver_type;
- typedef enum gs_opengl_compatibility_flags
- {
- GS_OPENGL_COMPATIBILITY_FLAGS_LEGACY = 0,
- GS_OPENGL_COMPATIBILITY_FLAGS_CORE = 1 << 1,
- GS_OPENGL_COMPATIBILITY_FLAGS_COMPATIBILITY = 1 << 2,
- GS_OPENGL_COMPATIBILITY_FLAGS_FORWARD = 1 << 3,
- GS_OPENGL_COMPATIBILITY_FLAGS_ES = 1 << 4,
- } gs_opengl_compatibility_flags;
- // A structure that contains OpenGL video settings
- typedef struct gs_opengl_video_settings_t
- {
- gs_opengl_compatibility_flags compability_flags;
- uint32_t major_version;
- uint32_t minor_version;
- uint8_t multi_sampling_count;
- void* ctx;
- } gs_opengl_video_settings_t;
-
- typedef union gs_graphics_api_settings_t
- {
- gs_opengl_video_settings_t opengl;
- bool32 debug;
- } gs_graphics_api_settings_t;
- typedef struct gs_platform_video_settings_t
- {
- gs_graphics_api_settings_t graphics;
- gs_platform_video_driver_type driver;
- b32 vsync_enabled;
- } gs_platform_video_settings_t;
- typedef struct gs_platform_settings_t
- {
- gs_platform_video_settings_t video;
- } gs_platform_settings_t;
- typedef enum gs_platform_event_type
- {
- GS_PLATFORM_EVENT_MOUSE,
- GS_PLATFORM_EVENT_KEY,
- GS_PLATFORM_EVENT_TEXT,
- GS_PLATFORM_EVENT_WINDOW,
- GS_PLATFORM_EVENT_TOUCH,
- GS_PLATFORM_EVENT_APP
- } gs_platform_event_type;
- typedef enum gs_platform_key_modifier_type
- {
- GS_PLATFORM_KEY_MODIFIER_NONE = 0x00,
- GS_PLATFORM_KEY_MODIFIER_SHIFT = 0x01,
- GS_PLATFORM_KEY_MODIFIER_CONTROL = 0x02,
- GS_PLATFORM_KEY_MODIFIER_ALT = 0x04
- } gs_platform_key_modifier_type;
- typedef enum gs_platform_key_action_type
- {
- GS_PLATFORM_KEY_PRESSED,
- GS_PLATFORM_KEY_DOWN,
- GS_PLATFORM_KEY_RELEASED
- } gs_platform_key_action_type;
- typedef struct gs_platform_key_event_t
- {
- int32_t codepoint;
- gs_platform_keycode keycode;
- gs_platform_key_action_type action;
- gs_platform_key_modifier_type modifier;
- } gs_platform_key_event_t;
- typedef enum gs_platform_mousebutton_action_type
- {
- GS_PLATFORM_MOUSE_BUTTON_PRESSED,
- GS_PLATFORM_MOUSE_BUTTON_DOWN,
- GS_PLATFORM_MOUSE_BUTTON_RELEASED,
- GS_PLATFORM_MOUSE_MOVE,
- GS_PLATFORM_MOUSE_ENTER,
- GS_PLATFORM_MOUSE_LEAVE,
- GS_PLATFORM_MOUSE_WHEEL
- } gs_platform_mousebutton_action_type;
- typedef struct gs_platform_mouse_event_t
- {
- int32_t codepoint;
- union {
- gs_platform_mouse_button_code button;
- gs_vec2 wheel;
- gs_vec2 move;
- };
- gs_platform_mousebutton_action_type action;
- } gs_platform_mouse_event_t;
- typedef enum gs_platform_window_action_type
- {
- GS_PLATFORM_WINDOW_RESIZE,
- GS_PLATFORM_WINDOW_LOSE_FOCUS,
- GS_PLATFORM_WINDOW_GAIN_FOCUS,
- GS_PLATFORM_WINDOW_CREATE,
- GS_PLATFORM_WINDOW_DESTROY
- } gs_platform_window_action_type;
- typedef struct gs_platform_window_event_t
- {
- uint32_t hndl;
- gs_platform_window_action_type action;
- } gs_platform_window_event_t;
- typedef struct gs_platform_text_event_t
- {
- uint32_t codepoint;
- } gs_platform_text_event_t;
- typedef enum gs_platform_touch_action_type
- {
- GS_PLATFORM_TOUCH_DOWN,
- GS_PLATFORM_TOUCH_UP,
- GS_PLATFORM_TOUCH_MOVE,
- GS_PLATFORM_TOUCH_CANCEL
- } gs_platform_touch_action_type;
- typedef struct gs_platform_point_event_data_t {
- uintptr_t id;
- gs_vec2 position;
- uint16_t changed;
- } gs_platform_point_event_data_t;
- typedef struct gs_platform_touch_event_t
- {
- gs_platform_touch_action_type action;
- gs_platform_point_event_data_t point;
- } gs_platform_touch_event_t;
- typedef enum gs_platform_app_action_type
- {
- GS_PLATFORM_APP_START,
- GS_PLATFORM_APP_PAUSE,
- GS_PLATFORM_APP_RESUME,
- GS_PLATFORM_APP_STOP
- } gs_platform_app_action_type;
- typedef struct gs_platform_app_event_t
- {
- gs_platform_app_action_type action;
- } gs_platform_app_event_t;
- // Platform events
- typedef struct gs_platform_event_t
- {
- gs_platform_event_type type;
- union {
- gs_platform_key_event_t key;
- gs_platform_mouse_event_t mouse;
- gs_platform_window_event_t window;
- gs_platform_touch_event_t touch;
- gs_platform_app_event_t app;
- gs_platform_text_event_t text;
- };
- uint32_t idx;
- } gs_platform_event_t;
- // Necessary function pointer typedefs
- typedef void (* gs_dropped_files_callback_t)(void*, int32_t count, const char** file_paths);
- typedef void (* gs_window_close_callback_t)(void*);
- typedef void (* gs_character_callback_t)(void*, uint32_t code_point);
- typedef void (* gs_framebuffer_resize_callback_t)(void*, int32_t width, int32_t height);
- /*===============================================================================================
- // Platform Interface
- ===============================================================================================*/
- struct gs_platform_interface_s;
- typedef struct gs_platform_t
- {
- // Settings for platform, including video
- gs_platform_settings_t settings;
- // Time
- gs_platform_time_t time;
- // Input
- gs_platform_input_t input;
- // Window data and handles
- gs_slot_array(gs_platform_window_t) windows;
- // Events that user can poll
- gs_dyn_array(gs_platform_event_t) events;
- // Cursors
- void* cursors[GS_PLATFORM_CURSOR_COUNT];
- // Specific user data (for custom implementations)
- void* user_data;
- // Optional api for stable access across .dll boundaries
- struct gs_platform_interface_s* api;
- } gs_platform_t;
- /*===============================================================================================
- // Platform API
- ===============================================================================================*/
- /* == Platform Default API == */
- // Platform Create / Destroy
- GS_API_DECL gs_platform_t* gs_platform_create();
- GS_API_DECL void gs_platform_destroy(gs_platform_t* platform);
- // Platform Init / Update / Shutdown
- GS_API_DECL void gs_platform_update(gs_platform_t* platform); // Update platform layer
- // Platform Util
- GS_API_DECL const gs_platform_time_t* gs_platform_time();
- GS_API_DECL float gs_platform_delta_time();
- GS_API_DECL float gs_platform_frame_time();
- // Platform UUID
- GS_API_DECL gs_uuid_t gs_platform_uuid_generate();
- GS_API_DECL void gs_platform_uuid_to_string(char* temp_buffer, const gs_uuid_t* uuid); // Expects a temp buffer with at least 32 bytes
- GS_API_DECL uint32_t gs_platform_uuid_hash(const gs_uuid_t* uuid);
- // Platform Input
- GS_API_DECL gs_platform_input_t* gs_platform_input();
- GS_API_DECL void gs_platform_update_input(gs_platform_input_t* input);
- GS_API_DECL void gs_platform_press_key(gs_platform_keycode code);
- GS_API_DECL void gs_platform_release_key(gs_platform_keycode code);
- GS_API_DECL bool gs_platform_was_key_down(gs_platform_keycode code);
- GS_API_DECL void gs_platform_press_mouse_button(gs_platform_mouse_button_code code);
- GS_API_DECL void gs_platform_release_mouse_button(gs_platform_mouse_button_code code);
- GS_API_DECL bool gs_platform_was_mouse_down(gs_platform_mouse_button_code code);
- GS_API_DECL void gs_platform_press_touch(uint32_t idx);
- GS_API_DECL void gs_platform_release_touch(uint32_t idx);
- GS_API_DECL bool gs_platform_was_touch_down(uint32_t idx);
- GS_API_DECL bool gs_platform_key_pressed(gs_platform_keycode code);
- GS_API_DECL bool gs_platform_key_down(gs_platform_keycode code);
- GS_API_DECL bool gs_platform_key_released(gs_platform_keycode code);
- GS_API_DECL bool gs_platform_touch_pressed(uint32_t idx);
- GS_API_DECL bool gs_platform_touch_down(uint32_t idx);
- GS_API_DECL bool gs_platform_touch_released(uint32_t idx);
- GS_API_DECL bool gs_platform_mouse_pressed(gs_platform_mouse_button_code code);
- GS_API_DECL bool gs_platform_mouse_down(gs_platform_mouse_button_code code);
- GS_API_DECL bool gs_platform_mouse_released(gs_platform_mouse_button_code code);
- GS_API_DECL gs_vec2 gs_platform_mouse_deltav();
- GS_API_DECL void gs_platform_mouse_delta(float* x, float* y);
- GS_API_DECL gs_vec2 gs_platform_mouse_positionv();
- GS_API_DECL void gs_platform_mouse_position(int32_t* x, int32_t* y);
- GS_API_DECL void gs_platform_mouse_wheel(float* x, float* y);
- GS_API_DECL gs_vec2 gs_platform_mouse_wheelv();
- GS_API_DECL bool gs_platform_mouse_moved();
- GS_API_DECL bool gs_platform_mouse_locked();
- GS_API_DECL gs_vec2 gs_platform_touch_deltav(uint32_t idx);
- GS_API_DECL void gs_platform_touch_delta(uint32_t idx, float* x, float* y);
- GS_API_DECL gs_vec2 gs_platform_touch_positionv(uint32_t idx);
- GS_API_DECL void gs_platform_touch_position(uint32_t idx, float* x, float* y);
- // Platform Events
- GS_API_DECL bool gs_platform_poll_events(gs_platform_event_t* evt, bool32_t consume);
- GS_API_DECL void gs_platform_add_event(gs_platform_event_t* evt);
- // Platform Window
- GS_API_DECL uint32_t gs_platform_window_create(const gs_platform_window_desc_t* desc);
- GS_API_DECL uint32_t gs_platform_main_window();
- GS_API_DECL void gs_platform_window_make_current(uint32_t hndl); // Binds context (main thread only)
- GS_API_DECL void gs_platform_window_make_current_raw(void* win); // Binds context (can be on separate thread with raw handle)
- typedef struct gs_platform_file_stats_s
- {
- uint64_t modified_time;
- uint64_t creation_time;
- uint64_t access_time;
- } gs_platform_file_stats_t;
- // Platform File IO (this all needs to be made available for impl rewrites)
- GS_API_DECL char* gs_platform_read_file_contents_default_impl(const char* file_path, const char* mode, size_t* sz);
- GS_API_DECL gs_result gs_platform_write_file_contents_default_impl(const char* file_path, const char* mode, void* data, size_t data_size);
- GS_API_DECL bool gs_platform_file_exists_default_impl(const char* file_path);
- GS_API_DECL bool gs_platform_dir_exists_default_impl(const char* dir_path);
- GS_API_DECL int32_t gs_platform_mkdir_default_impl(const char* dir_path, int32_t opt);
- GS_API_DECL int32_t gs_platform_file_size_in_bytes_default_impl(const char* file_path);
- GS_API_DECL void gs_platform_file_extension_default_impl(char* buffer, size_t buffer_sz, const char* file_path);
- GS_API_DECL int32_t gs_platform_file_delete_default_impl(const char* file_path);
- GS_API_DECL int32_t gs_platform_file_copy_default_impl(const char* src_path, const char* dst_path);
- GS_API_DECL int32_t gs_platform_file_compare_time(uint64_t time_a, uint64_t time_b);
- GS_API_DECL gs_platform_file_stats_t gs_platform_file_stats(const char* file_path);
- GS_API_DECL void* gs_platform_library_load_default_impl(const char* lib_path);
- GS_API_DECL void gs_platform_library_unload_default_impl(void* lib);
- GS_API_DECL void* gs_platform_library_proc_address_default_impl(void* lib, const char* func);
- // Default file implementations
- #ifndef gs_platform_read_file_contents
- #define gs_platform_read_file_contents gs_platform_read_file_contents_default_impl
- #endif
- #ifndef gs_platform_write_file_contents
- #define gs_platform_write_file_contents gs_platform_write_file_contents_default_impl
- #endif
- #ifndef gs_platform_file_exists
- #define gs_platform_file_exists gs_platform_file_exists_default_impl
- #endif
- #ifndef gs_platform_dir_exists
- #define gs_platform_dir_exists gs_platform_dir_exists_default_impl
- #endif
- #ifndef gs_platform_mkdir
- #define gs_platform_mkdir gs_platform_mkdir_default_impl
- #endif
- #ifndef gs_platform_file_exists
- #define gs_platform_file_exists gs_platform_file_exists_default_impl
- #endif
- #ifndef gs_platform_file_size_in_bytes
- #define gs_platform_file_size_in_bytes gs_platform_file_size_in_bytes_default_impl
- #endif
- #ifndef gs_platform_file_extension
- #define gs_platform_file_extension gs_platform_file_extension_default_impl
- #endif
- #ifndef gs_platform_file_delete
- #define gs_platform_file_delete gs_platform_file_delete_default_impl
- #endif
- #ifndef gs_platform_file_copy
- #define gs_platform_file_copy gs_platform_file_copy_default_impl
- #endif
- #ifndef gs_platform_library_load
- #define gs_platform_library_load gs_platform_library_load_default_impl
- #endif
- #ifndef gs_platform_library_unload
- #define gs_platform_library_unload gs_platform_library_unload_default_impl
- #endif
- #ifndef gs_platform_library_proc_addresss
- #define gs_platform_library_proc_address gs_platform_library_proc_address_default_impl
- #endif
- /* == Platform Dependent API == */
- GS_API_DECL void gs_platform_init(gs_platform_t* platform); // Initialize platform layer
- GS_API_DECL void gs_platform_shutdown(gs_platform_t* platform); // Shutdown platform layer
- GS_API_DECL void gs_platform_update_internal(gs_platform_t* platform);
- // Platform Util
- GS_API_DECL double gs_platform_elapsed_time(); // Returns time in ms since initialization of platform
- GS_API_DECL void gs_platform_sleep(float ms); // Sleeps platform for time in ms
- // Platform Video
- GS_API_DECL void gs_platform_enable_vsync(int32_t enabled);
- // Platform Input
- GS_API_DECL void gs_platform_process_input(gs_platform_input_t* input);
- GS_API_DECL uint32_t gs_platform_key_to_codepoint(gs_platform_keycode code);
- GS_API_DECL gs_platform_keycode gs_platform_codepoint_to_key(uint32_t code);
- GS_API_DECL void gs_platform_mouse_set_position(uint32_t handle, float x, float y);
- GS_API_DECL void gs_platform_lock_mouse(uint32_t handle, bool32_t lock);
- GS_API_DECL gs_platform_window_t gs_platform_window_create_internal(const gs_platform_window_desc_t* desc);
- GS_API_DECL void gs_platform_window_swap_buffer(uint32_t handle);
- GS_API_DECL gs_vec2 gs_platform_window_sizev(uint32_t handle);
- GS_API_DECL void gs_platform_window_size(uint32_t handle, uint32_t* width, uint32_t* height);
- GS_API_DECL uint32_t gs_platform_window_width(uint32_t handle);
- GS_API_DECL uint32_t gs_platform_window_height(uint32_t handle);
- GS_API_DECL bool32_t gs_platform_window_fullscreen(uint32_t handle);
- GS_API_DECL gs_vec2 gs_platform_window_positionv(uint32_t handle);
- GS_API_DECL void gs_platform_window_position(uint32_t handle, uint32_t* x, uint32_t* y);
- GS_API_DECL void gs_platform_set_window_size(uint32_t handle, uint32_t width, uint32_t height);
- GS_API_DECL void gs_platform_set_window_sizev(uint32_t handle, gs_vec2 v);
- GS_API_DECL void gs_platform_set_window_fullscreen(uint32_t handle, bool32_t fullscreen);
- GS_API_DECL void gs_platform_set_window_position(uint32_t handle, uint32_t x, uint32_t y);
- GS_API_DECL void gs_platform_set_window_positionv(uint32_t handle, gs_vec2 v);
- GS_API_DECL void gs_platform_set_cursor(uint32_t handle, gs_platform_cursor cursor);
- GS_API_DECL void* gs_platform_raw_window_handle(uint32_t handle);
- GS_API_DECL gs_vec2 gs_platform_framebuffer_sizev(uint32_t handle);
- GS_API_DECL void gs_platform_framebuffer_size(uint32_t handle, uint32_t* w, uint32_t* h);
- GS_API_DECL uint32_t gs_platform_framebuffer_width(uint32_t handle);
- GS_API_DECL uint32_t gs_platform_framebuffer_height(uint32_t handle);
- GS_API_DECL gs_vec2 gs_platform_monitor_sizev(uint32_t id);
- GS_API_DECL void gs_platform_window_set_clipboard(uint32_t handle, const char* str);
- GS_API_DECL const char* gs_platform_window_get_clipboard(uint32_t handle);
- // Platform callbacks
- GS_API_DECL void gs_platform_set_framebuffer_resize_callback(uint32_t handle, gs_framebuffer_resize_callback_t cb);
- GS_API_DECL void gs_platform_set_dropped_files_callback(uint32_t handle, gs_dropped_files_callback_t cb);
- GS_API_DECL void gs_platform_set_window_close_callback(uint32_t handle, gs_window_close_callback_t cb);
- GS_API_DECL void gs_platform_set_character_callback(uint32_t handle, gs_character_callback_t cb);
- /*
- typedef struct gs_platform_interface_s
- {
- } gs_platform_interface_t;
- */
- /** @} */ // end of gs_platform
- /*=============================
- // GS_AUDIO
- =============================*/
- /** @defgroup gs_audio Audio
- * Gunslinger Audio
- * @{
- */
- typedef enum gs_audio_file_type
- {
- GS_OGG = 0x00,
- GS_WAV,
- GS_MP3
- } gs_audio_file_type;
- /*==================
- // Audio Source
- ==================*/
- typedef struct gs_audio_source_t
- {
- int32_t channels;
- int32_t sample_rate;
- void* samples;
- int32_t sample_count;
- } gs_audio_source_t;
- gs_handle_decl(gs_audio_source_t);
- typedef struct gs_audio_instance_decl_t
- {
- gs_handle(gs_audio_source_t) src;
- float volume;
- float pitch;
- bool32_t loop;
- bool32_t persistent;
- bool32_t playing;
- double sample_position;
- void* user_data;
- } gs_audio_instance_decl_t;
- typedef gs_audio_instance_decl_t gs_audio_instance_t;
- gs_handle_decl(gs_audio_instance_t);
- typedef void (* gs_audio_commit)(int16_t* output, uint32_t num_channels, uint32_t sample_rate, uint32_t frame_count);
- /*=============================
- // Audio Interface
- =============================*/
- typedef struct gs_audio_t
- {
- // Audio source data cache
- gs_slot_array(gs_audio_source_t) sources;
- // Audio instance data cache
- gs_slot_array(gs_audio_instance_t) instances;
- // Max global volume setting
- float max_audio_volume;
- // Min global volume setting
- float min_audio_volume;
- // Samples to actually write to hardware
- void* sample_out;
- // Custom user commit function
- gs_audio_commit commit;
- // User data for custom impl
- void* user_data;
- } gs_audio_t;
- /*=============================
- // Audio API
- =============================*/
- /* Audio Create, Destroy, Init, Shutdown, Submit */
- GS_API_DECL gs_audio_t* gs_audio_create();
- GS_API_DECL void gs_audio_destroy(gs_audio_t* audio);
- GS_API_DECL gs_result gs_audio_init(gs_audio_t* audio);
- GS_API_DECL gs_result gs_audio_shutdown(gs_audio_t* audio);
- // Register commit function
- GS_API_DECL void gs_audio_register_commit(gs_audio_commit commit);
- /* Audio create source */
- GS_API_DECL gs_handle(gs_audio_source_t) gs_audio_load_from_file(const char* file_path);
- /* Audio create instance */
- GS_API_DECL gs_handle(gs_audio_instance_t) gs_audio_instance_create(gs_audio_instance_decl_t* decl);
- /* Locking audio thread (optional) */
- GS_API_DECL void gs_audio_mutex_lock(gs_audio_t* audio);
- GS_API_DECL void gs_audio_mutex_unlock(gs_audio_t* audio);
- /* Audio play instance */
- GS_API_DECL void gs_audio_play_source_with_pitch(gs_handle(gs_audio_source_t) src, float volume, float pitch);
- GS_API_DECL void gs_audio_play_source(gs_handle(gs_audio_source_t) src, float volume);
- GS_API_DECL void gs_audio_play(gs_handle(gs_audio_instance_t) inst);
- GS_API_DECL void gs_audio_pause(gs_handle(gs_audio_instance_t) inst);
- GS_API_DECL void gs_audio_stop(gs_handle(gs_audio_instance_t) inst);
- GS_API_DECL void gs_audio_restart(gs_handle(gs_audio_instance_t) inst);
- GS_API_DECL bool32_t gs_audio_is_playing(gs_handle(gs_audio_instance_t) inst);
- /* Audio instance data */
- GS_API_DECL void gs_audio_set_instance_data(gs_handle(gs_audio_instance_t) inst, gs_audio_instance_decl_t decl);
- GS_API_DECL gs_audio_instance_decl_t gs_audio_get_instance_data(gs_handle(gs_audio_instance_t) inst);
- GS_API_DECL float gs_audio_get_volume(gs_handle(gs_audio_instance_t) inst);
- GS_API_DECL void gs_audio_set_volume(gs_handle(gs_audio_instance_t) inst, float volume);
- /* Audio source data */
- GS_API_DECL gs_audio_source_t* gs_audio_get_source_data(gs_handle(gs_audio_source_t) src);
- GS_API_DECL void gs_audio_get_runtime(gs_handle(gs_audio_source_t) src, int32_t* minutes, int32_t* seconds);
- GS_API_DECL void gs_audio_convert_to_runtime(int32_t sample_count, int32_t sample_rate, int32_t num_channels, int32_t position, int32_t* minutes_out, int32_t* seconds_out);
- GS_API_DECL int32_t gs_audio_get_sample_count(gs_handle(gs_audio_source_t) src);
- GS_API_DECL int32_t gs_audio_get_sample_rate(gs_handle(gs_audio_source_t) src);
- GS_API_DECL int32_t gs_audio_get_num_channels(gs_handle(gs_audio_source_t) src);
- /* Resource Loading */
- GS_API_DECL bool32_t gs_audio_load_ogg_data_from_file(const char* file_path, int32_t* sample_count, int32_t* channels, int32_t* sample_rate, void** samples);
- GS_API_DECL bool32_t gs_audio_load_wav_data_from_file(const char* file_path, int32_t* sample_count, int32_t* channels, int32_t* sample_rate, void** samples);
- GS_API_DECL bool32_t gs_audio_load_mp3_data_from_file(const char* file_path, int32_t* sample_count, int32_t* channels, int32_t* sample_rate, void** samples);
- /* Short name definitions for convenience */
- #ifndef GS_NO_SHORT_NAME
- /* Resources */
- #define gsa_src gs_handle(gs_audio_source_t)
- #define gsa_inst gs_handle(gs_audio_instance_t)
- #define gsa_instdecl gs_audio_instance_decl_t
- /* Create */
- #define gsa_create gs_audio_create
- #define gsa_destroy gs_audio_destroy
- #define gsa_init gs_audio_init
- #define gsa_shutdown gs_audio_shutdown
- #define gsa_submit gs_audio_submit
- /* Source */
- #define gsa_load gs_audio_load_from_file
- /* Instance */
- #define gsa_make_inst gs_audio_instance_create
- /* Audio play instance */
- #define gsa_isplaying gs_audio_is_playing
- #define gsa_play gs_audio_play
- #define gsa_play_src gs_audio_play_source
- #define gsa_pause gs_audio_pause
- #define gsa_restart gs_audio_restart
- #endif
- /** @} */ // end of gs_audio
- /*=============================
- // GS_GRAPHICS
- =============================*/
- /** @defgroup gs_graphics Graphics
- * Gunslinger Graphics
- * @{
- */
- // Graphics Pipeline
- // Main graphics resources:
- // Shader description: vertex, fragment, compute, geometry, tesselation
- // Texture Description: texture, depth, render target
- // Buffer Description: vertex, index, uniform, frame, pixel
- // Pipeline Description: vert-layout, shader, bindables, render states
- // Pass Description: render pass, action on render targets (clear, set viewport, etc.)
- /* Useful macro for forcing enum decl to be uint32_t type with default = 0x00 for quick init */
- #define gs_enum_decl(NAME, ...)\
- typedef enum NAME {\
- _gs_##NAME##_default = 0x0,\
- __VA_ARGS__,\
- _gs_##NAME##_count,\
- _gs_##NAME##_force_u32 = 0x7fffffff\
- } NAME;
- #define gs_enum_count(NAME)\
- _gs_##NAME##_count
- /* Shader Stage Type */
- gs_enum_decl(gs_graphics_shader_stage_type,
- GS_GRAPHICS_SHADER_STAGE_VERTEX,
- GS_GRAPHICS_SHADER_STAGE_FRAGMENT,
- GS_GRAPHICS_SHADER_STAGE_COMPUTE
- );
- /* Winding Order Type */
- gs_enum_decl(gs_graphics_winding_order_type,
- GS_GRAPHICS_WINDING_ORDER_CW,
- GS_GRAPHICS_WINDING_ORDER_CCW
- );
- /* Face Culling Type */
- gs_enum_decl(gs_graphics_face_culling_type,
- GS_GRAPHICS_FACE_CULLING_FRONT,
- GS_GRAPHICS_FACE_CULLING_BACK,
- GS_GRAPHICS_FACE_CULLING_FRONT_AND_BACK
- );
- /* Blend Equation Type */
- gs_enum_decl(gs_graphics_blend_equation_type,
- GS_GRAPHICS_BLEND_EQUATION_ADD,
- GS_GRAPHICS_BLEND_EQUATION_SUBTRACT,
- GS_GRAPHICS_BLEND_EQUATION_REVERSE_SUBTRACT,
- GS_GRAPHICS_BLEND_EQUATION_MIN,
- GS_GRAPHICS_BLEND_EQUATION_MAX
- );
- /* Blend Mode Type */
- gs_enum_decl(gs_graphics_blend_mode_type,
- GS_GRAPHICS_BLEND_MODE_ZERO,
- GS_GRAPHICS_BLEND_MODE_ONE,
- GS_GRAPHICS_BLEND_MODE_SRC_COLOR,
- GS_GRAPHICS_BLEND_MODE_ONE_MINUS_SRC_COLOR,
- GS_GRAPHICS_BLEND_MODE_DST_COLOR,
- GS_GRAPHICS_BLEND_MODE_ONE_MINUS_DST_COLOR,
- GS_GRAPHICS_BLEND_MODE_SRC_ALPHA,
- GS_GRAPHICS_BLEND_MODE_ONE_MINUS_SRC_ALPHA,
- GS_GRAPHICS_BLEND_MODE_DST_ALPHA,
- GS_GRAPHICS_BLEND_MODE_ONE_MINUS_DST_ALPHA,
- GS_GRAPHICS_BLEND_MODE_CONSTANT_COLOR,
- GS_GRAPHICS_BLEND_MODE_ONE_MINUS_CONSTANT_COLOR,
- GS_GRAPHICS_BLEND_MODE_CONSTANT_ALPHA,
- GS_GRAPHICS_BLEND_MODE_ONE_MINUS_CONSTANT_ALPHA
- );
- /* Shader Language Type */
- gs_enum_decl(gs_graphics_shader_language_type,
- GS_GRAPHICS_SHADER_LANGUAGE_GLSL
- );
- /* Push Constant Type */
- // Really don't want to handle "auto-merging" of data types
- /* Uniform Type */
- gs_enum_decl(gs_graphics_uniform_type,
- GS_GRAPHICS_UNIFORM_FLOAT,
- GS_GRAPHICS_UNIFORM_INT,
- GS_GRAPHICS_UNIFORM_VEC2,
- GS_GRAPHICS_UNIFORM_VEC3,
- GS_GRAPHICS_UNIFORM_VEC4,
- GS_GRAPHICS_UNIFORM_MAT4,
- GS_GRAPHICS_UNIFORM_SAMPLER2D,
- GS_GRAPHICS_UNIFORM_SAMPLER2DSHADOW,
- GS_GRAPHICS_UNIFORM_USAMPLER2D,
- GS_GRAPHICS_UNIFORM_SAMPLERCUBE,
- GS_GRAPHICS_UNIFORM_IMAGE2D_RGBA32F,
- GS_GRAPHICS_UNIFORM_BLOCK
- );
- /* Uniform Block Usage Type */
- gs_enum_decl(gs_graphics_uniform_block_usage_type,
- GS_GRAPHICS_UNIFORM_BLOCK_USAGE_STATIC, // Default of 0x00 is static
- GS_GRAPHICS_UNIFORM_BLOCK_USAGE_PUSH_CONSTANT
- );
- /* Sampler Type */
- gs_enum_decl(gs_graphics_sampler_type,
- GS_GRAPHICS_SAMPLER_2D
- );
- /* Primitive Type */
- gs_enum_decl(gs_graphics_primitive_type,
- GS_GRAPHICS_PRIMITIVE_LINES,
- GS_GRAPHICS_PRIMITIVE_TRIANGLES,
- GS_GRAPHICS_PRIMITIVE_QUADS
- );
- /* Vertex Atribute Type */
- gs_enum_decl(gs_graphics_vertex_attribute_type,
- GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT4,
- GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT3,
- GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT2,
- GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT,
- GS_GRAPHICS_VERTEX_ATTRIBUTE_UINT4,
- GS_GRAPHICS_VERTEX_ATTRIBUTE_UINT3,
- GS_GRAPHICS_VERTEX_ATTRIBUTE_UINT2,
- GS_GRAPHICS_VERTEX_ATTRIBUTE_UINT,
- GS_GRAPHICS_VERTEX_ATTRIBUTE_BYTE4,
- GS_GRAPHICS_VERTEX_ATTRIBUTE_BYTE3,
- GS_GRAPHICS_VERTEX_ATTRIBUTE_BYTE2,
- GS_GRAPHICS_VERTEX_ATTRIBUTE_BYTE
- );
- /* Buffer Type */
- gs_enum_decl(gs_graphics_buffer_type,
- GS_GRAPHICS_BUFFER_VERTEX,
- GS_GRAPHICS_BUFFER_INDEX,
- GS_GRAPHICS_BUFFER_FRAME,
- GS_GRAPHICS_BUFFER_UNIFORM,
- GS_GRAPHICS_BUFFER_UNIFORM_CONSTANT,
- GS_GRAPHICS_BUFFER_SHADER_STORAGE,
- GS_GRAPHICS_BUFFER_SAMPLER
- );
- /* Buffer Usage Type */
- gs_enum_decl(gs_graphics_buffer_usage_type,
- GS_GRAPHICS_BUFFER_USAGE_STATIC,
- GS_GRAPHICS_BUFFER_USAGE_STREAM,
- GS_GRAPHICS_BUFFER_USAGE_DYNAMIC
- );
- /* Buffer Update Type */
- gs_enum_decl(gs_graphics_buffer_update_type,
- GS_GRAPHICS_BUFFER_UPDATE_RECREATE,
- GS_GRAPHICS_BUFFER_UPDATE_SUBDATA
- );
- gs_enum_decl(gs_graphics_access_type,
- GS_GRAPHICS_ACCESS_READ_ONLY,
- GS_GRAPHICS_ACCESS_WRITE_ONLY,
- GS_GRAPHICS_ACCESS_READ_WRITE
- );
- gs_enum_decl(gs_graphics_buffer_flags,
- GS_GRAPHICS_BUFFER_FLAG_MAP_PERSISTENT,
- GS_GRAPHICS_BUFFER_FLAG_MAP_COHERENT
- );
- //=== Texture ===//
- typedef enum
- {
- GS_GRAPHICS_TEXTURE_2D = 0x00,
- GS_GRAPHICS_TEXTURE_CUBEMAP
- } gs_graphics_texture_type;
- typedef enum
- {
- GS_GRAPHICS_TEXTURE_CUBEMAP_POSITIVE_X = 0x00,
- GS_GRAPHICS_TEXTURE_CUBEMAP_NEGATIVE_X,
- GS_GRAPHICS_TEXTURE_CUBEMAP_POSITIVE_Y,
- GS_GRAPHICS_TEXTURE_CUBEMAP_NEGATIVE_Y,
- GS_GRAPHICS_TEXTURE_CUBEMAP_POSITIVE_Z,
- GS_GRAPHICS_TEXTURE_CUBEMAP_NEGATIVE_Z
- } gs_graphics_cubemap_face_type;
- gs_enum_decl(gs_graphics_texture_format_type,
- GS_GRAPHICS_TEXTURE_FORMAT_RGBA8,
- GS_GRAPHICS_TEXTURE_FORMAT_RGB8,
- GS_GRAPHICS_TEXTURE_FORMAT_RG8,
- GS_GRAPHICS_TEXTURE_FORMAT_R16UI,
- GS_GRAPHICS_TEXTURE_FORMAT_R32UI,
- GS_GRAPHICS_TEXTURE_FORMAT_R32F,
- GS_GRAPHICS_TEXTURE_FORMAT_RGBA16F,
- GS_GRAPHICS_TEXTURE_FORMAT_RGBA32F,
- GS_GRAPHICS_TEXTURE_FORMAT_A8,
- GS_GRAPHICS_TEXTURE_FORMAT_R8,
- GS_GRAPHICS_TEXTURE_FORMAT_DEPTH8,
- GS_GRAPHICS_TEXTURE_FORMAT_DEPTH16,
- GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24,
- GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F,
- GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24_STENCIL8,
- GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F_STENCIL8,
- GS_GRAPHICS_TEXTURE_FORMAT_STENCIL8
- );
- gs_enum_decl(gs_graphics_texture_wrapping_type,
- GS_GRAPHICS_TEXTURE_WRAP_REPEAT,
- GS_GRAPHICS_TEXTURE_WRAP_MIRRORED_REPEAT,
- GS_GRAPHICS_TEXTURE_WRAP_CLAMP_TO_EDGE,
- GS_GRAPHICS_TEXTURE_WRAP_CLAMP_TO_BORDER
- );
- gs_enum_decl(gs_graphics_texture_filtering_type,
- GS_GRAPHICS_TEXTURE_FILTER_NEAREST,
- GS_GRAPHICS_TEXTURE_FILTER_LINEAR
- );
- //=== Clear ===//
- gs_enum_decl(gs_graphics_clear_flag,
- GS_GRAPHICS_CLEAR_COLOR = 0x01,
- GS_GRAPHICS_CLEAR_DEPTH = 0x02,
- GS_GRAPHICS_CLEAR_STENCIL = 0x04,
- GS_GRAPHICS_CLEAR_NONE = 0x08
- );
- #define GS_GRAPHICS_CLEAR_ALL\
- GS_GRAPHICS_CLEAR_COLOR |\
- GS_GRAPHICS_CLEAR_DEPTH |\
- GS_GRAPHICS_CLEAR_STENCIL
- //=== Bind Type ===//
- gs_enum_decl(gs_graphics_bind_type,
- GS_GRAPHICS_BIND_VERTEX_BUFFER,
- GS_GRAPHICS_BIND_INDEX_BUFFER,
- GS_GRAPHICS_BIND_UNIFORM_BUFFER,
- GS_GRAPHICS_BIND_STORAGE_BUFFER,
- GS_GRAPHICS_BIND_IMAGE_BUFFER,
- GS_GRAPHICS_BIND_UNIFORM
- );
- /* Depth Function Type */
- gs_enum_decl(gs_graphics_depth_func_type, // Default value of 0x00 means depth is disabled
- GS_GRAPHICS_DEPTH_FUNC_NEVER,
- GS_GRAPHICS_DEPTH_FUNC_LESS,
- GS_GRAPHICS_DEPTH_FUNC_EQUAL,
- GS_GRAPHICS_DEPTH_FUNC_LEQUAL,
- GS_GRAPHICS_DEPTH_FUNC_GREATER,
- GS_GRAPHICS_DEPTH_FUNC_NOTEQUAL,
- GS_GRAPHICS_DEPTH_FUNC_GEQUAL,
- GS_GRAPHICS_DEPTH_FUNC_ALWAYS
- );
- gs_enum_decl(gs_graphics_depth_mask_type, // Default value 0x00 means depth writing enabled
- GS_GRAPHICS_DEPTH_MASK_ENABLED,
- GS_GRAPHICS_DEPTH_MASK_DISABLED
- );
- /* Stencil Function Type */
- gs_enum_decl(gs_graphics_stencil_func_type,
- GS_GRAPHICS_STENCIL_FUNC_NEVER, // Default value of 0x00 means stencil is disabled
- GS_GRAPHICS_STENCIL_FUNC_LESS,
- GS_GRAPHICS_STENCIL_FUNC_EQUAL,
- GS_GRAPHICS_STENCIL_FUNC_LEQUAL,
- GS_GRAPHICS_STENCIL_FUNC_GREATER,
- GS_GRAPHICS_STENCIL_FUNC_NOTEQUAL,
- GS_GRAPHICS_STENCIL_FUNC_GEQUAL,
- GS_GRAPHICS_STENCIL_FUNC_ALWAYS
- );
- /* Stencil Op Type */
- gs_enum_decl(gs_graphics_stencil_op_type, // Default value of 0x00 means keep is used
- GS_GRAPHICS_STENCIL_OP_KEEP,
- GS_GRAPHICS_STENCIL_OP_ZERO,
- GS_GRAPHICS_STENCIL_OP_REPLACE,
- GS_GRAPHICS_STENCIL_OP_INCR,
- GS_GRAPHICS_STENCIL_OP_INCR_WRAP,
- GS_GRAPHICS_STENCIL_OP_DECR,
- GS_GRAPHICS_STENCIL_OP_DECR_WRAP,
- GS_GRAPHICS_STENCIL_OP_INVERT
- );
- /* Internal Graphics Resource Handles */
- gs_handle_decl(gs_graphics_shader_t);
- gs_handle_decl(gs_graphics_texture_t);
- gs_handle_decl(gs_graphics_vertex_buffer_t);
- gs_handle_decl(gs_graphics_index_buffer_t);
- gs_handle_decl(gs_graphics_uniform_buffer_t);
- gs_handle_decl(gs_graphics_storage_buffer_t);
- gs_handle_decl(gs_graphics_framebuffer_t);
- gs_handle_decl(gs_graphics_uniform_t);
- gs_handle_decl(gs_graphics_renderpass_t);
- gs_handle_decl(gs_graphics_pipeline_t);
- /* Graphics Shader Source Desc */
- typedef struct gs_graphics_shader_source_desc_t
- {
- gs_graphics_shader_stage_type type; // Shader stage type (vertex, fragment, tesselation, geometry, compute)
- const char* source; // Source for shader
- } gs_graphics_shader_source_desc_t;
- /* Graphics Shader Desc */
- typedef struct gs_graphics_shader_desc_t
- {
- gs_graphics_shader_source_desc_t* sources; // Array of shader source descriptions
- size_t size; // Size in bytes of shader source desc array
- char name[64]; // Optional (for logging and debugging mainly)
- } gs_graphics_shader_desc_t;
- #define GS_GRAPHICS_TEXTURE_DATA_MAX 6
- /* Graphics Texture Desc */
- typedef struct gs_graphics_texture_desc_t
- {
- gs_graphics_texture_type type;
- uint32_t width; // Width of texture in texels
- uint32_t height; // Height of texture in texels
- uint32_t depth; // Depth of texture
- void* data[GS_GRAPHICS_TEXTURE_DATA_MAX]; // Texture data to upload (can be null)
- gs_graphics_texture_format_type format; // Format of texture data (rgba32, rgba8, rgba32f, r8, depth32f, etc...)
- gs_graphics_texture_wrapping_type wrap_s; // Wrapping type for s axis of texture
- gs_graphics_texture_wrapping_type wrap_t; // Wrapping type for t axis of texture
- gs_graphics_texture_wrapping_type wrap_r; // Wrapping type for r axis of texture
- gs_graphics_texture_filtering_type min_filter; // Minification filter for texture
- gs_graphics_texture_filtering_type mag_filter; // Magnification filter for texture
- gs_graphics_texture_filtering_type mip_filter; // Mip filter for texture
- gs_vec2 offset; // Offset for updates
- uint32_t num_mips; // Number of mips to generate (default 0 is disable mip generation)
- struct {
- uint32_t x; // X offset in texels to start read
- uint32_t y; // Y offset in texels to start read
- uint32_t width; // Width in texels for texture
- uint32_t height; // Height in texels for texture
- size_t size; // Size in bytes for data to be read
- } read;
- uint16_t flip_y; // Whether or not y is flipped
- } gs_graphics_texture_desc_t;
- /* Graphics Uniform Layout Desc */
- typedef struct gs_graphics_uniform_layout_desc_t
- {
- gs_graphics_uniform_type type; // Type of field
- char fname[64]; // Name of field (required for implicit APIs, like OpenGL/ES)
- uint32_t count; // Count variable (used for arrays such as glUniformXXXv)
- } gs_graphics_uniform_layout_desc_t;
- /* Graphics Uniform Desc */
- typedef struct gs_graphics_uniform_desc_t
- {
- gs_graphics_shader_stage_type stage;
- char name[64]; // Name of uniform (required for OpenGL/ES, WebGL)
- gs_graphics_uniform_layout_desc_t* layout; // Layout array for uniform data
- size_t layout_size; // Size of uniform data in bytes
- } gs_graphics_uniform_desc_t;
- typedef struct gs_graphics_buffer_update_desc_t
- {
- gs_graphics_buffer_update_type type;
- size_t offset;
- } gs_graphics_buffer_update_desc_t;
- /* Graphics Buffer Desc General */
- typedef struct gs_graphics_buffer_base_desc_t
- {
- void * data;
- size_t size;
- gs_graphics_buffer_usage_type usage;
- } gs_graphics_buffer_base_desc_t;
- typedef struct gs_graphics_vertex_buffer_desc_t
- {
- void* data;
- size_t size;
- gs_graphics_buffer_usage_type usage;
- gs_graphics_buffer_update_desc_t update;
- } gs_graphics_vertex_buffer_desc_t;
- typedef gs_graphics_vertex_buffer_desc_t gs_graphics_index_buffer_desc_t;
- typedef struct gs_graphics_uniform_buffer_desc_t
- {
- void* data;
- size_t size;
- gs_graphics_buffer_usage_type usage;
- const char* name;
- gs_graphics_shader_stage_type stage;
- gs_graphics_buffer_update_desc_t update;
- } gs_graphics_uniform_buffer_desc_t;
- typedef struct gs_graphics_storage_buffer_desc_t
- {
- void* data;
- void* map;
- size_t size;
- char name[64];
- gs_graphics_buffer_usage_type usage;
- gs_graphics_access_type access;
- gs_graphics_buffer_flags flags;
- gs_graphics_buffer_update_desc_t update;
- } gs_graphics_storage_buffer_desc_t;
- typedef struct gs_graphics_framebuffer_desc_t
- {
- void* data;
- } gs_graphics_framebuffer_desc_t;
- /* Graphics Clear Action */
- typedef struct gs_graphics_clear_action_t
- {
- gs_graphics_clear_flag flag; // Flag to be set (clear color, clear depth, clear stencil, clear all)
- union
- {
- float color[4]; // Clear color value
- float depth; // Clear depth value
- int32_t stencil; // Clear stencil value
- };
- } gs_graphics_clear_action_t;
- /* Graphics Clear Desc */
- typedef struct gs_graphics_clear_desc_t
- {
- gs_graphics_clear_action_t* actions; // Clear action array
- size_t size; // Size
- } gs_graphics_clear_desc_t;
- /* Graphics Render Pass Desc */
- typedef struct gs_graphics_renderpass_desc_t
- {
- gs_handle(gs_graphics_framebuffer_t) fbo; // Default is set to invalid for backbuffer
- gs_handle(gs_graphics_texture_t)* color; // Array of color attachments to be bound (useful for MRT, if supported)
- size_t color_size; // Size of color attachment array
- gs_handle(gs_graphics_texture_t) depth; // Depth attachment to be bound
- gs_handle(gs_graphics_texture_t) stencil; // Depth attachment to be bound
- } gs_graphics_renderpass_desc_t;
- /*
- // If you want to write to a color attachment, you have to have a frame buffer attached that isn't the backbuffer
- */
- typedef enum gs_graphics_vertex_data_type
- {
- GS_GRAPHICS_VERTEX_DATA_INTERLEAVED = 0x00,
- GS_GRAPHICS_VERTEX_DATA_NONINTERLEAVED
- } gs_graphics_vertex_data_type;
- typedef struct gs_graphics_bind_vertex_buffer_desc_t {
- gs_handle(gs_graphics_vertex_buffer_t) buffer;
- size_t offset;
- gs_graphics_vertex_data_type data_type;
- } gs_graphics_bind_vertex_buffer_desc_t;
- typedef struct gs_graphics_bind_index_buffer_desc_t {
- gs_handle(gs_graphics_index_buffer_t) buffer;
- } gs_graphics_bind_index_buffer_desc_t;
- typedef struct gs_graphics_bind_image_buffer_desc_t {
- gs_handle(gs_graphics_texture_t) tex;
- uint32_t binding;
- gs_graphics_access_type access;
- } gs_graphics_bind_image_buffer_desc_t;
- typedef struct gs_graphics_bind_uniform_buffer_desc_t {
- gs_handle(gs_graphics_uniform_buffer_t) buffer;
- uint32_t binding;
- struct {
- size_t offset; // Specify an offset for ranged binds.
- size_t size; // Specify size for ranged binds.
- } range;
- } gs_graphics_bind_uniform_buffer_desc_t;
- // All this needs to be unified...
- typedef struct gs_graphics_bind_storage_buffer_desc_t {
- gs_handle(gs_graphics_storage_buffer_t) buffer;
- uint32_t binding;
- struct {
- size_t offset; // Specify an offset for ranged binds.
- size_t size; // Specify size for ranged binds.
- } range;
- } gs_graphics_bind_storage_buffer_desc_t;
- typedef struct gs_graphics_bind_uniform_desc_t {
- gs_handle(gs_graphics_uniform_t) uniform;
- void* data;
- uint32_t binding; // Base binding for samplers?
- } gs_graphics_bind_uniform_desc_t;
- /* Graphics Binding Desc */
- typedef struct gs_graphics_bind_desc_t
- {
- struct {
- gs_graphics_bind_vertex_buffer_desc_t* desc; // Array of vertex buffer declarations (NULL by default)
- size_t size; // Size of array in bytes (optional if only one)
- } vertex_buffers;
- struct {
- gs_graphics_bind_index_buffer_desc_t* desc; // Array of index buffer declarations (NULL by default)
- size_t size; // Size of array in bytes (optional if only one)
- } index_buffers;
- struct {
- gs_graphics_bind_uniform_buffer_desc_t* desc; // Array of uniform buffer declarations (NULL by default)
- size_t size; // Size of array in bytes (optional if only one)
- } uniform_buffers;
- struct {
- gs_graphics_bind_uniform_desc_t* desc; // Array of uniform declarations (NULL by default)
- size_t size; // Size of array in bytes (optional if one)
- } uniforms;
- struct {
- gs_graphics_bind_image_buffer_desc_t* desc;
- size_t size;
- } image_buffers;
- struct {
- gs_graphics_bind_storage_buffer_desc_t* desc;
- size_t size;
- } storage_buffers;
- } gs_graphics_bind_desc_t;
- /* Graphics Blend State Desc */
- typedef struct gs_graphics_blend_state_desc_t
- {
- gs_graphics_blend_equation_type func; // Equation function to use for blend ops
- gs_graphics_blend_mode_type src; // Source blend mode
- gs_graphics_blend_mode_type dst; // Destination blend mode
- } gs_graphics_blend_state_desc_t;
- /* Graphics Depth State Desc */
- typedef struct gs_graphics_depth_state_desc_t
- {
- gs_graphics_depth_func_type func; // Function to set for depth test
- gs_graphics_depth_mask_type mask; // Whether or not writing is enabled/disabled
- } gs_graphics_depth_state_desc_t;
- /* Graphics Stencil State Desc */
- typedef struct gs_graphics_stencil_state_desc_t
- {
- gs_graphics_stencil_func_type func; // Function to set for stencil test
- uint32_t ref; // Specifies reference val for stencil test
- uint32_t comp_mask; // Specifies mask that is ANDed with both ref val and stored stencil val
- uint32_t write_mask; // Specifies mask that is ANDed with both ref val and stored stencil val
- gs_graphics_stencil_op_type sfail; // Action to take when stencil test fails
- gs_graphics_stencil_op_type dpfail; // Action to take when stencil test passes but depth test fails
- gs_graphics_stencil_op_type dppass; // Action to take when both stencil test passes and either depth passes or is not enabled
- } gs_graphics_stencil_state_desc_t;
- /* Graphics Raster State Desc */
- typedef struct gs_graphics_raster_state_desc_t
- {
- gs_graphics_face_culling_type face_culling; // Face culling mode to be used (front, back, front and back)
- gs_graphics_winding_order_type winding_order; // Winding order mode to be used (ccw, cw)
- gs_graphics_primitive_type primitive; // Primitive type for drawing (lines, quads, triangles, triangle strip)
- gs_handle(gs_graphics_shader_t) shader; // Shader to bind and use (might be in bindables later on, not sure)
- size_t index_buffer_element_size; // Element size of index buffer (used for parsing internal data)
- } gs_graphics_raster_state_desc_t;
- /* Graphics Compute State Desc */
- typedef struct gs_graphics_compute_state_desc_t
- {
- gs_handle(gs_graphics_shader_t) shader; // Compute shader to bind
- } gs_graphics_compute_state_desc_t;
- /* Graphics Vertex Attribute Desc */
- typedef struct gs_graphics_vertex_attribute_desc_t {
- char name[64]; // Attribute name (required for lower versions of OpenGL and ES)
- gs_graphics_vertex_attribute_type format; // Format for vertex attribute
- size_t stride; // Total stride of vertex layout (optional, calculated by default)
- size_t offset; // Offset of this vertex from base pointer of data (optional, calaculated by default)
- size_t divisor; // Used for instancing. (optional, default = 0x00 for no instancing)
- uint32_t buffer_idx; // Vertex buffer to use (optional, default = 0x00)
- } gs_graphics_vertex_attribute_desc_t;
- /* Graphics Vertex Layout Desc */
- typedef struct gs_graphics_vertex_layout_desc_t {
- gs_graphics_vertex_attribute_desc_t* attrs; // Vertex attribute array
- size_t size; // Size in bytes of vertex attribute array
- } gs_graphics_vertex_layout_desc_t;
- /* Graphics Pipeline Desc */
- typedef struct gs_graphics_pipeline_desc_t
- {
- gs_graphics_blend_state_desc_t blend; // Blend state desc for pipeline
- gs_graphics_depth_state_desc_t depth; // Depth state desc for pipeline
- gs_graphics_raster_state_desc_t raster; // Raster state desc for pipeline
- gs_graphics_stencil_state_desc_t stencil; // Stencil state desc for pipeline
- gs_graphics_compute_state_desc_t compute; // Compute state desc for pipeline
- gs_graphics_vertex_layout_desc_t layout; // Vertex layout desc for pipeline
- } gs_graphics_pipeline_desc_t;
- /* Graphics Draw Desc */
- typedef struct gs_graphics_draw_desc_t
- {
- uint32_t start;
- uint32_t count;
- uint32_t instances;
- uint32_t base_vertex;
- struct {
- uint32_t start;
- uint32_t end;
- } range;
- } gs_graphics_draw_desc_t;
- gs_inline gs_handle(gs_graphics_renderpass_t)
- __gs_renderpass_default_impl()
- {
- gs_handle(gs_graphics_renderpass_t) hndl = gs_default_val();
- return hndl;
- }
- // Convenience define for default render pass to back buffer
- #define GS_GRAPHICS_RENDER_PASS_DEFAULT __gs_renderpass_default_impl()
- typedef struct gs_graphics_info_t
- {
- uint32_t major_version;
- uint32_t minor_version;
- uint32_t max_texture_units;
- uint32_t max_ssbo_block_size;
- struct {
- bool32 available;
- uint32_t max_work_group_count[3];
- uint32_t max_work_group_size[3];
- uint32_t max_work_group_invocations;
- } compute;
- } gs_graphics_info_t;
- /*==========================
- // Graphics Interface
- ==========================*/
- typedef struct gs_graphics_t
- {
- void* user_data; // For internal use
- gs_graphics_info_t info; // Used for querying by user for features
- struct {
- // Create
- gs_handle(gs_graphics_texture_t) (* texture_create)(const gs_graphics_texture_desc_t* desc);
- gs_handle(gs_graphics_uniform_t) (* uniform_create)(const gs_graphics_uniform_desc_t* desc);
- gs_handle(gs_graphics_shader_t) (* shader_create)(const gs_graphics_shader_desc_t* desc);
- gs_handle(gs_graphics_vertex_buffer_t) (* vertex_buffer_create)(const gs_graphics_vertex_buffer_desc_t* desc);
- gs_handle(gs_graphics_index_buffer_t) (* index_buffer_create)(const gs_graphics_index_buffer_desc_t* desc);
- gs_handle(gs_graphics_uniform_buffer_t) (* uniform_buffer_create)(const gs_graphics_uniform_buffer_desc_t* desc);
- gs_handle(gs_graphics_storage_buffer_t) (* storage_buffer_create)(const gs_graphics_storage_buffer_desc_t* desc);
- gs_handle(gs_graphics_framebuffer_t) (* framebuffer_create)(const gs_graphics_framebuffer_desc_t* desc);
- gs_handle(gs_graphics_renderpass_t) (* renderpass_create)(const gs_graphics_renderpass_desc_t* desc);
- gs_handle(gs_graphics_pipeline_t) (* pipeline_create)(const gs_graphics_pipeline_desc_t* desc);
- // Destroy
- void (* texture_destroy)(gs_handle(gs_graphics_texture_t) hndl);
- void (* uniform_destroy)(gs_handle(gs_graphics_uniform_t) hndl);
- void (* shader_destroy)(gs_handle(gs_graphics_shader_t) hndl);
- void (* vertex_buffer_destroy)(gs_handle(gs_graphics_vertex_buffer_t) hndl);
- void (* index_buffer_destroy)(gs_handle(gs_graphics_index_buffer_t) hndl);
- void (* uniform_buffer_destroy)(gs_handle(gs_graphics_uniform_buffer_t) hndl);
- void (* storage_buffer_destroy)(gs_handle(gs_graphics_storage_buffer_t) hndl);
- void (* framebuffer_destroy)(gs_handle(gs_graphics_framebuffer_t) hndl);
- void (* renderpass_destroy)(gs_handle(gs_graphics_renderpass_t) hndl);
- void (* pipeline_destroy)(gs_handle(gs_graphics_pipeline_t) hndl);
- // Resource Updates (main thread only)
- void (* vertex_buffer_update)(gs_handle(gs_graphics_vertex_buffer_t) hndl, gs_graphics_vertex_buffer_desc_t* desc);
- void (* index_buffer_update)(gs_handle(gs_graphics_index_buffer_t) hndl, gs_graphics_index_buffer_desc_t* desc);
- void (* storage_buffer_update)(gs_handle(gs_graphics_storage_buffer_t) hndl, gs_graphics_storage_buffer_desc_t* desc);
- void (* texture_update)(gs_handle(gs_graphics_texture_t) hndl, gs_graphics_texture_desc_t* desc);
- void (* texture_read)(gs_handle(gs_graphics_texture_t) hndl, gs_graphics_texture_desc_t* desc);
- // Util
- void* (* storage_buffer_map_get)(gs_handle(gs_graphics_storage_buffer_t) hndl);
- void* (* storage_buffer_lock)(gs_handle(gs_graphics_storage_buffer_t) hndl, size_t offset, size_t sz);
- void (* storage_buffer_unlock)(gs_handle(gs_graphics_storage_buffer_t) hndl);
- void (* storage_buffer_get_data)(gs_handle(gs_graphics_storage_buffer_t) hndl, size_t offset, size_t stride, void* out);
- // Submission (Main Thread)
- void (* command_buffer_submit)(gs_command_buffer_t* cb);
- } api; // Interface for stable access across .dll boundaries
- } gs_graphics_t;
- /*==========================
- // Graphics API
- ==========================*/
- #define gs_graphics() gs_ctx()->graphics
- // Graphics Interface Creation / Initialization / Shutdown / Destruction
- GS_API_DECL gs_graphics_t* gs_graphics_create();
- GS_API_DECL void gs_graphics_destroy(gs_graphics_t* graphics);
- GS_API_DECL void gs_graphics_init(gs_graphics_t* graphics);
- GS_API_DECL void gs_graphics_shutdown(gs_graphics_t* graphics);
- // Graphics Info Object Query
- GS_API_DECL gs_graphics_info_t* gs_graphics_info();
- // Resource Creation
- // Create
- GS_API_DECL gs_handle(gs_graphics_texture_t) gs_graphics_texture_create(const gs_graphics_texture_desc_t* desc);
- GS_API_DECL gs_handle(gs_graphics_uniform_t) gs_graphics_uniform_create(const gs_graphics_uniform_desc_t* desc);
- GS_API_DECL gs_handle(gs_graphics_shader_t) gs_graphics_shader_create(const gs_graphics_shader_desc_t* desc);
- GS_API_DECL gs_handle(gs_graphics_vertex_buffer_t) gs_graphics_vertex_buffer_create(const gs_graphics_vertex_buffer_desc_t* desc);
- GS_API_DECL gs_handle(gs_graphics_index_buffer_t) gs_graphics_index_buffer_create(const gs_graphics_index_buffer_desc_t* desc);
- GS_API_DECL gs_handle(gs_graphics_uniform_buffer_t) gs_graphics_uniform_buffer_create(const gs_graphics_uniform_buffer_desc_t* desc);
- GS_API_DECL gs_handle(gs_graphics_storage_buffer_t) gs_graphics_storage_buffer_create(const gs_graphics_storage_buffer_desc_t* desc);
- GS_API_DECL gs_handle(gs_graphics_framebuffer_t) gs_graphics_framebuffer_create(const gs_graphics_framebuffer_desc_t* desc);
- GS_API_DECL gs_handle(gs_graphics_renderpass_t) gs_graphics_renderpass_create(const gs_graphics_renderpass_desc_t* desc);
- GS_API_DECL gs_handle(gs_graphics_pipeline_t) gs_graphics_pipeline_create(const gs_graphics_pipeline_desc_t* desc);
- // Destroy
- GS_API_DECL void gs_graphics_texture_destroy(gs_handle(gs_graphics_texture_t) hndl);
- GS_API_DECL void gs_graphics_uniform_destroy(gs_handle(gs_graphics_uniform_t) hndl);
- GS_API_DECL void gs_graphics_shader_destroy(gs_handle(gs_graphics_shader_t) hndl);
- GS_API_DECL void gs_graphics_vertex_buffer_destroy(gs_handle(gs_graphics_vertex_buffer_t) hndl);
- GS_API_DECL void gs_graphics_index_buffer_destroy(gs_handle(gs_graphics_index_buffer_t) hndl);
- GS_API_DECL void gs_graphics_uniform_buffer_destroy(gs_handle(gs_graphics_uniform_buffer_t) hndl);
- GS_API_DECL void gs_graphics_storage_buffer_destroy(gs_handle(gs_graphics_storage_buffer_t) hndl);
- GS_API_DECL void gs_graphics_framebuffer_destroy(gs_handle(gs_graphics_framebuffer_t) hndl);
- GS_API_DECL void gs_graphics_renderpass_destroy(gs_handle(gs_graphics_renderpass_t) hndl);
- GS_API_DECL void gs_graphics_pipeline_destroy(gs_handle(gs_graphics_pipeline_t) hndl);
- // Resource Updates (main thread only)
- GS_API_DECL void gs_graphics_vertex_buffer_update(gs_handle(gs_graphics_vertex_buffer_t) hndl, gs_graphics_vertex_buffer_desc_t* desc);
- GS_API_DECL void gs_graphics_index_buffer_update(gs_handle(gs_graphics_index_buffer_t) hndl, gs_graphics_index_buffer_desc_t* desc);
- GS_API_DECL void gs_graphics_storage_buffer_update(gs_handle(gs_graphics_storage_buffer_t) hndl, gs_graphics_storage_buffer_desc_t* desc);
- GS_API_DECL void gs_graphics_texture_update(gs_handle(gs_graphics_texture_t) hndl, gs_graphics_texture_desc_t* desc);
- GS_API_DECL void gs_graphics_texture_read(gs_handle(gs_graphics_texture_t) hndl, gs_graphics_texture_desc_t* desc);
- // Resource Queries
- GS_API_DECL void gs_graphics_pipeline_desc_query(gs_handle(gs_graphics_pipeline_t) hndl, gs_graphics_pipeline_desc_t* out);
- GS_API_DECL void gs_graphics_texture_desc_query(gs_handle(gs_graphics_texture_t) hndl, gs_graphics_texture_desc_t* out);
- GS_API_DECL size_t gs_graphics_uniform_size_query(gs_handle(gs_graphics_uniform_t) hndl);
- // Util
- GS_API_DECL void* gs_graphics_storage_buffer_map_get(gs_handle(gs_graphics_storage_buffer_t) hndl);
- GS_API_DECL void* gs_graphics_storage_buffer_lock(gs_handle(gs_graphics_storage_buffer_t) hndl, size_t offset, size_t sz);
- GS_API_DECL void gs_graphics_storage_buffer_unlock(gs_handle(gs_graphics_storage_buffer_t) hndl);
- GS_API_DECL void gs_graphics_storage_buffer_get_data(gs_handle(gs_graphics_storage_buffer_t) hndl, size_t offset, size_t stride, void* out);
- // Resource In-Flight Update
- GS_API_DECL void gs_graphics_texture_request_update(gs_command_buffer_t* cb, gs_handle(gs_graphics_texture_t) hndl, gs_graphics_texture_desc_t* desc);
- GS_API_DECL void gs_graphics_vertex_buffer_request_update(gs_command_buffer_t* cb, gs_handle(gs_graphics_vertex_buffer_t) hndl, gs_graphics_vertex_buffer_desc_t* desc);
- GS_API_DECL void gs_graphics_index_buffer_request_update(gs_command_buffer_t* cb, gs_handle(gs_graphics_index_buffer_t) hndl, gs_graphics_index_buffer_desc_t* desc);
- GS_API_DECL void gs_graphics_uniform_buffer_request_update(gs_command_buffer_t* cb, gs_handle(gs_graphics_uniform_buffer_t) hndl, gs_graphics_uniform_buffer_desc_t* desc);
- GS_API_DECL void gs_graphics_storage_buffer_request_update(gs_command_buffer_t* cb, gs_handle(gs_graphics_storage_buffer_t) hndl, gs_graphics_storage_buffer_desc_t* desc);
- // Pipeline / Pass / Bind / Draw
- GS_API_DECL void gs_graphics_renderpass_begin(gs_command_buffer_t* cb, gs_handle(gs_graphics_renderpass_t) hndl);
- GS_API_DECL void gs_graphics_renderpass_end(gs_command_buffer_t* cb);
- GS_API_DECL void gs_graphics_set_viewport(gs_command_buffer_t* cb, uint32_t x, uint32_t y, uint32_t w, uint32_t h);
- GS_API_DECL void gs_graphics_set_view_scissor(gs_command_buffer_t* cb, uint32_t x, uint32_t y, uint32_t w, uint32_t h);
- GS_API_DECL void gs_graphics_clear(gs_command_buffer_t* cb, gs_graphics_clear_desc_t* desc);
- GS_API_DECL void gs_graphics_pipeline_bind(gs_command_buffer_t* cb, gs_handle(gs_graphics_pipeline_t) hndl);
- GS_API_DECL void gs_graphics_apply_bindings(gs_command_buffer_t* cb, gs_graphics_bind_desc_t* binds);
- GS_API_DECL void gs_graphics_draw(gs_command_buffer_t* cb, gs_graphics_draw_desc_t* desc);
- GS_API_DECL void gs_graphics_dispatch_compute(gs_command_buffer_t* cb, uint32_t num_x_groups, uint32_t num_y_groups, uint32_t num_z_groups);
- // Submission (Main Thread)
- #define gs_graphics_command_buffer_submit(CB) gs_graphics()->api.command_buffer_submit((CB))
- #ifndef GS_NO_SHORT_NAME
-
- typedef gs_handle(gs_graphics_shader_t) gs_shader_t;
- typedef gs_handle(gs_graphics_texture_t) gs_texture_t;
- typedef gs_handle(gs_graphics_renderpass_t) gs_renderpass_t;
- typedef gs_handle(gs_graphics_framebuffer_t) gs_framebuffer_t;
- typedef gs_handle(gs_graphics_pipeline_t) gs_pipeline_t;
- typedef gs_handle(gs_graphics_vertex_buffer_t) gs_vbo_t;
- typedef gs_handle(gs_graphics_index_buffer_t) gs_ibo_t;
- typedef gs_handle(gs_graphics_uniform_buffer_t) gs_ubo_t;
- typedef gs_handle(gs_graphics_uniform_t) gs_uniform_t;
- typedef gs_handle(gs_graphics_storage_buffer_t) gs_ssbo_t;
- #endif
- /** @} */ // end of gs_graphics
- /*==========================
- // GS_ASSET_TYPES
- ==========================*/
- /** @addtogroup gs_util
- * @{
- */
- // Texture
- typedef struct gs_asset_texture_t
- {
- gs_handle(gs_graphics_texture_t) hndl;
- gs_graphics_texture_desc_t desc;
- } gs_asset_texture_t;
- GS_API_DECL bool gs_asset_texture_load_from_file(const char* path, void* out, gs_graphics_texture_desc_t* desc, bool32_t flip_on_load, bool32_t keep_data);
- GS_API_DECL bool gs_asset_texture_load_from_memory(const void* memory, size_t sz, void* out, gs_graphics_texture_desc_t* desc, bool32_t flip_on_load, bool32_t keep_data);
- // Font
- typedef struct gs_baked_char_t
- {
- uint32_t codepoint;
- uint16_t x0, y0, x1, y1;
- float xoff, yoff, advance;
- uint32_t width, height;
- } gs_baked_char_t;
- typedef struct gs_asset_font_t
- {
- void* font_info;
- gs_baked_char_t glyphs[96];
- gs_asset_texture_t texture;
- float ascent;
- float descent;
- float line_gap;
- } gs_asset_font_t;
- GS_API_DECL bool gs_asset_font_load_from_file(const char* path, void* out, uint32_t point_size);
- GS_API_DECL bool gs_asset_font_load_from_memory(const void* memory, size_t sz, void* out, uint32_t point_size);
- GS_API_DECL gs_vec2 gs_asset_font_text_dimensions(const gs_asset_font_t* font, const char* text, int32_t len);
- GS_API_DECL gs_vec2 gs_asset_font_text_dimensions_ex(const gs_asset_font_t* fp, const char* text, int32_t len, bool32_t include_past_baseline);
- GS_API_DECL float gs_asset_font_max_height(const gs_asset_font_t* font);
- // Audio
- typedef struct gs_asset_audio_t
- {
- gs_handle(gs_audio_source_t) hndl;
- } gs_asset_audio_t;
- GS_API_DECL bool gs_asset_audio_load_from_file(const char* path, void* out);
- // Mesh
- gs_enum_decl(gs_asset_mesh_attribute_type,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_POSITION,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_NORMAL,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_TANGENT,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_JOINT,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_WEIGHT,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_TEXCOORD,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_COLOR,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_UINT
- );
- typedef struct gs_asset_mesh_layout_t {
- gs_asset_mesh_attribute_type type; // Type of attribute
- uint32_t idx; // Optional index (for joint/weight/texcoord/color)
- } gs_asset_mesh_layout_t;
- typedef struct gs_asset_mesh_decl_t
- {
- gs_asset_mesh_layout_t* layout; // Mesh attribute layout array
- size_t layout_size; // Size of mesh attribute layout array in bytes
- size_t index_buffer_element_size; // Size of index data size in bytes
- } gs_asset_mesh_decl_t;
- typedef struct gs_asset_mesh_primitive_t
- {
- gs_handle(gs_graphics_vertex_buffer_t) vbo;
- gs_handle(gs_graphics_index_buffer_t) ibo;
- uint32_t count;
- } gs_asset_mesh_primitive_t;
- typedef struct gs_asset_mesh_t
- {
- gs_dyn_array(gs_asset_mesh_primitive_t) primitives;
- } gs_asset_mesh_t;
- // Structured/packed raw mesh data
- typedef struct gs_asset_mesh_raw_data_t
- {
- uint32_t prim_count;
- size_t* vertex_sizes;
- size_t* index_sizes;
- void** vertices;
- void** indices;
- } gs_asset_mesh_raw_data_t;
- GS_API_DECL bool gs_asset_mesh_load_from_file(const char* path, void* out, gs_asset_mesh_decl_t* decl, void* data_out, size_t data_size);
- GS_API_DECL bool gs_util_load_gltf_data_from_file(const char* path, gs_asset_mesh_decl_t* decl, gs_asset_mesh_raw_data_t** out, uint32_t* mesh_count);
- GS_API_DECL bool gs_util_load_gltf_data_from_memory(const void* memory, size_t sz, gs_asset_mesh_decl_t* decl, gs_asset_mesh_raw_data_t** out, uint32_t* mesh_count);
- /** @} */ // end of gs_util
- // Material
- // How to do this? Materials really are utility types...
- // So should they be relegated to a utility file?
- /*
- gs_util_material?
- */
- // Pipeline
- // Uniform
- /*
- // Could pass in a mesh decl? Then it'll just give you back packed vertex/index data for each primitive?
- GS_API_DECL gs_util_load_gltf_from_file(const char* path, gs_asset_mesh_decl_t* decl, uint32_t* primitive_count, void*** verticies, size_t** vertex_sizes, void*** indices, size_t** index_sizes);
-
- To use:
- // For primitives
- uint32_t prim_count = 0;
- size_t* vertex_sizes = NULL;
- size_t* index_sizes = NULL;
- float** vertices = NULL;
- uint32_t** indices = NULL;
- gs_asset_mesh_raw_data_t data = {};
- gs_util_load_gltf_from_file("path", &decl, &data);
- */
- /*==========================
- // GS_ENGINE / GS_APP
- ==========================*/
- /** @defgroup gs_app App/Engine
- * Gunslinger App/Engine
- * @{
- */
- // Application descriptor for user application
- typedef struct gs_app_desc_t
- {
- void (* init)();
- void (* update)();
- void (* shutdown)();
- gs_platform_window_desc_t window;
- bool32 is_running;
- bool32 debug_gfx;
- void* user_data;
- int32_t argc;
- char** argv;
- // Platform specific data
- #ifdef GS_PLATFORM_ANDROID
- struct {
- void* activity;
- const char* internal_data_path;
- } android;
- #endif
- } gs_app_desc_t;
- /*
- Game Context:
- * This is the main context for the gunslinger framework. Holds pointers to
- all interfaces registered with the framework, including the description
- for your application.
- */
- typedef struct gs_context_t
- {
- gs_platform_t* platform;
- gs_graphics_t* graphics;
- gs_audio_t* audio;
- gs_app_desc_t app;
- gs_os_api_t os;
- gs_atomic_int_t lock;
- } gs_context_t;
- typedef struct gs_t
- {
- gs_context_t ctx;
- void (* shutdown)();
- } gs_t;
- /* Desc */
- GS_API_DECL gs_t*
- gs_create(gs_app_desc_t app_desc);
- /* Desc */
- GS_API_DECL void
- gs_destroy();
- /* Desc */
- GS_API_DECL gs_t*
- gs_instance();
- /* Desc */
- GS_API_DECL void
- gs_set_instance(gs_t* gs);
- /* Desc */
- GS_API_DECL gs_context_t*
- gs_ctx();
- /* Desc */
- GS_API_DECL gs_app_desc_t*
- gs_app();
- /* Desc */
- GS_API_DECL void
- gs_frame();
- /* Desc */
- GS_API_DECL void
- gs_quit();
- /* Desc */
- GS_API_DECL gs_app_desc_t
- gs_main(int32_t argc, char** argv);
- #define gs_subsystem(__T)\
- (gs_instance()->ctx.__T)
- #define gs_user_data(__T)\
- (__T*)(gs_instance()->ctx.app.user_data)
- /** @} */ // end of gs_app
- /*==================================================================================================================================
- // ===== Gunslinger Implementation ============================================================================================== //
- ==================================================================================================================================*/
- #ifdef GS_IMPL
- /*=============================
- // GS_PLATFORM
- =============================*/
- // Default provided platform implementations (these will be removed eventually)
- #ifndef GS_PLATFORM_IMPL_CUSTOM
- #if (defined GS_PLATFORM_WIN || defined GS_PLATFORM_APPLE || defined GS_PLATFORM_LINUX)
- #define GS_PLATFORM_IMPL_GLFW
- #elif (defined GS_PLATFORM_WEB)
- #define GS_PLATFORM_IMPL_EMSCRIPTEN
- #elif (defined GS_PLATFORM_ANDROID)
- #define GS_PLATFORM_IMPL_ANDROID
- #endif
- #endif
- #ifdef GS_PLATFORM_IMPL_FILE
- #include GS_PLATFORM_IMPL_FILE
- #endif
- #include "impl/gs_platform_impl.h"
- /*=============================
- // GS_GRAPHICS
- =============================*/
- #ifndef GS_GRAPHICS_IMPL_CUSTOM
- #if (defined GS_PLATFORM_WIN || defined GS_PLATFORM_APPLE || defined GS_PLATFORM_LINUX)
- #define GS_GRAPHICS_IMPL_OPENGL_CORE
- #else
- #define GS_GRAPHICS_IMPL_OPENGL_ES
- #endif
- #endif
- #include "impl/gs_graphics_impl.h"
- // Resource Creation
- GS_API_DECL gs_handle(gs_graphics_texture_t)
- gs_graphics_texture_create(const gs_graphics_texture_desc_t* desc)
- {
- return gs_graphics()->api.texture_create(desc);
- }
- GS_API_DECL gs_handle(gs_graphics_uniform_t)
- gs_graphics_uniform_create(const gs_graphics_uniform_desc_t* desc)
- {
- return gs_graphics()->api.uniform_create(desc);
- }
- GS_API_DECL gs_handle(gs_graphics_shader_t)
- gs_graphics_shader_create(const gs_graphics_shader_desc_t* desc)
- {
- return gs_graphics()->api.shader_create(desc);
- }
- GS_API_DECL gs_handle(gs_graphics_vertex_buffer_t)
- gs_graphics_vertex_buffer_create(const gs_graphics_vertex_buffer_desc_t* desc)
- {
- return gs_graphics()->api.vertex_buffer_create(desc);
- }
- GS_API_DECL gs_handle(gs_graphics_index_buffer_t)
- gs_graphics_index_buffer_create(const gs_graphics_index_buffer_desc_t* desc)
- {
- return gs_graphics()->api.index_buffer_create(desc);
- }
- GS_API_DECL gs_handle(gs_graphics_uniform_buffer_t)
- gs_graphics_uniform_buffer_create(const gs_graphics_uniform_buffer_desc_t* desc)
- {
- return gs_graphics()->api.uniform_buffer_create(desc);
- }
- GS_API_DECL gs_handle(gs_graphics_storage_buffer_t)
- gs_graphics_storage_buffer_create(const gs_graphics_storage_buffer_desc_t* desc)
- {
- return gs_graphics()->api.storage_buffer_create(desc);
- }
- GS_API_DECL gs_handle(gs_graphics_framebuffer_t)
- gs_graphics_framebuffer_create(const gs_graphics_framebuffer_desc_t* desc)
- {
- return gs_graphics()->api.framebuffer_create(desc);
- }
- GS_API_DECL gs_handle(gs_graphics_renderpass_t)
- gs_graphics_renderpass_create(const gs_graphics_renderpass_desc_t* desc)
- {
- return gs_graphics()->api.renderpass_create(desc);
- }
- GS_API_DECL gs_handle(gs_graphics_pipeline_t)
- gs_graphics_pipeline_create(const gs_graphics_pipeline_desc_t* desc)
- {
- return gs_graphics()->api.pipeline_create(desc);
- }
- // Destroy
- GS_API_DECL void
- gs_graphics_texture_destroy(gs_handle(gs_graphics_texture_t) hndl)
- {
- gs_graphics()->api.texture_destroy(hndl);
- }
- GS_API_DECL void
- gs_graphics_uniform_destroy(gs_handle(gs_graphics_uniform_t) hndl)
- {
- gs_graphics()->api.uniform_destroy(hndl);
- }
- GS_API_DECL void
- gs_graphics_shader_destroy(gs_handle(gs_graphics_shader_t) hndl)
- {
- gs_graphics()->api.shader_destroy(hndl);
- }
- GS_API_DECL void
- gs_graphics_vertex_buffer_destroy(gs_handle(gs_graphics_vertex_buffer_t) hndl)
- {
- gs_graphics()->api.vertex_buffer_destroy(hndl);
- }
- GS_API_DECL void
- gs_graphics_index_buffer_destroy(gs_handle(gs_graphics_index_buffer_t) hndl)
- {
- gs_graphics()->api.index_buffer_destroy(hndl);
- }
- GS_API_DECL void
- gs_graphics_uniform_buffer_destroy(gs_handle(gs_graphics_uniform_buffer_t) hndl)
- {
- gs_graphics()->api.uniform_buffer_destroy(hndl);
- }
- GS_API_DECL void
- gs_graphics_storage_buffer_destroy(gs_handle(gs_graphics_storage_buffer_t) hndl)
- {
- gs_graphics()->api.storage_buffer_destroy(hndl);
- }
- GS_API_DECL void
- gs_graphics_framebuffer_destroy(gs_handle(gs_graphics_framebuffer_t) hndl)
- {
- gs_graphics()->api.framebuffer_destroy(hndl);
- }
- GS_API_DECL void
- gs_graphics_renderpass_destroy(gs_handle(gs_graphics_renderpass_t) hndl)
- {
- gs_graphics()->api.renderpass_destroy(hndl);
- }
- GS_API_DECL void
- gs_graphics_pipeline_destroy(gs_handle(gs_graphics_pipeline_t) hndl)
- {
- gs_graphics()->api.pipeline_destroy(hndl);
- }
- // Resource Updates (main thread only)
- GS_API_DECL void
- gs_graphics_vertex_buffer_update(gs_handle(gs_graphics_vertex_buffer_t) hndl, gs_graphics_vertex_buffer_desc_t* desc)
- {
- gs_graphics()->api.vertex_buffer_update(hndl, desc);
- }
- GS_API_DECL void
- gs_graphics_index_buffer_update(gs_handle(gs_graphics_index_buffer_t) hndl, gs_graphics_index_buffer_desc_t* desc)
- {
- gs_graphics()->api.index_buffer_update(hndl, desc);
- }
- GS_API_DECL void
- gs_graphics_storage_buffer_update(gs_handle(gs_graphics_storage_buffer_t) hndl, gs_graphics_storage_buffer_desc_t* desc)
- {
- gs_graphics()->api.storage_buffer_update(hndl, desc);
- }
- GS_API_DECL void
- gs_graphics_texture_update(gs_handle(gs_graphics_texture_t) hndl, gs_graphics_texture_desc_t* desc)
- {
- gs_graphics()->api.texture_update(hndl, desc);
- }
- GS_API_DECL void
- gs_graphics_texture_read(gs_handle(gs_graphics_texture_t) hndl, gs_graphics_texture_desc_t* desc)
- {
- return gs_graphics()->api.texture_read(hndl, desc);
- }
- GS_API_DECL void*
- gs_graphics_storage_buffer_map_get(gs_handle(gs_graphics_storage_buffer_t) hndl)
- {
- return gs_graphics()->api.storage_buffer_map_get(hndl);
- }
- GS_API_DECL void
- gs_graphics_storage_buffer_unlock(gs_handle(gs_graphics_storage_buffer_t) hndl)
- {
- return gs_graphics()->api.storage_buffer_unlock(hndl);
- }
- GS_API_DECL void*
- gs_graphics_storage_buffer_lock(gs_handle(gs_graphics_storage_buffer_t) hndl, size_t offset, size_t sz)
- {
- return gs_graphics()->api.storage_buffer_lock(hndl, offset, sz);
- }
- GS_API_DECL void
- gs_graphics_storage_buffer_get_data(gs_handle(gs_graphics_storage_buffer_t) hndl, size_t offset, size_t sz, void* out)
- {
- return gs_graphics()->api.storage_buffer_get_data(hndl, offset, sz, out);
- }
- /*=============================
- // GS_AUDIO
- =============================*/
- #ifndef GS_AUDIO_IMPL_CUSTOM
- #define GS_AUDIO_IMPL_MINIAUDIO
- #endif
- #include "impl/gs_audio_impl.h"
- /*==========================
- // GS_OS
- ==========================*/
- GS_API_DECL
- void* _gs_malloc_init_impl(size_t sz)
- {
- void* data = gs_malloc(sz);
- memset(data, 0, sz);
- return data;
- }
- GS_API_DECL gs_os_api_t
- gs_os_api_new_default()
- {
- gs_os_api_t os = gs_default_val();
- os.malloc = malloc;
- os.malloc_init = _gs_malloc_init_impl;
- os.free = free;
- os.realloc = realloc;
- os.calloc = calloc;
- os.strdup = strdup;
- #ifdef GS_PLATFORM_WIN
- os.alloca = malloc;
- #else
- os.alloca = malloc;
- #endif
- return os;
- }
- /*========================
- // gs_byte_buffer
- ========================*/
- void gs_byte_buffer_init(gs_byte_buffer_t* buffer)
- {
- buffer->data = (uint8_t*)gs_malloc(GS_BYTE_BUFFER_DEFAULT_CAPCITY);
- buffer->capacity = GS_BYTE_BUFFER_DEFAULT_CAPCITY;
- buffer->size = 0;
- buffer->position = 0;
- }
- gs_byte_buffer_t gs_byte_buffer_new()
- {
- gs_byte_buffer_t buffer;
- gs_byte_buffer_init(&buffer);
- return buffer;
- }
- void gs_byte_buffer_free(gs_byte_buffer_t* buffer)
- {
- if (buffer && buffer->data) {
- gs_free(buffer->data);
- }
- }
- void gs_byte_buffer_clear(gs_byte_buffer_t* buffer)
- {
- buffer->size = 0;
- buffer->position = 0;
- }
- bool gs_byte_buffer_empty(gs_byte_buffer_t* buffer)
- {
- return (buffer->size == 0);
- }
- size_t gs_byte_buffer_size(gs_byte_buffer_t* buffer)
- {
- return buffer->size;
- }
- void gs_byte_buffer_resize(gs_byte_buffer_t* buffer, size_t sz)
- {
- if (!buffer) return;
-
- uint8_t* data = (uint8_t*)gs_realloc(buffer->data, sz);
- if (data == NULL) {
- gs_log_warning("gs_byte_buffer_resize: realloc failed for size %zu. Keeping old buffer.", sz);
- return;
- }
- buffer->data = data;
- buffer->capacity = (uint32_t)sz;
- }
- void gs_byte_buffer_copy_contents(gs_byte_buffer_t* dst, gs_byte_buffer_t* src)
- {
- gs_byte_buffer_seek_to_beg(dst);
- gs_byte_buffer_seek_to_beg(src);
- gs_byte_buffer_write_bulk(dst, src->data, src->size);
- }
- void gs_byte_buffer_seek_to_beg(gs_byte_buffer_t* buffer)
- {
- buffer->position = 0;
- }
- void gs_byte_buffer_seek_to_end(gs_byte_buffer_t* buffer)
- {
- buffer->position = buffer->size;
- }
- void gs_byte_buffer_advance_position(gs_byte_buffer_t* buffer, size_t sz)
- {
- buffer->position += (uint32_t)sz;
- }
- void gs_byte_buffer_write_bulk(gs_byte_buffer_t* buffer, void* src, size_t size)
- {
- if (!buffer || !src || !size) return;
-
- // Check for necessary resize
- size_t total_write_size = buffer->position + size;
- if (total_write_size >= (size_t)buffer->capacity)
- {
- size_t capacity = buffer->capacity * 2;
- while(capacity <= total_write_size)
- {
- capacity *= 2;
- }
- uint8_t* old_data = buffer->data;
- gs_byte_buffer_resize(buffer, capacity);
- if (buffer->data == NULL) {
- buffer->data = old_data;
- return;
- }
- }
- // Safety check before memcpy
- if (!buffer->data) return;
-
- // memcpy data
- memcpy((buffer->data + buffer->position), src, size);
- buffer->size += (uint32_t)size;
- buffer->position += (uint32_t)size;
- }
- void gs_byte_buffer_read_bulk(gs_byte_buffer_t* buffer, void** dst, size_t size)
- {
- memcpy(*dst, (buffer->data + buffer->position), size);
- buffer->position += (uint32_t)size;
- }
- void gs_byte_buffer_write_str(gs_byte_buffer_t* buffer, const char* str)
- {
- // Write size of string
- uint32_t str_len = gs_string_length(str);
- gs_byte_buffer_write(buffer, uint16_t, str_len);
- size_t i;
- for (i = 0; i < str_len; ++i)
- {
- gs_byte_buffer_write(buffer, uint8_t, str[i]);
- }
- }
- void gs_byte_buffer_read_str(gs_byte_buffer_t* buffer, char* str)
- {
- // Read in size of string from buffer
- uint16_t sz;
- gs_byte_buffer_read(buffer, uint16_t, &sz);
- uint32_t i;
- for (i = 0; i < sz; ++i)
- {
- gs_byte_buffer_read(buffer, uint8_t, &str[i]);
- }
- str[i] = '\0';
- }
- gs_result
- gs_byte_buffer_write_to_file
- (
- gs_byte_buffer_t* buffer,
- const char* output_path
- )
- {
- return gs_platform_write_file_contents(output_path, "wb", buffer->data, buffer->size);
- }
- gs_result
- gs_byte_buffer_read_from_file
- (
- gs_byte_buffer_t* buffer,
- const char* file_path
- )
- {
- if (!buffer) return GS_RESULT_FAILURE;
- if (buffer->data) {
- gs_byte_buffer_free(buffer);
- }
- buffer->data = (u8*)gs_platform_read_file_contents(file_path, "rb", (size_t*)&buffer->size);
- if (!buffer->data) {
- gs_assert(false);
- return GS_RESULT_FAILURE;
- }
- buffer->position = 0;
- buffer->capacity = buffer->size;
- return GS_RESULT_SUCCESS;
- }
- GS_API_DECL void gs_byte_buffer_memset(gs_byte_buffer_t* buffer, uint8_t val)
- {
- memset(buffer->data, val, buffer->capacity);
- }
- /*========================
- // Dynamic Array
- ========================*/
- GS_API_DECL void*
- gs_dyn_array_resize_impl(void* arr, size_t sz, size_t amount)
- {
- size_t capacity;
- if (arr) {
- capacity = amount;
- } else {
- capacity = 0;
- }
- // Create new gs_dyn_array with just the header information
- gs_dyn_array* data = (gs_dyn_array*)gs_realloc(arr ? gs_dyn_array_head(arr) : 0, capacity * sz + sizeof(gs_dyn_array));
- if (data) {
- if (!arr) {
- data->size = 0;
- }
- data->capacity = (int32_t)capacity;
- return ((int32_t*)data + 2);
- }
- return NULL;
- }
- GS_API_DECL void**
- gs_dyn_array_init(void** arr, size_t val_len)
- {
- if (*arr == NULL) {
- gs_dyn_array* data = (gs_dyn_array*)gs_malloc(val_len + sizeof(gs_dyn_array)); // Allocate capacity of one
- data->size = 0;
- data->capacity = 1;
- *arr = ((int32_t*)data + 2);
- }
- return arr;
- }
- GS_API_DECL void
- gs_dyn_array_push_data(void** arr, void* val, size_t val_len)
- {
- if (*arr == NULL) {
- gs_dyn_array_init(arr, val_len);
- }
- if (gs_dyn_array_need_grow(*arr, 1))
- {
- int32_t capacity = gs_dyn_array_capacity(*arr) * 2;
- // Create new gs_dyn_array with just the header information
- gs_dyn_array* data = (gs_dyn_array*)gs_realloc(gs_dyn_array_head(*arr), capacity * val_len + sizeof(gs_dyn_array));
- if (data) {
- data->capacity = capacity;
- *arr = ((int32_t*)data + 2);
- }
- }
- size_t offset = gs_dyn_array_size(*arr);
- memcpy(((uint8_t*)(*arr)) + offset * val_len, val, val_len);
- gs_dyn_array_head(*arr)->size++;
- }
- /*========================
- // Hash Table
- ========================*/
- GS_API_DECL void
- __gs_hash_table_init_impl(void** ht, size_t sz)
- {
- *ht = gs_malloc(sz);
- }
- /*========================
- // Hash Set
- ========================*/
- GS_API_DECL void
- __gs_hash_set_init_impl(void** hs, size_t sz)
- {
- *hs = gs_malloc(sz);
- }
- /*========================
- // Slot Array
- ========================*/
- GS_API_DECL void**
- gs_slot_array_init(void** sa, size_t sz)
- {
- if (*sa == NULL) {
- *sa = gs_malloc(sz);
- memset(*sa, 0, sz);
- return sa;
- }
- else {
- return NULL;
- }
- }
- /*========================
- // Slot Map
- ========================*/
- GS_API_DECL void**
- gs_slot_map_init(void** sm)
- {
- if (*sm == NULL) {
- (*sm) = gs_malloc(sizeof(size_t) * 2);\
- memset((*sm), 0, sizeof(size_t) * 2);\
- return sm;
- }
- return NULL;
- }
- /*========================
- // Priotity Queue
- ========================*/
- GS_API_DECL void**
- gs_pqueue_init(void** pq, size_t sz)
- {
- if (*pq == NULL) {
- (*pq) = gs_malloc(sz);
- memset((*pq), 0, sz);
- return pq;
- }
- return NULL;
- }
- GS_API_PRIVATE void
- __gs_pqueue_pop_internal(void** pqueue, void* tmp, void** data, int32_t* priority, int32_t pq_sz, size_t d_sz)
- {
- // TODO(): Remove these checks for perf
- if (!pqueue || !tmp || !data || !priority || !pq_sz || !d_sz) return;
- #define __SWP(__I0, __I1)\
- do {\
- {\
- size_t i0 = d_sz * (__I0);\
- size_t i1 = d_sz * (__I1);\
- uint8_t** d = (uint8_t**)data;\
- memcpy(tmp, ((char*)*(d)) + i0, d_sz);\
- memcpy(((char*)(*d)) + i0, ((char*)(*d)) + i1, d_sz);\
- memcpy(((char*)(*d)) + i1, tmp, d_sz);\
- }\
- {\
- int32_t t = 0;\
- uint32_t i0 = (__I0);\
- uint32_t i1 = (__I1);\
- uint32_t sz = sizeof(int32_t);\
- memcpy(&t, ((char*)((priority)) + i0), sz);\
- memcpy((char*)((priority) + i0), (char*)((priority) + i1), sz);\
- memcpy((char*)((priority) + i1), &t, sz);\
- }\
- } while (0)
- // Swap elements internal
- __SWP(0, pq_sz - 1);
- // Work down list from top until priority is sorted
- // THIS PART IS FUCKED
- // return;
- int32_t i = 0;
- int32_t c = 0;
- int32_t nwsz = pq_sz - 1; // Right up until the last item we removed
- int32_t psz = gs_dyn_array_size(priority) - 1;
- // int32_t* pa = priority;
- for (int32_t i = 0; gs_pqueue_child_left_idx(i) < psz; i = c)
- {
- // Set child to smaller of two
- c = gs_pqueue_child_left_idx(i);
- // if (c >= psz) break;
-
- // Set to right child if valid and less priority
- if ((c + 1) < psz && priority[c + 1] < priority[c]) {
- c++;
- }
- // Check to swp, if necessary
- if (priority[i] > priority[c]) {
- __SWP(i, c);
- }
- // Otherwise, we're done
- else
- {
- break;
- }
- }
- // gs_println("P: %d", priority[nwsz - 1]);
- }
- /*========================
- // GS_MEMORY
- ========================*/
- // typedef struct gs_memory_block_t {
- // uint8_t* data;
- // size_t size;
- // } gs_memory_block_t;
- GS_API_DECL gs_memory_block_t gs_memory_block_new(size_t sz)
- {
- gs_memory_block_t mem = gs_default_val();
- mem.data = (uint8_t*)gs_malloc(sz);
- memset(mem.data, 0, sz);
- mem.size = sz;
- return mem;
- }
- GS_API_DECL void gs_memory_block_free(gs_memory_block_t* mem)
- {
- gs_assert(mem);
- gs_assert(mem->data);
- gs_free(mem->data);
- mem->data = NULL;
- mem->size = 0;
- }
- // Modified from: https://github.com/mtrebi/memory-allocators/blob/master/includes/Utils.h
- GS_API_DECL size_t gs_memory_calc_padding(size_t base_address, size_t alignment)
- {
- size_t mult = (base_address / alignment) + 1;
- size_t aligned_addr = mult * alignment;
- size_t padding = aligned_addr - base_address;
- return padding;
- }
- GS_API_DECL size_t gs_memory_calc_padding_w_header(size_t base_address, size_t alignment, size_t header_sz)
- {
- size_t padding = gs_memory_calc_padding(base_address, alignment);
- size_t needed_space = header_sz;
- if (padding < needed_space) {
- needed_space -= padding;
- if (needed_space % alignment > 0) {
- padding += alignment * (1 + (needed_space / alignment));
- } else {
- padding += alignment * (needed_space / alignment);
- }
- }
- return padding;
- }
- /*================================================================================
- // Linear Allocator
- ================================================================================*/
- // typedef struct gs_linear_allocator_t {
- // uint8_t* memory;
- // size_t total_size;
- // size_t offset;
- // } gs_linear_allocator_t;
- GS_API_DECL gs_linear_allocator_t gs_linear_allocator_new(size_t sz)
- {
- gs_linear_allocator_t la = gs_default_val();
- la.memory = (uint8_t*)gs_malloc(sz);
- memset(la.memory, 0, sz);
- la.offset = 0;
- la.total_size = sz;
- return la;
- }
- GS_API_DECL void gs_linear_allocator_free(gs_linear_allocator_t* la)
- {
- gs_assert(la);
- gs_assert(la->memory);
- gs_free(la->memory);
- la->memory = NULL;
- }
- GS_API_DECL void* gs_linear_allocator_allocate(gs_linear_allocator_t* la, size_t sz, size_t alignment)
- {
- gs_assert(la);
- size_t padding = 0;
- size_t padding_address = 0;
- size_t cur_address = (size_t)la->memory + la->offset;
- // Calculate alignment required
- if (alignment != 0 && la->offset % alignment != 0) {
- padding = gs_memory_calc_padding(cur_address, alignment);
- }
- // Cannot allocate (not enough memory available)
- if (la->offset + padding + sz > la->total_size) {
- return NULL;
- }
- // Allocate and return pointer
- la->offset += padding;
- size_t next_address = cur_address + padding;
- la->offset += sz;
- return (void*)next_address;
- }
- GS_API_DECL void gs_linear_allocator_clear(gs_linear_allocator_t* la)
- {
- gs_assert(la);
- la->offset = 0;
- }
- /*================================================================================
- // Stack Allocator
- ================================================================================*/
- GS_API_DECL gs_stack_allocator_t gs_stack_allocator_new(size_t sz)
- {
- gs_stack_allocator_t alloc = gs_default_val();
- alloc.memory = gs_memory_block_new(sz);
- return alloc;
- }
- GS_API_DECL void gs_stack_allocator_free(gs_stack_allocator_t* sa)
- {
- gs_stack_allocator_clear(sa);
- gs_memory_block_free(&sa->memory);
- }
- GS_API_DECL void* gs_stack_allocator_allocate(gs_stack_allocator_t* sa, size_t sz)
- {
- // Not enough memory available
- size_t total_size = sz + sizeof(gs_stack_allocator_header_t);
- if (total_size > (size_t)sa->memory.size - sa->offset) {
- return NULL;
- }
- // Create new entry and push
- size_t header_addr = (size_t)(sa->memory.data + sa->offset + sz);
- gs_stack_allocator_header_t* header = (gs_stack_allocator_header_t*)(sa->memory.data + sa->offset + sz);
- uint8_t* data = (uint8_t*)(sa->memory.data + sa->offset);
- header->size = (uint32_t)sz;
- // Add this to the memory size
- sa->offset += total_size;
- // Return data
- return data;
- }
- GS_API_DECL void* gs_stack_allocator_pop(gs_stack_allocator_t* sa)
- {
- // If no entries left, then cannot pop
- if (sa->offset == 0) {
- return NULL;
- }
- // Move current size back
- gs_stack_allocator_header_t* header = (gs_stack_allocator_header_t*)(sa->memory.data + sa->offset - sizeof(gs_stack_allocator_header_t));
- void* data = (uint8_t*)(sa->memory.data + sa->offset - sizeof(gs_stack_allocator_header_t) - header->size);
- size_t total_sz = (size_t)header->size + sizeof(gs_stack_allocator_header_t);
- // Set offset back
- sa->offset -= total_sz;
- // Return data
- return (void*)data;
- }
- GS_API_DECL void* gs_stack_allocator_peek(gs_stack_allocator_t* sa)
- {
- if (sa->offset == 0) {
- return NULL;
- }
- gs_stack_allocator_header_t* header = (gs_stack_allocator_header_t*)(sa->memory.data + sa->offset - sizeof(gs_stack_allocator_header_t));
- return (void*)(sa->memory.data + sa->offset - sizeof(gs_stack_allocator_header_t) - (size_t)header->size);
- }
- GS_API_DECL void gs_stack_allocator_clear(gs_stack_allocator_t* sa)
- {
- // Clear offset
- sa->offset = 0;
- }
- /*================================================================================
- // Paged Allocator
- ================================================================================*/
- GS_API_DECL gs_paged_allocator_t gs_paged_allocator_new(size_t block_size, size_t blocks_per_page)
- {
- gs_paged_allocator_t pa = gs_default_val();
- pa.block_size = block_size;
- pa.blocks_per_page = blocks_per_page;
- pa.pages = NULL;
- pa.page_count = 0;
- pa.free_list = NULL;
- return pa;
- }
- GS_API_DECL void gs_paged_allocator_free(gs_paged_allocator_t* pa)
- {
- gs_paged_allocator_clear(pa);
- }
- GS_API_DECL void* gs_paged_allocator_allocate(gs_paged_allocator_t* pa)
- {
- if (pa->free_list)
- {
- gs_paged_allocator_block_t* data = pa->free_list;
- pa->free_list = data->next;
- return data;
- }
- else
- {
- gs_paged_allocator_page_t* page = (gs_paged_allocator_page_t*)_gs_malloc_init_impl(pa->block_size * pa->blocks_per_page + sizeof(gs_paged_allocator_page_t));
- pa->page_count++;
- page->next = pa->pages;
- page->data = (gs_paged_allocator_block_t*)gs_ptr_add(page, sizeof(gs_paged_allocator_page_t));
- pa->pages = page;
- // #define gs_ptr_add(P, BYTES) \
- // (((uint8_t*)P + (BYTES)))
- uint32_t bppmo = pa->blocks_per_page - 1;
- for (uint32_t i = 0; i < bppmo; ++i)
- {
- gs_paged_allocator_block_t* node = (gs_paged_allocator_block_t*)gs_ptr_add(page->data, pa->block_size * i);
- gs_paged_allocator_block_t* next = (gs_paged_allocator_block_t*)gs_ptr_add(page->data, pa->block_size * (i + 1));
- node->next = next;
- }
- gs_paged_allocator_block_t* last = (gs_paged_allocator_block_t*)gs_ptr_add(page->data, pa->block_size * bppmo);
- last->next = NULL;
- pa->free_list = page->data->next;
- return page->data;
- }
- }
- GS_API_DECL void gs_paged_allocator_deallocate(gs_paged_allocator_t* pa, void* data)
- {
- ((gs_paged_allocator_block_t*)data)->next = pa->free_list;
- pa->free_list = ((gs_paged_allocator_block_t*)data);
- }
- GS_API_DECL void gs_paged_allocator_clear(gs_paged_allocator_t* pa)
- {
- gs_paged_allocator_page_t* page = pa->pages;
- for (uint32_t i = 0; i < pa->page_count; ++i)
- {
- gs_paged_allocator_page_t* next = page->next;
- gs_free(page);
- page = next;
- }
- pa->free_list = NULL;
- pa->page_count = 0;
- }
- /*================================================================================
- // Heap Allocator
- ================================================================================*/
- // #ifndef GS_HEAP_ALLOC_DEFAULT_SIZE
- // #define GS_HEAP_ALLOC_DEFAULT_SIZE 1024 * 1024 * 20
- // #endif
- // #ifndef GS_HEAP_ALLOC_DEFAULT_CAPCITY
- // #define GS_HEAP_ALLOC_DEFAULT_CAPCITY 1024
- // #endif
- // typedef struct gs_heap_allocator_header_t {
- // struct gs_heap_allocator_header_t* next;
- // struct gs_heap_allocator_header_t* prev;
- // size_t size;
- // } gs_heap_allocator_header_t;
- // typedef struct gs_heap_allocator_free_block_t {
- // gs_heap_allocator_header_t* header;
- // size_t size;
- // } gs_heap_allocator_free_block_t;
- // typedef struct gs_heap_allocator_t {
- // gs_heap_allocator_header_t* memory;
- // gs_heap_allocator_free_block_t* free_blocks;
- // uint32_t free_block_count;
- // uint32_t free_block_capacity;
- // } gs_heap_allocator_t;
- GS_API_DECL gs_heap_allocator_t gs_heap_allocate_new()
- {
- gs_heap_allocator_t ha = gs_default_val();
- ha.memory = (gs_heap_allocator_header_t*)_gs_malloc_init_impl(GS_HEAP_ALLOC_DEFAULT_SIZE);
- ha.memory->next = NULL;
- ha.memory->prev = NULL;
- ha.memory->size = GS_HEAP_ALLOC_DEFAULT_SIZE;
- ha.free_blocks = (gs_heap_allocator_free_block_t*)_gs_malloc_init_impl(sizeof(gs_heap_allocator_free_block_t) * GS_HEAP_ALLOC_DEFAULT_CAPCITY);
- ha.free_block_count = 1;
- ha.free_block_capacity = GS_HEAP_ALLOC_DEFAULT_CAPCITY;
- ha.free_blocks->header = ha.memory;
- ha.free_blocks->size = GS_HEAP_ALLOC_DEFAULT_SIZE;
- return ha;
- }
- GS_API_DECL void gs_heap_allocator_free(gs_heap_allocator_t* ha)
- {
- gs_free(ha->memory);
- gs_free(ha->free_blocks);
- ha->memory = NULL;
- ha->free_blocks = NULL;
- }
- GS_API_DECL void* gs_heap_allocator_allocate(gs_heap_allocator_t* ha, size_t sz)
- {
- size_t size_needed = sz + sizeof(gs_heap_allocator_header_t);
- gs_heap_allocator_free_block_t* first_fit = NULL;
- for (uint32_t i = 0; i < ha->free_block_count; ++i)
- {
- gs_heap_allocator_free_block_t* block = ha->free_blocks + i;
- if (block->size >= size_needed)
- {
- first_fit = block;
- break;
- }
- }
- if (!first_fit) {
- return NULL;
- }
- gs_heap_allocator_header_t* node = first_fit->header;
- gs_heap_allocator_header_t* new_node = (gs_heap_allocator_header_t*)gs_ptr_add(node, size_needed);
- node->size = size_needed;
- first_fit->size -= size_needed;
- first_fit->header = new_node;
- new_node->next = node->next;
- if (node->next) {
- node->next->prev = new_node;
- }
- node->next = new_node;
- new_node->prev = node;
- return gs_ptr_add(node, sizeof(gs_heap_allocator_header_t));
- }
- GS_API_DECL void
- gs_heap_allocator_deallocate(gs_heap_allocator_t* ha, void* memory)
- {
- // Fill this out...
- }
- /*========================
- // Util
- ========================*/
- GS_API_DECL char*
- gs_util_string_concat(char* s1, const char* s2)
- {
- const size_t a = strlen(s1);
- const size_t b = strlen(s2);
- const size_t ab = a + b + 1;
- s1 = (char*)gs_realloc((void*)s1, ab);
- memcpy(s1 + a, s2, b + 1);
- return s1;
- }
- /*========================
- // Random
- ========================*/
- /* An implementation of the MT19937 Algorithm for the Mersenne Twister
- * by Evan Sultanik. Based upon the pseudocode in: M. Matsumoto and
- * T. Nishimura, "Mersenne Twister: A 623-dimensionally
- * equidistributed uniform pseudorandom number generator," ACM
- * Transactions on Modeling and Computer Simulation Vol. 8, No. 1,
- * January pp.3-30 1998.
- *
- * http://www.sultanik.com/Mersenne_twister
- */
- #define GS_RAND_UPPER_MASK 0x80000000
- #define GS_RAND_LOWER_MASK 0x7fffffff
- #define GS_RAND_TEMPERING_MASK_B 0x9d2c5680
- #define GS_RAND_TEMPERING_MASK_C 0xefc60000
- GS_API_PRIVATE void
- _gs_rand_seed_impl(gs_mt_rand_t* rand, uint64_t seed)
- {
- /* set initial seeds to mt[STATE_VECTOR_LENGTH] using the generator
- * from Line 25 of Table 1 in: Donald Knuth, "The Art of Computer
- * Programming," Vol. 2 (2nd Ed.) pp.102.
- */
- rand->mt[0] = seed & 0xffffffff;
- for (rand->index = 1; rand->index < GS_STATE_VECTOR_LENGTH; rand->index++)
- {
- rand->mt[rand->index] = (6069 * rand->mt[rand->index-1]) & 0xffffffff;
- }
- }
- GS_API_DECL gs_mt_rand_t
- gs_rand_seed(uint64_t seed)
- {
- gs_mt_rand_t rand;
- _gs_rand_seed_impl(&rand, seed);
- return rand;
- }
- GS_API_DECL int64_t
- gs_rand_gen_long(gs_mt_rand_t* rand)
- {
- uint64_t y;
- static uint64_t mag[2] = {0x0, 0x9908b0df}; /* mag[x] = x * 0x9908b0df for x = 0,1 */
- if(rand->index >= GS_STATE_VECTOR_LENGTH || rand->index < 0) {
- /* generate GS_STATE_VECTOR_LENGTH words at a time */
- int kk;
- if(rand->index >= GS_STATE_VECTOR_LENGTH+1 || rand->index < 0) {
- _gs_rand_seed_impl(rand, 4357);
- }
- for(kk=0; kk<GS_STATE_VECTOR_LENGTH-GS_STATE_VECTOR_M; kk++) {
- y = (rand->mt[kk] & GS_RAND_UPPER_MASK) | (rand->mt[kk+1] & GS_RAND_LOWER_MASK);
- rand->mt[kk] = rand->mt[kk+GS_STATE_VECTOR_M] ^ (y >> 1) ^ mag[y & 0x1];
- }
- for(; kk<GS_STATE_VECTOR_LENGTH-1; kk++) {
- y = (rand->mt[kk] & GS_RAND_UPPER_MASK) | (rand->mt[kk+1] & GS_RAND_LOWER_MASK);
- rand->mt[kk] = rand->mt[kk+(GS_STATE_VECTOR_M-GS_STATE_VECTOR_LENGTH)] ^ (y >> 1) ^ mag[y & 0x1];
- }
- y = (rand->mt[GS_STATE_VECTOR_LENGTH-1] & GS_RAND_UPPER_MASK) | (rand->mt[0] & GS_RAND_LOWER_MASK);
- rand->mt[GS_STATE_VECTOR_LENGTH-1] = rand->mt[GS_STATE_VECTOR_M-1] ^ (y >> 1) ^ mag[y & 0x1];
- rand->index = 0;
- }
- y = rand->mt[rand->index++];
- y ^= (y >> 11);
- y ^= (y << 7) & GS_RAND_TEMPERING_MASK_B;
- y ^= (y << 15) & GS_RAND_TEMPERING_MASK_C;
- y ^= (y >> 18);
- return y;
- }
- GS_API_DECL double
- gs_rand_gen(gs_mt_rand_t* rand)
- {
- return((double)gs_rand_gen_long(rand) / (uint64_t)0xffffffff);
- }
- GS_API_DECL int64_t
- gs_rand_gen_range_long(gs_mt_rand_t* rand, int32_t min, int32_t max)
- {
- return (int64_t)(floorf(gs_rand_gen_range(rand, (double)min, (double)max)));
- }
- GS_API_DECL double
- gs_rand_gen_range(gs_mt_rand_t* rand, double min, double max)
- {
- return gs_map_range(0.0, 1.0, min, max, gs_rand_gen(rand));
- }
- GS_API_DECL gs_color_t
- gs_rand_gen_color(gs_mt_rand_t* rand)
- {
- gs_color_t c = gs_default_val();
- c.r = (uint8_t)gs_rand_gen_range_long(rand, 0, 255);
- c.g = (uint8_t)gs_rand_gen_range_long(rand, 0, 255);
- c.b = (uint8_t)gs_rand_gen_range_long(rand, 0, 255);
- c.a = (uint8_t)gs_rand_gen_range_long(rand, 0, 255);
- return c;
- }
- /*================================================================================
- // Coroutine
- ================================================================================*/
- // Light wrapper around Minicoro
- #define MINICORO_IMPL
- #include "external/minicoro/minicoro.h"
- /*================================================================================
- // Scheduler
- ================================================================================*/
- #define SCHED_IMPLEMENTATION
- #include "external/sched/sched.h"
-
- /* ---------------------------------------------------------------
- * ATOMIC
- * ---------------------------------------------------------------*/
- #if defined(_WIN32) && !(defined(__MINGW32__) || defined(__MINGW64__))
- #include <intrin.h>
- void _ReadWriteBarrier();
- #pragma intrinsic(_ReadWriteBarrier)
- #pragma intrinsic(_InterlockedCompareExchange)
- #pragma intrinsic(_InterlockedExchangeAdd)
- #endif
- GS_API_DECL uint32_t
- gs_atomic_cmp_swp(volatile uint32_t *dst, uint32_t swap, uint32_t cmp)
- {
- /* Atomically performs: if (*dst == swapTp){ *dst = swapTo;}
- * return old *dst (so if sucessfull return cmp) */
- #if defined(_WIN32) && !(defined(__MINGW32__) || defined(__MINGW64__))
- /* assumes two's complement - unsigned /signed conversion leads to same bit pattern */
- return _InterlockedCompareExchange((volatile long*)dst, swap, cmp);
- #else
- return __sync_val_compare_and_swap(dst, cmp, swap);
- #endif
- }
- GS_API_DECL gs_atomic_int_t
- gs_atomic_add(volatile gs_atomic_int_t *dst, int32_t value)
- {
- /* Atomically performs: tmp = *dst: *dst += value; return tmp; */
- #if defined(_WIN32) && !(defined(__MINGW32__) || defined(__MINGW64__))
- return _InterlockedExchangeAdd((long*)dst, value);
- #else
- return (sched_int)__sync_add_and_fetch(dst, value);
- #endif
- }
- /*================================================================================
- // Noise
- ================================================================================*/
- #define SG_NOISE_IMPL
- #include "external/sg_noise/sg_noise.h"
- // Perlin noise
- GS_API_DECL float
- gs_perlin1(float x)
- {
- return sg_noise1(x);
- }
- GS_API_DECL float
- gs_perlin2(float x, float y)
- {
- return sg_noise2(x, y);
- }
- GS_API_DECL float
- gs_perlin3(float x, float y, float z)
- {
- return sg_noise3(x, y, z);
- }
- GS_API_DECL float
- gs_perlin4(float x, float y, float z, float w)
- {
- return sg_noise4(x, y, z, w);
- }
- // Perlin periodic noise
- GS_API_DECL float
- gs_perlin1p(float x, int32_t px)
- {
- return sg_pnoise1(x, px);
- }
- GS_API_DECL float
- gs_perlin2p(float x, float y, int32_t px, int32_t py)
- {
- return sg_pnoise2(x, y, px, py);
- }
- GS_API_DECL float
- gs_perlin3p(float x, float y, float z, int32_t px, int32_t py, int32_t pz)
- {
- return sg_pnoise3(x, y, z, px, py, pz);
- }
- GS_API_DECL float
- gs_perlin4p(float x, float y, float z, float w, int32_t px, int32_t py, int32_t pz, int32_t pw)
- {
- return sg_pnoise4(x, y, z, w, px, py, pz, pw);
- }
- /*=============================
- // Camera
- =============================*/
- GS_API_DECL gs_camera_t
- gs_camera_default()
- {
- // Construct default camera parameters
- gs_camera_t cam = gs_default_val();
- cam.transform = gs_vqs_default();
- cam.transform.position.z = 1.f;
- cam.fov = 60.f;
- cam.near_plane = 0.1f;
- cam.far_plane = 1000.f;
- cam.ortho_scale = 1.f;
- cam.proj_type = GS_PROJECTION_TYPE_ORTHOGRAPHIC;
- return cam;
- }
- GS_API_DECL gs_camera_t
- gs_camera_perspective()
- {
- gs_camera_t cam = gs_camera_default();
- cam.proj_type = GS_PROJECTION_TYPE_PERSPECTIVE;
- cam.transform.position.z = 1.f;
- return cam;
- }
- GS_API_DECL gs_vec3
- gs_camera_forward(const gs_camera_t* cam)
- {
- return (gs_quat_rotate(cam->transform.rotation, gs_v3(0.0f, 0.0f, -1.0f)));
- }
- GS_API_DECL gs_vec3
- gs_camera_backward(const gs_camera_t* cam)
- {
- return (gs_quat_rotate(cam->transform.rotation, gs_v3(0.0f, 0.0f, 1.0f)));
- }
- GS_API_DECL gs_vec3
- gs_camera_up(const gs_camera_t* cam)
- {
- return (gs_quat_rotate(cam->transform.rotation, gs_v3(0.0f, 1.0f, 0.0f)));
- }
- GS_API_DECL gs_vec3
- gs_camera_down(const gs_camera_t* cam)
- {
- return (gs_quat_rotate(cam->transform.rotation, gs_v3(0.0f, -1.0f, 0.0f)));
- }
- GS_API_DECL gs_vec3
- gs_camera_right(const gs_camera_t* cam)
- {
- return (gs_quat_rotate(cam->transform.rotation, gs_v3(1.0f, 0.0f, 0.0f)));
- }
- GS_API_DECL gs_vec3
- gs_camera_left(const gs_camera_t* cam)
- {
- return (gs_quat_rotate(cam->transform.rotation, gs_v3(-1.0f, 0.0f, 0.0f)));
- }
- GS_API_DECL gs_vec3
- gs_camera_world_to_screen(const gs_camera_t* cam, gs_vec3 coords, int32_t view_width, int32_t view_height)
- {
- // Transform world coords to screen coords to place billboarded UI elements in world
- gs_mat4 vp = gs_camera_get_view_projection(cam, view_width, view_height);
- gs_vec4 p4 = gs_v4(coords.x, coords.y, coords.z, 1.f);
- p4 = gs_mat4_mul_vec4(vp, p4);
- p4.x /= p4.w;
- p4.y /= p4.w;
- p4.z /= p4.w;
- // Bring into ndc
- p4.x = p4.x * 0.5f + 0.5f;
- p4.y = p4.y * 0.5f + 0.5f;
- // Bring into screen space
- p4.x = p4.x * (float)view_width;
- p4.y = gs_map_range(1.f, 0.f, 0.f, 1.f, p4.y) * (float)view_height;
- return gs_v3(p4.x, p4.y, p4.z);
- }
- GS_API_DECL gs_vec3
- gs_camera_screen_to_world(const gs_camera_t* cam, gs_vec3 coords, s32 view_x, s32 view_y, s32 view_width, s32 view_height)
- {
- gs_vec3 wc = gs_default_val();
- // Get inverse of view projection from camera
- gs_mat4 inverse_vp = gs_mat4_inverse(gs_camera_get_view_projection(cam, view_width, view_height));
- f32 w_x = (f32)coords.x - (f32)view_x;
- f32 w_y = (f32)coords.y - (f32)view_y;
- f32 w_z = (f32)coords.z;
- // Transform from ndc
- gs_vec4 in;
- in.x = (w_x / (f32)view_width) * 2.f - 1.f;
- in.y = 1.f - (w_y / (f32)view_height) * 2.f;
- in.z = 2.f * w_z - 1.f;
- in.w = 1.f;
- // To world coords
- gs_vec4 out = gs_mat4_mul_vec4(inverse_vp, in);
- if (out.w == 0.f)
- {
- // Avoid div by zero
- return wc;
- }
- out.w = fabsf(out.w) > GS_EPSILON ? 1.f / out.w : 0.0001f;
- wc = gs_v3(
- out.x * out.w,
- out.y * out.w,
- out.z * out.w
- );
- return wc;
- }
- GS_API_DECL gs_mat4
- gs_camera_get_view_projection(const gs_camera_t* cam, s32 view_width, s32 view_height)
- {
- gs_mat4 view = gs_camera_get_view(cam);
- gs_mat4 proj = gs_camera_get_proj(cam, view_width, view_height);
- return gs_mat4_mul(proj, view);
- }
- GS_API_DECL gs_mat4
- gs_camera_get_view(const gs_camera_t* cam)
- {
- gs_vec3 up = gs_camera_up(cam);
- gs_vec3 forward = gs_camera_forward(cam);
- gs_vec3 target = gs_vec3_add(forward, cam->transform.position);
- return gs_mat4_look_at(cam->transform.position, target, up);
- }
- GS_API_DECL gs_mat4
- gs_camera_get_proj(const gs_camera_t* cam, s32 view_width, s32 view_height)
- {
- gs_mat4 proj_mat = gs_mat4_identity();
- switch(cam->proj_type)
- {
- case GS_PROJECTION_TYPE_PERSPECTIVE:
- {
- proj_mat = gs_mat4_perspective(cam->fov, (f32)view_width / (f32)view_height, cam->near_plane, cam->far_plane);
- } break;
- // Don't like this...
- case GS_PROJECTION_TYPE_ORTHOGRAPHIC:
- {
- f32 _ar = (f32)view_width / (f32)view_height;
- f32 distance = 0.5f * (cam->far_plane - cam->near_plane);
- const f32 ortho_scale = cam->ortho_scale;
- const f32 aspect_ratio = _ar;
- proj_mat = gs_mat4_ortho
- (
- -ortho_scale * aspect_ratio,
- ortho_scale * aspect_ratio,
- -ortho_scale,
- ortho_scale,
- -distance,
- distance
- );
- } break;
- }
- return proj_mat;
- }
- GS_API_DECL void
- gs_camera_offset_orientation(gs_camera_t* cam, f32 yaw, f32 pitch)
- {
- gs_quat x = gs_quat_angle_axis(gs_deg2rad(yaw), gs_v3(0.f, 1.f, 0.f)); // Absolute up
- gs_quat y = gs_quat_angle_axis(gs_deg2rad(pitch), gs_camera_right(cam)); // Relative right
- cam->transform.rotation = gs_quat_mul(gs_quat_mul(x, y), cam->transform.rotation);
- }
- /*=============================
- // GS_UTIL
- =============================*/
- #define STBI_MALLOC(sz) gs_malloc(sz)
- #define STBI_REALLOC(p,newsz) gs_realloc(p,newsz)
- #define STBI_FREE(p) gs_free(p)
- #ifndef GS_NO_STB_RECT_PACK
- #define STB_RECT_PACK_IMPLEMENTATION
- #endif
- #ifndef GS_NO_STB_TRUETYPE
- // #define STBTT_RASTERIZER_VERSION 0
- #define STB_TRUETYPE_IMPLEMENTATION
- #endif
- #ifndef GS_NO_STB_DEFINE
- #define STB_DEFINE
- #endif
- #ifndef GS_NO_STB_IMAGE
- #define STB_IMAGE_IMPLEMENTATION
- // #define STB_IMAGE_WRITE_IMPLEMENTATION
- #endif
- // #ifndef GS_NO_STB_DS_DEFINE
- // #define STB_DS_IMPLEMENTATION
- // #endif
- #ifndef GS_NO_CGLTF
- #define CGLTF_IMPLEMENTATION
- #endif
- // STB
- #ifdef GS_STB_INCLUDE
- #include "external/stb/stb.h"
- #endif
- #include "external/stb/stb_rect_pack.h"
- #include "external/stb/stb_truetype.h"
- #include "external/stb/stb_image.h"
- // #include "external/stb/stb_ds.h"
- // CGLTF
- #include "external/cgltf/cgltf.h"
- GS_API_DECL char*
- gs_read_file_contents_into_string_null_term
- (
- const char* file_path,
- const char* mode,
- size_t* _sz
- )
- {
- char* buffer = 0;
- FILE* fp = fopen(file_path, mode);
- size_t sz = 0;
- if (fp)
- {
- fseek(fp, 0, SEEK_END);
- sz = ftell(fp);
- fseek(fp, 0, SEEK_SET);
- buffer = (char*)gs_malloc(sz + 1);
- if (buffer)
- {
- fread(buffer, 1, sz, fp);
- }
- fclose(fp);
- buffer[sz] = '\0';
- if (_sz) *_sz = sz;
- }
- return buffer;
- }
- bool32_t gs_util_load_texture_data_from_file(const char* file_path, int32_t* width, int32_t* height, uint32_t* num_comps, void** data, bool32_t flip_vertically_on_load)
- {
- size_t len = 0;
- char* file_data = gs_platform_read_file_contents(file_path, "rb", &len);
- gs_assert(file_data);
- bool32_t ret = gs_util_load_texture_data_from_memory(file_data, len, width, height, num_comps, data, flip_vertically_on_load);
- if (!ret) {
- gs_println("Warning: could not load texture: %s", file_path);
- }
- gs_free(file_data);
- return ret;
- }
- GS_API_DECL bool32_t
- gs_util_load_texture_data_from_memory(const void* memory, size_t sz, int32_t* width, int32_t* height, uint32_t* num_comps, void** data, bool32_t flip_vertically_on_load)
- {
- // Load texture data
- stbi_set_flip_vertically_on_load(flip_vertically_on_load);
- *data = stbi_load_from_memory((const stbi_uc*)memory, (int32_t)sz, (int32_t*)width, (int32_t*)height, (int32_t*)num_comps, STBI_rgb_alpha);
- if (!*data) {
- gs_free(*data);
- return false;
- }
- return true;
- }
- /*==========================
- // GS_ASSET_TYPES
- ==========================*/
- GS_API_DECL bool
- gs_asset_texture_load_from_file(const char* path, void* out, gs_graphics_texture_desc_t* desc, bool32_t flip_on_load, bool32_t keep_data)
- {
- gs_asset_texture_t* t = (gs_asset_texture_t*)out;
- memset(&t->desc, 0, sizeof(gs_graphics_texture_desc_t));
- if (desc) {
- t->desc = *desc;
- } else {
- t->desc.format = GS_GRAPHICS_TEXTURE_FORMAT_RGBA8;
- t->desc.min_filter = GS_GRAPHICS_TEXTURE_FILTER_LINEAR;
- t->desc.mag_filter = GS_GRAPHICS_TEXTURE_FILTER_LINEAR;
- t->desc.wrap_s = GS_GRAPHICS_TEXTURE_WRAP_REPEAT;
- t->desc.wrap_t = GS_GRAPHICS_TEXTURE_WRAP_REPEAT;
- }
- // Load texture data
- FILE* f = fopen(path, "rb");
- if (!f) {
- return false;
- }
- int32_t comp = 0;
- stbi_set_flip_vertically_on_load(t->desc.flip_y);
- *t->desc.data = (uint8_t*)stbi_load_from_file(f, (int32_t*)&t->desc.width, (int32_t*)&t->desc.height, (int32_t*)&comp, STBI_rgb_alpha);
- if (!*t->desc.data) {
- fclose(f);
- return false;
- }
- t->hndl = gs_graphics_texture_create(&t->desc);
- if (!keep_data) {
- gs_free(*t->desc.data);
- *t->desc.data = NULL;
- }
- fclose(f);
- return true;
- }
- /*
- bool gs_asset_texture_load_from_file(const char* path, void* out, gs_graphics_texture_desc_t* desc, bool32_t flip_on_load, bool32_t keep_data)
- {
- size_t len = 0;
- char* file_data = gs_platform_read_file_contents(path, "rb", &len);
- gs_assert(file_data);
- bool32_t ret = gs_asset_texture_load_from_memory(file_data, len, out, desc, flip_on_load, keep_data);
- gs_free(file_data);
- return ret;
- }
- */
- bool gs_asset_texture_load_from_memory(const void* memory, size_t sz, void* out, gs_graphics_texture_desc_t* desc, bool32_t flip_on_load, bool32_t keep_data)
- {
- gs_asset_texture_t* t = (gs_asset_texture_t*)out;
- memset(&t->desc, 0, sizeof(gs_graphics_texture_desc_t));
- if (desc) {
- t->desc = *desc;
- } else {
- t->desc.format = GS_GRAPHICS_TEXTURE_FORMAT_RGBA8;
- t->desc.min_filter = GS_GRAPHICS_TEXTURE_FILTER_LINEAR;
- t->desc.mag_filter = GS_GRAPHICS_TEXTURE_FILTER_LINEAR;
- t->desc.wrap_s = GS_GRAPHICS_TEXTURE_WRAP_REPEAT;
- t->desc.wrap_t = GS_GRAPHICS_TEXTURE_WRAP_REPEAT;
- }
- // Load texture data
- int32_t num_comps = 0;
- bool32_t loaded = gs_util_load_texture_data_from_memory(memory, sz, (int32_t*)&t->desc.width,
- (int32_t*)&t->desc.height, (uint32_t*)&num_comps, t->desc.data, t->desc.flip_y);
- if (!loaded) {
- return false;
- }
- t->hndl = gs_graphics_texture_create(&t->desc);
- if (!keep_data) {
- gs_free(*t->desc.data);
- *t->desc.data = NULL;
- }
- return true;
- }
- bool gs_asset_font_load_from_file(const char* path, void* out, uint32_t point_size)
- {
- size_t len = 0;
- char* ttf = gs_platform_read_file_contents(path, "rb", &len);
- if (!point_size) {
- gs_println("Warning: Font: %s: Point size not declared. Setting to default 16.", path);
- point_size = 16;
- }
- bool ret = gs_asset_font_load_from_memory(ttf, len, out, point_size);
- if (!ret) {
- gs_println("Font Failed to Load: %s", path);
- } else {
- gs_println("Font Successfully Loaded: %s", path);
- }
- gs_free(ttf);
- return ret;
- }
- bool gs_asset_font_load_from_memory(const void* memory, size_t sz, void* out, uint32_t point_size)
- {
- gs_asset_font_t* f = (gs_asset_font_t*)out;
- if (!point_size) {
- gs_println("Warning: Font: Point size not declared. Setting to default 16.");
- point_size = 16;
- }
- // Poor attempt at an auto resized texture
- const uint32_t point_wh = gs_max(point_size, 32);
- const uint32_t w = (point_wh/32 * 512) + (point_wh/32 * 512) % 512;
- const uint32_t h = (point_wh/32 * 512) + (point_wh/32 * 512) % 512;
- const uint32_t num_comps = 4;
- u8* alpha_bitmap = (uint8_t*)gs_malloc(w * h);
- u8* flipmap = (uint8_t*)gs_malloc(w * h * num_comps);
- memset(alpha_bitmap, 0, w * h);
- memset(flipmap, 0, w * h * num_comps);
- s32 v = stbtt_BakeFontBitmap((u8*)memory, 0, (float)point_size, alpha_bitmap, w, h, 32, 96, (stbtt_bakedchar*)f->glyphs); // no guarantee this fits!
- // Flip texture
- u32 r = h - 1;
- for (u32 i = 0; i < h; ++i)
- {
- for (u32 j = 0; j < w; ++j)
- {
- u32 i0 = i * w + j;
- u32 i1 = i * w * num_comps + j * num_comps;
- u8 a = alpha_bitmap[i0];
- flipmap[i1 + 0] = 255;
- flipmap[i1 + 1] = 255;
- flipmap[i1 + 2] = 255;
- flipmap[i1 + 3] = a;
- }
- r--;
- }
- gs_graphics_texture_desc_t desc = gs_default_val();
- desc.width = w;
- desc.height = h;
- *desc.data = flipmap;
- desc.format = GS_GRAPHICS_TEXTURE_FORMAT_RGBA8;
- desc.min_filter = GS_GRAPHICS_TEXTURE_FILTER_NEAREST;
- desc.mag_filter = GS_GRAPHICS_TEXTURE_FILTER_NEAREST;
- // Generate atlas texture for bitmap with bitmap data
- f->texture.hndl = gs_graphics_texture_create(&desc);
- f->texture.desc = desc;
- *f->texture.desc.data = NULL;
- bool success = false;
- if (v <= 0) {
- gs_println("Font Failed to Load, Baked Texture Was Too Small: %d", v);
- }
- else {
- gs_println("Font Successfully Loaded: %d", v);
- success = true;
- }
- gs_free(alpha_bitmap);
- gs_free(flipmap);
- return success;
- }
- GS_API_DECL float gs_asset_font_max_height(const gs_asset_font_t* fp)
- {
- if (!fp) return 0.f;
- float h = 0.f, x = 0.f, y = 0.f;
- const char* txt = "1l`'f()ABCDEFGHIJKLMNOjPQqSTU!";
- while (txt[0] != '\0')
- {
- char c = txt[0];
- if (c >= 32 && c <= 127)
- {
- stbtt_aligned_quad q = gs_default_val();
- stbtt_GetBakedQuad((stbtt_bakedchar*)fp->glyphs, fp->texture.desc.width, fp->texture.desc.height, c - 32, &x, &y, &q, 1);
- h = gs_max(gs_max(h, fabsf(q.y0)), fabsf(q.y1));
- }
- txt++;
- };
- return h;
- }
- GS_API_DECL gs_vec2 gs_asset_font_text_dimensions(const gs_asset_font_t* fp, const char* text, int32_t len)
- {
- return gs_asset_font_text_dimensions_ex(fp, text, len, 0);
- }
- GS_API_DECL gs_vec2 gs_asset_font_text_dimensions_ex(const gs_asset_font_t* fp, const char* text, int32_t len, bool32_t include_past_baseline)
- {
- gs_vec2 dimensions = gs_v2s(0.f);
- if (!fp || !text) return dimensions;
- float x = 0.f;
- float y = 0.f;
- float y_under = 0;
- while (text[0] != '\0' && len--)
- {
- char c = text[0];
- if (c >= 32 && c <= 127)
- {
- stbtt_aligned_quad q = gs_default_val();
- stbtt_GetBakedQuad((stbtt_bakedchar*)fp->glyphs, fp->texture.desc.width, fp->texture.desc.height, c - 32, &x, &y, &q, 1);
- dimensions.x = gs_max(dimensions.x, x);
- dimensions.y = gs_max(dimensions.y, fabsf(q.y0));
- if (include_past_baseline)
- y_under = gs_max(y_under, fabsf(q.y1));
- }
- text++;
- };
- if (include_past_baseline)
- dimensions.y += y_under;
- return dimensions;
- }
- // Audio
- bool gs_asset_audio_load_from_file(const char* path, void* out)
- {
- gs_asset_audio_t* a = (gs_asset_audio_t*)out;
- a->hndl = gs_audio_load_from_file(path);
- return gs_handle_is_valid(a->hndl);
- }
- bool gs_util_load_gltf_data_from_file(const char* path, gs_asset_mesh_decl_t* decl, gs_asset_mesh_raw_data_t** out, uint32_t* mesh_count)
- {
- // Use cgltf like a boss
- cgltf_options options = gs_default_val();
- size_t len = 0;
- char* file_data = gs_platform_read_file_contents(path, "rb", &len);
- gs_println("Loading GLTF: %s", path);
- cgltf_data* data = NULL;
- cgltf_result result = cgltf_parse(&options, file_data, (cgltf_size)len, &data);
- gs_free(file_data);
- if (result != cgltf_result_success) {
- gs_println("Mesh:LoadFromFile:Failed load gltf");
- cgltf_free(data);
- return false;
- }
- // Load buffers as well
- result = cgltf_load_buffers(&options, data, path);
- if (result != cgltf_result_success) {
- cgltf_free(data);
- gs_println("Mesh:LoadFromFile:Failed to load buffers");
- return false;
- }
- // Type of index data
- size_t index_element_size = decl ? decl->index_buffer_element_size : 0;
- // Temporary structures
- gs_dyn_array(gs_vec3) positions = NULL;
- gs_dyn_array(gs_vec3) normals = NULL;
- gs_dyn_array(gs_vec3) tangents = NULL;
- gs_dyn_array(gs_color_t) colors = NULL;
- gs_dyn_array(gs_vec2) uvs = NULL;
- gs_dyn_array(gs_asset_mesh_layout_t) layouts = NULL;
- gs_byte_buffer_t v_data = gs_byte_buffer_new();
- gs_byte_buffer_t i_data = gs_byte_buffer_new();
- // Allocate memory for buffers
- *mesh_count = data->meshes_count;
- *out = (gs_asset_mesh_raw_data_t*)gs_malloc(data->meshes_count * sizeof(gs_asset_mesh_raw_data_t));
- memset(*out, 0, sizeof(gs_asset_mesh_raw_data_t) * data->meshes_count);
- // Iterate through meshes in data
- for (uint32_t i = 0; i < data->meshes_count; ++i)
- {
- // Initialize mesh data
- gs_asset_mesh_raw_data_t* mesh = out[i];
- mesh->prim_count = data->meshes[i].primitives_count;
- mesh->vertex_sizes = (size_t*)gs_malloc(sizeof(size_t) * mesh->prim_count);
- mesh->index_sizes = (size_t*)gs_malloc(sizeof(size_t) * mesh->prim_count);
- mesh->vertices = (void**)gs_malloc(sizeof(size_t) * mesh->prim_count);
- mesh->indices = (void**)gs_malloc(sizeof(size_t) * mesh->prim_count);
- // For each primitive in mesh
- for (uint32_t p = 0; p < data->meshes[i].primitives_count; ++p)
- {
- // Clear temp data from previous use
- gs_dyn_array_clear(positions);
- gs_dyn_array_clear(normals);
- gs_dyn_array_clear(tangents);
- gs_dyn_array_clear(uvs);
- gs_dyn_array_clear(colors);
- gs_dyn_array_clear(layouts);
- gs_byte_buffer_clear(&v_data);
- gs_byte_buffer_clear(&i_data);
- #define __GLTF_PUSH_ATTR(ATTR, TYPE, COUNT, ARR, ARR_TYPE, LAYOUTS, LAYOUT_TYPE)\
- do {\
- int32_t N = 0;\
- TYPE* BUF = (TYPE*)ATTR->buffer_view->buffer->data + ATTR->buffer_view->offset/sizeof(TYPE) + ATTR->offset/sizeof(TYPE);\
- gs_assert(BUF);\
- TYPE V[COUNT] = gs_default_val();\
- /* For each vertex */\
- for (uint32_t k = 0; k < ATTR->count; k++)\
- {\
- /* For each element */\
- for (int l = 0; l < COUNT; l++) {\
- V[l] = BUF[N + l];\
- }\
- N += (int32_t)(ATTR->stride/sizeof(TYPE));\
- /* Add to temp data array */\
- ARR_TYPE ELEM = gs_default_val();\
- memcpy((void*)&ELEM, (void*)V, sizeof(ARR_TYPE));\
- gs_dyn_array_push(ARR, ELEM);\
- }\
- /* Push into layout */\
- gs_asset_mesh_layout_t LAYOUT = gs_default_val();\
- LAYOUT.type = LAYOUT_TYPE;\
- gs_dyn_array_push(LAYOUTS, LAYOUT);\
- } while (0)
- // For each attribute in primitive
- for (uint32_t a = 0; a < data->meshes[i].primitives[p].attributes_count; ++a)
- {
- // Accessor for attribute data
- cgltf_accessor* attr = data->meshes[i].primitives[p].attributes[a].data;
- // Switch on type for reading data
- switch (data->meshes[i].primitives[p].attributes[a].type)
- {
- case cgltf_attribute_type_position: {
- __GLTF_PUSH_ATTR(attr, float, 3, positions, gs_vec3, layouts, GS_ASSET_MESH_ATTRIBUTE_TYPE_POSITION);
- } break;
- case cgltf_attribute_type_normal: {
- __GLTF_PUSH_ATTR(attr, float, 3, normals, gs_vec3, layouts, GS_ASSET_MESH_ATTRIBUTE_TYPE_NORMAL);
- } break;
- case cgltf_attribute_type_tangent: {
- __GLTF_PUSH_ATTR(attr, float, 3, tangents, gs_vec3, layouts, GS_ASSET_MESH_ATTRIBUTE_TYPE_TANGENT);
- } break;
- case cgltf_attribute_type_texcoord: {
- __GLTF_PUSH_ATTR(attr, float, 2, uvs, gs_vec2, layouts, GS_ASSET_MESH_ATTRIBUTE_TYPE_TEXCOORD);
- } break;
- case cgltf_attribute_type_color: {
- __GLTF_PUSH_ATTR(attr, uint8_t, 4, colors, gs_color_t, layouts, GS_ASSET_MESH_ATTRIBUTE_TYPE_COLOR);
- } break;
- // Not sure what to do with these for now
- case cgltf_attribute_type_joints:
- {
- // Push into layout
- gs_asset_mesh_layout_t layout = gs_default_val();
- layout.type = GS_ASSET_MESH_ATTRIBUTE_TYPE_JOINT;
- gs_dyn_array_push(layouts, layout);
- } break;
- case cgltf_attribute_type_weights:
- {
- // Push into layout
- gs_asset_mesh_layout_t layout = gs_default_val();
- layout.type = GS_ASSET_MESH_ATTRIBUTE_TYPE_WEIGHT;
- gs_dyn_array_push(layouts, layout);
- } break;
- // Shouldn't hit here...
- default:
- {
- } break;
- }
- }
- // Indices for primitive
- cgltf_accessor* acc = data->meshes[i].primitives[p].indices;
- #define __GLTF_PUSH_IDX(BB, ACC, TYPE)\
- do {\
- int32_t n = 0;\
- TYPE* buf = (TYPE*)acc->buffer_view->buffer->data + acc->buffer_view->offset/sizeof(TYPE) + acc->offset/sizeof(TYPE);\
- gs_assert(buf);\
- TYPE v = 0;\
- /* For each index */\
- for (uint32_t k = 0; k < acc->count; k++) {\
- /* For each element */\
- for (int l = 0; l < 1; l++) {\
- v = buf[n + l];\
- }\
- n += (int32_t)(acc->stride/sizeof(TYPE));\
- /* Add to temp positions array */\
- switch (index_element_size) {\
- case 0: gs_byte_buffer_write(BB, uint16_t, (uint16_t)v); break;\
- case 2: gs_byte_buffer_write(BB, uint16_t, (uint16_t)v); break;\
- case 4: gs_byte_buffer_write(BB, uint32_t, (uint32_t)v); break;\
- }\
- }\
- } while (0)
- // If indices are available
- if (acc)
- {
- switch (acc->component_type)
- {
- case cgltf_component_type_r_8: __GLTF_PUSH_IDX(&i_data, acc, int8_t); break;
- case cgltf_component_type_r_8u: __GLTF_PUSH_IDX(&i_data, acc, uint8_t); break;
- case cgltf_component_type_r_16: __GLTF_PUSH_IDX(&i_data, acc, int16_t); break;
- case cgltf_component_type_r_16u: __GLTF_PUSH_IDX(&i_data, acc, uint16_t); break;
- case cgltf_component_type_r_32u: __GLTF_PUSH_IDX(&i_data, acc, uint32_t); break;
- case cgltf_component_type_r_32f: __GLTF_PUSH_IDX(&i_data, acc, float); break;
- // Shouldn't hit here
- default: {
- } break;
- }
- }
- else
- {
- // Iterate over positions size, then just push back indices
- for (uint32_t i = 0; i < gs_dyn_array_size(positions); ++i)
- {
- switch (index_element_size)
- {
- default:
- case 0: gs_byte_buffer_write(&i_data, uint16_t, (uint16_t)i); break;
- case 2: gs_byte_buffer_write(&i_data, uint16_t, (uint16_t)i); break;
- case 4: gs_byte_buffer_write(&i_data, uint32_t, (uint32_t)i); break;
- }
- }
- }
- bool warnings[gs_enum_count(gs_asset_mesh_attribute_type)] = gs_default_val();
- // Grab mesh layout pointer to use
- gs_asset_mesh_layout_t* layoutp = decl ? decl->layout : layouts;
- uint32_t layout_ct = decl ? decl->layout_size / sizeof(gs_asset_mesh_layout_t) : gs_dyn_array_size(layouts);
- // Iterate layout to fill data buffers according to provided layout
- {
- uint32_t vct = 0;
- vct = gs_max(vct, gs_dyn_array_size(positions));
- vct = gs_max(vct, gs_dyn_array_size(colors));
- vct = gs_max(vct, gs_dyn_array_size(uvs));
- vct = gs_max(vct, gs_dyn_array_size(normals));
- vct = gs_max(vct, gs_dyn_array_size(tangents));
- #define __GS_GLTF_WRITE_DATA(IT, VDATA, ARR, ARR_TYPE, ARR_DEF_VAL, LAYOUT_TYPE)\
- do {\
- /* Grab data at index, if available */\
- if (IT < gs_dyn_array_size(ARR)) {\
- gs_byte_buffer_write(&(VDATA), ARR_TYPE, ARR[IT]);\
- }\
- else {\
- /* Write default value and give warning.*/\
- gs_byte_buffer_write(&(VDATA), ARR_TYPE, ARR_DEF_VAL);\
- if (!warnings[LAYOUT_TYPE]) {\
- gs_println("Warning:Mesh:LoadFromFile:%s:Index out of range.", #LAYOUT_TYPE);\
- warnings[LAYOUT_TYPE] = true;\
- }\
- }\
- } while (0)
- for (uint32_t it = 0; it < vct; ++it)
- {
- // For each attribute in layout
- for (uint32_t l = 0; l < layout_ct; ++l)
- {
- switch (layoutp[l].type)
- {
- case GS_ASSET_MESH_ATTRIBUTE_TYPE_POSITION: {
- __GS_GLTF_WRITE_DATA(it, v_data, positions, gs_vec3, gs_v3(0.f, 0.f, 0.f), GS_ASSET_MESH_ATTRIBUTE_TYPE_POSITION);
- } break;
- case GS_ASSET_MESH_ATTRIBUTE_TYPE_TEXCOORD: {
- __GS_GLTF_WRITE_DATA(it, v_data, uvs, gs_vec2, gs_v2(0.f, 0.f), GS_ASSET_MESH_ATTRIBUTE_TYPE_TEXCOORD);
- } break;
- case GS_ASSET_MESH_ATTRIBUTE_TYPE_COLOR: {
- __GS_GLTF_WRITE_DATA(it, v_data, colors, gs_color_t, GS_COLOR_WHITE, GS_ASSET_MESH_ATTRIBUTE_TYPE_COLOR);
- } break;
- case GS_ASSET_MESH_ATTRIBUTE_TYPE_NORMAL: {
- __GS_GLTF_WRITE_DATA(it, v_data, normals, gs_vec3, gs_v3(0.f, 0.f, 1.f), GS_ASSET_MESH_ATTRIBUTE_TYPE_NORMAL);
- } break;
- case GS_ASSET_MESH_ATTRIBUTE_TYPE_TANGENT: {
- __GS_GLTF_WRITE_DATA(it, v_data, tangents, gs_vec3, gs_v3(0.f, 1.f, 0.f), GS_ASSET_MESH_ATTRIBUTE_TYPE_TANGENT);
- } break;
- default:
- {
- } break;
- }
- }
- }
- }
- // Add to out data
- mesh->vertices[p] = gs_malloc(v_data.size);
- mesh->indices[p] = gs_malloc(i_data.size);
- mesh->vertex_sizes[p] = v_data.size;
- mesh->index_sizes[p] = i_data.size;
- // Copy data
- memcpy(mesh->vertices[p], v_data.data, v_data.size);
- memcpy(mesh->indices[p], i_data.data, i_data.size);
- }
- }
- // Free all data at the end
- cgltf_free(data);
- gs_dyn_array_free(positions);
- gs_dyn_array_free(normals);
- gs_dyn_array_free(tangents);
- gs_dyn_array_free(colors);
- gs_dyn_array_free(uvs);
- gs_dyn_array_free(layouts);
- gs_byte_buffer_free(&v_data);
- gs_byte_buffer_free(&i_data);
- return true;
- }
- bool gs_asset_mesh_load_from_file(const char* path, void* out, gs_asset_mesh_decl_t* decl, void* data_out, size_t data_size)
- {
- // Cast mesh data to use
- gs_asset_mesh_t* mesh = (gs_asset_mesh_t*)out;
- if (!gs_platform_file_exists(path)) {
- gs_println("Warning:MeshLoadFromFile:File does not exist: %s", path);
- return false;
- }
- // Mesh data to fill out
- uint32_t mesh_count = 0;
- gs_asset_mesh_raw_data_t* meshes = NULL;
- // Get file extension from path
- gs_transient_buffer(file_ext, 32);
- gs_platform_file_extension(file_ext, 32, path);
- // GLTF
- if (gs_string_compare_equal(file_ext, "gltf"))
- {
- gs_util_load_gltf_data_from_file(path, decl, &meshes, &mesh_count);
- }
- else
- {
- gs_println("Warning:MeshLoadFromFile:File extension not supported: %s, file: %s", file_ext, path);
- return false;
- }
- // For now, handle meshes with only single mesh count
- if (mesh_count != 1) {
- // Error
- // Free all the memory
- return false;
- }
- // Process all mesh data, add meshes
- for (uint32_t i = 0; i < mesh_count; ++i)
- {
- gs_asset_mesh_raw_data_t* m = &meshes[i];
- for (uint32_t p = 0; p < m->prim_count; ++p)
- {
- // Construct primitive
- gs_asset_mesh_primitive_t prim = gs_default_val();
- prim.count = m->index_sizes[p] / sizeof(uint16_t);
- // Vertex buffer decl
- gs_graphics_vertex_buffer_desc_t vdesc = gs_default_val();
- vdesc.data = m->vertices[p];
- vdesc.size = m->vertex_sizes[p];
- // Construct vertex buffer for primitive
- prim.vbo = gs_graphics_vertex_buffer_create(&vdesc);
- // Index buffer decl
- gs_graphics_index_buffer_desc_t idesc = gs_default_val();
- idesc.data = m->indices[p];
- idesc.size = m->index_sizes[p];
- // Construct index buffer for primitive
- prim.ibo = gs_graphics_index_buffer_create(&idesc);
- // Add primitive to mesh
- gs_dyn_array_push(mesh->primitives, prim);
- }
- }
- // Free all mesh data
- return true;
- }
- /*========================
- // GS_LEXER
- ========================*/
- //==== [ Token ] ============================================================//
- GS_API_DECL gs_token_t gs_token_invalid_token()
- {
- gs_token_t t = gs_default_val();
- t.text = "";
- t.type = GS_TOKEN_UNKNOWN;
- t.len = 0;
- return t;
- }
- GS_API_DECL bool gs_token_compare_type(const gs_token_t* t, gs_token_type type)
- {
- return (t->type == type);
- }
- GS_API_DECL bool gs_token_compare_text(const gs_token_t* t, const char* match)
- {
- if (t->len != gs_string_length(match)) return false;
- return (gs_string_compare_equal_n(t->text, match, t->len));
- }
- GS_API_DECL void gs_token_print_text(const gs_token_t* t)
- {
- gs_println("%.*s\n", t->len, t->text);
- }
- GS_API_DECL void gs_token_debug_print(const gs_token_t* t)
- {
- gs_println("%s: %.*s", gs_token_type_to_str(t->type), t->len, t->text);
- }
- GS_API_DECL const char* gs_token_type_to_str(gs_token_type type)
- {
- switch (type)
- {
- default:
- case GS_TOKEN_UNKNOWN: return gs_to_str(GS_TOKEN_UNKNOWN); break;
- case GS_TOKEN_LPAREN: return gs_to_str(GS_TOKEN_LPAREN); break;
- case GS_TOKEN_RPAREN: return gs_to_str(GS_TOKEN_RPAREN); break;
- case GS_TOKEN_LTHAN: return gs_to_str(GS_TOKEN_LTHAN); break;
- case GS_TOKEN_GTHAN: return gs_to_str(GS_TOKEN_GTHAN); break;
- case GS_TOKEN_SEMICOLON: return gs_to_str(GS_TOKEN_SEMICOLON); break;
- case GS_TOKEN_COLON: return gs_to_str(GS_TOKEN_COLON); break;
- case GS_TOKEN_COMMA: return gs_to_str(GS_TOKEN_COMMA); break;
- case GS_TOKEN_EQUAL: return gs_to_str(GS_TOKEN_EQUAL); break;
- case GS_TOKEN_NOT: return gs_to_str(GS_TOKEN_NOT); break;
- case GS_TOKEN_HASH: return gs_to_str(GS_TOKEN_HASH); break;
- case GS_TOKEN_PIPE: return gs_to_str(GS_TOKEN_PIPE); break;
- case GS_TOKEN_AMPERSAND:return gs_to_str(GS_TOKEN_AMPERSAND); break;
- case GS_TOKEN_LBRACE: return gs_to_str(GS_TOKEN_LBRACE); break;
- case GS_TOKEN_RBRACE: return gs_to_str(GS_TOKEN_RBRACE); break;
- case GS_TOKEN_LBRACKET: return gs_to_str(GS_TOKEN_LBRACKET); break;
- case GS_TOKEN_RBRACKET: return gs_to_str(GS_TOKEN_RBRACKET); break;
- case GS_TOKEN_MINUS: return gs_to_str(GS_TOKEN_MINUS); break;
- case GS_TOKEN_PLUS: return gs_to_str(GS_TOKEN_PLUS); break;
- case GS_TOKEN_ASTERISK: return gs_to_str(GS_TOKEN_ASTERISK); break;
- case GS_TOKEN_BSLASH: return gs_to_str(GS_TOKEN_BLASH); break;
- case GS_TOKEN_FSLASH: return gs_to_str(GS_TOKEN_FLASH); break;
- case GS_TOKEN_QMARK: return gs_to_str(GS_TOKEN_QMARK); break;
- case GS_TOKEN_DOLLAR: return gs_to_str(GS_TOKEN_DOLLAR); break;
- case GS_TOKEN_SPACE: return gs_to_str(GS_TOKEN_SPACE); break;
- case GS_TOKEN_NEWLINE: return gs_to_str(GS_TOKEN_NEWLINE); break;
- case GS_TOKEN_TAB: return gs_to_str(GS_TOKEN_TAB); break;
- case GS_TOKEN_SINGLE_LINE_COMMENT: return gs_to_str(GS_TOKEN_SINGLE_LINE_COMMENT); break;
- case GS_TOKEN_MULTI_LINE_COMMENT: return gs_to_str(GS_TOKEN_MULTI_LINE_COMMENT); break;
- case GS_TOKEN_IDENTIFIER: return gs_to_str(GS_TOKEN_IDENTIFIER); break;
- case GS_TOKEN_NUMBER: return gs_to_str(GS_TOKEN_NUMBER); break;
- case GS_TOKEN_PERIOD: return gs_to_str(GS_TOKEN_PERIOD); break;
- case GS_TOKEN_STRING: return gs_to_str(GS_TOKEN_STRING); break;
- }
- }
- GS_API_DECL bool gs_char_is_null_term(char c)
- {
- return (c == '\0');
- }
- GS_API_DECL bool gs_char_is_end_of_line(char c)
- {
- return (c == '\n' || c == '\r');
- }
- GS_API_DECL bool gs_char_is_white_space(char c)
- {
- return (c == '\t' || c == ' ' || gs_char_is_end_of_line(c));
- }
- GS_API_DECL bool gs_char_is_alpha(char c)
- {
- return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
- }
- GS_API_DECL bool gs_char_is_numeric(char c)
- {
- return (c >= '0' && c <= '9');
- }
- //==== [ Lexer ] ============================================================//
- GS_API_DECL void gs_lexer_set_contents(gs_lexer_t* lex, const char* contents)
- {
- lex->at = contents;
- lex->current_token = gs_token_invalid_token();
- }
- GS_API_DECL bool gs_lexer_c_can_lex(gs_lexer_t* lex)
- {
- bool size_pass = lex->contents_size ? lex->size < lex->contents_size : true;
- return (size_pass && lex->at && !gs_char_is_null_term(*(lex->at)));
- }
- GS_API_DECL void gs_lexer_set_token(gs_lexer_t* lex, gs_token_t token)
- {
- lex->at = token.text;
- lex->current_token = token;
- }
- GS_API_DECL void gs_lexer_c_eat_white_space(gs_lexer_t* lex)
- {
- for (;;)
- {
- if (gs_char_is_white_space(*lex->at))
- {
- if (gs_char_is_end_of_line(*lex->at)) {lex->line++;}
- lex->at++;
- }
- // Single line comment
- else if ((lex->at[0] == '/') && (lex->at[1]) && (lex->at[1] == '/'))
- {
- lex->at += 2;
- while (*lex->at && !gs_char_is_end_of_line(*lex->at))
- {
- lex->at++;
- }
- }
- // Multi-line comment
- else if ((lex->at[0] == '/') && (lex->at[1]) && (lex->at[1] == '*'))
- {
- lex->at += 2;
- while (lex->at[0] && lex->at[1] && !(lex->at[0] == '*' && lex->at[1] == '/'))
- {
- // if (gs_char_is_end_of_line(*lex->at)) {lex->line++;}
- lex->at++;
- }
- if (lex->at[0] == '*')
- {
- lex->at++;
- }
- }
- else
- {
- break;
- }
- }
- }
- GS_API_DECL gs_token_t
- gs_lexer_c_next_token(gs_lexer_t* lex)
- {
- if (lex->skip_white_space)
- {
- lex->eat_white_space(lex);
- }
- gs_token_t t = gs_token_invalid_token();
- t.text = lex->at;
- t.len = 1;
- if (lex->can_lex(lex))
- {
- char c = *lex->at;
- switch (c)
- {
- case '(': {t.type = GS_TOKEN_LPAREN; lex->at++;} break;
- case ')': {t.type = GS_TOKEN_RPAREN; lex->at++;} break;
- case '<': {t.type = GS_TOKEN_LTHAN; lex->at++;} break;
- case '>': {t.type = GS_TOKEN_GTHAN; lex->at++;} break;
- case ';': {t.type = GS_TOKEN_SEMICOLON; lex->at++;} break;
- case ':': {t.type = GS_TOKEN_COLON; lex->at++;} break;
- case ',': {t.type = GS_TOKEN_COMMA; lex->at++;} break;
- case '=': {t.type = GS_TOKEN_EQUAL; lex->at++;} break;
- case '!': {t.type = GS_TOKEN_NOT; lex->at++;} break;
- case '#': {t.type = GS_TOKEN_HASH; lex->at++;} break;
- case '|': {t.type = GS_TOKEN_PIPE; lex->at++;} break;
- case '&': {t.type = GS_TOKEN_AMPERSAND; lex->at++;} break;
- case '{': {t.type = GS_TOKEN_LBRACE; lex->at++;} break;
- case '}': {t.type = GS_TOKEN_RBRACE; lex->at++;} break;
- case '[': {t.type = GS_TOKEN_LBRACKET; lex->at++;} break;
- case ']': {t.type = GS_TOKEN_RBRACKET; lex->at++;} break;
- case '+': {t.type = GS_TOKEN_PLUS; lex->at++;} break;
- case '*': {t.type = GS_TOKEN_ASTERISK; lex->at++;} break;
- case '\\': {t.type = GS_TOKEN_BSLASH; lex->at++;} break;
- case '?': {t.type = GS_TOKEN_QMARK; lex->at++;} break;
- case '%': {t.type = GS_TOKEN_PERCENT; lex->at++;} break;
- case '$': {t.type = GS_TOKEN_DOLLAR; lex->at++;} break;
- case ' ': {t.type = GS_TOKEN_SPACE; lex->at++;} break;
- case '\n': {t.type = GS_TOKEN_NEWLINE; lex->at++;} break;
- case '\r': {t.type = GS_TOKEN_NEWLINE; lex->at++;} break;
- case '\t': {t.type = GS_TOKEN_TAB; lex->at++;} break;
- case '.': {t.type = GS_TOKEN_PERIOD; lex->at++;} break;
- case '-':
- {
- if (lex->at[1] && !gs_char_is_numeric(lex->at[1]))
- {
- t.type = GS_TOKEN_MINUS;
- lex->at++;
- }
- else
- {
- lex->at++;
- uint32_t num_decimals = 0;
- while (
- lex->at[0] &&
- (gs_char_is_numeric(lex->at[0]) ||
- (lex->at[0] == '.' && num_decimals == 0) ||
- lex->at[0] == 'f')
- )
- {
- // Grab decimal
- num_decimals = lex->at[0] == '.' ? num_decimals + 1 : num_decimals;
- //Increment
- lex->at++;
- }
- t.len = lex->at - t.text;
- t.type = GS_TOKEN_NUMBER;
- }
- } break;
-
- case '/':
- {
- // Single line comment
- if ((lex->at[0] == '/') && (lex->at[1]) && (lex->at[1] == '/'))
- {
- lex->at += 2;
- while (lex->at[0] && !gs_char_is_end_of_line(lex->at[0]))
- {
- lex->at++;
- }
- t.len = lex->at - t.text;
- t.type = GS_TOKEN_SINGLE_LINE_COMMENT;
- }
- // Multi line comment
- else if ((lex->at[0] == '/') && (lex->at[1]) && (lex->at[1] == '*'))
- {
- lex->at += 2;
- while (lex->can_lex(lex))
- {
- // if (gs_char_is_end_of_line(*lex->at)) {lex->line++;}
- if (lex->at[0] == '*' && lex->at[1] == '/')
- {
- lex->at += 2;
- break;
- }
- lex->at++;
- }
- t.len = lex->at - t.text;
- t.type = GS_TOKEN_MULTI_LINE_COMMENT;
- }
- // it's just a forward slash
- else
- {
- t.type = GS_TOKEN_FSLASH;
- lex->at++;
- }
- } break;
- case '"':
- {
- // Move forward after finding first quotation
- lex->at++;
- while (lex->at && *lex->at != '"')
- {
- // if (gs_char_is_end_of_line(*lex->at)) {lex->line++;}
- if (lex->at[0] == '\\' && lex->at[1])
- {
- lex->at++;
- }
- lex->at++;
- }
- //Move past quotation
- lex->at++;
- t.len = lex->at - t.text;
- t.type = GS_TOKEN_STRING;
- } break;
- // Alpha/Numeric/Identifier
- default:
- {
- if ((gs_char_is_alpha(c) || c == '_') && c != '-')
- {
- while (
- gs_char_is_alpha(lex->at[0]) ||
- gs_char_is_numeric(lex->at[0]) ||
- lex->at[0] == '_'
- )
- {
- lex->at++;
- }
- t.len = lex->at - t.text;
- t.type = GS_TOKEN_IDENTIFIER;
- }
- else if (gs_char_is_numeric(c) && c != '-')
- {
- uint32_t num_decimals = 0;
- while (
- gs_char_is_numeric(lex->at[0]) ||
- (lex->at[0] == '.' && num_decimals == 0) ||
- lex->at[0] == 'f'
- )
- {
- // Grab decimal
- num_decimals = lex->at[0] == '.' ? num_decimals + 1 : num_decimals;
- //Increment
- lex->at++;
- }
- t.len = lex->at - t.text;
- t.type = GS_TOKEN_NUMBER;
- }
- else
- {
- t.type = GS_TOKEN_UNKNOWN;
- lex->at++;
- }
- } break;
- }
- }
- // Set current token for lex
- lex->current_token = t;
-
- // Record size
- lex->size += t.len;
- return t;
- }
- GS_API_DECL gs_token_t gs_lexer_next_token(gs_lexer_t* lex)
- {
- return lex->next_token(lex);
- }
- GS_API_DECL bool gs_lexer_can_lex(gs_lexer_t* lex)
- {
- return lex->can_lex(lex);
- }
- GS_API_DECL gs_token_t gs_lexer_current_token(const gs_lexer_t* lex)
- {
- return lex->current_token;
- }
- GS_API_DECL bool gs_lexer_current_token_compare_type(const gs_lexer_t* lex, gs_token_type type)
- {
- return (lex->current_token.type == type);
- }
- GS_API_DECL gs_token_t gs_lexer_peek(gs_lexer_t* lex)
- {
- // Store current at and current token
- const char* at = lex->at;
- gs_token_t cur_t = gs_lexer_current_token(lex);
- // Get next token
- gs_token_t next_t = lex->next_token(lex);
- // Reset
- lex->current_token = cur_t;
- lex->at = at;
- // Return
- return next_t;
- }
- // Check to see if token type of next valid token matches 'match'. Restores place in lex if not.
- GS_API_DECL bool gs_lexer_require_token_text(gs_lexer_t* lex, const char* match)
- {
- // Store current position and token
- const char* at = lex->at;
- gs_token_t cur_t = lex->current_token;
- // Get next token
- gs_token_t next_t = lex->next_token(lex);
- // Compare token text
- if (gs_token_compare_text(&next_t, match))
- {
- return true;
- }
- // Error
- gs_println("error::gs_lexer_require_token_text::%.*s, expected: %s", cur_t.len, cur_t.text, match);
- // Reset
- lex->at = at;
- lex->current_token = cur_t;
- return false;
- }
- GS_API_DECL bool gs_lexer_require_token_type(gs_lexer_t* lex, gs_token_type type)
- {
- // Store current position and token
- const char* at = lex->at;
- gs_token_t cur_t = lex->current_token;
- // Get next token
- gs_token_t next_t = lex->next_token(lex);
- // Compare token type
- if (gs_token_compare_type(&next_t, type))
- {
- return true;
- }
- // Error
- // gs_println("error::gs_lexer_require_token_type::%s, expected: %s", gs_token_type_to_str(next_t.type), gs_token_type_to_str(type));
- // Reset
- lex->at = at;
- lex->current_token = cur_t;
- return false;
- }
- // Advances until next token of given type is found
- GS_API_DECL bool gs_lexer_find_next_token_type(gs_lexer_t* lex, gs_token_type type)
- {
- gs_token_t t = lex->next_token(lex);
- while (lex->can_lex(lex))
- {
- if (gs_token_compare_type(&t, type))
- {
- return true;
- }
- t = lex->next_token(lex);
- }
- return false;
- }
- GS_API_DECL gs_token_t
- gs_lexer_advance_before_next_token_type(gs_lexer_t* lex, gs_token_type type)
- {
- gs_token_t t = lex->current_token;
- gs_token_t peek_t = gs_lexer_peek(lex);
- // Continue right up until required token type
- while (!gs_token_compare_type(&peek_t, type))
- {
- t = lex->next_token(lex);
- peek_t = gs_lexer_peek(lex);
- }
- return t;
- }
- GS_API_DECL gs_lexer_t
- gs_lexer_c_ctor(const char* contents)
- {
- gs_lexer_t lex = gs_default_val();
- lex.contents = contents;
- lex.at = contents;
- lex.can_lex = gs_lexer_c_can_lex;
- lex.eat_white_space = gs_lexer_c_eat_white_space;
- lex.next_token = gs_lexer_c_next_token;
- lex.skip_white_space = true;
- return lex;
- }
- /*=============================
- // GS_ENGINE
- =============================*/
- GS_API_DECL void
- gs_default_app_func();
- GS_API_DECL void
- gs_default_main_window_close_callback(void* window);
- // Global instance of gunslinger framework (...THERE CAN ONLY BE ONE)
- gs_global gs_t* _gs_instance = gs_default_val();
- GS_API_DECL gs_t*
- gs_create(gs_app_desc_t app_desc)
- {
- if (gs_instance() == NULL)
- {
- // Check app desc for defaults
- if (app_desc.window.width == 0) app_desc.window.width = 800;
- if (app_desc.window.height == 0) app_desc.window.height = 600;
- if (app_desc.window.title == 0) app_desc.window.title = "App";
- if (app_desc.window.frame_rate <= 0.f) app_desc.window.frame_rate = 60.f;
- if (app_desc.update == NULL) app_desc.update = &gs_default_app_func;
- if (app_desc.shutdown == NULL) app_desc.shutdown = &gs_default_app_func;
- if (app_desc.init == NULL) app_desc.init = &gs_default_app_func;
- // Set up os api before all?
- gs_os_api_t os = gs_os_api_new();
- // Construct instance and set
- _gs_instance = (gs_t*)os.malloc(sizeof(gs_t));
- memset(_gs_instance, 0, sizeof(gs_t));
- gs_instance()->ctx.lock = SCHED_PIPE_INVALID;
- // Set os api now allocated
- gs_instance()->ctx.os = os;
- // Set application description for framework
- gs_instance()->ctx.app = app_desc;
- // Set up function pointers
- gs_instance()->shutdown = &gs_destroy;
- // Need to have video settings passed down from user
- gs_subsystem(platform) = gs_platform_create();
- // Enable graphics API debugging
- gs_subsystem(platform)->settings.video.graphics.debug = app_desc.debug_gfx;
- // Default initialization for platform here
- gs_platform_init(gs_subsystem(platform));
- // Set frame rate for application
- gs_subsystem(platform)->time.max_fps = app_desc.window.frame_rate;
- // Construct main window
- gs_platform_window_create(&app_desc.window);
- // Set vsync for video
- gs_platform_enable_vsync(app_desc.window.vsync);
- // Construct graphics api
- gs_subsystem(graphics) = gs_graphics_create();
- // Initialize graphics here
- gs_graphics_init(gs_subsystem(graphics));
- // Construct audio api
- gs_subsystem(audio) = gs_audio_create();
- // Initialize audio
- gs_audio_init(gs_subsystem(audio));
- // Initialize application and set to running
- app_desc.init();
- gs_ctx()->app.is_running = true;
- // Set default callback for when main window close button is pressed
- gs_platform_set_window_close_callback(gs_platform_main_window(), &gs_default_main_window_close_callback);
- }
- return gs_instance();
- }
- GS_API_DECL void
- gs_set_instance(gs_t* gs)
- {
- _gs_instance = gs;
- }
- GS_API_DECL gs_t*
- gs_instance()
- {
- return _gs_instance;
- }
- GS_API_DECL gs_context_t*
- gs_ctx()
- {
- return &gs_instance()->ctx;
- }
- GS_API_DECL gs_app_desc_t*
- gs_app()
- {
- return &gs_instance()->ctx.app;
- }
- // Define main frame function for framework to step
- GS_API_DECL void
- gs_frame()
- {
- // Remove these...
- static uint32_t curr_ticks = 0;
- static uint32_t prev_ticks = 0;
- // Cache platform pointer
- gs_platform_t* platform = gs_subsystem(platform);
- // Cache times at start of frame
- platform->time.elapsed = (float)gs_platform_elapsed_time();
- platform->time.update = platform->time.elapsed - platform->time.previous;
- platform->time.previous = platform->time.elapsed;
- // Update platform and process input
- gs_platform_update(platform);
- if (!gs_instance()->ctx.app.is_running) {
- gs_instance()->shutdown();
- return;
- }
- // Process application context
- gs_instance()->ctx.app.update();
- if (!gs_instance()->ctx.app.is_running) {
- gs_instance()->shutdown();
- return;
- }
- // Clear all platform events
- gs_dyn_array_clear(platform->events);
- // NOTE(John): This won't work forever. Must change eventually.
- // Swap all platform window buffers? Sure...
- for
- (
- gs_slot_array_iter it = 0;
- gs_slot_array_iter_valid(platform->windows, it);
- gs_slot_array_iter_advance(platform->windows, it)
- )
- {
- gs_platform_window_swap_buffer(it);
- }
- // Frame locking (not sure if this should be done here, but it is what it is)
- platform->time.elapsed = (float)gs_platform_elapsed_time();
- platform->time.render = platform->time.elapsed - platform->time.previous;
- platform->time.previous = platform->time.elapsed;
- platform->time.frame = platform->time.update + platform->time.render; // Total frame time
- platform->time.delta = platform->time.frame / 1000.f;
- float target = (1000.f / platform->time.max_fps);
- if (platform->time.frame < target)
- {
- gs_platform_sleep((float)(target - platform->time.frame));
-
- platform->time.elapsed = (float)gs_platform_elapsed_time();
- double wait_time = platform->time.elapsed - platform->time.previous;
- platform->time.previous = platform->time.elapsed;
- platform->time.frame += wait_time;
- platform->time.delta = platform->time.frame / 1000.f;
- }
- }
- void gs_destroy()
- {
- // Shutdown application
- gs_ctx()->app.shutdown();
- gs_ctx()->app.is_running = false;
- // Shutdown subsystems
- gs_graphics_shutdown(gs_subsystem(graphics));
- gs_graphics_destroy(gs_subsystem(graphics));
- gs_audio_shutdown(gs_subsystem(audio));
- gs_audio_destroy(gs_subsystem(audio));
- gs_platform_shutdown(gs_subsystem(platform));
- gs_platform_destroy(gs_subsystem(platform));
- }
- GS_API_DECL void
- gs_default_app_func()
- {
- // Nothing...
- }
- GS_API_DECL void
- gs_default_main_window_close_callback(void* window)
- {
- gs_instance()->ctx.app.is_running = false;
- }
- void gs_quit()
- {
- #ifndef GS_PLATFORM_WEB
- gs_instance()->ctx.app.is_running = false;
- #endif
- }
- #undef GS_IMPL
- #endif // GS_IMPL
- #endif // GS_H
- /*
- Layout decl
- // Pipeline should have layout desc for vertices?
- // Or should it have layout for EACH buffer?
-
- non-interleaved vertex data
- have to be able to specific stride/offset for vertex layouts
- What are ways to interleave data?
- layout descriptor?
- gs_vertex_attribute_type layouts[] =
- {
- };
- // Need to codify strides/offsets/divisors
- // This can hold multiple layouts
- gs_vertex_layout_desc_t layout =
- {
- .layouts = layouts,
- .size = sizeof(layouts)
- };
- Don't want to have to make user calculate strides, right?
- // If you don't provide manual stride/offset, then it'll calculate it for you based on layout?
- #version 330 core
- layout (location = 0) in vec2 aPos;
- layout (location = 1) in vec3 aColor;
- layout (location = 2) in vec2 aOffset;
- out vec3 fColor;
- void main()
- {
- gl_Position = vec4(aPos + aOffset, 0.0, 1.0);
- fColor = aColor;
- }
- typedef struct gs_vertex_attribute_layout_desc_t {
- gs_vertex_attribute_type format;
- size_t stride;
- size_t offset;
- size_t divisor;
- } gs_vertex_attribute_layout_desc_t;
- gs_vertex_attribute_layout_desc_t layout[] = {
- {.format = GS_VERTEX_ATTRIBUTE_FLOAT2},
- {.format = GS_VERTEX_ATTRIBUTE_FLOAT3},
- {.format = GS_VERTEX_ATTRIBUTE_FLOAT2, .stride = 2 * sizeof(float), .offset = 0, .divisor = 1}
- };
- What about non-interleaved data? Almost would need to provide an offset.
- It's specific to the data itself, so have to provide manual offsets for data in binding data
- gs_graphics_bind_desc_t binds[] = {
- {.type = GS_GRAPHICS_BIND_VERTEX_BUFFER, .buffer = , .offset = };
- }
- gs_graphics_bind_desc_t binds[] = {
- (gs_graphics_bind_desc_t){.type = GS_GRAPHICS_BIND_VERTEX_BUFFER, .buffer = vbo, .offset = ...},
- (gs_graphics_bind_desc_t){.type = GS_GRAPHICS_BIND_VERTEX_BUFFER, .buffer = vbo, .offset = ...},
- };
- .layout = {
- .attributes = &(){
- {.format = GS_VERTEX_ATTRIBUTE_FLOAT2},
- {.format = GS_VERTEX_ATTRIBUTE_FLOAT2},
- {.format = GS_VERTEX_ATTRIBUTE_FLOAT4, .stride = 64, .offset =, .divisor = }
- }
- };
- sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){
- .shader = shd,
- .layout = {
- .attrs = {
- [0].format=SG_VERTEXFORMAT_FLOAT3,
- [1].format=SG_VERTEXFORMAT_FLOAT4
- }
- }
- });
- .layout = {
- .attrs = attrs,
- .attr_size = sizeof(attrs),
- .strides = strides,
- .stride_size = sizeof(strides),
- }
- sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){
- .layout = {
- .buffers = {
- [0] = { .stride = 28 },
- [1] = { .stride = 12, .step_func=SG_VERTEXSTEP_PER_INSTANCE }
- },
- .attrs = {
- [0] = { .offset = 0, .format=SG_VERTEXFORMAT_FLOAT3, .buffer_index=0 },
- [1] = { .offset = 12, .format=SG_VERTEXFORMAT_FLOAT4, .buffer_index=0 },
- [2] = { .offset = 0, .format=SG_VERTEXFORMAT_FLOAT3, .buffer_index=1 }
- }
- },
- .shader = shd,
- .index_type = SG_INDEXTYPE_UINT16,
- .depth_stencil = {
- .depth_compare_func = SG_COMPAREFUNC_LESS_EQUAL,
- .depth_write_enabled = true
- },
- .rasterizer.cull_mode = SG_CULLMODE_BACK
- });
- float quadVertices[] = {
- // positions // colors
- -0.05f, 0.05f, 1.0f, 0.0f, 0.0f,
- 0.05f, -0.05f, 0.0f, 1.0f, 0.0f,
- -0.05f, -0.05f, 0.0f, 0.0f, 1.0f,
- -0.05f, 0.05f, 1.0f, 0.0f, 0.0f,
- 0.05f, -0.05f, 0.0f, 1.0f, 0.0f,
- 0.05f, 0.05f, 0.0f, 1.0f, 1.0f
- };
- // also set instance data
- glEnableVertexAttribArray(2);
- glBindBuffer(GL_ARRAY_BUFFER, instanceVBO); // this attribute comes from a different vertex buffer
- glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glVertexAttribDivisor(2, 1); // tell OpenGL this is an instanced vertex attribute.
- gltf loading
- Mesh Attributes:
- cgltf_attribute_type_invalid,
- cgltf_attribute_type_position,
- cgltf_attribute_type_normal,
- cgltf_attribute_type_tangent,
- cgltf_attribute_type_texcoord,
- cgltf_attribute_type_color,
- cgltf_attribute_type_joints,
- cgltf_attribute_type_weights,
- Primitive types:
- cgltf_primitive_type_points,
- cgltf_primitive_type_lines,
- cgltf_primitive_type_line_loop,
- cgltf_primitive_type_line_strip,
- cgltf_primitive_type_triangles,
- cgltf_primitive_type_triangle_strip,
- cgltf_primitive_type_triangle_fan,
- For each mesh:
- For each primitive:
- For each attribute:
- Get data and push into mesh definition
- Is there a way to have the user be able to specify a layout and then use that for the mesh?
- gs_enum_decl(gs_asset_mesh_attribute_type,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_POSITION,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_NORMAL,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_TANGENT,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_JOINT,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_WEIGHT,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_TEXCOORD,
- GS_ASSET_MESH_ATTRIBUTE_TYPE_COLOR
- });
- typedef struct gs_asset_mesh_layout_t {
- gs_asset_mesh_attribute_type type; // Type of attribute
- uint32_t idx; // Optional index (for joint/weight/texcoord/color)
- } gs_asset_mesh_layout_t;
- typedef struct gs_asset_mesh_decl_t
- {
- gs_asset_mesh_layout_t* layout; // Mesh attribute layout array
- size_t layout_size; // Size of mesh attribute layout array in bytes
- } gs_asset_mesh_decl_t;
- // Mesh holds...what?
- // A pipeline? Shouldn't have to.
- // Material? Nope.
- // It's just mesh data. (so an index/vertex buffer)
- typedef struct gs_asset_mesh_t
- {
- gs_handle(gs_graphics_buffer_t) vbo;
- gs_handle(gs_graphics_buffer_t) ibo;
- } gs_asset_mesh_t;
- void gs_asset_mesh_load_from_file(const char* path, void* out, gs_asset_mesh_decl_t* decl, void* data_out, size_t data_size)
- {
- gs_asset_mesh_t* mesh = (gs_asset_mesh_t*)out;
- // Parse gltf data
- }
- Does this need to line up with a pipeline? Not necessarily, right?
- // At LEAST position is required to be passed in for the layout, so maybe it's not necessary
- // to provide this in the layout?
- // Can you duplicate? I don't think so...
- gs_asset_mesh_attribute_type layout[] =
- {
- POSITION,
- NORMAL,
- TANGENT,
- JOINTS_XXX,
- WEIGHTS_XXX,
- TEXCOORD_XXX,
- COLOR_XXX
- };
- gs_asset_mesh_t mesh = gs_asset_load_gltf(path, layout, sizeof(layout));
- // Do you HAVE to have certain attributes for a mesh to make any sense? For instance, do you HAVE to have position?
- // What if position is NOT the first attribute layout for your vertex attribute?
- // Need to fill out data for each attribute, then interleave?
- ^()
- {
- For each mesh:
- For each primitive:
- For each attribute:
- Get data and push into mesh definition
- }
- main update for web? android? probably want to move to different "main" implementations:
- gs_win32_main
- gs_glfw_linux_main
- gs_glfw_osx_main
- gs_glfw_win32_main
- gs_glfw_emsc_main
- Each platform should define its own main function, control its own loop, reach into application code, then
- run how it needs to.
- int main(int32_t argc, char** argv)
- {
- emscripten_set_main_loop(gs_create(gs_main(argc, argv))->run(), 0, true);
- }
- */
|