{"id":20164530,"url":"https://github.com/rogual/libtweak","last_synced_at":"2025-04-10T00:51:37.436Z","repository":{"id":149497029,"uuid":"69191996","full_name":"rogual/libtweak","owner":"rogual","description":"Runtime-editable variables for C++","archived":false,"fork":false,"pushed_at":"2024-01-16T15:42:46.000Z","size":18,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-10T00:51:32.297Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rogual.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-09-25T21:37:02.000Z","updated_at":"2024-01-16T15:41:38.000Z","dependencies_parsed_at":"2024-01-16T18:37:23.704Z","dependency_job_id":"984104ba-7474-4db1-ac93-a0f20bff7d72","html_url":"https://github.com/rogual/libtweak","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogual%2Flibtweak","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogual%2Flibtweak/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogual%2Flibtweak/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogual%2Flibtweak/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rogual","download_url":"https://codeload.github.com/rogual/libtweak/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248137997,"owners_count":21053775,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T00:34:59.951Z","updated_at":"2025-04-10T00:51:37.409Z","avatar_url":"https://github.com/rogual.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"#+TITLE: libtweak\n\n* Abstract\n\n=libtweak= lets you define parameters that can be adjusted while your\nC++ program is running. It is particularly suited to realtime\napplications like games, where you want instant feedback when making\nchanges.\n\n- Supported languages: C++11\n- Supported platforms\n  - Full Support: Linux, Mac\n  - Production mode only: All other platfoms\n- Extra Requirements: Python 3\n\n* Compiling\n\nRun =make=. Find =libtweak.a= in =build/= and link your program with\nit. Add libtweak's =include= directory to your header file search path.\n\nThe examples below will also assume that libtweak's =bin= directory is\non your =PATH=.\n\n* Usage\n\nDeclare tweakable parameters in your program:\n\n#+BEGIN_SRC c++\n\n#include \u003ctweak.h\u003e\n\nTWEAK(float, sausage_length)\nTWEAK(float, temperature)\n\n#+END_SRC\n\nUse them like ordinary variables:\n\n#+BEGIN_SRC c++\n\nint main()\n{\n  tweak::init();\n  // ...\n}\n\nvoid do_frame()\n{\n  tweak::process();\n  printf(\"The sausages are %fcm long and %f°C!\", sausage_length, temperature);\n}\n\n#+END_SRC\n\nWhile your program is running, adjust parameters using the GUI:\n\n#+BEGIN_SRC sh\ntweak\n#+END_SRC\n\n* Production Mode\n\nWhen distributing your program, you can build a version where =libtweak=\nis not linked in, and your parameters compile to ordinary constants.\n\nTo do this:\n\n1. Generate a header file with the constants baked in:\n\n    #+BEGIN_SRC sh\n\n    tweakc \u003e myconstants.h\n\n    #+END_SRC\n\n2. Include this file before =\u003ctweak.h\u003e=.\n\n3. Define =TWEAK_BAKE= before including =\u003ctweak.h\u003e=. This tells\n   =tweak.h= to use the constants from your generated header file.\n\n4. No need to link to =libtweak.a=\n\nFor example:\n\n#+BEGIN_SRC c++\n\n#ifdef MY_PRODUCTION_FLAG\n#  include \"myconstants.h\"\n#  define TWEAK_BAKE\n#endif\n\n#include \u003ctweak.h\u003e\n\n#+END_SRC\n\n\n* Test Program\n\nAs well as compiling =libtweak= itself, =make= will also compile a test\nprogram called =test=. This program will define some parameters and\ncontinuously output them to the terminal.\n\nTo try out libtweak, run this program and, while it's running, use\n=tweak= to adjust its parameters and see them update live.\n\n\n* Internals\n\nWhen your program calls =tweak::init=, a file named =Tweakfile= is\nwritten to the working directory, detailing the available parameters\nand their values. A Unix FIFO called =Tweakfifo= is also created.\n\nThe next time your program starts, values are read from the existing\n=Tweakfile=.\n\nAdditionally, when you call =tweak::process=, commands are read from\nthe =Tweakfifo= and used to update parameter values.\n\nTools that update values do two things:\n1. Update the =Tweakfile= so the program will see the value when it is\n   next started.\n\n2. Write a value change command to the =Tweakfifo= so the program can\n   instantly update that value on its next call to =tweak::process=.\n\nThe =tweakc= tool simply reads parameter values from the =Tweakfile= and\nwrites them out in the form of a C++ header.\n\n\n* API Reference\n\n** =tweak.h=\n\n*** =#define TWEAK(type, name)=\n\nDefine a tweakable parameter. If =TWEAK_BAKE= is defined this simply defines\na constant. Otherwise, it defines a const reference to a value, which\nmay change when you call =tweak::process=.\n\n*** =#define EXTERN_TWEAK(type, name)=\n\nUse this to refer to a tweakable parameter defined in another translation\nunit.\n\n*** =void tweak::init()=\n\nSets all parameters to their initial values. Reads the =Tweakfile= or\ncreates one if not present. Sets up the mechanism for live updating\n(=Tweakfifo=).\n\nYou'll usually want to call this early in your program's startup, or\nat least before you call =tweak::process= for the first time.\n\nIf =TWEAK_BAKE= is defined, =tweak::init= is a no-op and your compiler\nwill optimize out any calls to it.\n\n*** =void tweak::process()=\n\nCheck for new live-update messages and update any parameters. You'll\nwant to call this frequently during execution of your program.\n\nIn games, you can afford to call this every frame; if there's nothing\nto update it is very cheap.\n\nIf =TWEAK_BAKE= is defined, =tweak::process= is a no-op and your compiler\nwill optimize out any calls to it.\n\n* Tools Reference\n\nAll of these tools operate on the =Tweakfile= and =Tweakfifo= in the\nworking directory.\n\n** =tweak=\n\nStarts a GUI for tweaking the program's parameters.\n\n** =tweakc=\n\nWrites the current values of all parameters, formatted as a C++ header\nfile, to standard output. Use this file in conjunction with the\n=TWEAK_BAKE= option to optimize out all of =libtweak= for production\nbuilds.\n\n* File Format\n\nBoth =Tweakfile= and =Tweakfifo= have the same format: a list of lines\nwhere each line is a command name followed by a space-separated list\nof arguments. Possible commands are:\n\n** =type NAME TYPE=\n\nSpecifies the type of a parameter. Every parameter must have a type. By\ndefault, the available types are =int=, =float=, =string= and =bool=. You\ncan also add your own types; see [[Extending][Extending]].\n\n** =set NAME VALUE=\n\nSpecifies a value for a paramater. See [[Value Format][Value Format]].\n\n** =range NAME MIN MAX=\n\nSpecifies the range for a parameter. Only applies to =int= and =float=\nparameters. This is only used by the GUI tool to display an\nappropriate GUI; =libtweak= itself ignores =range= commands.\n\n* Value Format\n\nValues are converted to and from strings for storage in =Tweakfile= and\ntransmission through =Tweakfifo=. How a value is converted to and from a\nstring depends on its type:\n\n** =int=, =float=\n\nThese are read by the C++ formatted extraction operators and so are\ndependent on your locale.\n\n** =bool=\n\n=0= or =1=.\n\n** =string=\n\nStrings begin with a literal =$= character, and end at the end of the\nline. They may contain any characters except newlines.\n\n(This is a strange format, but it's very easy to parse and leaves the door\nopen to implement proper delimited strings later.)\n\n* Extending\n\nYou can add support for your own custom types to =libtweak=. To do\nso, you need to:\n\n1. Specialize the =type_name= struct so =libtweak= knows what your\n   type is called:\n\n    #+BEGIN_SRC C++\n\n    namespace tweak\n    {\n        template\u003c\u003e struct type_name\u003cMyType\u003e\n        {\n            static std::string get() { return \"mytype\"; }\n        }\n    }\n\n    #+END_SRC\n\n    This is the name that will be used in =type= commands in the =Tweakfile=.\n\n2. If necessary, specialize the =io= struct so =libtweak= knows how to load\n   and save your type. If you don't do this, the standard =iostream= ‘\u003c\u003c’ and\n   ‘\u003e\u003e’ operators will be used. You can overload these instead of specializing\n   =io=.\n\n   #+BEGIN_SRC C++\n\n   namespace tweak\n   {\n     template\u003c\u003e struct io\u003cMyType\u003e\n     {\n       static void load(MyType \u0026value, std::istream \u0026is) { /* ... */ }\n       static void save(const MyType \u0026value, std::ostream \u0026os) { /* ... */ }\n     }\n   }\n\n   #+END_SRC\n\nThat's enough for =libtweak= to handle your type. You can now use it in\n=TWEAK= declarations.\n\nHowever, the tools =tweak= and =tweakc= will not yet be able to\nintelligently handle your type.\n\n** =tweak=, =tweakc= and custom types\n\nBy default, =tweak= will show a text entry field for any type it doesn't\nknow about, allowing you to modify the raw textual representation of the\nparameter's value (as used by =load= and =save=).\n\n=tweakc= will take a shot at emitting C++ code for your type, but don't hold\nyour breath.\n\nYou can override these default behaviours by putting some code in a\n=tweak_ext.py= file alongside your =Tweakfile=:\n\n#+BEGIN_SRC python\n\nimport tweak\n\nclass MyWidget(tweak.Widget):\n    \"...\"\n\nclass MyType(tweak.Param):\n    widget = MyWidget\n\n    def cname(self):\n        return \"c++ type name here\"\n\n    def cvalue(self):\n        return \"c++ value of self.value here\"\n\ntweak.types['mytypename'] = MyType\n\n#+END_SRC\n\nFor guidance on implementing your own type and widget classes, see the existing\nclasses in =bin/tweak=.\n\n* Further Work\n\n** Windows Support\n\nThis library uses FIFOs which don't exist on Windows. The code is\norganized for easy porting, and full Windows support shouldn't be too much\nwork.\n\nIn production mode (with =TWEAK_BAKE= defined), Windows is supported,\nas =libtweak= becomes a trivial header-only library in that case. So,\nit's still possible to develop your program on Unix and support\nWindows as a release target.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frogual%2Flibtweak","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frogual%2Flibtweak","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frogual%2Flibtweak/lists"}