| @@ -68,6 +68,18 @@ LOL_CFLAGS="$LOL_CFLAGS -I\$(lol_srcdir)/src/3rdparty/mingw-std-threads" | |||||
| LOL_CFLAGS="$LOL_CFLAGS -I\$(lol_srcdir)/src/3rdparty/pegtl" | LOL_CFLAGS="$LOL_CFLAGS -I\$(lol_srcdir)/src/3rdparty/pegtl" | ||||
| LOL_CFLAGS="$LOL_CFLAGS -I\$(lol_srcdir)/src/3rdparty/imgui" | LOL_CFLAGS="$LOL_CFLAGS -I\$(lol_srcdir)/src/3rdparty/imgui" | ||||
| dnl Use system-provided getopt_long? | |||||
| ac_cv_have_getopt_long="no" | |||||
| AC_CHECK_HEADERS(getopt.h unistd.h) | |||||
| AC_CHECK_FUNCS(getopt_long, | |||||
| [ac_cv_have_getopt_long="yes"], | |||||
| [AC_CHECK_LIB(gnugetopt, getopt_long, | |||||
| [ac_cv_have_getopt_long="yes" | |||||
| LIBS="${LIBS} -lgnugetopt"])]) | |||||
| if test "$ac_cv_have_getopt_long" != "no"; then | |||||
| AC_DEFINE(HAVE_GETOPT_LONG, 1, Define to 1 if you have the ‘getopt_long’ function.) | |||||
| fi | |||||
| dnl Use NativeClient? | dnl Use NativeClient? | ||||
| ac_cv_my_have_nacl="no" | ac_cv_my_have_nacl="no" | ||||
| @@ -47,8 +47,8 @@ liblol_core_headers = \ | |||||
| lol/algorithm/sort.h lol/algorithm/portal.h lol/algorithm/aabb_tree.h \ | lol/algorithm/sort.h lol/algorithm/portal.h lol/algorithm/aabb_tree.h \ | ||||
| \ | \ | ||||
| lol/sys/all.h \ | lol/sys/all.h \ | ||||
| lol/sys/init.h lol/sys/file.h lol/sys/thread.h lol/sys/threadtypes.h \ | |||||
| lol/sys/timer.h \ | |||||
| lol/sys/init.h lol/sys/file.h lol/sys/getopt.h lol/sys/thread.h \ | |||||
| lol/sys/threadtypes.h lol/sys/timer.h \ | |||||
| \ | \ | ||||
| lol/image/all.h \ | lol/image/all.h \ | ||||
| lol/image/pixel.h lol/image/color.h lol/image/image.h lol/image/movie.h \ | lol/image/pixel.h lol/image/color.h lol/image/image.h lol/image/movie.h \ | ||||
| @@ -108,7 +108,7 @@ liblol_core_sources = \ | |||||
| mesh/primitivemesh.cpp mesh/primitivemesh.h \ | mesh/primitivemesh.cpp mesh/primitivemesh.h \ | ||||
| \ | \ | ||||
| sys/init.cpp sys/timer.cpp sys/file.cpp sys/hacks.cpp \ | sys/init.cpp sys/timer.cpp sys/file.cpp sys/hacks.cpp \ | ||||
| sys/thread.cpp sys/threadtypes.cpp \ | |||||
| sys/thread.cpp sys/threadtypes.cpp sys/getopt.cpp \ | |||||
| \ | \ | ||||
| image/image.cpp image/image-private.h image/kernel.cpp image/pixel.cpp \ | image/image.cpp image/image-private.h image/kernel.cpp image/pixel.cpp \ | ||||
| image/crop.cpp image/resample.cpp image/noise.cpp image/combine.cpp \ | image/crop.cpp image/resample.cpp image/noise.cpp image/combine.cpp \ | ||||
| @@ -202,6 +202,7 @@ | |||||
| <ClCompile Include="scene.cpp" /> | <ClCompile Include="scene.cpp" /> | ||||
| <ClCompile Include="sprite.cpp" /> | <ClCompile Include="sprite.cpp" /> | ||||
| <ClCompile Include="sys\file.cpp" /> | <ClCompile Include="sys\file.cpp" /> | ||||
| <ClCompile Include="sys\getopt.cpp" /> | |||||
| <ClCompile Include="sys\hacks.cpp" /> | <ClCompile Include="sys\hacks.cpp" /> | ||||
| <ClCompile Include="sys\init.cpp" /> | <ClCompile Include="sys\init.cpp" /> | ||||
| <ClCompile Include="sys\thread.cpp" /> | <ClCompile Include="sys\thread.cpp" /> | ||||
| @@ -301,6 +302,7 @@ | |||||
| <ClInclude Include="lol\public.h" /> | <ClInclude Include="lol\public.h" /> | ||||
| <ClInclude Include="lol\sys\all.h" /> | <ClInclude Include="lol\sys\all.h" /> | ||||
| <ClInclude Include="lol\sys\file.h" /> | <ClInclude Include="lol\sys\file.h" /> | ||||
| <ClInclude Include="lol\sys\getopt.h" /> | |||||
| <ClInclude Include="lol\sys\init.h" /> | <ClInclude Include="lol\sys\init.h" /> | ||||
| <ClInclude Include="lol\sys\thread.h" /> | <ClInclude Include="lol\sys\thread.h" /> | ||||
| <ClInclude Include="lol\sys\threadtypes.h" /> | <ClInclude Include="lol\sys\threadtypes.h" /> | ||||
| @@ -291,6 +291,9 @@ | |||||
| <ClCompile Include="sys\file.cpp"> | <ClCompile Include="sys\file.cpp"> | ||||
| <Filter>sys</Filter> | <Filter>sys</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| <ClCompile Include="sys\getopt.cpp"> | |||||
| <Filter>sys</Filter> | |||||
| </ClCompile> | |||||
| <ClCompile Include="sys\timer.cpp"> | <ClCompile Include="sys\timer.cpp"> | ||||
| <Filter>sys</Filter> | <Filter>sys</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| @@ -652,6 +655,9 @@ | |||||
| <ClInclude Include="lol\sys\file.h"> | <ClInclude Include="lol\sys\file.h"> | ||||
| <Filter>lol\sys</Filter> | <Filter>lol\sys</Filter> | ||||
| </ClInclude> | </ClInclude> | ||||
| <ClInclude Include="lol\sys\getopt.h"> | |||||
| <Filter>lol\sys</Filter> | |||||
| </ClInclude> | |||||
| <ClInclude Include="lol\gpu\framebuffer.h"> | <ClInclude Include="lol\gpu\framebuffer.h"> | ||||
| <Filter>lol\gpu</Filter> | <Filter>lol\gpu</Filter> | ||||
| </ClInclude> | </ClInclude> | ||||
| @@ -1,11 +1,13 @@ | |||||
| // | // | ||||
| // Lol Engine | |||||
| // Lol Engine | |||||
| // | // | ||||
| // Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net> | |||||
| // This program is free software; you can redistribute it and/or | |||||
| // modify it under the terms of the Do What The Fuck You Want To | |||||
| // Public License, Version 2, as published by Sam Hocevar. See | |||||
| // http://www.wtfpl.net/ for more details. | |||||
| // Copyright © 2010—2016 Sam Hocevar <sam@hocevar.net> | |||||
| // | |||||
| // Lol Engine is free software. It comes without any warranty, to | |||||
| // the extent permitted by applicable law. You can redistribute it | |||||
| // and/or modify it under the terms of the Do What the Fuck You Want | |||||
| // to Public License, Version 2, as published by the WTFPL Task Force. | |||||
| // See http://www.wtfpl.net/ for more details. | |||||
| // | // | ||||
| #pragma once | #pragma once | ||||
| @@ -13,6 +15,7 @@ | |||||
| #include <lol/sys/timer.h> | #include <lol/sys/timer.h> | ||||
| #include <lol/sys/thread.h> | #include <lol/sys/thread.h> | ||||
| #include <lol/sys/threadtypes.h> | #include <lol/sys/threadtypes.h> | ||||
| #include <lol/sys/getopt.h> | |||||
| #include <lol/sys/init.h> | #include <lol/sys/init.h> | ||||
| #include <lol/sys/file.h> | #include <lol/sys/file.h> | ||||
| @@ -0,0 +1,41 @@ | |||||
| // | |||||
| // Lol Engine | |||||
| // | |||||
| // Copyright © 2002—2016 Sam Hocevar <sam@hocevar.net> | |||||
| // | |||||
| // Lol Engine is free software. It comes without any warranty, to | |||||
| // the extent permitted by applicable law. You can redistribute it | |||||
| // and/or modify it under the terms of the Do What the Fuck You Want | |||||
| // to Public License, Version 2, as published by the WTFPL Task Force. | |||||
| // See http://www.wtfpl.net/ for more details. | |||||
| // | |||||
| #pragma once | |||||
| // | |||||
| // The getopt functions | |||||
| // -------------------- | |||||
| // | |||||
| namespace lol | |||||
| { | |||||
| class getopt | |||||
| { | |||||
| public: | |||||
| getopt(int argc, char ** _argv); | |||||
| getopt(int argc, char * const * _argv); | |||||
| ~getopt(); | |||||
| void add_arg(int short_opt, char const *long_opt, bool has_arg); | |||||
| int parse(); | |||||
| int index; | |||||
| char *arg; | |||||
| private: | |||||
| std::unique_ptr<struct getopt_private> m_private; | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,195 @@ | |||||
| // | |||||
| // Lol Engine | |||||
| // | |||||
| // Copyright © 2002—2016 Sam Hocevar <sam@hocevar.net> | |||||
| // | |||||
| // Lol Engine is free software. It comes without any warranty, to | |||||
| // the extent permitted by applicable law. You can redistribute it | |||||
| // and/or modify it under the terms of the Do What the Fuck You Want | |||||
| // to Public License, Version 2, as published by the WTFPL Task Force. | |||||
| // See http://www.wtfpl.net/ for more details. | |||||
| // | |||||
| #include <lol/engine-internal.h> | |||||
| #if HAVE_GETOPT_H | |||||
| # include <getopt.h> | |||||
| #endif | |||||
| #if HAVE_UNISTD_H | |||||
| # include <unistd.h> | |||||
| #endif | |||||
| namespace lol | |||||
| { | |||||
| struct getopt_private | |||||
| { | |||||
| getopt_private(int argc, char * const * _argv) | |||||
| : m_argc(argc), | |||||
| m_argv(_argv) | |||||
| {} | |||||
| #if HAVE_GETOPT_LONG | |||||
| typedef option optdesc; | |||||
| #else | |||||
| struct optdesc | |||||
| { | |||||
| char const *name; | |||||
| int has_arg; | |||||
| int *flag; | |||||
| int val; | |||||
| }; | |||||
| #endif | |||||
| int m_argc; | |||||
| char * const *m_argv; | |||||
| String m_optstring; | |||||
| array<optdesc> m_opts; | |||||
| }; | |||||
| getopt::getopt(int argc, char ** _argv) | |||||
| : index(1), | |||||
| arg(nullptr), | |||||
| m_private(new getopt_private(argc, _argv)) | |||||
| { | |||||
| } | |||||
| getopt::getopt(int argc, char * const * _argv) | |||||
| : index(1), | |||||
| arg(nullptr), | |||||
| m_private(new getopt_private(argc, _argv)) | |||||
| { | |||||
| } | |||||
| getopt::~getopt() | |||||
| { | |||||
| } | |||||
| void getopt::add_arg(int short_opt, char const *long_opt, bool has_arg) | |||||
| { | |||||
| getopt_private::optdesc o = { long_opt, has_arg, nullptr, short_opt }; | |||||
| m_private->m_opts.push(o); | |||||
| if (isalnum(short_opt)) | |||||
| { | |||||
| m_private->m_optstring += (char)short_opt; | |||||
| if (has_arg) | |||||
| m_private->m_optstring += ':'; | |||||
| } | |||||
| } | |||||
| int getopt::parse() | |||||
| { | |||||
| int longindex = 0; // FIXME: what is this? | |||||
| #if HAVE_GETOPT_LONG | |||||
| int ret; | |||||
| optind = this->index; | |||||
| optarg = this->arg; | |||||
| m_private->m_opts.push(getopt_private::optdesc { nullptr, 0, nullptr, 0 }); | |||||
| ret = getopt_long(m_private->m_argc, m_private->m_argv, m_private->m_optstring.C(), | |||||
| (option const *)m_private->m_opts.data(), &longindex); | |||||
| this->index = optind; | |||||
| this->arg = optarg; | |||||
| return ret; | |||||
| #else | |||||
| /* XXX: this getopt_long implementation should not be trusted for other | |||||
| * applications without any serious peer reviewing. It “just works” with | |||||
| * zzuf and a few libcaca programs but may fail miserably in other | |||||
| * programs. */ | |||||
| char **argv = (char **)(uintptr_t)m_private->m_argv; | |||||
| char *flag; | |||||
| if (this->index >= m_private->m_argc) | |||||
| return -1; | |||||
| flag = argv[this->index]; | |||||
| if (flag[0] == '-' && flag[1] != '-') | |||||
| { | |||||
| char const *tmp; | |||||
| int ret = flag[1]; | |||||
| if (ret == '\0') | |||||
| return -1; | |||||
| tmp = strchr(m_private->m_optstring.C(), ret); | |||||
| if (!tmp || ret == ':') | |||||
| return '?'; | |||||
| this->index++; | |||||
| if (tmp[1] == ':') | |||||
| { | |||||
| if (flag[2] != '\0') | |||||
| this->arg = flag + 2; | |||||
| else if (this->index < m_private->m_argc) | |||||
| this->arg = argv[this->index++]; | |||||
| else | |||||
| goto too_few; | |||||
| return ret; | |||||
| } | |||||
| if (flag[2] != '\0') | |||||
| { | |||||
| flag[1] = '-'; | |||||
| this->index--; | |||||
| argv[this->index]++; | |||||
| } | |||||
| return ret; | |||||
| } | |||||
| if (flag[0] == '-' && flag[1] == '-') | |||||
| { | |||||
| if (flag[2] == '\0') | |||||
| return -1; | |||||
| for (int i = 0; m_private->m_opts[i].name; i++) | |||||
| { | |||||
| size_t l = strlen(m_private->m_opts[i].name); | |||||
| if (strncmp(flag + 2, m_private->m_opts[i].name, l)) | |||||
| continue; | |||||
| switch (flag[2 + l]) | |||||
| { | |||||
| case '=': | |||||
| if (!m_private->m_opts[i].has_arg) | |||||
| goto bad_opt; | |||||
| longindex = i; | |||||
| this->index++; | |||||
| this->arg = flag + 2 + l + 1; | |||||
| return m_private->m_opts[i].val; | |||||
| case '\0': | |||||
| longindex = i; | |||||
| this->index++; | |||||
| if (m_private->m_opts[i].has_arg) | |||||
| { | |||||
| if (this->index < m_private->argc) | |||||
| this->arg = argv[this->index++]; | |||||
| else | |||||
| goto too_few; | |||||
| } | |||||
| return m_private->m_opts[i].val; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| bad_opt: | |||||
| fprintf(stderr, "%s: unrecognized option `%s'\n", argv[0], flag); | |||||
| return '?'; | |||||
| too_few: | |||||
| fprintf(stderr, "%s: option `%s' requires an argument\n", | |||||
| argv[0], flag); | |||||
| return '?'; | |||||
| } | |||||
| return -1; | |||||
| #endif | |||||
| } | |||||
| } // namespace lol | |||||
| @@ -1,7 +1,7 @@ | |||||
| // | // | ||||
| // LolRemez - Remez algorithm implementation | // LolRemez - Remez algorithm implementation | ||||
| // | // | ||||
| // Copyright © 2005—2015 Sam Hocevar <sam@hocevar.net> | |||||
| // Copyright © 2005—2016 Sam Hocevar <sam@hocevar.net> | |||||
| // | // | ||||
| // This program is free software. It comes without any warranty, to | // This program is free software. It comes without any warranty, to | ||||
| // the extent permitted by applicable law. You can redistribute it | // the extent permitted by applicable law. You can redistribute it | ||||
| @@ -21,70 +21,108 @@ | |||||
| #include "solver.h" | #include "solver.h" | ||||
| #include "expression.h" | #include "expression.h" | ||||
| using lol::array; | |||||
| using lol::real; | using lol::real; | ||||
| using lol::String; | using lol::String; | ||||
| void FAIL(char const *message) | |||||
| static void version(void) | |||||
| { | { | ||||
| printf("Error: %s\n", message); | |||||
| printf("lolremez %s\n", PACKAGE_VERSION); | |||||
| printf("Copyright © 2005—2016 Sam Hocevar <sam@hocevar.net>\n"); | |||||
| printf("This program is free software. It comes without any warranty, to the extent\n"); | |||||
| printf("permitted by applicable law. You can redistribute it and/or modify it under\n"); | |||||
| printf("the terms of the Do What the Fuck You Want to Public License, Version 2, as\n"); | |||||
| printf("published by the WTFPL Task Force. See http://www.wtfpl.net/ for more details.\n"); | |||||
| printf("\n"); | |||||
| printf("Written by Sam Hocevar. Report bugs to <sam@hocevar.net>.\n"); | |||||
| } | |||||
| static void usage() | |||||
| { | |||||
| printf("Usage: lolremez [-d degree] [-r xmin:xmax] x-expression [x-error]\n"); | |||||
| printf(" lolremez -h | --help\n"); | |||||
| printf(" lolremez -V | --version\n"); | |||||
| printf("Find a polynomial approximation for x-expression.\n"); | |||||
| printf("\n"); | printf("\n"); | ||||
| printf("Usage:\n"); | |||||
| printf(" lolremez [-d degree] [-i xmin xmax] x-expression [x-error]\n"); | |||||
| printf("Mandatory arguments to long options are mandatory for short options too.\n"); | |||||
| printf(" -d, --degree <degree> degree of final polynomial\n"); | |||||
| printf(" -r, --range <xmin>:<xmax> range over which to approximate\n"); | |||||
| printf(" -h, --help display this help and exit\n"); | |||||
| printf(" -V, --version output version information and exit\n"); | |||||
| printf("\n"); | printf("\n"); | ||||
| printf("Example:\n"); | |||||
| printf(" lolremez -d 4 -i -1 1 \"atan(exp(1+x))\"\n"); | |||||
| printf(" lolremez -d 4 -i -1 1 \"atan(exp(1+x))\" \"exp(1+x)\"\n"); | |||||
| printf("Examples:\n"); | |||||
| printf(" lolremez -d 4 -r -1:1 \"atan(exp(1+x))\"\n"); | |||||
| printf(" lolremez -d 4 -r -1:1 \"atan(exp(1+x))\" \"exp(1+x)\"\n"); | |||||
| printf("\n"); | printf("\n"); | ||||
| printf("Written by Sam Hocevar. Report bugs to <sam@hocevar.net>.\n"); | |||||
| } | |||||
| static void FAIL(char const *message) | |||||
| { | |||||
| printf("Error: %s\n", message); | |||||
| printf("\n"); | |||||
| usage(); | |||||
| exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||||
| } | } | ||||
| /* See the tutorial at http://lolengine.net/wiki/doc/maths/remez */ | /* See the tutorial at http://lolengine.net/wiki/doc/maths/remez */ | ||||
| int main(int argc, char **argv) | int main(int argc, char **argv) | ||||
| { | { | ||||
| char const *xmin = "-1", *xmax = "1"; | |||||
| String xmin("-1"), xmax("1"); | |||||
| char const *f = nullptr, *g = nullptr; | char const *f = nullptr, *g = nullptr; | ||||
| int degree = 4; | int degree = 4; | ||||
| for (int i = 1; i < argc; ++i) | |||||
| { | |||||
| if (argv[i] == String("-d")) | |||||
| { | |||||
| if (i + 1 >= argc) | |||||
| FAIL("not enough arguments for -d"); | |||||
| lol::getopt opt(argc, argv); | |||||
| opt.add_arg('d', "degree", true); | |||||
| opt.add_arg('r', "range", true); | |||||
| opt.add_arg('h', "help", false); | |||||
| opt.add_arg('v', "version", false); | |||||
| degree = atoi(argv[++i]); | |||||
| } | |||||
| else if (argv[i] == String("-i")) | |||||
| { | |||||
| if (i + 2 >= argc) | |||||
| FAIL("not enough arguments for -i"); | |||||
| for (;;) | |||||
| { | |||||
| int c = opt.parse(); | |||||
| if (c == -1) | |||||
| break; | |||||
| xmin = argv[++i]; | |||||
| xmax = argv[++i]; | |||||
| } | |||||
| else if (g) | |||||
| { | |||||
| FAIL("unknown argument"); | |||||
| } | |||||
| else if (f) | |||||
| { | |||||
| g = argv[i]; | |||||
| } | |||||
| else | |||||
| switch (c) | |||||
| { | { | ||||
| f = argv[i]; | |||||
| case 'd': /* --degree */ | |||||
| degree = atoi(opt.arg); | |||||
| break; | |||||
| case 'r': { /* --range */ | |||||
| array<String> arg = String(opt.arg).split(':'); | |||||
| if (arg.count() != 2) | |||||
| FAIL("invalid range"); | |||||
| xmin = arg[0]; | |||||
| xmax = arg[1]; | |||||
| } break; | |||||
| case 'h': /* --help */ | |||||
| usage(); | |||||
| return EXIT_SUCCESS; | |||||
| case 'v': /* --version */ | |||||
| version(); | |||||
| return EXIT_SUCCESS; | |||||
| default: | |||||
| return EXIT_FAILURE; | |||||
| } | } | ||||
| } | } | ||||
| if (opt.index < argc) | |||||
| f = argv[opt.index++]; | |||||
| if (opt.index < argc) | |||||
| g = argv[opt.index++]; | |||||
| if (!f) | if (!f) | ||||
| FAIL("no function specified"); | FAIL("no function specified"); | ||||
| else if (opt.index < argc) | |||||
| FAIL("too many arguments"); | |||||
| if (real(xmin) >= real(xmax)) | |||||
| if (real(xmin.C()) >= real(xmax.C())) | |||||
| FAIL("invalid range"); | FAIL("invalid range"); | ||||
| remez_solver solver(degree, 20); | remez_solver solver(degree, 20); | ||||
| solver.run(xmin, xmax, f, g); | |||||
| solver.run(xmin.C(), xmax.C(), f, g); | |||||
| return 0; | return 0; | ||||
| } | } | ||||