stb_tilemap_editor.h 143 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188
  1. // stb_tilemap_editor.h - v0.42 - Sean Barrett - http://nothings.org/stb
  2. // placed in the public domain - not copyrighted - first released 2014-09
  3. //
  4. // Embeddable tilemap editor for C/C++
  5. //
  6. //
  7. // TABLE OF CONTENTS
  8. // FAQ
  9. // How to compile/use the library
  10. // Additional configuration macros
  11. // API documentation
  12. // Info on editing multiple levels
  13. // Revision history
  14. // Todo
  15. // Credits
  16. // License
  17. //
  18. //
  19. // FAQ
  20. //
  21. // Q: What counts as a tilemap for this library?
  22. //
  23. // A: An array of rectangles, where each rectangle contains a small
  24. // stack of images.
  25. //
  26. // Q: What are the limitations?
  27. //
  28. // A: Maps are limited to 4096x4096 in dimension.
  29. // Each map square can only contain a stack of at most 32 images.
  30. // A map can only use up to 32768 distinct image tiles.
  31. //
  32. // Q: How do I compile this?
  33. //
  34. // A: You need to #define several symbols before #including it, but only
  35. // in one file. This will cause all the function definitions to be
  36. // generated in that file. See the "HOW TO COMPILE" section.
  37. //
  38. // Q: What advantages does this have over a standalone editor?
  39. //
  40. // A: For one, you can integrate the editor into your game so you can
  41. // flip between editing and testing without even switching windows.
  42. // For another, you don't need an XML parser to get at the map data.
  43. //
  44. // Q: Can I live-edit my game maps?
  45. //
  46. // A: Not really, the editor keeps its own map representation.
  47. //
  48. // Q: How do I save and load maps?
  49. //
  50. // A: You have to do this yourself. The editor provides serialization
  51. // functions (get & set) for reading and writing the map it holds.
  52. // You can choose whatever format you want to store the map to on
  53. // disk; you just need to provide functions to convert. (For example,
  54. // I actually store the editor's map representation to disk basically
  55. // as-is; then I have a single function that converts from the editor
  56. // map representation to the game representation, which is used both
  57. // to go from editor-to-game and from loaded-map-to-game.)
  58. //
  59. // Q: I want to have tiles change appearance based on what's
  60. // adjacent, or other tile-display/substitution trickiness.
  61. //
  62. // A: You can do this when you convert from the editor's map
  63. // representation to the game representation, but there's
  64. // no way to show this live in the editor.
  65. //
  66. // Q: The editor appears to be put map location (0,0) at the top left?
  67. // I want to use a different coordinate system in my game (e.g. y
  68. // increasing upwards, or origin at the center).
  69. //
  70. // A: You can do this when you convert from the editor's map
  71. // representation to the game representation. (Don't forget to
  72. // translate link coordinates as well!)
  73. //
  74. // Q: The editor appears to put pixel (0,0) at the top left? I want
  75. // to use a different coordinate system in my game.
  76. //
  77. // A: The editor defines an "editor pixel coordinate system" with
  78. // (0,0) at the top left and requires you to display things in
  79. // that coordinate system. You can freely remap those coordinates
  80. // to anything you want on screen.
  81. //
  82. // Q: How do I scale the user interface?
  83. //
  84. // A: Since you do all the rendering, you can scale up all the rendering
  85. // calls that the library makes to you. If you do, (a) you need
  86. // to also scale up the mouse coordinates, and (b) you may want
  87. // to scale the map display back down so that you're only scaling
  88. // the UI and not everything. See the next question.
  89. //
  90. // Q: How do I scale the map display?
  91. //
  92. // A: Use stbte_set_spacing() to change the size that the map is displayed
  93. // at. Note that the "callbacks" to draw tiles are used for both drawing
  94. // the map and drawing the tile palette, so that callback may need to
  95. // draw at two different scales. You should choose the scales to match
  96. // You can tell them apart because the
  97. // tile palette gets NULL for the property pointer.
  98. //
  99. // Q: How does object editing work?
  100. //
  101. // A: One way to think of this is that in the editor, you're placing
  102. // spawners, not objects. Each spawner must be tile-aligned, because
  103. // it's only a tile editor. Each tile (stack of layers) gets
  104. // an associated set of properties, and it's up to you to
  105. // determine what properties should appear for a given tile,
  106. // based on e.g. the spawners that are in it.
  107. //
  108. // Q: How are properties themselves handled?
  109. //
  110. // A: All properties, regardless of UI behavior, are internally floats.
  111. // Each tile has an array of floats associated with it, which is
  112. // passed back to you when drawing the tiles so you can draw
  113. // objects appropriately modified by the properties.
  114. //
  115. // Q: What if I want to have two different objects/spawners in
  116. // one tile, both of which have their own properties?
  117. //
  118. // A: Make sure STBTE_MAX_PROPERTIES is large enough for the sum of
  119. // properties in both objects, and then you have to explicitly
  120. // map the property slot #s to the appropriate objects. They'll
  121. // still all appear in a single property panel; there's no way
  122. // to get multiple panels.
  123. //
  124. // Q: Can I do one-to-many linking?
  125. //
  126. // A: The library only supports one link per tile. However, you
  127. // can have multiple tiles all link to a single tile. So, you
  128. // can fake one-to-many linking by linking in the reverse
  129. // direction.
  130. //
  131. // Q: What if I have two objects in the same tile, and they each
  132. // need an independent link? Or I have two kinds of link associated
  133. // with a single object?
  134. //
  135. // A: There is no way to do this. (Unless you can reverse one link.)
  136. //
  137. // Q: How does cut & paste interact with object properties & links?
  138. //
  139. // A: Currently the library has no idea which properties or links
  140. // are associated with which layers of a tile. So currently, the
  141. // library will only copy properties & links if the layer panel
  142. // is set to allow all layers to be copied, OR if you set the
  143. // "props" in the layer panel to "always". Similarly, you can
  144. // set "props" to "none" so it will never copy.
  145. //
  146. // Q: What happens if the library gets a memory allocation failure
  147. // while I'm editing? Will I lose my work?
  148. //
  149. // A: The library allocates all editor memory when you create
  150. // the tilemap. It allocates a maximally-sized map and a
  151. // fixed-size undo buffer (and the fixed-size copy buffer
  152. // is static), and never allocates memory while it's running.
  153. // So it can't fail due to running out of memory.
  154. //
  155. // Q: What happens if the library crashes while I'm editing? Will
  156. // I lose my work?
  157. //
  158. // A: Yes. Save often.
  159. //
  160. //
  161. // HOW TO COMPILE
  162. //
  163. // This header file contains both the header file and the
  164. // implementation file in one. To create the implementation,
  165. // in one source file define a few symbols first and then
  166. // include this header:
  167. //
  168. // #define STB_TILEMAP_EDITOR_IMPLEMENTATION
  169. // // this triggers the implementation
  170. //
  171. // void STBTE_DRAW_RECT(int x0, int y0, int x1, int y1, unsigned int color);
  172. // // this must draw a filled rectangle (exclusive on right/bottom)
  173. // // color = (r<<16)|(g<<8)|(b)
  174. //
  175. // void STBTE_DRAW_TILE(int x0, int y0,
  176. // unsigned short id, int highlight, float *data);
  177. // // this draws the tile image identified by 'id' in one of several
  178. // // highlight modes (see STBTE_drawmode_* in the header section);
  179. // // if 'data' is NULL, it's drawing the tile in the palette; if 'data'
  180. // // is not NULL, it's drawing a tile on the map, and that is the data
  181. // // associated with that map tile
  182. //
  183. // #include "stb_tilemap_editor.h"
  184. //
  185. // Optionally you can define the following functions before the include;
  186. // note these must be macros (but they can just call a function) so
  187. // this library can #ifdef to detect if you've defined them:
  188. //
  189. // #define STBTE_PROP_TYPE(int n, short *tiledata, float *params) ...
  190. // // Returns the type of the n'th property of a given tile, which
  191. // // controls how it is edited. Legal types are:
  192. // // 0 /* no editable property in this slot */
  193. // // STBTE_PROP_int /* uses a slider to adjust value */
  194. // // STBTE_PROP_float /* uses a weird multi-axis control */
  195. // // STBTE_PROP_bool /* uses a checkbox to change value */
  196. // // And you can bitwise-OR in the following flags:
  197. // // STBTE_PROP_disabled
  198. // // Note that all of these are stored as floats in the param array.
  199. // // The integer slider is limited in precision based on the space
  200. // // available on screen, so for wide-ranged integers you may want
  201. // // to use floats instead.
  202. // //
  203. // // Since the tiledata is passed to you, you can choose which property
  204. // // is bound to that slot based on that data.
  205. // //
  206. // // Changing the type of a parameter does not cause the underlying
  207. // // value to be clamped to the type min/max except when the tile is
  208. // // explicitly selected.
  209. //
  210. // #define STBTE_PROP_NAME(int n, short *tiledata, float *params) ...
  211. // // these return a string with the name for slot #n in the float
  212. // // property list for the tile.
  213. //
  214. // #define STBTE_PROP_MIN(int n, short *tiledata) ...your code here...
  215. // #define STBTE_PROP_MAX(int n, short *tiledata) ...your code here...
  216. // // These return the allowable range for the property values for
  217. // // the specified slot. It is never called for boolean types.
  218. //
  219. // #define STBTE_PROP_FLOAT_SCALE(int n, short *tiledata, float *params)
  220. // // This rescales the float control for a given property; by default
  221. // // left mouse drags add integers, right mouse drags adds fractions,
  222. // // but you can rescale this per-property.
  223. //
  224. // #define STBTE_FLOAT_CONTROL_GRANULARITY ... value ...
  225. // // This returns the number of pixels of mouse motion necessary
  226. // // to advance the object float control. Default is 4
  227. //
  228. // #define STBTE_ALLOW_LINK(short *src, float *src_data, \
  229. // short *dest, float *dest_data) ...your code...
  230. // // this returns true or false depending on whether you allow a link
  231. // // to be drawn from a tile 'src' to a tile 'dest'. if you don't
  232. // // define this, linking will not be supported
  233. //
  234. // #define STBTE_LINK_COLOR(short *src, float *src_data, \
  235. // short *dest, float *dest_data) ...your code...
  236. // // return a color encoded as a 24-bit unsigned integer in the
  237. // // form 0xRRGGBB. If you don't define this, default colors will
  238. // // be used.
  239. //
  240. //
  241. // [[ support for those below is not implemented yet ]]
  242. //
  243. // #define STBTE_HITTEST_TILE(x0,y0,id,mx,my) ...your code here...
  244. // // this returns true or false depending on whether the mouse
  245. // // pointer at mx,my is over (touching) a tile of type 'id'
  246. // // displayed at x0,y0. Normally stb_tilemap_editor just does
  247. // // this hittest based on the tile geometry, but if you have
  248. // // tiles whose images extend out of the tile, you'll need this.
  249. //
  250. // ADDITIONAL CONFIGURATION
  251. //
  252. // The following symbols set static limits which determine how much
  253. // memory will be allocated for the editor. You can override them
  254. // by making similar definitions, but memory usage will increase.
  255. //
  256. // #define STBTE_MAX_TILEMAP_X 200 // max 4096
  257. // #define STBTE_MAX_TILEMAP_Y 200 // max 4096
  258. // #define STBTE_MAX_LAYERS 8 // max 32
  259. // #define STBTE_MAX_CATEGORIES 100
  260. // #define STBTE_UNDO_BUFFER_BYTES (1 << 24) // 16 MB
  261. // #define STBTE_MAX_COPY 90000 // e.g. 300x300
  262. // #define STBTE_MAX_PROPERTIES 10 // max properties per tile
  263. //
  264. // API
  265. //
  266. // Further documentation appears in the header-file section below.
  267. //
  268. // EDITING MULTIPLE LEVELS
  269. //
  270. // You can only have one active editor instance. To switch between multiple
  271. // levels, you can either store the levels in your own format and copy them
  272. // in and out of the editor format, or you can create multiple stbte_tilemap
  273. // objects and switch between them. The latter has the advantage that each
  274. // stbte_tilemap keeps its own undo state. (The clipboard is global, so
  275. // either approach allows cut&pasting between levels.)
  276. //
  277. // REVISION HISTORY
  278. // 0.42 fix compilation errors
  279. // 0.41 fix warnings
  280. // 0.40 fix warning
  281. // 0.39 fix warning
  282. // 0.38 fix warning
  283. // 0.37 fix warning
  284. // 0.36 minor compiler support
  285. // 0.35 layername button changes
  286. // - layername buttons grow with the layer panel
  287. // - fix stbte_create_map being declared as stbte_create
  288. // - fix declaration of stbte_create_map
  289. // 0.30 properties release
  290. // - properties panel for editing user-defined "object" properties
  291. // - can link each tile to one other tile
  292. // - keyboard interface
  293. // - fix eraser tool bug (worked in complex cases, failed in simple)
  294. // - undo/redo tools have visible disabled state
  295. // - tiles on higher layers draw on top of adjacent lower-layer tiles
  296. // 0.20 erasable release
  297. // - eraser tool
  298. // - fix bug when pasting into protected layer
  299. // - better color scheme
  300. // - internal-use color picker
  301. // 0.10 initial release
  302. //
  303. // TODO
  304. //
  305. // Separate scroll state for each category
  306. // Implement paint bucket
  307. // Support STBTE_HITTEST_TILE above
  308. // ?Cancel drags by clicking other button? - may be fixed
  309. // Finish support for toolbar at side
  310. //
  311. // CREDITS
  312. //
  313. //
  314. // Main editor & features
  315. // Sean Barrett
  316. // Additional features:
  317. // Josh Huelsman
  318. // Bugfixes:
  319. // Ryan Whitworth
  320. // Eugene Opalev
  321. // Rob Loach
  322. // github:wernsey
  323. //
  324. // LICENSE
  325. //
  326. // See end of file for license information.
  327. ///////////////////////////////////////////////////////////////////////
  328. //
  329. // HEADER SECTION
  330. #ifndef STB_TILEMAP_INCLUDE_STB_TILEMAP_EDITOR_H
  331. #define STB_TILEMAP_INCLUDE_STB_TILEMAP_EDITOR_H
  332. #ifdef _WIN32
  333. #ifndef _CRT_SECURE_NO_WARNINGS
  334. #define _CRT_SECURE_NO_WARNINGS
  335. #endif
  336. #include <stdlib.h>
  337. #include <stdio.h>
  338. #endif
  339. typedef struct stbte_tilemap stbte_tilemap;
  340. // these are the drawmodes used in STBTE_DRAW_TILE
  341. enum
  342. {
  343. STBTE_drawmode_deemphasize = -1,
  344. STBTE_drawmode_normal = 0,
  345. STBTE_drawmode_emphasize = 1,
  346. };
  347. // these are the property types
  348. #define STBTE_PROP_none 0
  349. #define STBTE_PROP_int 1
  350. #define STBTE_PROP_float 2
  351. #define STBTE_PROP_bool 3
  352. #define STBTE_PROP_disabled 4
  353. ////////
  354. //
  355. // creation
  356. //
  357. extern stbte_tilemap *stbte_create_map(int map_x, int map_y, int map_layers, int spacing_x, int spacing_y, int max_tiles);
  358. // create an editable tilemap
  359. // map_x : dimensions of map horizontally (user can change this in editor), <= STBTE_MAX_TILEMAP_X
  360. // map_y : dimensions of map vertically (user can change this in editor) <= STBTE_MAX_TILEMAP_Y
  361. // map_layers : number of layers to use (fixed), <= STBTE_MAX_LAYERS
  362. // spacing_x : initial horizontal distance between left edges of map tiles in stb_tilemap_editor pixels
  363. // spacing_y : initial vertical distance between top edges of map tiles in stb_tilemap_editor pixels
  364. // max_tiles : maximum number of tiles that can defined
  365. //
  366. // If insufficient memory, returns NULL
  367. extern void stbte_define_tile(stbte_tilemap *tm, unsigned short id, unsigned int layermask, const char * category);
  368. // call this repeatedly for each tile to install the tile definitions into the editable tilemap
  369. // tm : tilemap created by stbte_create_map
  370. // id : unique identifier for each tile, 0 <= id < 32768
  371. // layermask : bitmask of which layers tile is allowed on: 1 = layer 0, 255 = layers 0..7
  372. // (note that onscreen, the editor numbers the layers from 1 not 0)
  373. // layer 0 is the furthest back, layer 1 is just in front of layer 0, etc
  374. // category : which category this tile is grouped in
  375. extern void stbte_set_display(int x0, int y0, int x1, int y1);
  376. // call this once to set the size; if you resize, call it again
  377. /////////
  378. //
  379. // every frame
  380. //
  381. extern void stbte_draw(stbte_tilemap *tm);
  382. extern void stbte_tick(stbte_tilemap *tm, float time_in_seconds_since_last_frame);
  383. ////////////
  384. //
  385. // user input
  386. //
  387. // if you're using SDL, call the next function for SDL_MOUSEMOTION, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP, SDL_MOUSEWHEEL;
  388. // the transformation lets you scale from SDL mouse coords to stb_tilemap_editor coords
  389. extern void stbte_mouse_sdl(stbte_tilemap *tm, const void *sdl_event, float xscale, float yscale, int xoffset, int yoffset);
  390. // otherwise, hook these up explicitly:
  391. extern void stbte_mouse_move(stbte_tilemap *tm, int x, int y, int shifted, int scrollkey);
  392. extern void stbte_mouse_button(stbte_tilemap *tm, int x, int y, int right, int down, int shifted, int scrollkey);
  393. extern void stbte_mouse_wheel(stbte_tilemap *tm, int x, int y, int vscroll);
  394. // note: at the moment, mouse wheel events (SDL_MOUSEWHEEL) are ignored.
  395. // for keyboard, define your own mapping from keys to the following actions.
  396. // this is totally optional, as all features are accessible with the mouse
  397. enum stbte_action
  398. {
  399. STBTE_tool_select,
  400. STBTE_tool_brush,
  401. STBTE_tool_erase,
  402. STBTE_tool_rectangle,
  403. STBTE_tool_eyedropper,
  404. STBTE_tool_link,
  405. STBTE_act_toggle_grid,
  406. STBTE_act_toggle_links,
  407. STBTE_act_undo,
  408. STBTE_act_redo,
  409. STBTE_act_cut,
  410. STBTE_act_copy,
  411. STBTE_act_paste,
  412. STBTE_scroll_left,
  413. STBTE_scroll_right,
  414. STBTE_scroll_up,
  415. STBTE_scroll_down,
  416. };
  417. extern void stbte_action(stbte_tilemap *tm, enum stbte_action act);
  418. ////////////////
  419. //
  420. // save/load
  421. //
  422. // There is no editor file format. You have to save and load the data yourself
  423. // through the following functions. You can also use these functions to get the
  424. // data to generate game-formatted levels directly. (But make sure you save
  425. // first! You may also want to autosave to a temp file periodically, etc etc.)
  426. #define STBTE_EMPTY -1
  427. extern void stbte_get_dimensions(stbte_tilemap *tm, int *max_x, int *max_y);
  428. // get the dimensions of the level, since the user can change them
  429. extern short* stbte_get_tile(stbte_tilemap *tm, int x, int y);
  430. // returns an array of shorts that is 'map_layers' in length. each short is
  431. // either one of the tile_id values from define_tile, or STBTE_EMPTY.
  432. extern float *stbte_get_properties(stbte_tilemap *tm, int x, int y);
  433. // get the property array associated with the tile at x,y. this is an
  434. // array of floats that is STBTE_MAX_PROPERTIES in length; you have to
  435. // interpret the slots according to the semantics you've chosen
  436. extern void stbte_get_link(stbte_tilemap *tm, int x, int y, int *destx, int *desty);
  437. // gets the link associated with the tile at x,y.
  438. extern void stbte_set_dimensions(stbte_tilemap *tm, int max_x, int max_y);
  439. // set the dimensions of the level, overrides previous stbte_create_map()
  440. // values or anything the user has changed
  441. extern void stbte_clear_map(stbte_tilemap *tm);
  442. // clears the map, including the region outside the defined region, so if the
  443. // user expands the map, they won't see garbage there
  444. extern void stbte_set_tile(stbte_tilemap *tm, int x, int y, int layer, signed short tile);
  445. // tile is your tile_id from define_tile, or STBTE_EMPTY
  446. extern void stbte_set_property(stbte_tilemap *tm, int x, int y, int n, float val);
  447. // set the value of the n'th slot of the tile at x,y
  448. extern void stbte_set_link(stbte_tilemap *tm, int x, int y, int destx, int desty);
  449. // set a link going from x,y to destx,desty. to force no link,
  450. // use destx=desty=-1
  451. ////////
  452. //
  453. // optional
  454. //
  455. extern void stbte_set_background_tile(stbte_tilemap *tm, short id);
  456. // selects the tile to fill the bottom layer with and used to clear bottom tiles to;
  457. // should be same ID as
  458. extern void stbte_set_sidewidths(int left, int right);
  459. // call this once to set the left & right side widths. don't call
  460. // it again since the user can change it
  461. extern void stbte_set_spacing(stbte_tilemap *tm, int spacing_x, int spacing_y, int palette_spacing_x, int palette_spacing_y);
  462. // call this to set the spacing of map tiles and the spacing of palette tiles.
  463. // if you rescale your display, call it again (e.g. you can implement map zooming yourself)
  464. extern void stbte_set_layername(stbte_tilemap *tm, int layer, const char *layername);
  465. // sets a string name for your layer that shows in the layer selector. note that this
  466. // makes the layer selector wider. 'layer' is from 0..(map_layers-1)
  467. #endif
  468. #ifdef STB_TILEMAP_EDITOR_IMPLEMENTATION
  469. #ifndef STBTE_ASSERT
  470. #define STBTE_ASSERT assert
  471. #include <assert.h>
  472. #endif
  473. #ifdef _MSC_VER
  474. #define STBTE__NOTUSED(v) (void)(v)
  475. #else
  476. #define STBTE__NOTUSED(v) (void)sizeof(v)
  477. #endif
  478. #ifndef STBTE_MAX_TILEMAP_X
  479. #define STBTE_MAX_TILEMAP_X 200
  480. #endif
  481. #ifndef STBTE_MAX_TILEMAP_Y
  482. #define STBTE_MAX_TILEMAP_Y 200
  483. #endif
  484. #ifndef STBTE_MAX_LAYERS
  485. #define STBTE_MAX_LAYERS 8
  486. #endif
  487. #ifndef STBTE_MAX_CATEGORIES
  488. #define STBTE_MAX_CATEGORIES 100
  489. #endif
  490. #ifndef STBTE_MAX_COPY
  491. #define STBTE_MAX_COPY 65536
  492. #endif
  493. #ifndef STBTE_UNDO_BUFFER_BYTES
  494. #define STBTE_UNDO_BUFFER_BYTES (1 << 24) // 16 MB
  495. #endif
  496. #ifndef STBTE_PROP_TYPE
  497. #define STBTE__NO_PROPS
  498. #define STBTE_PROP_TYPE(n,td,tp) 0
  499. #endif
  500. #ifndef STBTE_PROP_NAME
  501. #define STBTE_PROP_NAME(n,td,tp) ""
  502. #endif
  503. #ifndef STBTE_MAX_PROPERTIES
  504. #define STBTE_MAX_PROPERTIES 10
  505. #endif
  506. #ifndef STBTE_PROP_MIN
  507. #define STBTE_PROP_MIN(n,td,tp) 0
  508. #endif
  509. #ifndef STBTE_PROP_MAX
  510. #define STBTE_PROP_MAX(n,td,tp) 100.0
  511. #endif
  512. #ifndef STBTE_PROP_FLOAT_SCALE
  513. #define STBTE_PROP_FLOAT_SCALE(n,td,tp) 1 // default scale size
  514. #endif
  515. #ifndef STBTE_FLOAT_CONTROL_GRANULARITY
  516. #define STBTE_FLOAT_CONTROL_GRANULARITY 4
  517. #endif
  518. #define STBTE__UNDO_BUFFER_COUNT (STBTE_UNDO_BUFFER_BYTES>>1)
  519. #if STBTE_MAX_TILEMAP_X > 4096 || STBTE_MAX_TILEMAP_Y > 4096
  520. #error "Maximum editable map size is 4096 x 4096"
  521. #endif
  522. #if STBTE_MAX_LAYERS > 32
  523. #error "Maximum layers allowed is 32"
  524. #endif
  525. #if STBTE_UNDO_BUFFER_COUNT & (STBTE_UNDO_BUFFER_COUNT-1)
  526. #error "Undo buffer size must be a power of 2"
  527. #endif
  528. #if STBTE_MAX_PROPERTIES == 0
  529. #define STBTE__NO_PROPS
  530. #endif
  531. #ifdef STBTE__NO_PROPS
  532. #undef STBTE_MAX_PROPERTIES
  533. #define STBTE_MAX_PROPERTIES 1 // so we can declare arrays
  534. #endif
  535. typedef struct
  536. {
  537. short x,y;
  538. } stbte__link;
  539. enum
  540. {
  541. STBTE__base,
  542. STBTE__outline,
  543. STBTE__text,
  544. STBTE__num_color_aspects,
  545. };
  546. enum
  547. {
  548. STBTE__idle,
  549. STBTE__over,
  550. STBTE__down,
  551. STBTE__over_down,
  552. STBTE__selected,
  553. STBTE__selected_over,
  554. STBTE__disabled,
  555. STBTE__num_color_states,
  556. };
  557. enum
  558. {
  559. STBTE__cexpander,
  560. STBTE__ctoolbar,
  561. STBTE__ctoolbar_button,
  562. STBTE__cpanel,
  563. STBTE__cpanel_sider,
  564. STBTE__cpanel_sizer,
  565. STBTE__cscrollbar,
  566. STBTE__cmapsize,
  567. STBTE__clayer_button,
  568. STBTE__clayer_hide,
  569. STBTE__clayer_lock,
  570. STBTE__clayer_solo,
  571. STBTE__ccategory_button,
  572. STBTE__num_color_modes,
  573. };
  574. #ifdef STBTE__COLORPICKER
  575. static char *stbte__color_names[] =
  576. {
  577. "expander", "toolbar", "tool button", "panel",
  578. "panel c1", "panel c2", "scollbar", "map button",
  579. "layer", "hide", "lock", "solo",
  580. "category",
  581. };
  582. #endif // STBTE__COLORPICKER
  583. // idle, over, down, over&down, selected, sel&over, disabled
  584. static int stbte__color_table[STBTE__num_color_modes][STBTE__num_color_aspects][STBTE__num_color_states] =
  585. {
  586. {
  587. { 0x000000, 0x84987c, 0xdcdca8, 0xdcdca8, 0x40c040, 0x60d060, 0x505050, },
  588. { 0xa4b090, 0xe0ec80, 0xffffc0, 0xffffc0, 0x80ff80, 0x80ff80, 0x606060, },
  589. { 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x909090, },
  590. }, {
  591. { 0x808890, 0x606060, 0x606060, 0x606060, 0x606060, 0x606060, 0x606060, },
  592. { 0x605860, 0x606060, 0x606060, 0x606060, 0x606060, 0x606060, 0x606060, },
  593. { 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, },
  594. }, {
  595. { 0x3c5068, 0x7088a8, 0x647488, 0x94b4dc, 0x8890c4, 0x9caccc, 0x404040, },
  596. { 0x889cb8, 0x889cb8, 0x889cb8, 0x889cb8, 0x84c4e8, 0xacc8ff, 0x0c0c08, },
  597. { 0xbcc4cc, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x707074, },
  598. }, {
  599. { 0x403848, 0x403010, 0x403010, 0x403010, 0x403010, 0x403010, 0x303024, },
  600. { 0x68546c, 0xc08040, 0xc08040, 0xc08040, 0xc08040, 0xc08040, 0x605030, },
  601. { 0xf4e4ff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x909090, },
  602. }, {
  603. { 0xb4b04c, 0xacac60, 0xc0ffc0, 0xc0ffc0, 0x40c040, 0x60d060, 0x505050, },
  604. { 0xa0a04c, 0xd0d04c, 0xffff80, 0xffff80, 0x80ff80, 0x80ff80, 0x606060, },
  605. { 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x909090, },
  606. }, {
  607. { 0x40c440, 0x60d060, 0xc0ffc0, 0xc0ffc0, 0x40c040, 0x60d060, 0x505050, },
  608. { 0x40c040, 0x80ff80, 0x80ff80, 0x80ff80, 0x80ff80, 0x80ff80, 0x606060, },
  609. { 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x909090, },
  610. }, {
  611. { 0x9090ac, 0xa0a0b8, 0xbcb8cc, 0xbcb8cc, 0x909040, 0x909040, 0x909040, },
  612. { 0xa0a0b8, 0xb0b4d0, 0xa0a0b8, 0xa0a0b8, 0xa0a050, 0xa0a050, 0xa0a050, },
  613. { 0x808088, 0x808030, 0x808030, 0x808030, 0x808030, 0x808030, 0x808030, },
  614. }, {
  615. { 0x704c70, 0x885c8c, 0x9c68a4, 0xb870bc, 0xb490bc, 0xb490bc, 0x302828, },
  616. { 0x646064, 0xcca8d4, 0xc060c0, 0xa07898, 0xe0b8e0, 0xe0b8e0, 0x403838, },
  617. { 0xdccce4, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x909090, },
  618. }, {
  619. { 0x704c70, 0x885c8c, 0x9c68a4, 0xb870bc, 0xb490bc, 0xb490bc, 0x302828, },
  620. { 0xb09cb4, 0xcca8d4, 0xc060c0, 0xa07898, 0xe0b8e0, 0xe0b8e0, 0x403838, },
  621. { 0xdccce4, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x909090, },
  622. }, {
  623. { 0x646494, 0x888cb8, 0xb0b0b0, 0xb0b0cc, 0x9c9cf4, 0x8888b0, 0x50506c, },
  624. { 0x9090a4, 0xb0b4d4, 0xb0b0dc, 0xb0b0cc, 0xd0d0fc, 0xd0d4f0, 0x606060, },
  625. { 0xb4b4d4, 0xe4e4ff, 0xffffff, 0xffffff, 0xe0e4ff, 0xececff, 0x909090, },
  626. }, {
  627. { 0x646444, 0x888c64, 0xb0b0b0, 0xb0b088, 0xaca858, 0x88886c, 0x505050, },
  628. { 0x88886c, 0xb0b490, 0xb0b0b0, 0xb0b088, 0xd8d898, 0xd0d4b0, 0x606060, },
  629. { 0xb4b49c, 0xffffd8, 0xffffff, 0xffffd4, 0xffffdc, 0xffffcc, 0x909090, },
  630. }, {
  631. { 0x906464, 0xb48c8c, 0xd4b0b0, 0xdcb0b0, 0xff9c9c, 0xc88888, 0x505050, },
  632. { 0xb47c80, 0xd4b4b8, 0xc4a8a8, 0xdcb0b0, 0xffc0c0, 0xfce8ec, 0x606060, },
  633. { 0xe0b4b4, 0xffdcd8, 0xffd8d4, 0xffe0e4, 0xffece8, 0xffffff, 0x909090, },
  634. }, {
  635. { 0x403848, 0x403848, 0x403848, 0x886894, 0x7c80c8, 0x7c80c8, 0x302828, },
  636. { 0x403848, 0x403848, 0x403848, 0x403848, 0x7c80c8, 0x7c80c8, 0x403838, },
  637. { 0xc8c4c8, 0xffffff, 0xffffff, 0xffffff, 0xe8e8ec, 0xffffff, 0x909090, },
  638. },
  639. };
  640. #define STBTE_COLOR_TILEMAP_BACKGROUND 0x000000
  641. #define STBTE_COLOR_TILEMAP_BORDER 0x203060
  642. #define STBTE_COLOR_TILEMAP_HIGHLIGHT 0xffffff
  643. #define STBTE_COLOR_GRID 0x404040
  644. #define STBTE_COLOR_SELECTION_OUTLINE1 0xdfdfdf
  645. #define STBTE_COLOR_SELECTION_OUTLINE2 0x303030
  646. #define STBTE_COLOR_TILEPALETTE_OUTLINE 0xffffff
  647. #define STBTE_COLOR_TILEPALETTE_BACKGROUND 0x000000
  648. #ifndef STBTE_LINK_COLOR
  649. #define STBTE_LINK_COLOR(src,sp,dest,dp) 0x5030ff
  650. #endif
  651. #ifndef STBTE_LINK_COLOR_DRAWING
  652. #define STBTE_LINK_COLOR_DRAWING 0xff40ff
  653. #endif
  654. #ifndef STBTE_LINK_COLOR_DISALLOWED
  655. #define STBTE_LINK_COLOR_DISALLOWED 0x602060
  656. #endif
  657. // disabled, selected, down, over
  658. static unsigned char stbte__state_to_index[2][2][2][2] =
  659. {
  660. {
  661. { { STBTE__idle , STBTE__over }, { STBTE__down , STBTE__over_down }, },
  662. { { STBTE__selected, STBTE__selected_over }, { STBTE__down , STBTE__over_down }, },
  663. },{
  664. { { STBTE__disabled, STBTE__disabled }, { STBTE__disabled, STBTE__disabled }, },
  665. { { STBTE__selected, STBTE__selected_over }, { STBTE__disabled, STBTE__disabled }, },
  666. }
  667. };
  668. #define STBTE__INDEX_FOR_STATE(disable,select,down,over) stbte__state_to_index[disable][select][down][over]
  669. #define STBTE__INDEX_FOR_ID(id,disable,select) STBTE__INDEX_FOR_STATE(disable,select,STBTE__IS_ACTIVE(id),STBTE__IS_HOT(id))
  670. #define STBTE__FONT_HEIGHT 9
  671. static short stbte__font_offset[95+16];
  672. static short stbte__fontdata[769] =
  673. {
  674. 4,9,6,9,9,9,9,8,9,8,4,9,7,7,7,7,4,2,6,8,6,6,7,3,4,4,8,6,3,6,2,6,6,6,6,6,6,
  675. 6,6,6,6,6,2,3,5,4,5,6,6,6,6,6,6,6,6,6,6,6,6,7,6,7,7,7,6,7,6,6,6,6,7,7,6,6,
  676. 6,4,6,4,7,7,3,6,6,5,6,6,5,6,6,4,5,6,4,7,6,6,6,6,6,6,6,6,6,7,6,6,6,5,2,5,8,
  677. 0,0,0,0,2,253,130,456,156,8,72,184,64,2,125,66,64,160,64,146,511,146,146,
  678. 511,146,146,511,146,511,257,341,297,341,297,341,257,511,16,56,124,16,16,16,
  679. 124,56,16,96,144,270,261,262,136,80,48,224,192,160,80,40,22,14,15,3,448,496,
  680. 496,240,232,20,10,5,2,112,232,452,450,225,113,58,28,63,30,60,200,455,257,
  681. 257,0,0,0,257,257,455,120,204,132,132,159,14,4,4,14,159,132,132,204,120,8,
  682. 24,56,120,56,24,8,32,48,56,60,56,48,32,0,0,0,0,111,111,7,7,0,0,7,7,34,127,
  683. 127,34,34,127,127,34,36,46,107,107,58,18,99,51,24,12,102,99,48,122,79,93,
  684. 55,114,80,4,7,3,62,127,99,65,65,99,127,62,8,42,62,28,28,62,42,8,8,8,62,62,
  685. 8,8,128,224,96,8,8,8,8,8,8,96,96,96,48,24,12,6,3,62,127,89,77,127,62,64,66,
  686. 127,127,64,64,98,115,89,77,71,66,33,97,73,93,119,35,24,28,22,127,127,16,39,
  687. 103,69,69,125,57,62,127,73,73,121,48,1,1,113,121,15,7,54,127,73,73,127,54,
  688. 6,79,73,105,63,30,54,54,128,246,118,8,28,54,99,65,20,20,20,20,65,99,54,28,
  689. 8,2,3,105,109,7,2,30,63,33,45,47,46,124,126,19,19,126,124,127,127,73,73,127,
  690. 54,62,127,65,65,99,34,127,127,65,99,62,28,127,127,73,73,73,65,127,127,9,9,
  691. 9,1,62,127,65,73,121,121,127,127,8,8,127,127,65,65,127,127,65,65,32,96,64,
  692. 64,127,63,127,127,8,28,54,99,65,127,127,64,64,64,64,127,127,6,12,6,127,127,
  693. 127,127,6,12,24,127,127,62,127,65,65,65,127,62,127,127,9,9,15,6,62,127,65,
  694. 81,49,127,94,127,127,9,25,127,102,70,79,73,73,121,49,1,1,127,127,1,1,63,127,
  695. 64,64,127,63,15,31,48,96,48,31,15,127,127,48,24,48,127,127,99,119,28,28,119,
  696. 99,7,15,120,120,15,7,97,113,89,77,71,67,127,127,65,65,3,6,12,24,48,96,65,
  697. 65,127,127,8,12,6,3,6,12,8,64,64,64,64,64,64,64,3,7,4,32,116,84,84,124,120,
  698. 127,127,68,68,124,56,56,124,68,68,68,56,124,68,68,127,127,56,124,84,84,92,
  699. 24,8,124,126,10,10,56,380,324,324,508,252,127,127,4,4,124,120,72,122,122,
  700. 64,256,256,256,506,250,126,126,16,56,104,64,66,126,126,64,124,124,24,56,28,
  701. 124,120,124,124,4,4,124,120,56,124,68,68,124,56,508,508,68,68,124,56,56,124,
  702. 68,68,508,508,124,124,4,4,12,8,72,92,84,84,116,36,4,4,62,126,68,68,60,124,
  703. 64,64,124,124,28,60,96,96,60,28,28,124,112,56,112,124,28,68,108,56,56,108,
  704. 68,284,316,352,320,508,252,68,100,116,92,76,68,8,62,119,65,65,127,127,65,
  705. 65,119,62,8,16,24,12,12,24,24,12,4,
  706. };
  707. typedef struct
  708. {
  709. short id;
  710. unsigned short category_id;
  711. char *category;
  712. unsigned int layermask;
  713. } stbte__tileinfo;
  714. #define MAX_LAYERMASK (1 << (8*sizeof(unsigned int)))
  715. typedef short stbte__tiledata;
  716. #define STBTE__NO_TILE -1
  717. enum
  718. {
  719. STBTE__panel_toolbar,
  720. STBTE__panel_colorpick,
  721. STBTE__panel_info,
  722. STBTE__panel_layers,
  723. STBTE__panel_props,
  724. STBTE__panel_categories,
  725. STBTE__panel_tiles,
  726. STBTE__num_panel,
  727. };
  728. enum
  729. {
  730. STBTE__side_left,
  731. STBTE__side_right,
  732. STBTE__side_top,
  733. STBTE__side_bottom,
  734. };
  735. enum
  736. {
  737. STBTE__tool_select,
  738. STBTE__tool_brush,
  739. STBTE__tool_erase,
  740. STBTE__tool_rect,
  741. STBTE__tool_eyedrop,
  742. STBTE__tool_fill,
  743. STBTE__tool_link,
  744. STBTE__tool_showgrid,
  745. STBTE__tool_showlinks,
  746. STBTE__tool_undo,
  747. STBTE__tool_redo,
  748. // copy/cut/paste aren't included here because they're displayed differently
  749. STBTE__num_tool,
  750. };
  751. // icons are stored in the 0-31 range of ASCII in the font
  752. static int toolchar[] = { 26,24,25,20,23,22,18, 19,17, 29,28, };
  753. enum
  754. {
  755. STBTE__propmode_default,
  756. STBTE__propmode_always,
  757. STBTE__propmode_never,
  758. };
  759. enum
  760. {
  761. STBTE__paint,
  762. // from here down does hittesting
  763. STBTE__tick,
  764. STBTE__mousemove,
  765. STBTE__mousewheel,
  766. STBTE__leftdown,
  767. STBTE__leftup,
  768. STBTE__rightdown,
  769. STBTE__rightup,
  770. };
  771. typedef struct
  772. {
  773. int expanded, mode;
  774. int delta_height; // number of rows they've requested for this
  775. int side;
  776. int width,height;
  777. int x0,y0;
  778. } stbte__panel;
  779. typedef struct
  780. {
  781. int x0,y0,x1,y1,color;
  782. } stbte__colorrect;
  783. #define STBTE__MAX_DELAYRECT 256
  784. typedef struct
  785. {
  786. int tool, active_event;
  787. int active_id, hot_id, next_hot_id;
  788. int event;
  789. int mx,my, dx,dy;
  790. int ms_time;
  791. int shift, scrollkey;
  792. int initted;
  793. int side_extended[2];
  794. stbte__colorrect delayrect[STBTE__MAX_DELAYRECT];
  795. int delaycount;
  796. int show_grid, show_links;
  797. int brush_state; // used to decide which kind of erasing
  798. int eyedrop_x, eyedrop_y, eyedrop_last_layer;
  799. int pasting, paste_x, paste_y;
  800. int scrolling, start_x, start_y;
  801. int last_mouse_x, last_mouse_y;
  802. int accum_x, accum_y;
  803. int linking;
  804. int dragging;
  805. int drag_x, drag_y, drag_w, drag_h;
  806. int drag_offx, drag_offy, drag_dest_x, drag_dest_y;
  807. int undoing;
  808. int has_selection, select_x0, select_y0, select_x1, select_y1;
  809. int sx,sy;
  810. int x0,y0,x1,y1, left_width, right_width; // configurable widths
  811. float alert_timer;
  812. const char *alert_msg;
  813. float dt;
  814. stbte__panel panel[STBTE__num_panel];
  815. short copybuffer[STBTE_MAX_COPY][STBTE_MAX_LAYERS];
  816. float copyprops[STBTE_MAX_COPY][STBTE_MAX_PROPERTIES];
  817. #ifdef STBTE_ALLOW_LINK
  818. stbte__link copylinks[STBTE_MAX_COPY];
  819. #endif
  820. int copy_src_x, copy_src_y;
  821. stbte_tilemap *copy_src;
  822. int copy_width,copy_height,has_copy,copy_has_props;
  823. } stbte__ui_t;
  824. // there's only one UI system at a time, so we can globalize this
  825. static stbte__ui_t stbte__ui = { STBTE__tool_brush, 0 };
  826. #define STBTE__INACTIVE() (stbte__ui.active_id == 0)
  827. #define STBTE__IS_ACTIVE(id) (stbte__ui.active_id == (id))
  828. #define STBTE__IS_HOT(id) (stbte__ui.hot_id == (id))
  829. #define STBTE__BUTTON_HEIGHT (STBTE__FONT_HEIGHT + 2 * STBTE__BUTTON_INTERNAL_SPACING)
  830. #define STBTE__BUTTON_INTERNAL_SPACING (2 + (STBTE__FONT_HEIGHT>>4))
  831. typedef struct
  832. {
  833. const char *name;
  834. int locked;
  835. int hidden;
  836. } stbte__layer;
  837. enum
  838. {
  839. STBTE__unlocked,
  840. STBTE__protected,
  841. STBTE__locked,
  842. };
  843. struct stbte_tilemap
  844. {
  845. stbte__tiledata data[STBTE_MAX_TILEMAP_Y][STBTE_MAX_TILEMAP_X][STBTE_MAX_LAYERS];
  846. float props[STBTE_MAX_TILEMAP_Y][STBTE_MAX_TILEMAP_X][STBTE_MAX_PROPERTIES];
  847. #ifdef STBTE_ALLOW_LINK
  848. stbte__link link[STBTE_MAX_TILEMAP_Y][STBTE_MAX_TILEMAP_X];
  849. int linkcount[STBTE_MAX_TILEMAP_Y][STBTE_MAX_TILEMAP_X];
  850. #endif
  851. int max_x, max_y, num_layers;
  852. int spacing_x, spacing_y;
  853. int palette_spacing_x, palette_spacing_y;
  854. int scroll_x,scroll_y;
  855. int cur_category, cur_tile, cur_layer;
  856. char *categories[STBTE_MAX_CATEGORIES];
  857. int num_categories, category_scroll;
  858. stbte__tileinfo *tiles;
  859. int num_tiles, max_tiles, digits;
  860. unsigned char undo_available_valid;
  861. unsigned char undo_available;
  862. unsigned char redo_available;
  863. unsigned char padding;
  864. int cur_palette_count;
  865. int palette_scroll;
  866. int tileinfo_dirty;
  867. stbte__layer layerinfo[STBTE_MAX_LAYERS];
  868. int has_layer_names;
  869. int layername_width;
  870. int layer_scroll;
  871. int propmode;
  872. int solo_layer;
  873. int undo_pos, undo_len, redo_len;
  874. short background_tile;
  875. unsigned char id_in_use[32768>>3];
  876. short *undo_buffer;
  877. };
  878. static char *default_category = (char*) "[unassigned]";
  879. static void stbte__init_gui(void)
  880. {
  881. int i,n;
  882. stbte__ui.initted = 1;
  883. // init UI state
  884. stbte__ui.show_links = 1;
  885. for (i=0; i < STBTE__num_panel; ++i) {
  886. stbte__ui.panel[i].expanded = 1; // visible if not autohidden
  887. stbte__ui.panel[i].delta_height = 0;
  888. stbte__ui.panel[i].side = STBTE__side_left;
  889. }
  890. stbte__ui.panel[STBTE__panel_toolbar ].side = STBTE__side_top;
  891. stbte__ui.panel[STBTE__panel_colorpick].side = STBTE__side_right;
  892. if (stbte__ui.left_width == 0)
  893. stbte__ui.left_width = 80;
  894. if (stbte__ui.right_width == 0)
  895. stbte__ui.right_width = 80;
  896. // init font
  897. n=95+16;
  898. for (i=0; i < 95+16; ++i) {
  899. stbte__font_offset[i] = n;
  900. n += stbte__fontdata[i];
  901. }
  902. }
  903. stbte_tilemap *stbte_create_map(int map_x, int map_y, int map_layers, int spacing_x, int spacing_y, int max_tiles)
  904. {
  905. int i;
  906. stbte_tilemap *tm;
  907. STBTE_ASSERT(map_layers >= 0 && map_layers <= STBTE_MAX_LAYERS);
  908. STBTE_ASSERT(map_x >= 0 && map_x <= STBTE_MAX_TILEMAP_X);
  909. STBTE_ASSERT(map_y >= 0 && map_y <= STBTE_MAX_TILEMAP_Y);
  910. if (map_x < 0 || map_y < 0 || map_layers < 0 ||
  911. map_x > STBTE_MAX_TILEMAP_X || map_y > STBTE_MAX_TILEMAP_Y || map_layers > STBTE_MAX_LAYERS)
  912. return NULL;
  913. if (!stbte__ui.initted)
  914. stbte__init_gui();
  915. tm = (stbte_tilemap *) malloc(sizeof(*tm) + sizeof(*tm->tiles) * max_tiles + STBTE_UNDO_BUFFER_BYTES);
  916. if (tm == NULL)
  917. return NULL;
  918. tm->tiles = (stbte__tileinfo *) (tm+1);
  919. tm->undo_buffer = (short *) (tm->tiles + max_tiles);
  920. tm->num_layers = map_layers;
  921. tm->max_x = map_x;
  922. tm->max_y = map_y;
  923. tm->spacing_x = spacing_x;
  924. tm->spacing_y = spacing_y;
  925. tm->scroll_x = 0;
  926. tm->scroll_y = 0;
  927. tm->palette_scroll = 0;
  928. tm->palette_spacing_x = spacing_x+1;
  929. tm->palette_spacing_y = spacing_y+1;
  930. tm->cur_category = -1;
  931. tm->cur_tile = 0;
  932. tm->solo_layer = -1;
  933. tm->undo_len = 0;
  934. tm->redo_len = 0;
  935. tm->undo_pos = 0;
  936. tm->category_scroll = 0;
  937. tm->layer_scroll = 0;
  938. tm->propmode = 0;
  939. tm->has_layer_names = 0;
  940. tm->layername_width = 0;
  941. tm->undo_available_valid = 0;
  942. for (i=0; i < tm->num_layers; ++i) {
  943. tm->layerinfo[i].hidden = 0;
  944. tm->layerinfo[i].locked = STBTE__unlocked;
  945. tm->layerinfo[i].name = 0;
  946. }
  947. tm->background_tile = STBTE__NO_TILE;
  948. stbte_clear_map(tm);
  949. tm->max_tiles = max_tiles;
  950. tm->num_tiles = 0;
  951. for (i=0; i < 32768/8; ++i)
  952. tm->id_in_use[i] = 0;
  953. tm->tileinfo_dirty = 1;
  954. return tm;
  955. }
  956. void stbte_set_background_tile(stbte_tilemap *tm, short id)
  957. {
  958. int i;
  959. STBTE_ASSERT(id >= -1);
  960. // STBTE_ASSERT(id < 32768);
  961. if (id < -1)
  962. return;
  963. for (i=0; i < STBTE_MAX_TILEMAP_X * STBTE_MAX_TILEMAP_Y; ++i)
  964. if (tm->data[0][i][0] == -1)
  965. tm->data[0][i][0] = id;
  966. tm->background_tile = id;
  967. }
  968. void stbte_set_spacing(stbte_tilemap *tm, int spacing_x, int spacing_y, int palette_spacing_x, int palette_spacing_y)
  969. {
  970. tm->spacing_x = spacing_x;
  971. tm->spacing_y = spacing_y;
  972. tm->palette_spacing_x = palette_spacing_x;
  973. tm->palette_spacing_y = palette_spacing_y;
  974. }
  975. void stbte_set_sidewidths(int left, int right)
  976. {
  977. stbte__ui.left_width = left;
  978. stbte__ui.right_width = right;
  979. }
  980. void stbte_set_display(int x0, int y0, int x1, int y1)
  981. {
  982. stbte__ui.x0 = x0;
  983. stbte__ui.y0 = y0;
  984. stbte__ui.x1 = x1;
  985. stbte__ui.y1 = y1;
  986. }
  987. void stbte_define_tile(stbte_tilemap *tm, unsigned short id, unsigned int layermask, const char * category_c)
  988. {
  989. char *category = (char *) category_c;
  990. STBTE_ASSERT(id < 32768);
  991. STBTE_ASSERT(tm->num_tiles < tm->max_tiles);
  992. STBTE_ASSERT((tm->id_in_use[id>>3]&(1<<(id&7))) == 0);
  993. if (id >= 32768 || tm->num_tiles >= tm->max_tiles || (tm->id_in_use[id>>3]&(1<<(id&7))))
  994. return;
  995. if (category == NULL)
  996. category = (char*) default_category;
  997. tm->id_in_use[id>>3] |= 1 << (id&7);
  998. tm->tiles[tm->num_tiles].category = category;
  999. tm->tiles[tm->num_tiles].id = id;
  1000. tm->tiles[tm->num_tiles].layermask = layermask;
  1001. ++tm->num_tiles;
  1002. tm->tileinfo_dirty = 1;
  1003. }
  1004. static int stbte__text_width(const char *str);
  1005. void stbte_set_layername(stbte_tilemap *tm, int layer, const char *layername)
  1006. {
  1007. STBTE_ASSERT(layer >= 0 && layer < tm->num_layers);
  1008. if (layer >= 0 && layer < tm->num_layers) {
  1009. int width;
  1010. tm->layerinfo[layer].name = layername;
  1011. tm->has_layer_names = 1;
  1012. width = stbte__text_width(layername);
  1013. tm->layername_width = (width > tm->layername_width ? width : tm->layername_width);
  1014. }
  1015. }
  1016. void stbte_get_dimensions(stbte_tilemap *tm, int *max_x, int *max_y)
  1017. {
  1018. *max_x = tm->max_x;
  1019. *max_y = tm->max_y;
  1020. }
  1021. short* stbte_get_tile(stbte_tilemap *tm, int x, int y)
  1022. {
  1023. STBTE_ASSERT(x >= 0 && x < tm->max_x && y >= 0 && y < tm->max_y);
  1024. if (x < 0 || x >= STBTE_MAX_TILEMAP_X || y < 0 || y >= STBTE_MAX_TILEMAP_Y)
  1025. return NULL;
  1026. return tm->data[y][x];
  1027. }
  1028. float *stbte_get_properties(stbte_tilemap *tm, int x, int y)
  1029. {
  1030. STBTE_ASSERT(x >= 0 && x < tm->max_x && y >= 0 && y < tm->max_y);
  1031. if (x < 0 || x >= STBTE_MAX_TILEMAP_X || y < 0 || y >= STBTE_MAX_TILEMAP_Y)
  1032. return NULL;
  1033. return tm->props[y][x];
  1034. }
  1035. void stbte_get_link(stbte_tilemap *tm, int x, int y, int *destx, int *desty)
  1036. {
  1037. int gx=-1,gy=-1;
  1038. STBTE_ASSERT(x >= 0 && x < tm->max_x && y >= 0 && y < tm->max_y);
  1039. #ifdef STBTE_ALLOW_LINK
  1040. if (x >= 0 && x < STBTE_MAX_TILEMAP_X && y >= 0 && y < STBTE_MAX_TILEMAP_Y) {
  1041. gx = tm->link[y][x].x;
  1042. gy = tm->link[y][x].y;
  1043. if (gx >= 0)
  1044. if (!STBTE_ALLOW_LINK(tm->data[y][x], tm->props[y][x], tm->data[gy][gx], tm->props[gy][gx]))
  1045. gx = gy = -1;
  1046. }
  1047. #endif
  1048. *destx = gx;
  1049. *desty = gy;
  1050. }
  1051. void stbte_set_property(stbte_tilemap *tm, int x, int y, int n, float val)
  1052. {
  1053. tm->props[y][x][n] = val;
  1054. }
  1055. #ifdef STBTE_ALLOW_LINK
  1056. static void stbte__set_link(stbte_tilemap *tm, int src_x, int src_y, int dest_x, int dest_y, int undo_mode);
  1057. #endif
  1058. enum
  1059. {
  1060. STBTE__undo_none,
  1061. STBTE__undo_record,
  1062. STBTE__undo_block,
  1063. };
  1064. void stbte_set_link(stbte_tilemap *tm, int x, int y, int destx, int desty)
  1065. {
  1066. #ifdef STBTE_ALLOW_LINK
  1067. stbte__set_link(tm, x, y, destx, desty, STBTE__undo_none);
  1068. #else
  1069. STBTE_ASSERT(0);
  1070. #endif
  1071. }
  1072. // returns an array of map_layers shorts. each short is either
  1073. // one of the tile_id values from define_tile, or STBTE_EMPTY
  1074. void stbte_set_dimensions(stbte_tilemap *tm, int map_x, int map_y)
  1075. {
  1076. STBTE_ASSERT(map_x >= 0 && map_x <= STBTE_MAX_TILEMAP_X);
  1077. STBTE_ASSERT(map_y >= 0 && map_y <= STBTE_MAX_TILEMAP_Y);
  1078. if (map_x < 0 || map_y < 0 || map_x > STBTE_MAX_TILEMAP_X || map_y > STBTE_MAX_TILEMAP_Y)
  1079. return;
  1080. tm->max_x = map_x;
  1081. tm->max_y = map_y;
  1082. }
  1083. void stbte_clear_map(stbte_tilemap *tm)
  1084. {
  1085. int i,j;
  1086. for (i=0; i < STBTE_MAX_TILEMAP_X * STBTE_MAX_TILEMAP_Y; ++i) {
  1087. tm->data[0][i][0] = tm->background_tile;
  1088. for (j=1; j < tm->num_layers; ++j)
  1089. tm->data[0][i][j] = STBTE__NO_TILE;
  1090. for (j=0; j < STBTE_MAX_PROPERTIES; ++j)
  1091. tm->props[0][i][j] = 0;
  1092. #ifdef STBTE_ALLOW_LINK
  1093. tm->link[0][i].x = -1;
  1094. tm->link[0][i].y = -1;
  1095. tm->linkcount[0][i] = 0;
  1096. #endif
  1097. }
  1098. }
  1099. void stbte_set_tile(stbte_tilemap *tm, int x, int y, int layer, signed short tile)
  1100. {
  1101. STBTE_ASSERT(x >= 0 && x < tm->max_x && y >= 0 && y < tm->max_y);
  1102. STBTE_ASSERT(layer >= 0 && layer < tm->num_layers);
  1103. STBTE_ASSERT(tile >= -1);
  1104. //STBTE_ASSERT(tile < 32768);
  1105. if (x < 0 || x >= STBTE_MAX_TILEMAP_X || y < 0 || y >= STBTE_MAX_TILEMAP_Y)
  1106. return;
  1107. if (layer < 0 || layer >= tm->num_layers || tile < -1)
  1108. return;
  1109. tm->data[y][x][layer] = tile;
  1110. }
  1111. static void stbte__choose_category(stbte_tilemap *tm, int category)
  1112. {
  1113. int i,n=0;
  1114. tm->cur_category = category;
  1115. for (i=0; i < tm->num_tiles; ++i)
  1116. if (tm->tiles[i].category_id == category || category == -1)
  1117. ++n;
  1118. tm->cur_palette_count = n;
  1119. tm->palette_scroll = 0;
  1120. }
  1121. static int stbte__strequal(char *p, char *q)
  1122. {
  1123. while (*p)
  1124. if (*p++ != *q++) return 0;
  1125. return *q == 0;
  1126. }
  1127. static void stbte__compute_tileinfo(stbte_tilemap *tm)
  1128. {
  1129. int i,j;
  1130. tm->num_categories=0;
  1131. for (i=0; i < tm->num_tiles; ++i) {
  1132. stbte__tileinfo *t = &tm->tiles[i];
  1133. // find category
  1134. for (j=0; j < tm->num_categories; ++j)
  1135. if (stbte__strequal(t->category, tm->categories[j]))
  1136. goto found;
  1137. tm->categories[j] = t->category;
  1138. ++tm->num_categories;
  1139. found:
  1140. t->category_id = (unsigned short) j;
  1141. }
  1142. // currently number of categories can never decrease because you
  1143. // can't remove tile definitions, but let's get it right anyway
  1144. if (tm->cur_category > tm->num_categories) {
  1145. tm->cur_category = -1;
  1146. }
  1147. stbte__choose_category(tm, tm->cur_category);
  1148. tm->tileinfo_dirty = 0;
  1149. }
  1150. static void stbte__prepare_tileinfo(stbte_tilemap *tm)
  1151. {
  1152. if (tm->tileinfo_dirty)
  1153. stbte__compute_tileinfo(tm);
  1154. }
  1155. /////////////////////// undo system ////////////////////////
  1156. // the undo system works by storing "commands" into a buffer, and
  1157. // then playing back those commands. undo and redo have to store
  1158. // the commands in different order.
  1159. //
  1160. // the commands are:
  1161. //
  1162. // 1) end_of_undo_record
  1163. // -1:short
  1164. //
  1165. // 2) end_of_redo_record
  1166. // -2:short
  1167. //
  1168. // 3) tile update
  1169. // tile_id:short (-1..32767)
  1170. // x_coord:short
  1171. // y_coord:short
  1172. // layer:short (0..31)
  1173. //
  1174. // 4) property update (also used for links)
  1175. // value_hi:short
  1176. // value_lo:short
  1177. // y_coord:short
  1178. // x_coord:short
  1179. // property:short (256+prop#)
  1180. //
  1181. // Since we use a circular buffer, we might overwrite the undo storage.
  1182. // To detect this, before playing back commands we scan back and see
  1183. // if we see an end_of_undo_record before hitting the relevant boundary,
  1184. // it's wholly contained.
  1185. //
  1186. // When we read back through, we see them in reverse order, so
  1187. // we'll see the layer number or property number first
  1188. //
  1189. // To be clearer about the circular buffer, there are two cases:
  1190. // 1. a single record is larger than the whole buffer.
  1191. // this is caught because the end_of_undo_record will
  1192. // get overwritten.
  1193. // 2. multiple records written are larger than the whole
  1194. // buffer, so some of them have been overwritten by
  1195. // the later ones. this is handled by explicitly tracking
  1196. // the undo length; we never try to parse the data that
  1197. // got overwritten
  1198. // given two points, compute the length between them
  1199. #define stbte__wrap(pos) ((pos) & (STBTE__UNDO_BUFFER_COUNT-1))
  1200. #define STBTE__undo_record -2
  1201. #define STBTE__redo_record -3
  1202. #define STBTE__undo_junk -4 // this is written underneath the undo pointer, never used
  1203. static void stbte__write_undo(stbte_tilemap *tm, short value)
  1204. {
  1205. int pos = tm->undo_pos;
  1206. tm->undo_buffer[pos] = value;
  1207. tm->undo_pos = stbte__wrap(pos+1);
  1208. tm->undo_len += (tm->undo_len < STBTE__UNDO_BUFFER_COUNT-2);
  1209. tm->redo_len -= (tm->redo_len > 0);
  1210. tm->undo_available_valid = 0;
  1211. }
  1212. static void stbte__write_redo(stbte_tilemap *tm, short value)
  1213. {
  1214. int pos = tm->undo_pos;
  1215. tm->undo_buffer[pos] = value;
  1216. tm->undo_pos = stbte__wrap(pos-1);
  1217. tm->redo_len += (tm->redo_len < STBTE__UNDO_BUFFER_COUNT-2);
  1218. tm->undo_len -= (tm->undo_len > 0);
  1219. tm->undo_available_valid = 0;
  1220. }
  1221. static void stbte__begin_undo(stbte_tilemap *tm)
  1222. {
  1223. tm->redo_len = 0;
  1224. stbte__write_undo(tm, STBTE__undo_record);
  1225. stbte__ui.undoing = 1;
  1226. stbte__ui.alert_msg = 0; // clear alert if they start doing something
  1227. }
  1228. static void stbte__end_undo(stbte_tilemap *tm)
  1229. {
  1230. if (stbte__ui.undoing) {
  1231. // check if anything got written
  1232. int pos = stbte__wrap(tm->undo_pos-1);
  1233. if (tm->undo_buffer[pos] == STBTE__undo_record) {
  1234. // empty undo record, move back
  1235. tm->undo_pos = pos;
  1236. STBTE_ASSERT(tm->undo_len > 0);
  1237. tm->undo_len -= 1;
  1238. }
  1239. tm->undo_buffer[tm->undo_pos] = STBTE__undo_junk;
  1240. // otherwise do nothing
  1241. stbte__ui.undoing = 0;
  1242. }
  1243. }
  1244. static void stbte__undo_record(stbte_tilemap *tm, int x, int y, int i, int v)
  1245. {
  1246. STBTE_ASSERT(stbte__ui.undoing);
  1247. if (stbte__ui.undoing) {
  1248. stbte__write_undo(tm, v);
  1249. stbte__write_undo(tm, x);
  1250. stbte__write_undo(tm, y);
  1251. stbte__write_undo(tm, i);
  1252. }
  1253. }
  1254. static void stbte__redo_record(stbte_tilemap *tm, int x, int y, int i, int v)
  1255. {
  1256. stbte__write_redo(tm, v);
  1257. stbte__write_redo(tm, x);
  1258. stbte__write_redo(tm, y);
  1259. stbte__write_redo(tm, i);
  1260. }
  1261. static float stbte__extract_float(short s0, short s1)
  1262. {
  1263. union { float f; short s[2]; } converter;
  1264. converter.s[0] = s0;
  1265. converter.s[1] = s1;
  1266. return converter.f;
  1267. }
  1268. static short stbte__extract_short(float f, int slot)
  1269. {
  1270. union { float f; short s[2]; } converter;
  1271. converter.f = f;
  1272. return converter.s[slot];
  1273. }
  1274. static void stbte__undo_record_prop(stbte_tilemap *tm, int x, int y, int i, short s0, short s1)
  1275. {
  1276. STBTE_ASSERT(stbte__ui.undoing);
  1277. if (stbte__ui.undoing) {
  1278. stbte__write_undo(tm, s1);
  1279. stbte__write_undo(tm, s0);
  1280. stbte__write_undo(tm, x);
  1281. stbte__write_undo(tm, y);
  1282. stbte__write_undo(tm, 256+i);
  1283. }
  1284. }
  1285. static void stbte__undo_record_prop_float(stbte_tilemap *tm, int x, int y, int i, float f)
  1286. {
  1287. stbte__undo_record_prop(tm, x,y,i, stbte__extract_short(f,0), stbte__extract_short(f,1));
  1288. }
  1289. static void stbte__redo_record_prop(stbte_tilemap *tm, int x, int y, int i, short s0, short s1)
  1290. {
  1291. stbte__write_redo(tm, s1);
  1292. stbte__write_redo(tm, s0);
  1293. stbte__write_redo(tm, x);
  1294. stbte__write_redo(tm, y);
  1295. stbte__write_redo(tm, 256+i);
  1296. }
  1297. static int stbte__undo_find_end(stbte_tilemap *tm)
  1298. {
  1299. // first scan through for the end record
  1300. int i, pos = stbte__wrap(tm->undo_pos-1);
  1301. for (i=0; i < tm->undo_len;) {
  1302. STBTE_ASSERT(tm->undo_buffer[pos] != STBTE__undo_junk);
  1303. if (tm->undo_buffer[pos] == STBTE__undo_record)
  1304. break;
  1305. if (tm->undo_buffer[pos] >= 255)
  1306. pos = stbte__wrap(pos-5), i += 5;
  1307. else
  1308. pos = stbte__wrap(pos-4), i += 4;
  1309. }
  1310. if (i >= tm->undo_len)
  1311. return -1;
  1312. return pos;
  1313. }
  1314. static void stbte__undo(stbte_tilemap *tm)
  1315. {
  1316. int i, pos, endpos;
  1317. endpos = stbte__undo_find_end(tm);
  1318. if (endpos < 0)
  1319. return;
  1320. // we found a complete undo record
  1321. pos = stbte__wrap(tm->undo_pos-1);
  1322. // start a redo record
  1323. stbte__write_redo(tm, STBTE__redo_record);
  1324. // so now go back through undo and apply in reverse
  1325. // order, and copy it to redo
  1326. for (i=0; endpos != pos; i += 4) {
  1327. int x,y,n,v;
  1328. // get the undo entry
  1329. n = tm->undo_buffer[pos];
  1330. y = tm->undo_buffer[stbte__wrap(pos-1)];
  1331. x = tm->undo_buffer[stbte__wrap(pos-2)];
  1332. v = tm->undo_buffer[stbte__wrap(pos-3)];
  1333. if (n >= 255) {
  1334. short s0=0,s1=0;
  1335. int v2 = tm->undo_buffer[stbte__wrap(pos-4)];
  1336. pos = stbte__wrap(pos-5);
  1337. if (n > 255) {
  1338. float vf = stbte__extract_float(v, v2);
  1339. s0 = stbte__extract_short(tm->props[y][x][n-256], 0);
  1340. s1 = stbte__extract_short(tm->props[y][x][n-256], 1);
  1341. tm->props[y][x][n-256] = vf;
  1342. } else {
  1343. #ifdef STBTE_ALLOW_LINK
  1344. s0 = tm->link[y][x].x;
  1345. s1 = tm->link[y][x].y;
  1346. stbte__set_link(tm, x,y, v, v2, STBTE__undo_none);
  1347. #endif
  1348. }
  1349. // write the redo entry
  1350. stbte__redo_record_prop(tm, x, y, n-256, s0,s1);
  1351. // apply the undo entry
  1352. } else {
  1353. pos = stbte__wrap(pos-4);
  1354. // write the redo entry
  1355. stbte__redo_record(tm, x, y, n, tm->data[y][x][n]);
  1356. // apply the undo entry
  1357. tm->data[y][x][n] = (short) v;
  1358. }
  1359. }
  1360. // overwrite undo record with junk
  1361. tm->undo_buffer[tm->undo_pos] = STBTE__undo_junk;
  1362. }
  1363. static int stbte__redo_find_end(stbte_tilemap *tm)
  1364. {
  1365. // first scan through for the end record
  1366. int i, pos = stbte__wrap(tm->undo_pos+1);
  1367. for (i=0; i < tm->redo_len;) {
  1368. STBTE_ASSERT(tm->undo_buffer[pos] != STBTE__undo_junk);
  1369. if (tm->undo_buffer[pos] == STBTE__redo_record)
  1370. break;
  1371. if (tm->undo_buffer[pos] >= 255)
  1372. pos = stbte__wrap(pos+5), i += 5;
  1373. else
  1374. pos = stbte__wrap(pos+4), i += 4;
  1375. }
  1376. if (i >= tm->redo_len)
  1377. return -1; // this should only ever happen if redo buffer is empty
  1378. return pos;
  1379. }
  1380. static void stbte__redo(stbte_tilemap *tm)
  1381. {
  1382. // first scan through for the end record
  1383. int i, pos, endpos;
  1384. endpos = stbte__redo_find_end(tm);
  1385. if (endpos < 0)
  1386. return;
  1387. // we found a complete redo record
  1388. pos = stbte__wrap(tm->undo_pos+1);
  1389. // start an undo record
  1390. stbte__write_undo(tm, STBTE__undo_record);
  1391. for (i=0; pos != endpos; i += 4) {
  1392. int x,y,n,v;
  1393. n = tm->undo_buffer[pos];
  1394. y = tm->undo_buffer[stbte__wrap(pos+1)];
  1395. x = tm->undo_buffer[stbte__wrap(pos+2)];
  1396. v = tm->undo_buffer[stbte__wrap(pos+3)];
  1397. if (n >= 255) {
  1398. int v2 = tm->undo_buffer[stbte__wrap(pos+4)];
  1399. short s0=0,s1=0;
  1400. pos = stbte__wrap(pos+5);
  1401. if (n > 255) {
  1402. float vf = stbte__extract_float(v, v2);
  1403. s0 = stbte__extract_short(tm->props[y][x][n-256],0);
  1404. s1 = stbte__extract_short(tm->props[y][x][n-256],1);
  1405. tm->props[y][x][n-256] = vf;
  1406. } else {
  1407. #ifdef STBTE_ALLOW_LINK
  1408. s0 = tm->link[y][x].x;
  1409. s1 = tm->link[y][x].y;
  1410. stbte__set_link(tm, x,y,v,v2, STBTE__undo_none);
  1411. #endif
  1412. }
  1413. // don't use stbte__undo_record_prop because it's guarded
  1414. stbte__write_undo(tm, s1);
  1415. stbte__write_undo(tm, s0);
  1416. stbte__write_undo(tm, x);
  1417. stbte__write_undo(tm, y);
  1418. stbte__write_undo(tm, n);
  1419. } else {
  1420. pos = stbte__wrap(pos+4);
  1421. // don't use stbte__undo_record because it's guarded
  1422. stbte__write_undo(tm, tm->data[y][x][n]);
  1423. stbte__write_undo(tm, x);
  1424. stbte__write_undo(tm, y);
  1425. stbte__write_undo(tm, n);
  1426. tm->data[y][x][n] = (short) v;
  1427. }
  1428. }
  1429. tm->undo_buffer[tm->undo_pos] = STBTE__undo_junk;
  1430. }
  1431. // because detecting that undo is available
  1432. static void stbte__recompute_undo_available(stbte_tilemap *tm)
  1433. {
  1434. tm->undo_available = (stbte__undo_find_end(tm) >= 0);
  1435. tm->redo_available = (stbte__redo_find_end(tm) >= 0);
  1436. }
  1437. static int stbte__undo_available(stbte_tilemap *tm)
  1438. {
  1439. if (!tm->undo_available_valid)
  1440. stbte__recompute_undo_available(tm);
  1441. return tm->undo_available;
  1442. }
  1443. static int stbte__redo_available(stbte_tilemap *tm)
  1444. {
  1445. if (!tm->undo_available_valid)
  1446. stbte__recompute_undo_available(tm);
  1447. return tm->redo_available;
  1448. }
  1449. ///////////////////////////////////////////////////////////////////////////////////////////////////
  1450. #ifdef STBTE_ALLOW_LINK
  1451. static void stbte__set_link(stbte_tilemap *tm, int src_x, int src_y, int dest_x, int dest_y, int undo_mode)
  1452. {
  1453. stbte__link *a;
  1454. STBTE_ASSERT(src_x >= 0 && src_x < STBTE_MAX_TILEMAP_X && src_y >= 0 && src_y < STBTE_MAX_TILEMAP_Y);
  1455. a = &tm->link[src_y][src_x];
  1456. // check if it's a do nothing
  1457. if (a->x == dest_x && a->y == dest_y)
  1458. return;
  1459. if (undo_mode != STBTE__undo_none ) {
  1460. if (undo_mode == STBTE__undo_block) stbte__begin_undo(tm);
  1461. stbte__undo_record_prop(tm, src_x, src_y, -1, a->x, a->y);
  1462. if (undo_mode == STBTE__undo_block) stbte__end_undo(tm);
  1463. }
  1464. // check if there's an existing link
  1465. if (a->x >= 0) {
  1466. // decrement existing link refcount
  1467. STBTE_ASSERT(tm->linkcount[a->y][a->x] > 0);
  1468. --tm->linkcount[a->y][a->x];
  1469. }
  1470. // increment new dest
  1471. if (dest_x >= 0) {
  1472. ++tm->linkcount[dest_y][dest_x];
  1473. }
  1474. a->x = dest_x;
  1475. a->y = dest_y;
  1476. }
  1477. #endif
  1478. static void stbte__draw_rect(int x0, int y0, int x1, int y1, unsigned int color)
  1479. {
  1480. STBTE_DRAW_RECT(x0,y0,x1,y1, color);
  1481. }
  1482. #ifdef STBTE_ALLOW_LINK
  1483. static void stbte__draw_line(int x0, int y0, int x1, int y1, unsigned int color)
  1484. {
  1485. int temp;
  1486. if (x1 < x0) temp=x0,x0=x1,x1=temp;
  1487. if (y1 < y0) temp=y0,y0=y1,y1=temp;
  1488. stbte__draw_rect(x0,y0,x1+1,y1+1,color);
  1489. }
  1490. static void stbte__draw_link(int x0, int y0, int x1, int y1, unsigned int color)
  1491. {
  1492. stbte__draw_line(x0,y0,x0,y1, color);
  1493. stbte__draw_line(x0,y1,x1,y1, color);
  1494. }
  1495. #endif
  1496. static void stbte__draw_frame(int x0, int y0, int x1, int y1, unsigned int color)
  1497. {
  1498. stbte__draw_rect(x0,y0,x1-1,y0+1,color);
  1499. stbte__draw_rect(x1-1,y0,x1,y1-1,color);
  1500. stbte__draw_rect(x0+1,y1-1,x1,y1,color);
  1501. stbte__draw_rect(x0,y0+1,x0+1,y1,color);
  1502. }
  1503. static int stbte__get_char_width(int ch)
  1504. {
  1505. return stbte__fontdata[ch-16];
  1506. }
  1507. static short *stbte__get_char_bitmap(int ch)
  1508. {
  1509. return stbte__fontdata + stbte__font_offset[ch-16];
  1510. }
  1511. static void stbte__draw_bitmask_as_columns(int x, int y, short bitmask, int color)
  1512. {
  1513. int start_i = -1, i=0;
  1514. while (bitmask) {
  1515. if (bitmask & (1<<i)) {
  1516. if (start_i < 0)
  1517. start_i = i;
  1518. } else if (start_i >= 0) {
  1519. stbte__draw_rect(x, y+start_i, x+1, y+i, color);
  1520. start_i = -1;
  1521. bitmask &= ~((1<<i)-1); // clear all the old bits; we don't clear them as we go to save code
  1522. }
  1523. ++i;
  1524. }
  1525. }
  1526. static void stbte__draw_bitmap(int x, int y, int w, short *bitmap, int color)
  1527. {
  1528. int i;
  1529. for (i=0; i < w; ++i)
  1530. stbte__draw_bitmask_as_columns(x+i, y, *bitmap++, color);
  1531. }
  1532. static void stbte__draw_text_core(int x, int y, const char *str, int w, int color, int digitspace)
  1533. {
  1534. int x_end = x+w;
  1535. while (*str) {
  1536. int c = *str++;
  1537. int cw = stbte__get_char_width(c);
  1538. if (x + cw > x_end)
  1539. break;
  1540. stbte__draw_bitmap(x, y, cw, stbte__get_char_bitmap(c), color);
  1541. if (digitspace && c == ' ')
  1542. cw = stbte__get_char_width('0');
  1543. x += cw+1;
  1544. }
  1545. }
  1546. static void stbte__draw_text(int x, int y, const char *str, int w, int color)
  1547. {
  1548. stbte__draw_text_core(x,y,str,w,color,0);
  1549. }
  1550. static int stbte__text_width(const char *str)
  1551. {
  1552. int x = 0;
  1553. while (*str) {
  1554. int c = *str++;
  1555. int cw = stbte__get_char_width(c);
  1556. x += cw+1;
  1557. }
  1558. return x;
  1559. }
  1560. static void stbte__draw_frame_delayed(int x0, int y0, int x1, int y1, int color)
  1561. {
  1562. if (stbte__ui.delaycount < STBTE__MAX_DELAYRECT) {
  1563. stbte__colorrect r = { x0,y0,x1,y1,color };
  1564. stbte__ui.delayrect[stbte__ui.delaycount++] = r;
  1565. }
  1566. }
  1567. static void stbte__flush_delay(void)
  1568. {
  1569. stbte__colorrect *r;
  1570. int i;
  1571. r = stbte__ui.delayrect;
  1572. for (i=0; i < stbte__ui.delaycount; ++i,++r)
  1573. stbte__draw_frame(r->x0,r->y0,r->x1,r->y1,r->color);
  1574. stbte__ui.delaycount = 0;
  1575. }
  1576. static void stbte__activate(int id)
  1577. {
  1578. stbte__ui.active_id = id;
  1579. stbte__ui.active_event = stbte__ui.event;
  1580. stbte__ui.accum_x = 0;
  1581. stbte__ui.accum_y = 0;
  1582. }
  1583. static int stbte__hittest(int x0, int y0, int x1, int y1, int id)
  1584. {
  1585. int over = stbte__ui.mx >= x0 && stbte__ui.my >= y0
  1586. && stbte__ui.mx < x1 && stbte__ui.my < y1;
  1587. if (over && stbte__ui.event >= STBTE__tick)
  1588. stbte__ui.next_hot_id = id;
  1589. return over;
  1590. }
  1591. static int stbte__button_core(int id)
  1592. {
  1593. switch (stbte__ui.event) {
  1594. case STBTE__leftdown:
  1595. if (stbte__ui.hot_id == id && STBTE__INACTIVE())
  1596. stbte__activate(id);
  1597. break;
  1598. case STBTE__leftup:
  1599. if (stbte__ui.active_id == id && STBTE__IS_HOT(id)) {
  1600. stbte__activate(0);
  1601. return 1;
  1602. }
  1603. break;
  1604. case STBTE__rightdown:
  1605. if (stbte__ui.hot_id == id && STBTE__INACTIVE())
  1606. stbte__activate(id);
  1607. break;
  1608. case STBTE__rightup:
  1609. if (stbte__ui.active_id == id && STBTE__IS_HOT(id)) {
  1610. stbte__activate(0);
  1611. return -1;
  1612. }
  1613. break;
  1614. }
  1615. return 0;
  1616. }
  1617. static void stbte__draw_box(int x0, int y0, int x1, int y1, int colormode, int colorindex)
  1618. {
  1619. stbte__draw_rect (x0,y0,x1,y1, stbte__color_table[colormode][STBTE__base ][colorindex]);
  1620. stbte__draw_frame(x0,y0,x1,y1, stbte__color_table[colormode][STBTE__outline][colorindex]);
  1621. }
  1622. static void stbte__draw_textbox(int x0, int y0, int x1, int y1, char *text, int xoff, int yoff, int colormode, int colorindex)
  1623. {
  1624. stbte__draw_box(x0,y0,x1,y1,colormode,colorindex);
  1625. stbte__draw_text(x0+xoff,y0+yoff, text, x1-x0-xoff-1, stbte__color_table[colormode][STBTE__text][colorindex]);
  1626. }
  1627. static int stbte__button(int colormode, const char *label, int x, int y, int textoff, int width, int id, int toggled, int disabled)
  1628. {
  1629. int x0=x,y0=y, x1=x+width,y1=y+STBTE__BUTTON_HEIGHT;
  1630. int s = STBTE__BUTTON_INTERNAL_SPACING;
  1631. if(!disabled) stbte__hittest(x0,y0,x1,y1,id);
  1632. if (stbte__ui.event == STBTE__paint)
  1633. stbte__draw_textbox(x0,y0,x1,y1, (char*) label,s+textoff,s, colormode, STBTE__INDEX_FOR_ID(id,disabled,toggled));
  1634. if (disabled)
  1635. return 0;
  1636. return (stbte__button_core(id) == 1);
  1637. }
  1638. static int stbte__button_icon(int colormode, char ch, int x, int y, int width, int id, int toggled, int disabled)
  1639. {
  1640. int x0=x,y0=y, x1=x+width,y1=y+STBTE__BUTTON_HEIGHT;
  1641. int s = STBTE__BUTTON_INTERNAL_SPACING;
  1642. stbte__hittest(x0,y0,x1,y1,id);
  1643. if (stbte__ui.event == STBTE__paint) {
  1644. char label[2] = { ch, 0 };
  1645. int pad = (9 - stbte__get_char_width(ch))/2;
  1646. stbte__draw_textbox(x0,y0,x1,y1, label,s+pad,s, colormode, STBTE__INDEX_FOR_ID(id,disabled,toggled));
  1647. }
  1648. if (disabled)
  1649. return 0;
  1650. return (stbte__button_core(id) == 1);
  1651. }
  1652. static int stbte__minibutton(int colormode, int x, int y, int ch, int id)
  1653. {
  1654. int x0 = x, y0 = y, x1 = x+8, y1 = y+7;
  1655. stbte__hittest(x0,y0,x1,y1,id);
  1656. if (stbte__ui.event == STBTE__paint) {
  1657. char str[2] = { (char)ch, 0 };
  1658. stbte__draw_textbox(x0,y0,x1,y1, str,1,0,colormode, STBTE__INDEX_FOR_ID(id,0,0));
  1659. }
  1660. return stbte__button_core(id);
  1661. }
  1662. static int stbte__layerbutton(int x, int y, int ch, int id, int toggled, int disabled, int colormode)
  1663. {
  1664. int x0 = x, y0 = y, x1 = x+10, y1 = y+11;
  1665. if(!disabled) stbte__hittest(x0,y0,x1,y1,id);
  1666. if (stbte__ui.event == STBTE__paint) {
  1667. char str[2] = { (char)ch, 0 };
  1668. int off = (9-stbte__get_char_width(ch))/2;
  1669. stbte__draw_textbox(x0,y0,x1,y1, str, off+1,2, colormode, STBTE__INDEX_FOR_ID(id,disabled,toggled));
  1670. }
  1671. if (disabled)
  1672. return 0;
  1673. return stbte__button_core(id);
  1674. }
  1675. static int stbte__microbutton(int x, int y, int size, int id, int colormode)
  1676. {
  1677. int x0 = x, y0 = y, x1 = x+size, y1 = y+size;
  1678. stbte__hittest(x0,y0,x1,y1,id);
  1679. if (stbte__ui.event == STBTE__paint) {
  1680. stbte__draw_box(x0,y0,x1,y1, colormode, STBTE__INDEX_FOR_ID(id,0,0));
  1681. }
  1682. return stbte__button_core(id);
  1683. }
  1684. static int stbte__microbutton_dragger(int x, int y, int size, int id, int *pos)
  1685. {
  1686. int x0 = x, y0 = y, x1 = x+size, y1 = y+size;
  1687. stbte__hittest(x0,y0,x1,y1,id);
  1688. switch (stbte__ui.event) {
  1689. case STBTE__paint:
  1690. stbte__draw_box(x0,y0,x1,y1, STBTE__cexpander, STBTE__INDEX_FOR_ID(id,0,0));
  1691. break;
  1692. case STBTE__leftdown:
  1693. if (STBTE__IS_HOT(id) && STBTE__INACTIVE()) {
  1694. stbte__activate(id);
  1695. stbte__ui.sx = stbte__ui.mx - *pos;
  1696. }
  1697. break;
  1698. case STBTE__mousemove:
  1699. if (STBTE__IS_ACTIVE(id) && stbte__ui.active_event == STBTE__leftdown) {
  1700. *pos = stbte__ui.mx - stbte__ui.sx;
  1701. }
  1702. break;
  1703. case STBTE__leftup:
  1704. if (STBTE__IS_ACTIVE(id))
  1705. stbte__activate(0);
  1706. break;
  1707. default:
  1708. return stbte__button_core(id);
  1709. }
  1710. return 0;
  1711. }
  1712. static int stbte__category_button(const char *label, int x, int y, int width, int id, int toggled)
  1713. {
  1714. int x0=x,y0=y, x1=x+width,y1=y+STBTE__BUTTON_HEIGHT;
  1715. int s = STBTE__BUTTON_INTERNAL_SPACING;
  1716. stbte__hittest(x0,y0,x1,y1,id);
  1717. if (stbte__ui.event == STBTE__paint)
  1718. stbte__draw_textbox(x0,y0,x1,y1, (char*) label, s,s, STBTE__ccategory_button, STBTE__INDEX_FOR_ID(id,0,toggled));
  1719. return (stbte__button_core(id) == 1);
  1720. }
  1721. enum
  1722. {
  1723. STBTE__none,
  1724. STBTE__begin,
  1725. STBTE__end,
  1726. STBTE__change,
  1727. };
  1728. // returns -1 if value changes, 1 at end of drag
  1729. static int stbte__slider(int x0, int w, int y, int range, int *value, int id)
  1730. {
  1731. int x1 = x0+w;
  1732. int pos = *value * w / (range+1);
  1733. stbte__hittest(x0,y-2,x1,y+3,id);
  1734. int event_mouse_move = STBTE__change;
  1735. switch (stbte__ui.event) {
  1736. case STBTE__paint:
  1737. stbte__draw_rect(x0,y,x1,y+1, 0x808080);
  1738. stbte__draw_rect(x0+pos-1,y-1,x0+pos+2,y+2, 0xffffff);
  1739. break;
  1740. case STBTE__leftdown:
  1741. if (STBTE__IS_HOT(id) && STBTE__INACTIVE()) {
  1742. stbte__activate(id);
  1743. event_mouse_move = STBTE__begin;
  1744. }
  1745. // fall through
  1746. case STBTE__mousemove:
  1747. if (STBTE__IS_ACTIVE(id)) {
  1748. int v = (stbte__ui.mx-x0)*(range+1)/w;
  1749. if (v < 0) v = 0; else if (v > range) v = range;
  1750. *value = v;
  1751. return event_mouse_move;
  1752. }
  1753. break;
  1754. case STBTE__leftup:
  1755. if (STBTE__IS_ACTIVE(id)) {
  1756. stbte__activate(0);
  1757. return STBTE__end;
  1758. }
  1759. break;
  1760. }
  1761. return STBTE__none;
  1762. }
  1763. #if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__)
  1764. #define stbte__sprintf sprintf_s
  1765. #define stbte__sizeof(s) , sizeof(s)
  1766. #else
  1767. #define stbte__sprintf sprintf
  1768. #define stbte__sizeof(s)
  1769. #endif
  1770. static int stbte__float_control(int x0, int y0, int w, float minv, float maxv, float scale, const char *fmt, float *value, int colormode, int id)
  1771. {
  1772. int x1 = x0+w;
  1773. int y1 = y0+11;
  1774. stbte__hittest(x0,y0,x1,y1,id);
  1775. switch (stbte__ui.event) {
  1776. case STBTE__paint: {
  1777. char text[32];
  1778. stbte__sprintf(text stbte__sizeof(text), fmt ? fmt : "%6.2f", *value);
  1779. stbte__draw_textbox(x0,y0,x1,y1, text, 1,2, colormode, STBTE__INDEX_FOR_ID(id,0,0));
  1780. break;
  1781. }
  1782. case STBTE__leftdown:
  1783. case STBTE__rightdown:
  1784. if (STBTE__IS_HOT(id) && STBTE__INACTIVE())
  1785. stbte__activate(id);
  1786. return STBTE__begin;
  1787. break;
  1788. case STBTE__leftup:
  1789. case STBTE__rightup:
  1790. if (STBTE__IS_ACTIVE(id)) {
  1791. stbte__activate(0);
  1792. return STBTE__end;
  1793. }
  1794. break;
  1795. case STBTE__mousemove:
  1796. if (STBTE__IS_ACTIVE(id)) {
  1797. float v = *value, delta;
  1798. int ax = stbte__ui.accum_x/STBTE_FLOAT_CONTROL_GRANULARITY;
  1799. int ay = stbte__ui.accum_y/STBTE_FLOAT_CONTROL_GRANULARITY;
  1800. stbte__ui.accum_x -= ax*STBTE_FLOAT_CONTROL_GRANULARITY;
  1801. stbte__ui.accum_y -= ay*STBTE_FLOAT_CONTROL_GRANULARITY;
  1802. if (stbte__ui.shift) {
  1803. if (stbte__ui.active_event == STBTE__leftdown)
  1804. delta = ax * 16.0f + ay;
  1805. else
  1806. delta = ax / 16.0f + ay / 256.0f;
  1807. } else {
  1808. if (stbte__ui.active_event == STBTE__leftdown)
  1809. delta = ax*10.0f + ay;
  1810. else
  1811. delta = ax * 0.1f + ay * 0.01f;
  1812. }
  1813. v += delta * scale;
  1814. if (v < minv) v = minv;
  1815. if (v > maxv) v = maxv;
  1816. *value = v;
  1817. return STBTE__change;
  1818. }
  1819. break;
  1820. }
  1821. return STBTE__none;
  1822. }
  1823. static void stbte__scrollbar(int x, int y0, int y1, int *val, int v0, int v1, int num_vis, int id)
  1824. {
  1825. int thumbpos;
  1826. if (v1 - v0 <= num_vis)
  1827. return;
  1828. // generate thumbpos from numvis
  1829. thumbpos = y0+2 + (y1-y0-4) * *val / (v1 - v0 - num_vis);
  1830. if (thumbpos < y0) thumbpos = y0;
  1831. if (thumbpos >= y1) thumbpos = y1;
  1832. stbte__hittest(x-1,y0,x+2,y1,id);
  1833. switch (stbte__ui.event) {
  1834. case STBTE__paint:
  1835. stbte__draw_rect(x,y0,x+1,y1, stbte__color_table[STBTE__cscrollbar][STBTE__text][STBTE__idle]);
  1836. stbte__draw_box(x-1,thumbpos-3,x+2,thumbpos+4, STBTE__cscrollbar, STBTE__INDEX_FOR_ID(id,0,0));
  1837. break;
  1838. case STBTE__leftdown:
  1839. if (STBTE__IS_HOT(id) && STBTE__INACTIVE()) {
  1840. // check if it's over the thumb
  1841. stbte__activate(id);
  1842. *val = ((stbte__ui.my-y0) * (v1 - v0 - num_vis) + (y1-y0)/2)/ (y1-y0);
  1843. }
  1844. break;
  1845. case STBTE__mousemove:
  1846. if (STBTE__IS_ACTIVE(id) && stbte__ui.mx >= x-15 && stbte__ui.mx <= x+15)
  1847. *val = ((stbte__ui.my-y0) * (v1 - v0 - num_vis) + (y1-y0)/2)/ (y1-y0);
  1848. break;
  1849. case STBTE__leftup:
  1850. if (STBTE__IS_ACTIVE(id))
  1851. stbte__activate(0);
  1852. break;
  1853. }
  1854. if (*val >= v1-num_vis)
  1855. *val = v1-num_vis;
  1856. if (*val <= v0)
  1857. *val = v0;
  1858. }
  1859. static void stbte__compute_digits(stbte_tilemap *tm)
  1860. {
  1861. if (tm->max_x >= 1000 || tm->max_y >= 1000)
  1862. tm->digits = 4;
  1863. else if (tm->max_x >= 100 || tm->max_y >= 100)
  1864. tm->digits = 3;
  1865. else
  1866. tm->digits = 2;
  1867. }
  1868. static int stbte__is_single_selection(void)
  1869. {
  1870. return stbte__ui.has_selection
  1871. && stbte__ui.select_x0 == stbte__ui.select_x1
  1872. && stbte__ui.select_y0 == stbte__ui.select_y1;
  1873. }
  1874. typedef struct
  1875. {
  1876. int width, height;
  1877. int x,y;
  1878. int active;
  1879. float retracted;
  1880. } stbte__region_t;
  1881. static stbte__region_t stbte__region[4];
  1882. #define STBTE__TOOLBAR_ICON_SIZE (9+2*2)
  1883. #define STBTE__TOOLBAR_PASTE_SIZE (34+2*2)
  1884. // This routine computes where every panel goes onscreen: computes
  1885. // a minimum width for each side based on which panels are on that
  1886. // side, and accounts for width-dependent layout of certain panels.
  1887. static void stbte__compute_panel_locations(stbte_tilemap *tm)
  1888. {
  1889. int i, limit, w, k;
  1890. int window_width = stbte__ui.x1 - stbte__ui.x0;
  1891. int window_height = stbte__ui.y1 - stbte__ui.y0;
  1892. int min_width[STBTE__num_panel]={0,0,0,0,0,0,0};
  1893. int height[STBTE__num_panel]={0,0,0,0,0,0,0};
  1894. int panel_active[STBTE__num_panel]={1,0,1,1,1,1,1};
  1895. int vpos[4] = { 0,0,0,0 };
  1896. stbte__panel *p = stbte__ui.panel;
  1897. stbte__panel *pt = &p[STBTE__panel_toolbar];
  1898. #ifdef STBTE__NO_PROPS
  1899. int props = 0;
  1900. #else
  1901. int props = 1;
  1902. #endif
  1903. for (i=0; i < 4; ++i) {
  1904. stbte__region[i].active = 0;
  1905. stbte__region[i].width = 0;
  1906. stbte__region[i].height = 0;
  1907. }
  1908. // compute number of digits needs for info panel
  1909. stbte__compute_digits(tm);
  1910. // determine which panels are active
  1911. panel_active[STBTE__panel_categories] = tm->num_categories != 0;
  1912. panel_active[STBTE__panel_layers ] = tm->num_layers > 1;
  1913. #ifdef STBTE__COLORPICKER
  1914. panel_active[STBTE__panel_colorpick ] = 1;
  1915. #endif
  1916. panel_active[STBTE__panel_props ] = props && stbte__is_single_selection();
  1917. // compute minimum widths for each panel (assuming they're on sides not top)
  1918. min_width[STBTE__panel_info ] = 8 + 11 + 7*tm->digits+17+7; // estimate min width of "w:0000"
  1919. min_width[STBTE__panel_colorpick ] = 120;
  1920. min_width[STBTE__panel_tiles ] = 4 + tm->palette_spacing_x + 5; // 5 for scrollbar
  1921. min_width[STBTE__panel_categories] = 4 + 42 + 5; // 42 is enough to show ~7 chars; 5 for scrollbar
  1922. min_width[STBTE__panel_layers ] = 4 + 54 + 30*tm->has_layer_names; // 2 digits plus 3 buttons plus scrollbar
  1923. min_width[STBTE__panel_toolbar ] = 4 + STBTE__TOOLBAR_PASTE_SIZE; // wide enough for 'Paste' button
  1924. min_width[STBTE__panel_props ] = 80; // narrowest info panel
  1925. // compute minimum widths for left & right panels based on the above
  1926. stbte__region[0].width = stbte__ui.left_width;
  1927. stbte__region[1].width = stbte__ui.right_width;
  1928. for (i=0; i < STBTE__num_panel; ++i) {
  1929. if (panel_active[i]) {
  1930. int side = stbte__ui.panel[i].side;
  1931. if (min_width[i] > stbte__region[side].width)
  1932. stbte__region[side].width = min_width[i];
  1933. stbte__region[side].active = 1;
  1934. }
  1935. }
  1936. // now compute the heights of each panel
  1937. // if toolbar at top, compute its size & push the left and right start points down
  1938. if (stbte__region[STBTE__side_top].active) {
  1939. int height = STBTE__TOOLBAR_ICON_SIZE+2;
  1940. pt->x0 = stbte__ui.x0;
  1941. pt->y0 = stbte__ui.y0;
  1942. pt->width = window_width;
  1943. pt->height = height;
  1944. vpos[STBTE__side_left] = vpos[STBTE__side_right] = height;
  1945. } else {
  1946. int num_rows = STBTE__num_tool * ((stbte__region[pt->side].width-4)/STBTE__TOOLBAR_ICON_SIZE);
  1947. height[STBTE__panel_toolbar] = num_rows*13 + 3*15 + 4; // 3*15 for cut/copy/paste, which are stacked vertically
  1948. }
  1949. for (i=0; i < 4; ++i)
  1950. stbte__region[i].y = stbte__ui.y0 + vpos[i];
  1951. for (i=0; i < 2; ++i) {
  1952. int anim = (int) (stbte__region[i].width * stbte__region[i].retracted);
  1953. stbte__region[i].x = (i == STBTE__side_left) ? stbte__ui.x0 - anim : stbte__ui.x1 - stbte__region[i].width + anim;
  1954. }
  1955. // color picker
  1956. height[STBTE__panel_colorpick] = 300;
  1957. // info panel
  1958. w = stbte__region[p[STBTE__panel_info].side].width;
  1959. p[STBTE__panel_info].mode = (w >= 8 + (11+7*tm->digits+17)*2 + 4);
  1960. if (p[STBTE__panel_info].mode)
  1961. height[STBTE__panel_info] = 5 + 11*2 + 2 + tm->palette_spacing_y;
  1962. else
  1963. height[STBTE__panel_info] = 5 + 11*4 + 2 + tm->palette_spacing_y;
  1964. // layers
  1965. limit = 6 + stbte__ui.panel[STBTE__panel_layers].delta_height;
  1966. height[STBTE__panel_layers] = (tm->num_layers > limit ? limit : tm->num_layers)*15 + 7 + (tm->has_layer_names ? 0 : 11) + props*13;
  1967. // categories
  1968. limit = 6 + stbte__ui.panel[STBTE__panel_categories].delta_height;
  1969. height[STBTE__panel_categories] = (tm->num_categories+1 > limit ? limit : tm->num_categories+1)*11 + 14;
  1970. if (stbte__ui.panel[STBTE__panel_categories].side == stbte__ui.panel[STBTE__panel_categories].side)
  1971. height[STBTE__panel_categories] -= 4;
  1972. // palette
  1973. k = (stbte__region[p[STBTE__panel_tiles].side].width - 8) / tm->palette_spacing_x;
  1974. if (k == 0) k = 1;
  1975. height[STBTE__panel_tiles] = ((tm->num_tiles+k-1)/k) * tm->palette_spacing_y + 8;
  1976. // properties panel
  1977. height[STBTE__panel_props] = 9 + STBTE_MAX_PROPERTIES*14;
  1978. // now compute the locations of all the panels
  1979. for (i=0; i < STBTE__num_panel; ++i) {
  1980. if (panel_active[i]) {
  1981. int side = p[i].side;
  1982. if (side == STBTE__side_left || side == STBTE__side_right) {
  1983. p[i].width = stbte__region[side].width;
  1984. p[i].x0 = stbte__region[side].x;
  1985. p[i].y0 = stbte__ui.y0 + vpos[side];
  1986. p[i].height = height[i];
  1987. vpos[side] += height[i];
  1988. if (vpos[side] > window_height) {
  1989. vpos[side] = window_height;
  1990. p[i].height = stbte__ui.y1 - p[i].y0;
  1991. }
  1992. } else {
  1993. ; // it's at top, it's already been explicitly set up earlier
  1994. }
  1995. } else {
  1996. // inactive panel
  1997. p[i].height = 0;
  1998. p[i].width = 0;
  1999. p[i].x0 = stbte__ui.x1;
  2000. p[i].y0 = stbte__ui.y1;
  2001. }
  2002. }
  2003. }
  2004. // unique identifiers for imgui
  2005. enum
  2006. {
  2007. STBTE__map=1,
  2008. STBTE__region,
  2009. STBTE__panel, // panel background to hide map, and misc controls
  2010. STBTE__info, // info data
  2011. STBTE__toolbarA, STBTE__toolbarB, // toolbar buttons: param is tool number
  2012. STBTE__palette, // palette selectors: param is tile index
  2013. STBTE__categories, // category selectors: param is category index
  2014. STBTE__layer, //
  2015. STBTE__solo, STBTE__hide, STBTE__lock, // layer controls: param is layer
  2016. STBTE__scrollbar, // param is panel ID
  2017. STBTE__panel_mover, // p1 is panel ID, p2 is destination side
  2018. STBTE__panel_sizer, // param panel ID
  2019. STBTE__scrollbar_id,
  2020. STBTE__colorpick_id,
  2021. STBTE__prop_flag,
  2022. STBTE__prop_float,
  2023. STBTE__prop_int,
  2024. };
  2025. // id is: [ 24-bit data : 7-bit identifier ]
  2026. // map id is: [ 12-bit y : 12 bit x : 7-bit identifier ]
  2027. #define STBTE__ID(n,p) ((n) + ((p)<<7))
  2028. #define STBTE__ID2(n,p,q) STBTE__ID(n, ((p)<<12)+(q) )
  2029. #define STBTE__IDMAP(x,y) STBTE__ID2(STBTE__map, x,y)
  2030. static void stbte__activate_map(int x, int y)
  2031. {
  2032. stbte__ui.active_id = STBTE__IDMAP(x,y);
  2033. stbte__ui.active_event = stbte__ui.event;
  2034. stbte__ui.sx = x;
  2035. stbte__ui.sy = y;
  2036. }
  2037. static void stbte__alert(const char *msg)
  2038. {
  2039. stbte__ui.alert_msg = msg;
  2040. stbte__ui.alert_timer = 3;
  2041. }
  2042. #define STBTE__BG(tm,layer) ((layer) == 0 ? (tm)->background_tile : STBTE__NO_TILE)
  2043. static void stbte__brush_predict(stbte_tilemap *tm, short result[])
  2044. {
  2045. stbte__tileinfo *ti;
  2046. int i;
  2047. if (tm->cur_tile < 0) return;
  2048. ti = &tm->tiles[tm->cur_tile];
  2049. // find lowest legit layer to paint it on, and put it there
  2050. for (i=0; i < tm->num_layers; ++i) {
  2051. // check if object is allowed on layer
  2052. if (!(ti->layermask & (1 << i)))
  2053. continue;
  2054. if (i != tm->solo_layer) {
  2055. // if there's a selected layer, can only paint on that
  2056. if (tm->cur_layer >= 0 && i != tm->cur_layer)
  2057. continue;
  2058. // if the layer is hidden, we can't see it
  2059. if (tm->layerinfo[i].hidden)
  2060. continue;
  2061. // if the layer is locked, we can't write to it
  2062. if (tm->layerinfo[i].locked == STBTE__locked)
  2063. continue;
  2064. // if the layer is non-empty and protected, can't write to it
  2065. if (tm->layerinfo[i].locked == STBTE__protected && result[i] != STBTE__BG(tm,i))
  2066. continue;
  2067. }
  2068. result[i] = ti->id;
  2069. return;
  2070. }
  2071. }
  2072. static void stbte__brush(stbte_tilemap *tm, int x, int y)
  2073. {
  2074. stbte__tileinfo *ti;
  2075. // find lowest legit layer to paint it on, and put it there
  2076. int i;
  2077. if (tm->cur_tile < 0) return;
  2078. ti = &tm->tiles[tm->cur_tile];
  2079. for (i=0; i < tm->num_layers; ++i) {
  2080. // check if object is allowed on layer
  2081. if (!(ti->layermask & (1 << i)))
  2082. continue;
  2083. if (i != tm->solo_layer) {
  2084. // if there's a selected layer, can only paint on that
  2085. if (tm->cur_layer >= 0 && i != tm->cur_layer)
  2086. continue;
  2087. // if the layer is hidden, we can't see it
  2088. if (tm->layerinfo[i].hidden)
  2089. continue;
  2090. // if the layer is locked, we can't write to it
  2091. if (tm->layerinfo[i].locked == STBTE__locked)
  2092. continue;
  2093. // if the layer is non-empty and protected, can't write to it
  2094. if (tm->layerinfo[i].locked == STBTE__protected && tm->data[y][x][i] != STBTE__BG(tm,i))
  2095. continue;
  2096. }
  2097. stbte__undo_record(tm,x,y,i,tm->data[y][x][i]);
  2098. tm->data[y][x][i] = ti->id;
  2099. return;
  2100. }
  2101. //stbte__alert("Selected tile not valid on active layer(s)");
  2102. }
  2103. enum
  2104. {
  2105. STBTE__erase_none = -1,
  2106. STBTE__erase_brushonly = 0,
  2107. STBTE__erase_any = 1,
  2108. STBTE__erase_all = 2,
  2109. };
  2110. static int stbte__erase_predict(stbte_tilemap *tm, short result[], int allow_any)
  2111. {
  2112. stbte__tileinfo *ti = tm->cur_tile >= 0 ? &tm->tiles[tm->cur_tile] : NULL;
  2113. int i;
  2114. if (allow_any == STBTE__erase_none)
  2115. return allow_any;
  2116. // first check if only one layer is legit
  2117. i = tm->cur_layer;
  2118. if (tm->solo_layer >= 0)
  2119. i = tm->solo_layer;
  2120. // if only one layer is legit, directly process that one for clarity
  2121. if (i >= 0) {
  2122. short bg = (i == 0 ? tm->background_tile : -1);
  2123. if (tm->solo_layer < 0) {
  2124. // check that we're allowed to write to it
  2125. if (tm->layerinfo[i].hidden) return STBTE__erase_none;
  2126. if (tm->layerinfo[i].locked) return STBTE__erase_none;
  2127. }
  2128. if (result[i] == bg)
  2129. return STBTE__erase_none; // didn't erase anything
  2130. if (ti && result[i] == ti->id && (i != 0 || ti->id != tm->background_tile)) {
  2131. result[i] = bg;
  2132. return STBTE__erase_brushonly;
  2133. }
  2134. if (allow_any == STBTE__erase_any) {
  2135. result[i] = bg;
  2136. return STBTE__erase_any;
  2137. }
  2138. return STBTE__erase_none;
  2139. }
  2140. // if multiple layers are legit, first scan all for brush data
  2141. if (ti && allow_any != STBTE__erase_all) {
  2142. for (i=tm->num_layers-1; i >= 0; --i) {
  2143. if (result[i] != ti->id)
  2144. continue;
  2145. if (tm->layerinfo[i].locked || tm->layerinfo[i].hidden)
  2146. continue;
  2147. if (i == 0 && result[i] == tm->background_tile)
  2148. return STBTE__erase_none;
  2149. result[i] = STBTE__BG(tm,i);
  2150. return STBTE__erase_brushonly;
  2151. }
  2152. }
  2153. if (allow_any != STBTE__erase_any && allow_any != STBTE__erase_all)
  2154. return STBTE__erase_none;
  2155. // apply layer filters, erase from top
  2156. for (i=tm->num_layers-1; i >= 0; --i) {
  2157. if (result[i] < 0)
  2158. continue;
  2159. if (tm->layerinfo[i].locked || tm->layerinfo[i].hidden)
  2160. continue;
  2161. if (i == 0 && result[i] == tm->background_tile)
  2162. return STBTE__erase_none;
  2163. result[i] = STBTE__BG(tm,i);
  2164. if (allow_any != STBTE__erase_all)
  2165. return STBTE__erase_any;
  2166. }
  2167. if (allow_any == STBTE__erase_all)
  2168. return allow_any;
  2169. return STBTE__erase_none;
  2170. }
  2171. static int stbte__erase(stbte_tilemap *tm, int x, int y, int allow_any)
  2172. {
  2173. stbte__tileinfo *ti = tm->cur_tile >= 0 ? &tm->tiles[tm->cur_tile] : NULL;
  2174. int i;
  2175. if (allow_any == STBTE__erase_none)
  2176. return allow_any;
  2177. // first check if only one layer is legit
  2178. i = tm->cur_layer;
  2179. if (tm->solo_layer >= 0)
  2180. i = tm->solo_layer;
  2181. // if only one layer is legit, directly process that one for clarity
  2182. if (i >= 0) {
  2183. short bg = (i == 0 ? tm->background_tile : -1);
  2184. if (tm->solo_layer < 0) {
  2185. // check that we're allowed to write to it
  2186. if (tm->layerinfo[i].hidden) return STBTE__erase_none;
  2187. if (tm->layerinfo[i].locked) return STBTE__erase_none;
  2188. }
  2189. if (tm->data[y][x][i] == bg)
  2190. return -1; // didn't erase anything
  2191. if (ti && tm->data[y][x][i] == ti->id && (i != 0 || ti->id != tm->background_tile)) {
  2192. stbte__undo_record(tm,x,y,i,tm->data[y][x][i]);
  2193. tm->data[y][x][i] = bg;
  2194. return STBTE__erase_brushonly;
  2195. }
  2196. if (allow_any == STBTE__erase_any) {
  2197. stbte__undo_record(tm,x,y,i,tm->data[y][x][i]);
  2198. tm->data[y][x][i] = bg;
  2199. return STBTE__erase_any;
  2200. }
  2201. return STBTE__erase_none;
  2202. }
  2203. // if multiple layers are legit, first scan all for brush data
  2204. if (ti && allow_any != STBTE__erase_all) {
  2205. for (i=tm->num_layers-1; i >= 0; --i) {
  2206. if (tm->data[y][x][i] != ti->id)
  2207. continue;
  2208. if (tm->layerinfo[i].locked || tm->layerinfo[i].hidden)
  2209. continue;
  2210. if (i == 0 && tm->data[y][x][i] == tm->background_tile)
  2211. return STBTE__erase_none;
  2212. stbte__undo_record(tm,x,y,i,tm->data[y][x][i]);
  2213. tm->data[y][x][i] = STBTE__BG(tm,i);
  2214. return STBTE__erase_brushonly;
  2215. }
  2216. }
  2217. if (allow_any != STBTE__erase_any && allow_any != STBTE__erase_all)
  2218. return STBTE__erase_none;
  2219. // apply layer filters, erase from top
  2220. for (i=tm->num_layers-1; i >= 0; --i) {
  2221. if (tm->data[y][x][i] < 0)
  2222. continue;
  2223. if (tm->layerinfo[i].locked || tm->layerinfo[i].hidden)
  2224. continue;
  2225. if (i == 0 && tm->data[y][x][i] == tm->background_tile)
  2226. return STBTE__erase_none;
  2227. stbte__undo_record(tm,x,y,i,tm->data[y][x][i]);
  2228. tm->data[y][x][i] = STBTE__BG(tm,i);
  2229. if (allow_any != STBTE__erase_all)
  2230. return STBTE__erase_any;
  2231. }
  2232. if (allow_any == STBTE__erase_all)
  2233. return allow_any;
  2234. return STBTE__erase_none;
  2235. }
  2236. static int stbte__find_tile(stbte_tilemap *tm, int tile_id)
  2237. {
  2238. int i;
  2239. for (i=0; i < tm->num_tiles; ++i)
  2240. if (tm->tiles[i].id == tile_id)
  2241. return i;
  2242. stbte__alert("Eyedropped tile that isn't in tileset");
  2243. return -1;
  2244. }
  2245. static void stbte__eyedrop(stbte_tilemap *tm, int x, int y)
  2246. {
  2247. int i,j;
  2248. // flush eyedropper state
  2249. if (stbte__ui.eyedrop_x != x || stbte__ui.eyedrop_y != y) {
  2250. stbte__ui.eyedrop_x = x;
  2251. stbte__ui.eyedrop_y = y;
  2252. stbte__ui.eyedrop_last_layer = tm->num_layers;
  2253. }
  2254. // if only one layer is active, query that
  2255. i = tm->cur_layer;
  2256. if (tm->solo_layer >= 0)
  2257. i = tm->solo_layer;
  2258. if (i >= 0) {
  2259. if (tm->data[y][x][i] == STBTE__NO_TILE)
  2260. return;
  2261. tm->cur_tile = stbte__find_tile(tm, tm->data[y][x][i]);
  2262. return;
  2263. }
  2264. // if multiple layers, continue from previous
  2265. i = stbte__ui.eyedrop_last_layer;
  2266. for (j=0; j < tm->num_layers; ++j) {
  2267. if (--i < 0)
  2268. i = tm->num_layers-1;
  2269. if (tm->layerinfo[i].hidden)
  2270. continue;
  2271. if (tm->data[y][x][i] == STBTE__NO_TILE)
  2272. continue;
  2273. stbte__ui.eyedrop_last_layer = i;
  2274. tm->cur_tile = stbte__find_tile(tm, tm->data[y][x][i]);
  2275. return;
  2276. }
  2277. }
  2278. static int stbte__should_copy_properties(stbte_tilemap *tm)
  2279. {
  2280. int i;
  2281. if (tm->propmode == STBTE__propmode_always)
  2282. return 1;
  2283. if (tm->propmode == STBTE__propmode_never)
  2284. return 0;
  2285. if (tm->solo_layer >= 0 || tm->cur_layer >= 0)
  2286. return 0;
  2287. for (i=0; i < tm->num_layers; ++i)
  2288. if (tm->layerinfo[i].hidden || tm->layerinfo[i].locked)
  2289. return 0;
  2290. return 1;
  2291. }
  2292. // compute the result of pasting into a tile non-destructively so we can preview it
  2293. static void stbte__paste_stack(stbte_tilemap *tm, short result[], short dest[], short src[], int dragging)
  2294. {
  2295. int i;
  2296. // special case single-layer
  2297. i = tm->cur_layer;
  2298. if (tm->solo_layer >= 0)
  2299. i = tm->solo_layer;
  2300. if (i >= 0) {
  2301. if (tm->solo_layer < 0) {
  2302. // check that we're allowed to write to it
  2303. if (tm->layerinfo[i].hidden) return;
  2304. if (tm->layerinfo[i].locked == STBTE__locked) return;
  2305. // if protected, dest has to be empty
  2306. if (tm->layerinfo[i].locked == STBTE__protected && dest[i] != STBTE__BG(tm,i)) return;
  2307. // if dragging w/o copy, we will try to erase stuff, which protection disallows
  2308. if (dragging && tm->layerinfo[i].locked == STBTE__protected)
  2309. return;
  2310. }
  2311. result[i] = dest[i];
  2312. if (src[i] != STBTE__BG(tm,i))
  2313. result[i] = src[i];
  2314. return;
  2315. }
  2316. for (i=0; i < tm->num_layers; ++i) {
  2317. result[i] = dest[i];
  2318. if (src[i] != STBTE__NO_TILE)
  2319. if (!tm->layerinfo[i].hidden && tm->layerinfo[i].locked != STBTE__locked)
  2320. if (tm->layerinfo[i].locked == STBTE__unlocked || (!dragging && dest[i] == STBTE__BG(tm,i)))
  2321. result[i] = src[i];
  2322. }
  2323. }
  2324. // compute the result of dragging away from a tile
  2325. static void stbte__clear_stack(stbte_tilemap *tm, short result[])
  2326. {
  2327. int i;
  2328. // special case single-layer
  2329. i = tm->cur_layer;
  2330. if (tm->solo_layer >= 0)
  2331. i = tm->solo_layer;
  2332. if (i >= 0)
  2333. result[i] = STBTE__BG(tm,i);
  2334. else
  2335. for (i=0; i < tm->num_layers; ++i)
  2336. if (!tm->layerinfo[i].hidden && tm->layerinfo[i].locked == STBTE__unlocked)
  2337. result[i] = STBTE__BG(tm,i);
  2338. }
  2339. // check if some map square is active
  2340. #define STBTE__IS_MAP_ACTIVE() ((stbte__ui.active_id & 127) == STBTE__map)
  2341. #define STBTE__IS_MAP_HOT() ((stbte__ui.hot_id & 127) == STBTE__map)
  2342. static void stbte__fillrect(stbte_tilemap *tm, int x0, int y0, int x1, int y1, int fill)
  2343. {
  2344. int i,j;
  2345. stbte__begin_undo(tm);
  2346. if (x0 > x1) i=x0,x0=x1,x1=i;
  2347. if (y0 > y1) j=y0,y0=y1,y1=j;
  2348. for (j=y0; j <= y1; ++j)
  2349. for (i=x0; i <= x1; ++i)
  2350. if (fill)
  2351. stbte__brush(tm, i,j);
  2352. else
  2353. stbte__erase(tm, i,j,STBTE__erase_any);
  2354. stbte__end_undo(tm);
  2355. // suppress warning from brush
  2356. stbte__ui.alert_msg = 0;
  2357. }
  2358. static void stbte__select_rect(stbte_tilemap *tm, int x0, int y0, int x1, int y1)
  2359. {
  2360. stbte__ui.has_selection = 1;
  2361. stbte__ui.select_x0 = (x0 < x1 ? x0 : x1);
  2362. stbte__ui.select_x1 = (x0 < x1 ? x1 : x0);
  2363. stbte__ui.select_y0 = (y0 < y1 ? y0 : y1);
  2364. stbte__ui.select_y1 = (y0 < y1 ? y1 : y0);
  2365. }
  2366. static void stbte__copy_properties(float *dest, float *src)
  2367. {
  2368. int i;
  2369. for (i=0; i < STBTE_MAX_PROPERTIES; ++i)
  2370. dest[i] = src[i];
  2371. }
  2372. static void stbte__copy_cut(stbte_tilemap *tm, int cut)
  2373. {
  2374. int i,j,n,w,h,p=0;
  2375. int copy_props = stbte__should_copy_properties(tm);
  2376. if (!stbte__ui.has_selection)
  2377. return;
  2378. w = stbte__ui.select_x1 - stbte__ui.select_x0 + 1;
  2379. h = stbte__ui.select_y1 - stbte__ui.select_y0 + 1;
  2380. if (STBTE_MAX_COPY / w < h) {
  2381. stbte__alert("Selection too large for copy buffer, increase STBTE_MAX_COPY");
  2382. return;
  2383. }
  2384. for (i=0; i < w*h; ++i)
  2385. for (n=0; n < tm->num_layers; ++n)
  2386. stbte__ui.copybuffer[i][n] = STBTE__NO_TILE;
  2387. if (cut)
  2388. stbte__begin_undo(tm);
  2389. for (j=stbte__ui.select_y0; j <= stbte__ui.select_y1; ++j) {
  2390. for (i=stbte__ui.select_x0; i <= stbte__ui.select_x1; ++i) {
  2391. for (n=0; n < tm->num_layers; ++n) {
  2392. if (tm->solo_layer >= 0) {
  2393. if (tm->solo_layer != n)
  2394. continue;
  2395. } else {
  2396. if (tm->cur_layer >= 0)
  2397. if (tm->cur_layer != n)
  2398. continue;
  2399. if (tm->layerinfo[n].hidden)
  2400. continue;
  2401. if (cut && tm->layerinfo[n].locked)
  2402. continue;
  2403. }
  2404. stbte__ui.copybuffer[p][n] = tm->data[j][i][n];
  2405. if (cut) {
  2406. stbte__undo_record(tm,i,j,n, tm->data[j][i][n]);
  2407. tm->data[j][i][n] = (n==0 ? tm->background_tile : -1);
  2408. }
  2409. }
  2410. if (copy_props) {
  2411. stbte__copy_properties(stbte__ui.copyprops[p], tm->props[j][i]);
  2412. #ifdef STBTE_ALLOW_LINK
  2413. stbte__ui.copylinks[p] = tm->link[j][i];
  2414. if (cut)
  2415. stbte__set_link(tm, i,j,-1,-1, STBTE__undo_record);
  2416. #endif
  2417. }
  2418. ++p;
  2419. }
  2420. }
  2421. if (cut)
  2422. stbte__end_undo(tm);
  2423. stbte__ui.copy_width = w;
  2424. stbte__ui.copy_height = h;
  2425. stbte__ui.has_copy = 1;
  2426. //stbte__ui.has_selection = 0;
  2427. stbte__ui.copy_has_props = copy_props;
  2428. stbte__ui.copy_src = tm; // used to give better semantics when copying links
  2429. stbte__ui.copy_src_x = stbte__ui.select_x0;
  2430. stbte__ui.copy_src_y = stbte__ui.select_y0;
  2431. }
  2432. static int stbte__in_rect(int x, int y, int x0, int y0, int w, int h)
  2433. {
  2434. return x >= x0 && x < x0+w && y >= y0 && y < y0+h;
  2435. }
  2436. #ifdef STBTE_ALLOW_LINK
  2437. static int stbte__in_src_rect(int x, int y)
  2438. {
  2439. return stbte__in_rect(x,y, stbte__ui.copy_src_x, stbte__ui.copy_src_y, stbte__ui.copy_width, stbte__ui.copy_height);
  2440. }
  2441. static int stbte__in_dest_rect(int x, int y, int destx, int desty)
  2442. {
  2443. return stbte__in_rect(x,y, destx, desty, stbte__ui.copy_width, stbte__ui.copy_height);
  2444. }
  2445. #endif
  2446. static void stbte__paste(stbte_tilemap *tm, int mapx, int mapy)
  2447. {
  2448. int w = stbte__ui.copy_width;
  2449. int h = stbte__ui.copy_height;
  2450. int i,j,k,p;
  2451. int x = mapx - (w>>1);
  2452. int y = mapy - (h>>1);
  2453. int copy_props = stbte__should_copy_properties(tm) && stbte__ui.copy_has_props;
  2454. if (stbte__ui.has_copy == 0)
  2455. return;
  2456. stbte__begin_undo(tm);
  2457. p = 0;
  2458. for (j=0; j < h; ++j) {
  2459. for (i=0; i < w; ++i) {
  2460. if (y+j >= 0 && y+j < tm->max_y && x+i >= 0 && x+i < tm->max_x) {
  2461. // compute the new stack
  2462. short tilestack[STBTE_MAX_LAYERS];
  2463. for (k=0; k < tm->num_layers; ++k)
  2464. tilestack[k] = tm->data[y+j][x+i][k];
  2465. stbte__paste_stack(tm, tilestack, tilestack, stbte__ui.copybuffer[p], 0);
  2466. // update anything that changed
  2467. for (k=0; k < tm->num_layers; ++k) {
  2468. if (tilestack[k] != tm->data[y+j][x+i][k]) {
  2469. stbte__undo_record(tm, x+i,y+j,k, tm->data[y+j][x+i][k]);
  2470. tm->data[y+j][x+i][k] = tilestack[k];
  2471. }
  2472. }
  2473. }
  2474. if (copy_props) {
  2475. #ifdef STBTE_ALLOW_LINK
  2476. // need to decide how to paste a link, so there's a few cases
  2477. int destx = -1, desty = -1;
  2478. stbte__link *link = &stbte__ui.copylinks[p];
  2479. // check if link is within-rect
  2480. if (stbte__in_src_rect(link->x, link->y)) {
  2481. // new link should point to copy (but only if copy is within map)
  2482. destx = x + (link->x - stbte__ui.copy_src_x);
  2483. desty = y + (link->y - stbte__ui.copy_src_y);
  2484. } else if (tm == stbte__ui.copy_src) {
  2485. // if same map, then preserve link unless target is overwritten
  2486. if (!stbte__in_dest_rect(link->x,link->y,x,y)) {
  2487. destx = link->x;
  2488. desty = link->y;
  2489. }
  2490. }
  2491. // this is necessary for offset-copy, but also in case max_x/max_y has changed
  2492. if (destx < 0 || destx >= tm->max_x || desty < 0 || desty >= tm->max_y)
  2493. destx = -1, desty = -1;
  2494. stbte__set_link(tm, x+i, y+j, destx, desty, STBTE__undo_record);
  2495. #endif
  2496. for (k=0; k < STBTE_MAX_PROPERTIES; ++k) {
  2497. if (tm->props[y+j][x+i][k] != stbte__ui.copyprops[p][k])
  2498. stbte__undo_record_prop_float(tm, x+i, y+j, k, tm->props[y+j][x+i][k]);
  2499. }
  2500. stbte__copy_properties(tm->props[y+j][x+i], stbte__ui.copyprops[p]);
  2501. }
  2502. ++p;
  2503. }
  2504. }
  2505. stbte__end_undo(tm);
  2506. }
  2507. static void stbte__drag_update(stbte_tilemap *tm, int mapx, int mapy, int copy_props)
  2508. {
  2509. int w = stbte__ui.drag_w, h = stbte__ui.drag_h;
  2510. int ox,oy,i,deleted=0,written=0;
  2511. short temp[STBTE_MAX_LAYERS];
  2512. short *data = NULL;
  2513. STBTE__NOTUSED(deleted);
  2514. STBTE__NOTUSED(written);
  2515. if (!stbte__ui.shift) {
  2516. ox = mapx - stbte__ui.drag_x;
  2517. oy = mapy - stbte__ui.drag_y;
  2518. if (ox >= 0 && ox < w && oy >= 0 && oy < h) {
  2519. deleted=1;
  2520. for (i=0; i < tm->num_layers; ++i)
  2521. temp[i] = tm->data[mapy][mapx][i];
  2522. data = temp;
  2523. stbte__clear_stack(tm, data);
  2524. }
  2525. }
  2526. ox = mapx - stbte__ui.drag_dest_x;
  2527. oy = mapy - stbte__ui.drag_dest_y;
  2528. // if this map square is in the target drag region
  2529. if (ox >= 0 && ox < w && oy >= 0 && oy < h) {
  2530. // and the src map square is on the map
  2531. if (stbte__in_rect(stbte__ui.drag_x+ox, stbte__ui.drag_y+oy, 0, 0, tm->max_x, tm->max_y)) {
  2532. written = 1;
  2533. if (data == NULL) {
  2534. for (i=0; i < tm->num_layers; ++i)
  2535. temp[i] = tm->data[mapy][mapx][i];
  2536. data = temp;
  2537. }
  2538. stbte__paste_stack(tm, data, data, tm->data[stbte__ui.drag_y+oy][stbte__ui.drag_x+ox], !stbte__ui.shift);
  2539. if (copy_props) {
  2540. for (i=0; i < STBTE_MAX_PROPERTIES; ++i) {
  2541. if (tm->props[mapy][mapx][i] != tm->props[stbte__ui.drag_y+oy][stbte__ui.drag_x+ox][i]) {
  2542. stbte__undo_record_prop_float(tm, mapx, mapy, i, tm->props[mapy][mapx][i]);
  2543. tm->props[mapy][mapx][i] = tm->props[stbte__ui.drag_y+oy][stbte__ui.drag_x+ox][i];
  2544. }
  2545. }
  2546. }
  2547. }
  2548. }
  2549. if (data) {
  2550. for (i=0; i < tm->num_layers; ++i) {
  2551. if (tm->data[mapy][mapx][i] != data[i]) {
  2552. stbte__undo_record(tm, mapx, mapy, i, tm->data[mapy][mapx][i]);
  2553. tm->data[mapy][mapx][i] = data[i];
  2554. }
  2555. }
  2556. }
  2557. #ifdef STBTE_ALLOW_LINK
  2558. if (copy_props) {
  2559. int overwritten=0, moved=0, copied=0;
  2560. // since this function is called on EVERY tile, we can fix up even tiles not
  2561. // involved in the move
  2562. stbte__link *k;
  2563. // first, determine what src link ends up here
  2564. k = &tm->link[mapy][mapx]; // by default, it's the one currently here
  2565. if (deleted) // if dragged away, it's erased
  2566. k = NULL;
  2567. if (written) // if dragged into, it gets that link
  2568. k = &tm->link[stbte__ui.drag_y+oy][stbte__ui.drag_x+ox];
  2569. // now check whether the *target* gets moved or overwritten
  2570. if (k && k->x >= 0) {
  2571. overwritten = stbte__in_rect(k->x, k->y, stbte__ui.drag_dest_x, stbte__ui.drag_dest_y, w, h);
  2572. if (!stbte__ui.shift)
  2573. moved = stbte__in_rect(k->x, k->y, stbte__ui.drag_x , stbte__ui.drag_y , w, h);
  2574. else
  2575. copied = stbte__in_rect(k->x, k->y, stbte__ui.drag_x , stbte__ui.drag_y , w, h);
  2576. }
  2577. if (deleted || written || overwritten || moved || copied) {
  2578. // choose the final link value based on the above
  2579. if (k == NULL || k->x < 0)
  2580. stbte__set_link(tm, mapx, mapy, -1, -1, STBTE__undo_record);
  2581. else if (moved || (copied && written)) {
  2582. // if we move the target, we update to point to the new target;
  2583. // or, if we copy the target and the source is part of the copy, then update to new target
  2584. int x = k->x + (stbte__ui.drag_dest_x - stbte__ui.drag_x);
  2585. int y = k->y + (stbte__ui.drag_dest_y - stbte__ui.drag_y);
  2586. if (!(x >= 0 && y >= 0 && x < tm->max_x && y < tm->max_y))
  2587. x = -1, y = -1;
  2588. stbte__set_link(tm, mapx, mapy, x, y, STBTE__undo_record);
  2589. } else if (overwritten) {
  2590. stbte__set_link(tm, mapx, mapy, -1, -1, STBTE__undo_record);
  2591. } else
  2592. stbte__set_link(tm, mapx, mapy, k->x, k->y, STBTE__undo_record);
  2593. }
  2594. }
  2595. #endif
  2596. }
  2597. static void stbte__drag_place(stbte_tilemap *tm, int mapx, int mapy)
  2598. {
  2599. int i,j;
  2600. int copy_props = stbte__should_copy_properties(tm);
  2601. int move_x = (stbte__ui.drag_dest_x - stbte__ui.drag_x);
  2602. int move_y = (stbte__ui.drag_dest_y - stbte__ui.drag_y);
  2603. if (move_x == 0 && move_y == 0)
  2604. return;
  2605. stbte__begin_undo(tm);
  2606. // we now need a 2D memmove-style mover that doesn't
  2607. // overwrite any data as it goes. this requires being
  2608. // direction sensitive in the same way as memmove
  2609. if (move_y > 0 || (move_y == 0 && move_x > 0)) {
  2610. for (j=tm->max_y-1; j >= 0; --j)
  2611. for (i=tm->max_x-1; i >= 0; --i)
  2612. stbte__drag_update(tm,i,j,copy_props);
  2613. } else {
  2614. for (j=0; j < tm->max_y; ++j)
  2615. for (i=0; i < tm->max_x; ++i)
  2616. stbte__drag_update(tm,i,j,copy_props);
  2617. }
  2618. stbte__end_undo(tm);
  2619. stbte__ui.has_selection = 1;
  2620. stbte__ui.select_x0 = stbte__ui.drag_dest_x;
  2621. stbte__ui.select_y0 = stbte__ui.drag_dest_y;
  2622. stbte__ui.select_x1 = stbte__ui.select_x0 + stbte__ui.drag_w - 1;
  2623. stbte__ui.select_y1 = stbte__ui.select_y0 + stbte__ui.drag_h - 1;
  2624. }
  2625. static void stbte__tile_paint(stbte_tilemap *tm, int sx, int sy, int mapx, int mapy, int layer)
  2626. {
  2627. int i;
  2628. int id = STBTE__IDMAP(mapx,mapy);
  2629. int x0=sx, y0=sy;
  2630. int x1=sx+tm->spacing_x, y1=sy+tm->spacing_y;
  2631. stbte__hittest(x0,y0,x1,y1, id);
  2632. short *data = tm->data[mapy][mapx];
  2633. short temp[STBTE_MAX_LAYERS];
  2634. if (STBTE__IS_MAP_HOT()) {
  2635. if (stbte__ui.pasting) {
  2636. int ox = mapx - stbte__ui.paste_x;
  2637. int oy = mapy - stbte__ui.paste_y;
  2638. if (ox >= 0 && ox < stbte__ui.copy_width && oy >= 0 && oy < stbte__ui.copy_height) {
  2639. stbte__paste_stack(tm, temp, tm->data[mapy][mapx], stbte__ui.copybuffer[oy*stbte__ui.copy_width+ox], 0);
  2640. data = temp;
  2641. }
  2642. } else if (stbte__ui.dragging) {
  2643. int ox,oy;
  2644. for (i=0; i < tm->num_layers; ++i)
  2645. temp[i] = tm->data[mapy][mapx][i];
  2646. data = temp;
  2647. // if it's in the source area, remove things unless shift-dragging
  2648. ox = mapx - stbte__ui.drag_x;
  2649. oy = mapy - stbte__ui.drag_y;
  2650. if (!stbte__ui.shift && ox >= 0 && ox < stbte__ui.drag_w && oy >= 0 && oy < stbte__ui.drag_h) {
  2651. stbte__clear_stack(tm, temp);
  2652. }
  2653. ox = mapx - stbte__ui.drag_dest_x;
  2654. oy = mapy - stbte__ui.drag_dest_y;
  2655. if (ox >= 0 && ox < stbte__ui.drag_w && oy >= 0 && oy < stbte__ui.drag_h) {
  2656. stbte__paste_stack(tm, temp, temp, tm->data[stbte__ui.drag_y+oy][stbte__ui.drag_x+ox], !stbte__ui.shift);
  2657. }
  2658. } else if (STBTE__IS_MAP_ACTIVE()) {
  2659. if (stbte__ui.tool == STBTE__tool_rect) {
  2660. if ((stbte__ui.ms_time & 511) < 380) {
  2661. int ex = ((stbte__ui.hot_id >> 19) & 4095);
  2662. int ey = ((stbte__ui.hot_id >> 7) & 4095);
  2663. int sx = stbte__ui.sx;
  2664. int sy = stbte__ui.sy;
  2665. if ( ((mapx >= sx && mapx < ex+1) || (mapx >= ex && mapx < sx+1))
  2666. && ((mapy >= sy && mapy < ey+1) || (mapy >= ey && mapy < sy+1))) {
  2667. int i;
  2668. for (i=0; i < tm->num_layers; ++i)
  2669. temp[i] = tm->data[mapy][mapx][i];
  2670. data = temp;
  2671. if (stbte__ui.active_event == STBTE__leftdown)
  2672. stbte__brush_predict(tm, temp);
  2673. else
  2674. stbte__erase_predict(tm, temp, STBTE__erase_any);
  2675. }
  2676. }
  2677. }
  2678. }
  2679. }
  2680. if (STBTE__IS_HOT(id) && STBTE__INACTIVE() && !stbte__ui.pasting) {
  2681. if (stbte__ui.tool == STBTE__tool_brush) {
  2682. if ((stbte__ui.ms_time & 511) < 300) {
  2683. data = temp;
  2684. for (i=0; i < tm->num_layers; ++i)
  2685. temp[i] = tm->data[mapy][mapx][i];
  2686. stbte__brush_predict(tm, temp);
  2687. }
  2688. }
  2689. }
  2690. {
  2691. i = layer;
  2692. if (i == tm->solo_layer || (!tm->layerinfo[i].hidden && tm->solo_layer < 0))
  2693. if (data[i] >= 0)
  2694. STBTE_DRAW_TILE(sx,sy, (unsigned short) data[i], 0, tm->props[mapy][mapx]);
  2695. }
  2696. }
  2697. static void stbte__tile(stbte_tilemap *tm, int sx, int sy, int mapx, int mapy)
  2698. {
  2699. int tool = stbte__ui.tool;
  2700. int x0=sx, y0=sy;
  2701. int x1=sx+tm->spacing_x, y1=sy+tm->spacing_y;
  2702. int id = STBTE__IDMAP(mapx,mapy);
  2703. int over = stbte__hittest(x0,y0,x1,y1, id);
  2704. switch (stbte__ui.event) {
  2705. case STBTE__paint: {
  2706. if (stbte__ui.pasting || stbte__ui.dragging || stbte__ui.scrolling)
  2707. break;
  2708. if (stbte__ui.scrollkey && !STBTE__IS_MAP_ACTIVE())
  2709. break;
  2710. if (STBTE__IS_HOT(id) && STBTE__IS_MAP_ACTIVE() && (tool == STBTE__tool_rect || tool == STBTE__tool_select)) {
  2711. int rx0,ry0,rx1,ry1,t;
  2712. // compute the center of each rect
  2713. rx0 = x0 + tm->spacing_x/2;
  2714. ry0 = y0 + tm->spacing_y/2;
  2715. rx1 = rx0 + (stbte__ui.sx - mapx) * tm->spacing_x;
  2716. ry1 = ry0 + (stbte__ui.sy - mapy) * tm->spacing_y;
  2717. if (rx0 > rx1) t=rx0,rx0=rx1,rx1=t;
  2718. if (ry0 > ry1) t=ry0,ry0=ry1,ry1=t;
  2719. rx0 -= tm->spacing_x/2;
  2720. ry0 -= tm->spacing_y/2;
  2721. rx1 += tm->spacing_x/2;
  2722. ry1 += tm->spacing_y/2;
  2723. stbte__draw_frame(rx0-1,ry0-1,rx1+1,ry1+1, STBTE_COLOR_TILEMAP_HIGHLIGHT);
  2724. break;
  2725. }
  2726. if (STBTE__IS_HOT(id) && STBTE__INACTIVE()) {
  2727. stbte__draw_frame(x0-1,y0-1,x1+1,y1+1, STBTE_COLOR_TILEMAP_HIGHLIGHT);
  2728. }
  2729. #ifdef STBTE_ALLOW_LINK
  2730. if (stbte__ui.show_links && tm->link[mapy][mapx].x >= 0) {
  2731. int tx = tm->link[mapy][mapx].x;
  2732. int ty = tm->link[mapy][mapx].y;
  2733. int lx0,ly0,lx1,ly1;
  2734. if (STBTE_ALLOW_LINK(tm->data[mapy][mapx], tm->props[mapy][mapx],
  2735. tm->data[ty ][tx ], tm->props[ty ][tx ]))
  2736. {
  2737. lx0 = x0 + (tm->spacing_x >> 1) - 1;
  2738. ly0 = y0 + (tm->spacing_y >> 1) - 1;
  2739. lx1 = lx0 + (tx - mapx) * tm->spacing_x + 2;
  2740. ly1 = ly0 + (ty - mapy) * tm->spacing_y + 2;
  2741. stbte__draw_link(lx0,ly0,lx1,ly1,
  2742. STBTE_LINK_COLOR(tm->data[mapy][mapx], tm->props[mapy][mapx],
  2743. tm->data[ty ][tx ], tm->props[ty ][tx]));
  2744. }
  2745. }
  2746. #endif
  2747. break;
  2748. }
  2749. }
  2750. if (stbte__ui.pasting) {
  2751. switch (stbte__ui.event) {
  2752. case STBTE__leftdown:
  2753. if (STBTE__IS_HOT(id)) {
  2754. stbte__ui.pasting = 0;
  2755. stbte__paste(tm, mapx, mapy);
  2756. stbte__activate(0);
  2757. }
  2758. break;
  2759. case STBTE__leftup:
  2760. // just clear it no matter what, since they might click away to clear it
  2761. stbte__activate(0);
  2762. break;
  2763. case STBTE__rightdown:
  2764. if (STBTE__IS_HOT(id)) {
  2765. stbte__activate(0);
  2766. stbte__ui.pasting = 0;
  2767. }
  2768. break;
  2769. }
  2770. return;
  2771. }
  2772. if (stbte__ui.scrolling) {
  2773. if (stbte__ui.event == STBTE__leftup) {
  2774. stbte__activate(0);
  2775. stbte__ui.scrolling = 0;
  2776. }
  2777. if (stbte__ui.event == STBTE__mousemove) {
  2778. tm->scroll_x += (stbte__ui.start_x - stbte__ui.mx);
  2779. tm->scroll_y += (stbte__ui.start_y - stbte__ui.my);
  2780. stbte__ui.start_x = stbte__ui.mx;
  2781. stbte__ui.start_y = stbte__ui.my;
  2782. }
  2783. return;
  2784. }
  2785. // regardless of tool, leftdown is a scrolldrag
  2786. if (STBTE__IS_HOT(id) && stbte__ui.scrollkey && stbte__ui.event == STBTE__leftdown) {
  2787. stbte__ui.scrolling = 1;
  2788. stbte__ui.start_x = stbte__ui.mx;
  2789. stbte__ui.start_y = stbte__ui.my;
  2790. return;
  2791. }
  2792. switch (tool) {
  2793. case STBTE__tool_brush:
  2794. switch (stbte__ui.event) {
  2795. case STBTE__mousemove:
  2796. if (STBTE__IS_MAP_ACTIVE() && over) {
  2797. // don't brush/erase same tile multiple times unless they move away and back @TODO should just be only once, but that needs another data structure
  2798. if (!STBTE__IS_ACTIVE(id)) {
  2799. if (stbte__ui.active_event == STBTE__leftdown)
  2800. stbte__brush(tm, mapx, mapy);
  2801. else
  2802. stbte__erase(tm, mapx, mapy, stbte__ui.brush_state);
  2803. stbte__ui.active_id = id; // switch to this map square so we don't rebrush IT multiple times
  2804. }
  2805. }
  2806. break;
  2807. case STBTE__leftdown:
  2808. if (STBTE__IS_HOT(id) && STBTE__INACTIVE()) {
  2809. stbte__activate(id);
  2810. stbte__begin_undo(tm);
  2811. stbte__brush(tm, mapx, mapy);
  2812. }
  2813. break;
  2814. case STBTE__rightdown:
  2815. if (STBTE__IS_HOT(id) && STBTE__INACTIVE()) {
  2816. stbte__activate(id);
  2817. stbte__begin_undo(tm);
  2818. if (stbte__erase(tm, mapx, mapy, STBTE__erase_any) == STBTE__erase_brushonly)
  2819. stbte__ui.brush_state = STBTE__erase_brushonly;
  2820. else
  2821. stbte__ui.brush_state = STBTE__erase_any;
  2822. }
  2823. break;
  2824. case STBTE__leftup:
  2825. case STBTE__rightup:
  2826. if (STBTE__IS_MAP_ACTIVE()) {
  2827. stbte__end_undo(tm);
  2828. stbte__activate(0);
  2829. }
  2830. break;
  2831. }
  2832. break;
  2833. #ifdef STBTE_ALLOW_LINK
  2834. case STBTE__tool_link:
  2835. switch (stbte__ui.event) {
  2836. case STBTE__leftdown:
  2837. if (STBTE__IS_HOT(id) && STBTE__INACTIVE()) {
  2838. stbte__activate(id);
  2839. stbte__ui.linking = 1;
  2840. stbte__ui.sx = mapx;
  2841. stbte__ui.sy = mapy;
  2842. // @TODO: undo
  2843. }
  2844. break;
  2845. case STBTE__leftup:
  2846. if (STBTE__IS_HOT(id) && STBTE__IS_MAP_ACTIVE()) {
  2847. if ((mapx != stbte__ui.sx || mapy != stbte__ui.sy) &&
  2848. STBTE_ALLOW_LINK(tm->data[stbte__ui.sy][stbte__ui.sx], tm->props[stbte__ui.sy][stbte__ui.sx],
  2849. tm->data[mapy][mapx], tm->props[mapy][mapx]))
  2850. stbte__set_link(tm, stbte__ui.sx, stbte__ui.sy, mapx, mapy, STBTE__undo_block);
  2851. else
  2852. stbte__set_link(tm, stbte__ui.sx, stbte__ui.sy, -1,-1, STBTE__undo_block);
  2853. stbte__ui.linking = 0;
  2854. stbte__activate(0);
  2855. }
  2856. break;
  2857. case STBTE__rightdown:
  2858. if (STBTE__IS_ACTIVE(id)) {
  2859. stbte__activate(0);
  2860. stbte__ui.linking = 0;
  2861. }
  2862. break;
  2863. }
  2864. break;
  2865. #endif
  2866. case STBTE__tool_erase:
  2867. switch (stbte__ui.event) {
  2868. case STBTE__mousemove:
  2869. if (STBTE__IS_MAP_ACTIVE() && over)
  2870. stbte__erase(tm, mapx, mapy, STBTE__erase_all);
  2871. break;
  2872. case STBTE__leftdown:
  2873. if (STBTE__IS_HOT(id) && STBTE__INACTIVE()) {
  2874. stbte__activate(id);
  2875. stbte__begin_undo(tm);
  2876. stbte__erase(tm, mapx, mapy, STBTE__erase_all);
  2877. }
  2878. break;
  2879. case STBTE__leftup:
  2880. if (STBTE__IS_MAP_ACTIVE()) {
  2881. stbte__end_undo(tm);
  2882. stbte__activate(0);
  2883. }
  2884. break;
  2885. }
  2886. break;
  2887. case STBTE__tool_select:
  2888. if (STBTE__IS_HOT(id)) {
  2889. switch (stbte__ui.event) {
  2890. case STBTE__leftdown:
  2891. if (STBTE__INACTIVE()) {
  2892. // if we're clicking in an existing selection...
  2893. if (stbte__ui.has_selection) {
  2894. if ( mapx >= stbte__ui.select_x0 && mapx <= stbte__ui.select_x1
  2895. && mapy >= stbte__ui.select_y0 && mapy <= stbte__ui.select_y1)
  2896. {
  2897. stbte__ui.dragging = 1;
  2898. stbte__ui.drag_x = stbte__ui.select_x0;
  2899. stbte__ui.drag_y = stbte__ui.select_y0;
  2900. stbte__ui.drag_w = stbte__ui.select_x1 - stbte__ui.select_x0 + 1;
  2901. stbte__ui.drag_h = stbte__ui.select_y1 - stbte__ui.select_y0 + 1;
  2902. stbte__ui.drag_offx = mapx - stbte__ui.select_x0;
  2903. stbte__ui.drag_offy = mapy - stbte__ui.select_y0;
  2904. }
  2905. }
  2906. stbte__ui.has_selection = 0; // no selection until it completes
  2907. stbte__activate_map(mapx,mapy);
  2908. }
  2909. break;
  2910. case STBTE__leftup:
  2911. if (STBTE__IS_MAP_ACTIVE()) {
  2912. if (stbte__ui.dragging) {
  2913. stbte__drag_place(tm, mapx,mapy);
  2914. stbte__ui.dragging = 0;
  2915. stbte__activate(0);
  2916. } else {
  2917. stbte__select_rect(tm, stbte__ui.sx, stbte__ui.sy, mapx, mapy);
  2918. stbte__activate(0);
  2919. }
  2920. }
  2921. break;
  2922. case STBTE__rightdown:
  2923. stbte__ui.has_selection = 0;
  2924. break;
  2925. }
  2926. }
  2927. break;
  2928. case STBTE__tool_rect:
  2929. if (STBTE__IS_HOT(id)) {
  2930. switch (stbte__ui.event) {
  2931. case STBTE__leftdown:
  2932. if (STBTE__INACTIVE())
  2933. stbte__activate_map(mapx,mapy);
  2934. break;
  2935. case STBTE__leftup:
  2936. if (STBTE__IS_MAP_ACTIVE()) {
  2937. stbte__fillrect(tm, stbte__ui.sx, stbte__ui.sy, mapx, mapy, 1);
  2938. stbte__activate(0);
  2939. }
  2940. break;
  2941. case STBTE__rightdown:
  2942. if (STBTE__INACTIVE())
  2943. stbte__activate_map(mapx,mapy);
  2944. break;
  2945. case STBTE__rightup:
  2946. if (STBTE__IS_MAP_ACTIVE()) {
  2947. stbte__fillrect(tm, stbte__ui.sx, stbte__ui.sy, mapx, mapy, 0);
  2948. stbte__activate(0);
  2949. }
  2950. break;
  2951. }
  2952. }
  2953. break;
  2954. case STBTE__tool_eyedrop:
  2955. switch (stbte__ui.event) {
  2956. case STBTE__leftdown:
  2957. if (STBTE__IS_HOT(id) && STBTE__INACTIVE())
  2958. stbte__eyedrop(tm,mapx,mapy);
  2959. break;
  2960. }
  2961. break;
  2962. }
  2963. }
  2964. static void stbte__start_paste(stbte_tilemap *tm)
  2965. {
  2966. if (stbte__ui.has_copy) {
  2967. stbte__ui.pasting = 1;
  2968. stbte__activate(STBTE__ID(STBTE__toolbarB,3));
  2969. }
  2970. }
  2971. static void stbte__toolbar(stbte_tilemap *tm, int x0, int y0, int w, int h)
  2972. {
  2973. int i;
  2974. int estimated_width = 13 * STBTE__num_tool + 8+8+ 120+4 - 30;
  2975. int x = x0 + w/2 - estimated_width/2;
  2976. int y = y0+1;
  2977. for (i=0; i < STBTE__num_tool; ++i) {
  2978. int highlight=0, disable=0;
  2979. highlight = (stbte__ui.tool == i);
  2980. if (i == STBTE__tool_undo || i == STBTE__tool_showgrid)
  2981. x += 8;
  2982. if (i == STBTE__tool_showgrid && stbte__ui.show_grid)
  2983. highlight = 1;
  2984. if (i == STBTE__tool_showlinks && stbte__ui.show_links)
  2985. highlight = 1;
  2986. if (i == STBTE__tool_fill)
  2987. continue;
  2988. #ifndef STBTE_ALLOW_LINK
  2989. if (i == STBTE__tool_link || i == STBTE__tool_showlinks)
  2990. disable = 1;
  2991. #endif
  2992. if (i == STBTE__tool_undo && !stbte__undo_available(tm))
  2993. disable = 1;
  2994. if (i == STBTE__tool_redo && !stbte__redo_available(tm))
  2995. disable = 1;
  2996. if (stbte__button_icon(STBTE__ctoolbar_button, toolchar[i], x, y, 13, STBTE__ID(STBTE__toolbarA, i), highlight, disable)) {
  2997. switch (i) {
  2998. case STBTE__tool_eyedrop:
  2999. stbte__ui.eyedrop_last_layer = tm->num_layers; // flush eyedropper state
  3000. // fallthrough
  3001. default:
  3002. stbte__ui.tool = i;
  3003. stbte__ui.has_selection = 0;
  3004. break;
  3005. case STBTE__tool_showlinks:
  3006. stbte__ui.show_links = !stbte__ui.show_links;
  3007. break;
  3008. case STBTE__tool_showgrid:
  3009. stbte__ui.show_grid = (stbte__ui.show_grid+1)%3;
  3010. break;
  3011. case STBTE__tool_undo:
  3012. stbte__undo(tm);
  3013. break;
  3014. case STBTE__tool_redo:
  3015. stbte__redo(tm);
  3016. break;
  3017. }
  3018. }
  3019. x += 13;
  3020. }
  3021. x += 8;
  3022. if (stbte__button(STBTE__ctoolbar_button, "cut" , x, y,10, 40, STBTE__ID(STBTE__toolbarB,0), 0, !stbte__ui.has_selection))
  3023. stbte__copy_cut(tm, 1);
  3024. x += 42;
  3025. if (stbte__button(STBTE__ctoolbar_button, "copy" , x, y, 5, 40, STBTE__ID(STBTE__toolbarB,1), 0, !stbte__ui.has_selection))
  3026. stbte__copy_cut(tm, 0);
  3027. x += 42;
  3028. if (stbte__button(STBTE__ctoolbar_button, "paste", x, y, 0, 40, STBTE__ID(STBTE__toolbarB,2), stbte__ui.pasting, !stbte__ui.has_copy))
  3029. stbte__start_paste(tm);
  3030. }
  3031. #define STBTE__TEXTCOLOR(n) stbte__color_table[n][STBTE__text][STBTE__idle]
  3032. static int stbte__info_value(const char *label, int x, int y, int val, int digits, int id)
  3033. {
  3034. if (stbte__ui.event == STBTE__paint) {
  3035. int off = 9-stbte__get_char_width(label[0]);
  3036. char text[16];
  3037. stbte__sprintf(text stbte__sizeof(text), label, digits, val);
  3038. stbte__draw_text_core(x+off,y, text, 999, STBTE__TEXTCOLOR(STBTE__cpanel),1);
  3039. }
  3040. if (id) {
  3041. x += 9+7*digits+4;
  3042. if (stbte__minibutton(STBTE__cmapsize, x,y, '+', STBTE__ID2(id,1,0)))
  3043. val += (stbte__ui.shift ? 10 : 1);
  3044. x += 9;
  3045. if (stbte__minibutton(STBTE__cmapsize, x,y, '-', STBTE__ID2(id,2,0)))
  3046. val -= (stbte__ui.shift ? 10 : 1);
  3047. if (val < 1) val = 1; else if (val > 4096) val = 4096;
  3048. }
  3049. return val;
  3050. }
  3051. static void stbte__info(stbte_tilemap *tm, int x0, int y0, int w, int h)
  3052. {
  3053. int mode = stbte__ui.panel[STBTE__panel_info].mode;
  3054. int s = 11+7*tm->digits+4+15;
  3055. int x,y;
  3056. int in_region;
  3057. x = x0+2;
  3058. y = y0+2;
  3059. tm->max_x = stbte__info_value("w:%*d",x,y, tm->max_x, tm->digits, STBTE__ID(STBTE__info,0));
  3060. if (mode)
  3061. x += s;
  3062. else
  3063. y += 11;
  3064. tm->max_y = stbte__info_value("h:%*d",x,y, tm->max_y, tm->digits, STBTE__ID(STBTE__info,1));
  3065. x = x0+2;
  3066. y += 11;
  3067. in_region = (stbte__ui.hot_id & 127) == STBTE__map;
  3068. stbte__info_value(in_region ? "x:%*d" : "x:",x,y, (stbte__ui.hot_id>>19)&4095, tm->digits, 0);
  3069. if (mode)
  3070. x += s;
  3071. else
  3072. y += 11;
  3073. stbte__info_value(in_region ? "y:%*d" : "y:",x,y, (stbte__ui.hot_id>> 7)&4095, tm->digits, 0);
  3074. y += 15;
  3075. x = x0+2;
  3076. stbte__draw_text(x,y,"brush:",40,STBTE__TEXTCOLOR(STBTE__cpanel));
  3077. if (tm->cur_tile >= 0)
  3078. STBTE_DRAW_TILE(x+43,y-3,tm->tiles[tm->cur_tile].id,1,0);
  3079. }
  3080. static void stbte__layers(stbte_tilemap *tm, int x0, int y0, int w, int h)
  3081. {
  3082. static const char *propmodes[3] = {
  3083. "default", "always", "never"
  3084. };
  3085. int num_rows;
  3086. int i, y, n;
  3087. int x1 = x0+w;
  3088. int y1 = y0+h;
  3089. int xoff = 20;
  3090. if (tm->has_layer_names) {
  3091. int side = stbte__ui.panel[STBTE__panel_layers].side;
  3092. xoff = stbte__region[side].width - 42;
  3093. xoff = (xoff < tm->layername_width + 10 ? xoff : tm->layername_width + 10);
  3094. }
  3095. x0 += 2;
  3096. y0 += 5;
  3097. if (!tm->has_layer_names) {
  3098. if (stbte__ui.event == STBTE__paint) {
  3099. stbte__draw_text(x0,y0, "Layers", w-4, STBTE__TEXTCOLOR(STBTE__cpanel));
  3100. }
  3101. y0 += 11;
  3102. }
  3103. num_rows = (y1-y0)/15;
  3104. #ifndef STBTE_NO_PROPS
  3105. --num_rows;
  3106. #endif
  3107. y = y0;
  3108. for (i=0; i < tm->num_layers; ++i) {
  3109. char text[3], *str = (char *) tm->layerinfo[i].name;
  3110. static char lockedchar[3] = { 'U', 'P', 'L' };
  3111. int locked = tm->layerinfo[i].locked;
  3112. int disabled = (tm->solo_layer >= 0 && tm->solo_layer != i);
  3113. if (i-tm->layer_scroll >= 0 && i-tm->layer_scroll < num_rows) {
  3114. if (str == NULL)
  3115. stbte__sprintf(str=text stbte__sizeof(text), "%2d", i+1);
  3116. if (stbte__button(STBTE__clayer_button, str, x0,y,(i+1<10)*2,xoff-2, STBTE__ID(STBTE__layer,i), tm->cur_layer==i,0))
  3117. tm->cur_layer = (tm->cur_layer == i ? -1 : i);
  3118. if (stbte__layerbutton(x0+xoff + 0,y+1,'H',STBTE__ID(STBTE__hide,i), tm->layerinfo[i].hidden,disabled,STBTE__clayer_hide))
  3119. tm->layerinfo[i].hidden = !tm->layerinfo[i].hidden;
  3120. if (stbte__layerbutton(x0+xoff + 12,y+1,lockedchar[locked],STBTE__ID(STBTE__lock,i), locked!=0,disabled,STBTE__clayer_lock))
  3121. tm->layerinfo[i].locked = (locked+1)%3;
  3122. if (stbte__layerbutton(x0+xoff + 24,y+1,'S',STBTE__ID(STBTE__solo,i), tm->solo_layer==i,0,STBTE__clayer_solo))
  3123. tm->solo_layer = (tm->solo_layer == i ? -1 : i);
  3124. y += 15;
  3125. }
  3126. }
  3127. stbte__scrollbar(x1-4, y0,y-2, &tm->layer_scroll, 0, tm->num_layers, num_rows, STBTE__ID(STBTE__scrollbar_id, STBTE__layer));
  3128. #ifndef STBTE_NO_PROPS
  3129. n = stbte__text_width("prop:")+2;
  3130. stbte__draw_text(x0,y+2, "prop:", w, STBTE__TEXTCOLOR(STBTE__cpanel));
  3131. i = w - n - 4;
  3132. if (i > 50) i = 50;
  3133. if (stbte__button(STBTE__clayer_button, propmodes[tm->propmode], x0+n,y,0,i, STBTE__ID(STBTE__layer,256), 0,0))
  3134. tm->propmode = (tm->propmode+1)%3;
  3135. #endif
  3136. }
  3137. static void stbte__categories(stbte_tilemap *tm, int x0, int y0, int w, int h)
  3138. {
  3139. int s=11, x,y, i;
  3140. int num_rows = h / s;
  3141. w -= 4;
  3142. x = x0+2;
  3143. y = y0+4;
  3144. if (tm->category_scroll == 0) {
  3145. if (stbte__category_button("*ALL*", x,y, w, STBTE__ID(STBTE__categories, 65535), tm->cur_category == -1)) {
  3146. stbte__choose_category(tm, -1);
  3147. }
  3148. y += s;
  3149. }
  3150. for (i=0; i < tm->num_categories; ++i) {
  3151. if (i+1 - tm->category_scroll >= 0 && i+1 - tm->category_scroll < num_rows) {
  3152. if (y + 10 > y0+h)
  3153. return;
  3154. if (stbte__category_button(tm->categories[i], x,y,w, STBTE__ID(STBTE__categories,i), tm->cur_category == i))
  3155. stbte__choose_category(tm, i);
  3156. y += s;
  3157. }
  3158. }
  3159. stbte__scrollbar(x0+w, y0+4, y0+h-4, &tm->category_scroll, 0, tm->num_categories+1, num_rows, STBTE__ID(STBTE__scrollbar_id, STBTE__categories));
  3160. }
  3161. static void stbte__tile_in_palette(stbte_tilemap *tm, int x, int y, int slot)
  3162. {
  3163. stbte__tileinfo *t = &tm->tiles[slot];
  3164. int x0=x, y0=y, x1 = x+tm->palette_spacing_x - 1, y1 = y+tm->palette_spacing_y;
  3165. int id = STBTE__ID(STBTE__palette, slot);
  3166. stbte__hittest(x0,y0,x1,y1, id);
  3167. switch (stbte__ui.event) {
  3168. case STBTE__paint:
  3169. stbte__draw_rect(x,y,x+tm->palette_spacing_x-1,y+tm->palette_spacing_x-1, STBTE_COLOR_TILEPALETTE_BACKGROUND);
  3170. STBTE_DRAW_TILE(x,y,id, slot == tm->cur_tile,0);
  3171. if (slot == tm->cur_tile)
  3172. stbte__draw_frame_delayed(x-1,y-1,x+tm->palette_spacing_x,y+tm->palette_spacing_y, STBTE_COLOR_TILEPALETTE_OUTLINE);
  3173. break;
  3174. default:
  3175. if (stbte__button_core(id))
  3176. tm->cur_tile = slot;
  3177. break;
  3178. }
  3179. }
  3180. static void stbte__palette_of_tiles(stbte_tilemap *tm, int x0, int y0, int w, int h)
  3181. {
  3182. int i,x,y;
  3183. int num_vis_rows = (h-6) / tm->palette_spacing_y;
  3184. int num_columns = (w-2-6) / tm->palette_spacing_x;
  3185. int num_total_rows;
  3186. int column,row;
  3187. int x1 = x0+w, y1=y0+h;
  3188. x = x0+2;
  3189. y = y0+6;
  3190. if (num_columns == 0)
  3191. return;
  3192. num_total_rows = (tm->cur_palette_count + num_columns-1) / num_columns; // ceil()
  3193. column = 0;
  3194. row = -tm->palette_scroll;
  3195. for (i=0; i < tm->num_tiles; ++i) {
  3196. stbte__tileinfo *t = &tm->tiles[i];
  3197. // filter based on category
  3198. if (tm->cur_category >= 0 && t->category_id != tm->cur_category)
  3199. continue;
  3200. // display it
  3201. if (row >= 0 && row < num_vis_rows) {
  3202. x = x0 + 2 + tm->palette_spacing_x * column;
  3203. y = y0 + 6 + tm->palette_spacing_y * row;
  3204. stbte__tile_in_palette(tm,x,y,i);
  3205. }
  3206. ++column;
  3207. if (column == num_columns) {
  3208. column = 0;
  3209. ++row;
  3210. }
  3211. }
  3212. stbte__flush_delay();
  3213. stbte__scrollbar(x1-4, y0+6, y1-2, &tm->palette_scroll, 0, num_total_rows, num_vis_rows, STBTE__ID(STBTE__scrollbar_id, STBTE__palette));
  3214. }
  3215. static float stbte__saved;
  3216. static void stbte__props_panel(stbte_tilemap *tm, int x0, int y0, int w, int h)
  3217. {
  3218. int x1 = x0+w;
  3219. int i;
  3220. int y = y0 + 5, x = x0+2;
  3221. int slider_width = 60;
  3222. int mx,my;
  3223. float *p;
  3224. short *data;
  3225. if (!stbte__is_single_selection())
  3226. return;
  3227. mx = stbte__ui.select_x0;
  3228. my = stbte__ui.select_y0;
  3229. p = tm->props[my][mx];
  3230. data = tm->data[my][mx];
  3231. STBTE__NOTUSED(data);
  3232. for (i=0; i < STBTE_MAX_PROPERTIES; ++i) {
  3233. unsigned int n = STBTE_PROP_TYPE(i, data, p);
  3234. if (n) {
  3235. char *s = (char*) STBTE_PROP_NAME(i, data, p);
  3236. if (s == NULL) s = (char*) "";
  3237. switch (n & 3) {
  3238. case STBTE_PROP_bool: {
  3239. int flag = (int) p[i];
  3240. if (stbte__layerbutton(x,y, flag ? 'x' : ' ', STBTE__ID(STBTE__prop_flag,i), flag, 0, 2)) {
  3241. stbte__begin_undo(tm);
  3242. stbte__undo_record_prop_float(tm,mx,my,i,(float) flag);
  3243. p[i] = (float) !flag;
  3244. stbte__end_undo(tm);
  3245. }
  3246. stbte__draw_text(x+13,y+1,s,x1-(x+13)-2,STBTE__TEXTCOLOR(STBTE__cpanel));
  3247. y += 13;
  3248. break;
  3249. }
  3250. case STBTE_PROP_int: {
  3251. int a = (int) STBTE_PROP_MIN(i,data,p);
  3252. int b = (int) STBTE_PROP_MAX(i,data,p);
  3253. int v = (int) p[i] - a;
  3254. if (a+v != p[i] || v < 0 || v > b-a) {
  3255. if (v < 0) v = 0;
  3256. if (v > b-a) v = b-a;
  3257. p[i] = (float) (a+v); // @TODO undo
  3258. }
  3259. switch (stbte__slider(x, slider_width, y+7, b-a, &v, STBTE__ID(STBTE__prop_int,i)))
  3260. {
  3261. case STBTE__begin:
  3262. stbte__saved = p[i];
  3263. // fallthrough
  3264. case STBTE__change:
  3265. p[i] = (float) (a+v); // @TODO undo
  3266. break;
  3267. case STBTE__end:
  3268. if (p[i] != stbte__saved) {
  3269. stbte__begin_undo(tm);
  3270. stbte__undo_record_prop_float(tm,mx,my,i,stbte__saved);
  3271. stbte__end_undo(tm);
  3272. }
  3273. break;
  3274. }
  3275. stbte__draw_text(x+slider_width+2,y+2, s, x1-1-(x+slider_width+2), STBTE__TEXTCOLOR(STBTE__cpanel));
  3276. y += 12;
  3277. break;
  3278. }
  3279. case STBTE_PROP_float: {
  3280. float a = (float) STBTE_PROP_MIN(i, data,p);
  3281. float b = (float) STBTE_PROP_MAX(i, data,p);
  3282. float c = STBTE_PROP_FLOAT_SCALE(i, data, p);
  3283. float old;
  3284. if (p[i] < a || p[i] > b) {
  3285. // @TODO undo
  3286. if (p[i] < a) p[i] = a;
  3287. if (p[i] > b) p[i] = b;
  3288. }
  3289. old = p[i];
  3290. switch (stbte__float_control(x, y, 50, a, b, c, "%8.4f", &p[i], STBTE__layer,STBTE__ID(STBTE__prop_float,i))) {
  3291. case STBTE__begin:
  3292. stbte__saved = old;
  3293. break;
  3294. case STBTE__end:
  3295. if (stbte__saved != p[i]) {
  3296. stbte__begin_undo(tm);
  3297. stbte__undo_record_prop_float(tm,mx,my,i, stbte__saved);
  3298. stbte__end_undo(tm);
  3299. }
  3300. break;
  3301. }
  3302. stbte__draw_text(x+53,y+1, s, x1-1-(x+53), STBTE__TEXTCOLOR(STBTE__cpanel));
  3303. y += 12;
  3304. break;
  3305. }
  3306. }
  3307. }
  3308. }
  3309. }
  3310. static int stbte__cp_mode, stbte__cp_aspect, stbte__save, stbte__cp_altered;
  3311. #ifdef STBTE__COLORPICKER
  3312. static int stbte__cp_state, stbte__cp_index, stbte__color_copy;
  3313. static void stbte__dump_colorstate(void)
  3314. {
  3315. int i,j,k;
  3316. printf("static int stbte__color_table[STBTE__num_color_modes][STBTE__num_color_aspects][STBTE__num_color_states] =\n");
  3317. printf("{\n");
  3318. printf(" {\n");
  3319. for (k=0; k < STBTE__num_color_modes; ++k) {
  3320. for (j=0; j < STBTE__num_color_aspects; ++j) {
  3321. printf(" { ");
  3322. for (i=0; i < STBTE__num_color_states; ++i) {
  3323. printf("0x%06x, ", stbte__color_table[k][j][i]);
  3324. }
  3325. printf("},\n");
  3326. }
  3327. if (k+1 < STBTE__num_color_modes)
  3328. printf(" }, {\n");
  3329. else
  3330. printf(" },\n");
  3331. }
  3332. printf("};\n");
  3333. }
  3334. static void stbte__colorpicker(int x0, int y0, int w, int h)
  3335. {
  3336. int x1 = x0+w, y1 = y0+h, x,y, i;
  3337. x = x0+2; y = y0+6;
  3338. y += 5;
  3339. x += 8;
  3340. {
  3341. int color = stbte__color_table[stbte__cp_mode][stbte__cp_aspect][stbte__cp_index];
  3342. int rgb[3];
  3343. if (stbte__cp_altered && stbte__cp_index == STBTE__idle)
  3344. color = stbte__save;
  3345. if (stbte__minibutton(STBTE__cmapsize, x1-20,y+ 5, 'C', STBTE__ID2(STBTE__colorpick_id,4,0)))
  3346. stbte__color_copy = color;
  3347. if (stbte__minibutton(STBTE__cmapsize, x1-20,y+15, 'P', STBTE__ID2(STBTE__colorpick_id,4,1)))
  3348. color = stbte__color_copy;
  3349. rgb[0] = color >> 16; rgb[1] = (color>>8)&255; rgb[2] = color & 255;
  3350. for (i=0; i < 3; ++i) {
  3351. if (stbte__slider(x+8,64, y, 255, rgb+i, STBTE__ID2(STBTE__colorpick_id,3,i)) > 0)
  3352. stbte__dump_colorstate();
  3353. y += 15;
  3354. }
  3355. if (stbte__ui.event != STBTE__paint && stbte__ui.event != STBTE__tick)
  3356. stbte__color_table[stbte__cp_mode][stbte__cp_aspect][stbte__cp_index] = (rgb[0]<<16)|(rgb[1]<<8)|(rgb[2]);
  3357. }
  3358. y += 5;
  3359. // states
  3360. x = x0+2+35;
  3361. if (stbte__ui.event == STBTE__paint) {
  3362. static char *states[] = { "idle", "over", "down", "down&over", "selected", "selected&over", "disabled" };
  3363. stbte__draw_text(x, y+1, states[stbte__cp_index], x1-x-1, 0xffffff);
  3364. }
  3365. x = x0+24; y += 12;
  3366. for (i=3; i >= 0; --i) {
  3367. int state = 0 != (stbte__cp_state & (1 << i));
  3368. if (stbte__layerbutton(x,y, "OASD"[i], STBTE__ID2(STBTE__colorpick_id, 0,i), state,0, STBTE__clayer_button)) {
  3369. stbte__cp_state ^= (1 << i);
  3370. stbte__cp_index = stbte__state_to_index[0][0][0][stbte__cp_state];
  3371. }
  3372. x += 16;
  3373. }
  3374. x = x0+2; y += 18;
  3375. for (i=0; i < 3; ++i) {
  3376. static char *labels[] = { "Base", "Edge", "Text" };
  3377. if (stbte__button(STBTE__ctoolbar_button, labels[i], x,y,0,36, STBTE__ID2(STBTE__colorpick_id,1,i), stbte__cp_aspect==i,0))
  3378. stbte__cp_aspect = i;
  3379. x += 40;
  3380. }
  3381. y += 18;
  3382. x = x0+2;
  3383. for (i=0; i < STBTE__num_color_modes; ++i) {
  3384. if (stbte__button(STBTE__ctoolbar_button, stbte__color_names[i], x, y, 0,80, STBTE__ID2(STBTE__colorpick_id,2,i), stbte__cp_mode == i,0))
  3385. stbte__cp_mode = i;
  3386. y += 12;
  3387. }
  3388. // make the currently selected aspect flash, unless we're actively dragging color slider etc
  3389. if (stbte__ui.event == STBTE__tick) {
  3390. stbte__save = stbte__color_table[stbte__cp_mode][stbte__cp_aspect][STBTE__idle];
  3391. if ((stbte__ui.active_id & 127) != STBTE__colorpick_id) {
  3392. if ((stbte__ui.ms_time & 2047) < 200) {
  3393. stbte__color_table[stbte__cp_mode][stbte__cp_aspect][STBTE__idle] ^= 0x1f1f1f;
  3394. stbte__cp_altered = 1;
  3395. }
  3396. }
  3397. }
  3398. }
  3399. #endif
  3400. static void stbte__editor_traverse(stbte_tilemap *tm)
  3401. {
  3402. int i,j,i0,j0,i1,j1,n;
  3403. if (tm == NULL)
  3404. return;
  3405. if (stbte__ui.x0 == stbte__ui.x1 || stbte__ui.y0 == stbte__ui.y1)
  3406. return;
  3407. stbte__prepare_tileinfo(tm);
  3408. stbte__compute_panel_locations(tm); // @OPTIMIZE: we don't need to recompute this every time
  3409. if (stbte__ui.event == STBTE__paint) {
  3410. // fill screen with border
  3411. stbte__draw_rect(stbte__ui.x0, stbte__ui.y0, stbte__ui.x1, stbte__ui.y1, STBTE_COLOR_TILEMAP_BORDER);
  3412. // fill tilemap with tilemap background
  3413. stbte__draw_rect(stbte__ui.x0 - tm->scroll_x, stbte__ui.y0 - tm->scroll_y,
  3414. stbte__ui.x0 - tm->scroll_x + tm->spacing_x * tm->max_x,
  3415. stbte__ui.y0 - tm->scroll_y + tm->spacing_y * tm->max_y, STBTE_COLOR_TILEMAP_BACKGROUND);
  3416. }
  3417. // step 1: traverse all the tilemap data...
  3418. i0 = (tm->scroll_x - tm->spacing_x) / tm->spacing_x;
  3419. j0 = (tm->scroll_y - tm->spacing_y) / tm->spacing_y;
  3420. i1 = (tm->scroll_x + stbte__ui.x1 - stbte__ui.x0) / tm->spacing_x + 1;
  3421. j1 = (tm->scroll_y + stbte__ui.y1 - stbte__ui.y0) / tm->spacing_y + 1;
  3422. if (i0 < 0) i0 = 0;
  3423. if (j0 < 0) j0 = 0;
  3424. if (i1 > tm->max_x) i1 = tm->max_x;
  3425. if (j1 > tm->max_y) j1 = tm->max_y;
  3426. if (stbte__ui.event == STBTE__paint) {
  3427. // draw all of layer 0, then all of layer 1, etc, instead of old
  3428. // way which drew entire stack of each tile at once
  3429. for (n=0; n < tm->num_layers; ++n) {
  3430. for (j=j0; j < j1; ++j) {
  3431. for (i=i0; i < i1; ++i) {
  3432. int x = stbte__ui.x0 + i * tm->spacing_x - tm->scroll_x;
  3433. int y = stbte__ui.y0 + j * tm->spacing_y - tm->scroll_y;
  3434. stbte__tile_paint(tm, x, y, i, j, n);
  3435. }
  3436. }
  3437. if (n == 0 && stbte__ui.show_grid == 1) {
  3438. int x = stbte__ui.x0 + i0 * tm->spacing_x - tm->scroll_x;
  3439. int y = stbte__ui.y0 + j0 * tm->spacing_y - tm->scroll_y;
  3440. for (i=0; x < stbte__ui.x1 && i <= i1; ++i, x += tm->spacing_x)
  3441. stbte__draw_rect(x, stbte__ui.y0, x+1, stbte__ui.y1, STBTE_COLOR_GRID);
  3442. for (j=0; y < stbte__ui.y1 && j <= j1; ++j, y += tm->spacing_y)
  3443. stbte__draw_rect(stbte__ui.x0, y, stbte__ui.x1, y+1, STBTE_COLOR_GRID);
  3444. }
  3445. }
  3446. }
  3447. if (stbte__ui.event == STBTE__paint) {
  3448. // draw grid on top of everything except UI
  3449. if (stbte__ui.show_grid == 2) {
  3450. int x = stbte__ui.x0 + i0 * tm->spacing_x - tm->scroll_x;
  3451. int y = stbte__ui.y0 + j0 * tm->spacing_y - tm->scroll_y;
  3452. for (i=0; x < stbte__ui.x1 && i <= i1; ++i, x += tm->spacing_x)
  3453. stbte__draw_rect(x, stbte__ui.y0, x+1, stbte__ui.y1, STBTE_COLOR_GRID);
  3454. for (j=0; y < stbte__ui.y1 && j <= j1; ++j, y += tm->spacing_y)
  3455. stbte__draw_rect(stbte__ui.x0, y, stbte__ui.x1, y+1, STBTE_COLOR_GRID);
  3456. }
  3457. }
  3458. for (j=j0; j < j1; ++j) {
  3459. for (i=i0; i < i1; ++i) {
  3460. int x = stbte__ui.x0 + i * tm->spacing_x - tm->scroll_x;
  3461. int y = stbte__ui.y0 + j * tm->spacing_y - tm->scroll_y;
  3462. stbte__tile(tm, x, y, i, j);
  3463. }
  3464. }
  3465. if (stbte__ui.event == STBTE__paint) {
  3466. // draw the selection border
  3467. if (stbte__ui.has_selection) {
  3468. int x0,y0,x1,y1;
  3469. x0 = stbte__ui.x0 + (stbte__ui.select_x0 ) * tm->spacing_x - tm->scroll_x;
  3470. y0 = stbte__ui.y0 + (stbte__ui.select_y0 ) * tm->spacing_y - tm->scroll_y;
  3471. x1 = stbte__ui.x0 + (stbte__ui.select_x1 + 1) * tm->spacing_x - tm->scroll_x + 1;
  3472. y1 = stbte__ui.y0 + (stbte__ui.select_y1 + 1) * tm->spacing_y - tm->scroll_y + 1;
  3473. stbte__draw_frame(x0,y0,x1,y1, (stbte__ui.ms_time & 256 ? STBTE_COLOR_SELECTION_OUTLINE1 : STBTE_COLOR_SELECTION_OUTLINE2));
  3474. }
  3475. stbte__flush_delay(); // draw a dynamic link on top of the queued links
  3476. #ifdef STBTE_ALLOW_LINK
  3477. if (stbte__ui.linking && STBTE__IS_MAP_HOT()) {
  3478. int x0,y0,x1,y1;
  3479. int color;
  3480. int ex = ((stbte__ui.hot_id >> 19) & 4095);
  3481. int ey = ((stbte__ui.hot_id >> 7) & 4095);
  3482. x0 = stbte__ui.x0 + (stbte__ui.sx ) * tm->spacing_x - tm->scroll_x + (tm->spacing_x>>1)+1;
  3483. y0 = stbte__ui.y0 + (stbte__ui.sy ) * tm->spacing_y - tm->scroll_y + (tm->spacing_y>>1)+1;
  3484. x1 = stbte__ui.x0 + (ex ) * tm->spacing_x - tm->scroll_x + (tm->spacing_x>>1)-1;
  3485. y1 = stbte__ui.y0 + (ey ) * tm->spacing_y - tm->scroll_y + (tm->spacing_y>>1)-1;
  3486. if (STBTE_ALLOW_LINK(tm->data[stbte__ui.sy][stbte__ui.sx], tm->props[stbte__ui.sy][stbte__ui.sx], tm->data[ey][ex], tm->props[ey][ex]))
  3487. color = STBTE_LINK_COLOR_DRAWING;
  3488. else
  3489. color = STBTE_LINK_COLOR_DISALLOWED;
  3490. stbte__draw_link(x0,y0,x1,y1, color);
  3491. }
  3492. #endif
  3493. }
  3494. stbte__flush_delay();
  3495. // step 2: traverse the panels
  3496. for (i=0; i < STBTE__num_panel; ++i) {
  3497. stbte__panel *p = &stbte__ui.panel[i];
  3498. if (stbte__ui.event == STBTE__paint) {
  3499. stbte__draw_box(p->x0,p->y0,p->x0+p->width,p->y0+p->height, STBTE__cpanel, STBTE__idle);
  3500. }
  3501. // obscure tilemap data underneath panel
  3502. stbte__hittest(p->x0,p->y0,p->x0+p->width,p->y0+p->height, STBTE__ID2(STBTE__panel, i, 0));
  3503. switch (i) {
  3504. case STBTE__panel_toolbar:
  3505. if (stbte__ui.event == STBTE__paint)
  3506. stbte__draw_rect(p->x0,p->y0,p->x0+p->width,p->y0+p->height, stbte__color_table[STBTE__ctoolbar][STBTE__base][STBTE__idle]);
  3507. stbte__toolbar(tm,p->x0,p->y0,p->width,p->height);
  3508. break;
  3509. case STBTE__panel_info:
  3510. stbte__info(tm,p->x0,p->y0,p->width,p->height);
  3511. break;
  3512. case STBTE__panel_layers:
  3513. stbte__layers(tm,p->x0,p->y0,p->width,p->height);
  3514. break;
  3515. case STBTE__panel_categories:
  3516. stbte__categories(tm,p->x0,p->y0,p->width,p->height);
  3517. break;
  3518. case STBTE__panel_colorpick:
  3519. #ifdef STBTE__COLORPICKER
  3520. stbte__colorpicker(p->x0,p->y0,p->width,p->height);
  3521. #endif
  3522. break;
  3523. case STBTE__panel_tiles:
  3524. // erase boundary between categories and tiles if they're on same side
  3525. if (stbte__ui.event == STBTE__paint && p->side == stbte__ui.panel[STBTE__panel_categories].side)
  3526. stbte__draw_rect(p->x0+1,p->y0-1,p->x0+p->width-1,p->y0+1, stbte__color_table[STBTE__cpanel][STBTE__base][STBTE__idle]);
  3527. stbte__palette_of_tiles(tm,p->x0,p->y0,p->width,p->height);
  3528. break;
  3529. case STBTE__panel_props:
  3530. stbte__props_panel(tm,p->x0,p->y0,p->width,p->height);
  3531. break;
  3532. }
  3533. // draw the panel side selectors
  3534. for (j=0; j < 2; ++j) {
  3535. int result;
  3536. if (i == STBTE__panel_toolbar) continue;
  3537. result = stbte__microbutton(p->x0+p->width - 1 - 2*4 + 4*j,p->y0+2,3, STBTE__ID2(STBTE__panel, i, j+1), STBTE__cpanel_sider+j);
  3538. if (result) {
  3539. switch (j) {
  3540. case 0: p->side = result > 0 ? STBTE__side_left : STBTE__side_right; break;
  3541. case 1: p->delta_height += result; break;
  3542. }
  3543. }
  3544. }
  3545. }
  3546. if (stbte__ui.panel[STBTE__panel_categories].delta_height < -5) stbte__ui.panel[STBTE__panel_categories].delta_height = -5;
  3547. if (stbte__ui.panel[STBTE__panel_layers ].delta_height < -5) stbte__ui.panel[STBTE__panel_layers ].delta_height = -5;
  3548. // step 3: traverse the regions to place expander controls on them
  3549. for (i=0; i < 2; ++i) {
  3550. if (stbte__region[i].active) {
  3551. int x = stbte__region[i].x;
  3552. int width;
  3553. if (i == STBTE__side_left)
  3554. width = stbte__ui.left_width , x += stbte__region[i].width + 1;
  3555. else
  3556. width = -stbte__ui.right_width, x -= 6;
  3557. if (stbte__microbutton_dragger(x, stbte__region[i].y+2, 5, STBTE__ID(STBTE__region,i), &width)) {
  3558. // if non-0, it is expanding, so retract it
  3559. if (stbte__region[i].retracted == 0.0)
  3560. stbte__region[i].retracted = 0.01f;
  3561. else
  3562. stbte__region[i].retracted = 0.0;
  3563. }
  3564. if (i == STBTE__side_left)
  3565. stbte__ui.left_width = width;
  3566. else
  3567. stbte__ui.right_width = -width;
  3568. if (stbte__ui.event == STBTE__tick) {
  3569. if (stbte__region[i].retracted && stbte__region[i].retracted < 1.0f) {
  3570. stbte__region[i].retracted += stbte__ui.dt*4;
  3571. if (stbte__region[i].retracted > 1)
  3572. stbte__region[i].retracted = 1;
  3573. }
  3574. }
  3575. }
  3576. }
  3577. if (stbte__ui.event == STBTE__paint && stbte__ui.alert_msg) {
  3578. int w = stbte__text_width(stbte__ui.alert_msg);
  3579. int x = (stbte__ui.x0+stbte__ui.x1)/2;
  3580. int y = (stbte__ui.y0+stbte__ui.y1)*5/6;
  3581. stbte__draw_rect (x-w/2-4,y-8, x+w/2+4,y+8, 0x604020);
  3582. stbte__draw_frame(x-w/2-4,y-8, x+w/2+4,y+8, 0x906030);
  3583. stbte__draw_text (x-w/2,y-4, stbte__ui.alert_msg, w+1, 0xff8040);
  3584. }
  3585. #ifdef STBTE_SHOW_CURSOR
  3586. if (stbte__ui.event == STBTE__paint)
  3587. stbte__draw_bitmap(stbte__ui.mx, stbte__ui.my, stbte__get_char_width(26), stbte__get_char_bitmap(26), 0xe0e0e0);
  3588. #endif
  3589. if (stbte__ui.event == STBTE__tick && stbte__ui.alert_msg) {
  3590. stbte__ui.alert_timer -= stbte__ui.dt;
  3591. if (stbte__ui.alert_timer < 0) {
  3592. stbte__ui.alert_timer = 0;
  3593. stbte__ui.alert_msg = 0;
  3594. }
  3595. }
  3596. if (stbte__ui.event == STBTE__paint) {
  3597. stbte__color_table[stbte__cp_mode][stbte__cp_aspect][STBTE__idle] = stbte__save;
  3598. stbte__cp_altered = 0;
  3599. }
  3600. }
  3601. static void stbte__do_event(stbte_tilemap *tm)
  3602. {
  3603. stbte__ui.next_hot_id = 0;
  3604. stbte__editor_traverse(tm);
  3605. stbte__ui.hot_id = stbte__ui.next_hot_id;
  3606. // automatically cancel on mouse-up in case the object that triggered it
  3607. // doesn't exist anymore
  3608. if (stbte__ui.active_id) {
  3609. if (stbte__ui.event == STBTE__leftup || stbte__ui.event == STBTE__rightup) {
  3610. if (!stbte__ui.pasting) {
  3611. stbte__activate(0);
  3612. if (stbte__ui.undoing)
  3613. stbte__end_undo(tm);
  3614. stbte__ui.scrolling = 0;
  3615. stbte__ui.dragging = 0;
  3616. stbte__ui.linking = 0;
  3617. }
  3618. }
  3619. }
  3620. // we could do this stuff in the widgets directly, but it would keep recomputing
  3621. // the same thing on every tile, which seems dumb.
  3622. if (stbte__ui.pasting) {
  3623. if (STBTE__IS_MAP_HOT()) {
  3624. // compute pasting location based on last hot
  3625. stbte__ui.paste_x = ((stbte__ui.hot_id >> 19) & 4095) - (stbte__ui.copy_width >> 1);
  3626. stbte__ui.paste_y = ((stbte__ui.hot_id >> 7) & 4095) - (stbte__ui.copy_height >> 1);
  3627. }
  3628. }
  3629. if (stbte__ui.dragging) {
  3630. if (STBTE__IS_MAP_HOT()) {
  3631. stbte__ui.drag_dest_x = ((stbte__ui.hot_id >> 19) & 4095) - stbte__ui.drag_offx;
  3632. stbte__ui.drag_dest_y = ((stbte__ui.hot_id >> 7) & 4095) - stbte__ui.drag_offy;
  3633. }
  3634. }
  3635. }
  3636. static void stbte__set_event(int event, int x, int y)
  3637. {
  3638. stbte__ui.event = event;
  3639. stbte__ui.mx = x;
  3640. stbte__ui.my = y;
  3641. stbte__ui.dx = x - stbte__ui.last_mouse_x;
  3642. stbte__ui.dy = y - stbte__ui.last_mouse_y;
  3643. stbte__ui.last_mouse_x = x;
  3644. stbte__ui.last_mouse_y = y;
  3645. stbte__ui.accum_x += stbte__ui.dx;
  3646. stbte__ui.accum_y += stbte__ui.dy;
  3647. }
  3648. void stbte_draw(stbte_tilemap *tm)
  3649. {
  3650. stbte__ui.event = STBTE__paint;
  3651. stbte__editor_traverse(tm);
  3652. }
  3653. void stbte_mouse_move(stbte_tilemap *tm, int x, int y, int shifted, int scrollkey)
  3654. {
  3655. stbte__set_event(STBTE__mousemove, x,y);
  3656. stbte__ui.shift = shifted;
  3657. stbte__ui.scrollkey = scrollkey;
  3658. stbte__do_event(tm);
  3659. }
  3660. void stbte_mouse_button(stbte_tilemap *tm, int x, int y, int right, int down, int shifted, int scrollkey)
  3661. {
  3662. static int events[2][2] = { { STBTE__leftup , STBTE__leftdown },
  3663. { STBTE__rightup, STBTE__rightdown } };
  3664. stbte__set_event(events[right][down], x,y);
  3665. stbte__ui.shift = shifted;
  3666. stbte__ui.scrollkey = scrollkey;
  3667. stbte__do_event(tm);
  3668. }
  3669. void stbte_mouse_wheel(stbte_tilemap *tm, int x, int y, int vscroll)
  3670. {
  3671. // not implemented yet -- need different way of hittesting
  3672. }
  3673. void stbte_action(stbte_tilemap *tm, enum stbte_action act)
  3674. {
  3675. switch (act) {
  3676. case STBTE_tool_select: stbte__ui.tool = STBTE__tool_select; break;
  3677. case STBTE_tool_brush: stbte__ui.tool = STBTE__tool_brush; break;
  3678. case STBTE_tool_erase: stbte__ui.tool = STBTE__tool_erase; break;
  3679. case STBTE_tool_rectangle: stbte__ui.tool = STBTE__tool_rect; break;
  3680. case STBTE_tool_eyedropper: stbte__ui.tool = STBTE__tool_eyedrop; break;
  3681. case STBTE_tool_link: stbte__ui.tool = STBTE__tool_link; break;
  3682. case STBTE_act_toggle_grid: stbte__ui.show_grid = (stbte__ui.show_grid+1) % 3; break;
  3683. case STBTE_act_toggle_links: stbte__ui.show_links ^= 1; break;
  3684. case STBTE_act_undo: stbte__undo(tm); break;
  3685. case STBTE_act_redo: stbte__redo(tm); break;
  3686. case STBTE_act_cut: stbte__copy_cut(tm, 1); break;
  3687. case STBTE_act_copy: stbte__copy_cut(tm, 0); break;
  3688. case STBTE_act_paste: stbte__start_paste(tm); break;
  3689. case STBTE_scroll_left: tm->scroll_x -= tm->spacing_x; break;
  3690. case STBTE_scroll_right: tm->scroll_x += tm->spacing_x; break;
  3691. case STBTE_scroll_up: tm->scroll_y -= tm->spacing_y; break;
  3692. case STBTE_scroll_down: tm->scroll_y += tm->spacing_y; break;
  3693. }
  3694. }
  3695. void stbte_tick(stbte_tilemap *tm, float dt)
  3696. {
  3697. stbte__ui.event = STBTE__tick;
  3698. stbte__ui.dt = dt;
  3699. stbte__do_event(tm);
  3700. stbte__ui.ms_time += (int) (dt * 1024) + 1; // make sure if time is superfast it always updates a little
  3701. }
  3702. void stbte_mouse_sdl(stbte_tilemap *tm, const void *sdl_event, float xs, float ys, int xo, int yo)
  3703. {
  3704. #ifdef _SDL_H
  3705. SDL_Event *event = (SDL_Event *) sdl_event;
  3706. SDL_Keymod km = SDL_GetModState();
  3707. int shift = (km & KMOD_LCTRL) || (km & KMOD_RCTRL);
  3708. int scrollkey = 0 != SDL_GetKeyboardState(NULL)[SDL_SCANCODE_SPACE];
  3709. switch (event->type) {
  3710. case SDL_MOUSEMOTION:
  3711. stbte_mouse_move(tm, (int) (xs*event->motion.x+xo), (int) (ys*event->motion.y+yo), shift, scrollkey);
  3712. break;
  3713. case SDL_MOUSEBUTTONUP:
  3714. stbte_mouse_button(tm, (int) (xs*event->button.x+xo), (int) (ys*event->button.y+yo), event->button.button != SDL_BUTTON_LEFT, 0, shift, scrollkey);
  3715. break;
  3716. case SDL_MOUSEBUTTONDOWN:
  3717. stbte_mouse_button(tm, (int) (xs*event->button.x+xo), (int) (ys*event->button.y+yo), event->button.button != SDL_BUTTON_LEFT, 1, shift, scrollkey);
  3718. break;
  3719. case SDL_MOUSEWHEEL:
  3720. stbte_mouse_wheel(tm, stbte__ui.mx, stbte__ui.my, event->wheel.y);
  3721. break;
  3722. }
  3723. #else
  3724. STBTE__NOTUSED(tm);
  3725. STBTE__NOTUSED(sdl_event);
  3726. STBTE__NOTUSED(xs);
  3727. STBTE__NOTUSED(ys);
  3728. STBTE__NOTUSED(xo);
  3729. STBTE__NOTUSED(yo);
  3730. #endif
  3731. }
  3732. #endif // STB_TILEMAP_EDITOR_IMPLEMENTATION
  3733. /*
  3734. ------------------------------------------------------------------------------
  3735. This software is available under 2 licenses -- choose whichever you prefer.
  3736. ------------------------------------------------------------------------------
  3737. ALTERNATIVE A - MIT License
  3738. Copyright (c) 2017 Sean Barrett
  3739. Permission is hereby granted, free of charge, to any person obtaining a copy of
  3740. this software and associated documentation files (the "Software"), to deal in
  3741. the Software without restriction, including without limitation the rights to
  3742. use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  3743. of the Software, and to permit persons to whom the Software is furnished to do
  3744. so, subject to the following conditions:
  3745. The above copyright notice and this permission notice shall be included in all
  3746. copies or substantial portions of the Software.
  3747. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  3748. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  3749. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  3750. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  3751. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  3752. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  3753. SOFTWARE.
  3754. ------------------------------------------------------------------------------
  3755. ALTERNATIVE B - Public Domain (www.unlicense.org)
  3756. This is free and unencumbered software released into the public domain.
  3757. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
  3758. software, either in source code form or as a compiled binary, for any purpose,
  3759. commercial or non-commercial, and by any means.
  3760. In jurisdictions that recognize copyright laws, the author or authors of this
  3761. software dedicate any and all copyright interest in the software to the public
  3762. domain. We make this dedication for the benefit of the public at large and to
  3763. the detriment of our heirs and successors. We intend this dedication to be an
  3764. overt act of relinquishment in perpetuity of all present and future rights to
  3765. this software under copyright law.
  3766. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  3767. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  3768. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  3769. AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  3770. ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  3771. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  3772. ------------------------------------------------------------------------------
  3773. */