| @@ -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/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? | |||
| 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/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/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 \ | |||
| \ | |||
| 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/crop.cpp image/resample.cpp image/noise.cpp image/combine.cpp \ | |||
| @@ -202,6 +202,7 @@ | |||
| <ClCompile Include="scene.cpp" /> | |||
| <ClCompile Include="sprite.cpp" /> | |||
| <ClCompile Include="sys\file.cpp" /> | |||
| <ClCompile Include="sys\getopt.cpp" /> | |||
| <ClCompile Include="sys\hacks.cpp" /> | |||
| <ClCompile Include="sys\init.cpp" /> | |||
| <ClCompile Include="sys\thread.cpp" /> | |||
| @@ -301,6 +302,7 @@ | |||
| <ClInclude Include="lol\public.h" /> | |||
| <ClInclude Include="lol\sys\all.h" /> | |||
| <ClInclude Include="lol\sys\file.h" /> | |||
| <ClInclude Include="lol\sys\getopt.h" /> | |||
| <ClInclude Include="lol\sys\init.h" /> | |||
| <ClInclude Include="lol\sys\thread.h" /> | |||
| <ClInclude Include="lol\sys\threadtypes.h" /> | |||
| @@ -291,6 +291,9 @@ | |||
| <ClCompile Include="sys\file.cpp"> | |||
| <Filter>sys</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="sys\getopt.cpp"> | |||
| <Filter>sys</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="sys\timer.cpp"> | |||
| <Filter>sys</Filter> | |||
| </ClCompile> | |||
| @@ -652,6 +655,9 @@ | |||
| <ClInclude Include="lol\sys\file.h"> | |||
| <Filter>lol\sys</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\sys\getopt.h"> | |||
| <Filter>lol\sys</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\gpu\framebuffer.h"> | |||
| <Filter>lol\gpu</Filter> | |||
| </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 | |||
| @@ -13,6 +15,7 @@ | |||
| #include <lol/sys/timer.h> | |||
| #include <lol/sys/thread.h> | |||
| #include <lol/sys/threadtypes.h> | |||
| #include <lol/sys/getopt.h> | |||
| #include <lol/sys/init.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 | |||
| // | |||
| // 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 | |||
| // the extent permitted by applicable law. You can redistribute it | |||
| @@ -21,70 +21,108 @@ | |||
| #include "solver.h" | |||
| #include "expression.h" | |||
| using lol::array; | |||
| using lol::real; | |||
| 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("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("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("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); | |||
| } | |||
| /* See the tutorial at http://lolengine.net/wiki/doc/maths/remez */ | |||
| int main(int argc, char **argv) | |||
| { | |||
| char const *xmin = "-1", *xmax = "1"; | |||
| String xmin("-1"), xmax("1"); | |||
| char const *f = nullptr, *g = nullptr; | |||
| 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) | |||
| 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"); | |||
| remez_solver solver(degree, 20); | |||
| solver.run(xmin, xmax, f, g); | |||
| solver.run(xmin.C(), xmax.C(), f, g); | |||
| return 0; | |||
| } | |||