stb_tilemap_editor.h 142 KB

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