@@ -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; | |||
} | |||