@ -1,282 +0,0 @@ | |||||
#ifndef __khrplatform_h_ | |||||
#define __khrplatform_h_ | |||||
/* | |||||
** Copyright (c) 2008-2009 The Khronos Group Inc. | |||||
** | |||||
** Permission is hereby granted, free of charge, to any person obtaining a | |||||
** copy of this software and/or associated documentation files (the | |||||
** "Materials"), to deal in the Materials without restriction, including | |||||
** without limitation the rights to use, copy, modify, merge, publish, | |||||
** distribute, sublicense, and/or sell copies of the Materials, and to | |||||
** permit persons to whom the Materials are furnished to do so, subject to | |||||
** the following conditions: | |||||
** | |||||
** The above copyright notice and this permission notice shall be included | |||||
** in all copies or substantial portions of the Materials. | |||||
** | |||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. | |||||
*/ | |||||
/* Khronos platform-specific types and definitions. | |||||
* | |||||
* $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $ | |||||
* | |||||
* Adopters may modify this file to suit their platform. Adopters are | |||||
* encouraged to submit platform specific modifications to the Khronos | |||||
* group so that they can be included in future versions of this file. | |||||
* Please submit changes by sending them to the public Khronos Bugzilla | |||||
* (http://khronos.org/bugzilla) by filing a bug against product | |||||
* "Khronos (general)" component "Registry". | |||||
* | |||||
* A predefined template which fills in some of the bug fields can be | |||||
* reached using http://tinyurl.com/khrplatform-h-bugreport, but you | |||||
* must create a Bugzilla login first. | |||||
* | |||||
* | |||||
* See the Implementer's Guidelines for information about where this file | |||||
* should be located on your system and for more details of its use: | |||||
* http://www.khronos.org/registry/implementers_guide.pdf | |||||
* | |||||
* This file should be included as | |||||
* #include <KHR/khrplatform.h> | |||||
* by Khronos client API header files that use its types and defines. | |||||
* | |||||
* The types in khrplatform.h should only be used to define API-specific types. | |||||
* | |||||
* Types defined in khrplatform.h: | |||||
* khronos_int8_t signed 8 bit | |||||
* khronos_uint8_t unsigned 8 bit | |||||
* khronos_int16_t signed 16 bit | |||||
* khronos_uint16_t unsigned 16 bit | |||||
* khronos_int32_t signed 32 bit | |||||
* khronos_uint32_t unsigned 32 bit | |||||
* khronos_int64_t signed 64 bit | |||||
* khronos_uint64_t unsigned 64 bit | |||||
* khronos_intptr_t signed same number of bits as a pointer | |||||
* khronos_uintptr_t unsigned same number of bits as a pointer | |||||
* khronos_ssize_t signed size | |||||
* khronos_usize_t unsigned size | |||||
* khronos_float_t signed 32 bit floating point | |||||
* khronos_time_ns_t unsigned 64 bit time in nanoseconds | |||||
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in | |||||
* nanoseconds | |||||
* khronos_stime_nanoseconds_t signed time interval in nanoseconds | |||||
* khronos_boolean_enum_t enumerated boolean type. This should | |||||
* only be used as a base type when a client API's boolean type is | |||||
* an enum. Client APIs which use an integer or other type for | |||||
* booleans cannot use this as the base type for their boolean. | |||||
* | |||||
* Tokens defined in khrplatform.h: | |||||
* | |||||
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. | |||||
* | |||||
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. | |||||
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. | |||||
* | |||||
* Calling convention macros defined in this file: | |||||
* KHRONOS_APICALL | |||||
* KHRONOS_APIENTRY | |||||
* KHRONOS_APIATTRIBUTES | |||||
* | |||||
* These may be used in function prototypes as: | |||||
* | |||||
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname( | |||||
* int arg1, | |||||
* int arg2) KHRONOS_APIATTRIBUTES; | |||||
*/ | |||||
/*------------------------------------------------------------------------- | |||||
* Definition of KHRONOS_APICALL | |||||
*------------------------------------------------------------------------- | |||||
* This precedes the return type of the function in the function prototype. | |||||
*/ | |||||
#if defined(_WIN32) && !defined(__SCITECH_SNAP__) | |||||
# define KHRONOS_APICALL __declspec(dllimport) | |||||
#elif defined (__SYMBIAN32__) | |||||
# define KHRONOS_APICALL IMPORT_C | |||||
#else | |||||
# define KHRONOS_APICALL | |||||
#endif | |||||
/*------------------------------------------------------------------------- | |||||
* Definition of KHRONOS_APIENTRY | |||||
*------------------------------------------------------------------------- | |||||
* This follows the return type of the function and precedes the function | |||||
* name in the function prototype. | |||||
*/ | |||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) | |||||
/* Win32 but not WinCE */ | |||||
# define KHRONOS_APIENTRY __stdcall | |||||
#else | |||||
# define KHRONOS_APIENTRY | |||||
#endif | |||||
/*------------------------------------------------------------------------- | |||||
* Definition of KHRONOS_APIATTRIBUTES | |||||
*------------------------------------------------------------------------- | |||||
* This follows the closing parenthesis of the function prototype arguments. | |||||
*/ | |||||
#if defined (__ARMCC_2__) | |||||
#define KHRONOS_APIATTRIBUTES __softfp | |||||
#else | |||||
#define KHRONOS_APIATTRIBUTES | |||||
#endif | |||||
/*------------------------------------------------------------------------- | |||||
* basic type definitions | |||||
*-----------------------------------------------------------------------*/ | |||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) | |||||
/* | |||||
* Using <stdint.h> | |||||
*/ | |||||
#include <stdint.h> | |||||
typedef int32_t khronos_int32_t; | |||||
typedef uint32_t khronos_uint32_t; | |||||
typedef int64_t khronos_int64_t; | |||||
typedef uint64_t khronos_uint64_t; | |||||
#define KHRONOS_SUPPORT_INT64 1 | |||||
#define KHRONOS_SUPPORT_FLOAT 1 | |||||
#elif defined(__VMS ) || defined(__sgi) | |||||
/* | |||||
* Using <inttypes.h> | |||||
*/ | |||||
#include <inttypes.h> | |||||
typedef int32_t khronos_int32_t; | |||||
typedef uint32_t khronos_uint32_t; | |||||
typedef int64_t khronos_int64_t; | |||||
typedef uint64_t khronos_uint64_t; | |||||
#define KHRONOS_SUPPORT_INT64 1 | |||||
#define KHRONOS_SUPPORT_FLOAT 1 | |||||
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) | |||||
/* | |||||
* Win32 | |||||
*/ | |||||
typedef __int32 khronos_int32_t; | |||||
typedef unsigned __int32 khronos_uint32_t; | |||||
typedef __int64 khronos_int64_t; | |||||
typedef unsigned __int64 khronos_uint64_t; | |||||
#define KHRONOS_SUPPORT_INT64 1 | |||||
#define KHRONOS_SUPPORT_FLOAT 1 | |||||
#elif defined(__sun__) || defined(__digital__) | |||||
/* | |||||
* Sun or Digital | |||||
*/ | |||||
typedef int khronos_int32_t; | |||||
typedef unsigned int khronos_uint32_t; | |||||
#if defined(__arch64__) || defined(_LP64) | |||||
typedef long int khronos_int64_t; | |||||
typedef unsigned long int khronos_uint64_t; | |||||
#else | |||||
typedef long long int khronos_int64_t; | |||||
typedef unsigned long long int khronos_uint64_t; | |||||
#endif /* __arch64__ */ | |||||
#define KHRONOS_SUPPORT_INT64 1 | |||||
#define KHRONOS_SUPPORT_FLOAT 1 | |||||
#elif 0 | |||||
/* | |||||
* Hypothetical platform with no float or int64 support | |||||
*/ | |||||
typedef int khronos_int32_t; | |||||
typedef unsigned int khronos_uint32_t; | |||||
#define KHRONOS_SUPPORT_INT64 0 | |||||
#define KHRONOS_SUPPORT_FLOAT 0 | |||||
#else | |||||
/* | |||||
* Generic fallback | |||||
*/ | |||||
#include <stdint.h> | |||||
typedef int32_t khronos_int32_t; | |||||
typedef uint32_t khronos_uint32_t; | |||||
typedef int64_t khronos_int64_t; | |||||
typedef uint64_t khronos_uint64_t; | |||||
#define KHRONOS_SUPPORT_INT64 1 | |||||
#define KHRONOS_SUPPORT_FLOAT 1 | |||||
#endif | |||||
/* | |||||
* Types that are (so far) the same on all platforms | |||||
*/ | |||||
typedef signed char khronos_int8_t; | |||||
typedef unsigned char khronos_uint8_t; | |||||
typedef signed short int khronos_int16_t; | |||||
typedef unsigned short int khronos_uint16_t; | |||||
/* | |||||
* Types that differ between LLP64 and LP64 architectures - in LLP64, | |||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears | |||||
* to be the only LLP64 architecture in current use. | |||||
*/ | |||||
#ifdef _WIN64 | |||||
typedef signed long long int khronos_intptr_t; | |||||
typedef unsigned long long int khronos_uintptr_t; | |||||
typedef signed long long int khronos_ssize_t; | |||||
typedef unsigned long long int khronos_usize_t; | |||||
#else | |||||
typedef signed long int khronos_intptr_t; | |||||
typedef unsigned long int khronos_uintptr_t; | |||||
typedef signed long int khronos_ssize_t; | |||||
typedef unsigned long int khronos_usize_t; | |||||
#endif | |||||
#if KHRONOS_SUPPORT_FLOAT | |||||
/* | |||||
* Float type | |||||
*/ | |||||
typedef float khronos_float_t; | |||||
#endif | |||||
#if KHRONOS_SUPPORT_INT64 | |||||
/* Time types | |||||
* | |||||
* These types can be used to represent a time interval in nanoseconds or | |||||
* an absolute Unadjusted System Time. Unadjusted System Time is the number | |||||
* of nanoseconds since some arbitrary system event (e.g. since the last | |||||
* time the system booted). The Unadjusted System Time is an unsigned | |||||
* 64 bit value that wraps back to 0 every 584 years. Time intervals | |||||
* may be either signed or unsigned. | |||||
*/ | |||||
typedef khronos_uint64_t khronos_utime_nanoseconds_t; | |||||
typedef khronos_int64_t khronos_stime_nanoseconds_t; | |||||
#endif | |||||
/* | |||||
* Dummy value used to pad enum types to 32 bits. | |||||
*/ | |||||
#ifndef KHRONOS_MAX_ENUM | |||||
#define KHRONOS_MAX_ENUM 0x7FFFFFFF | |||||
#endif | |||||
/* | |||||
* Enumerated boolean type | |||||
* | |||||
* Values other than zero should be considered to be true. Therefore | |||||
* comparisons should not be made against KHRONOS_TRUE. | |||||
*/ | |||||
typedef enum { | |||||
KHRONOS_FALSE = 0, | |||||
KHRONOS_TRUE = 1, | |||||
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM | |||||
} khronos_boolean_enum_t; | |||||
#endif /* __khrplatform_h_ */ |
@ -1,230 +0,0 @@ | |||||
/* Copyright (c) 2012, Kim Gräsman | |||||
* All rights reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions are met: | |||||
* * Redistributions of source code must retain the above copyright notice, | |||||
* this list of conditions and the following disclaimer. | |||||
* * Redistributions in binary form must reproduce the above copyright notice, | |||||
* this list of conditions and the following disclaimer in the documentation | |||||
* and/or other materials provided with the distribution. | |||||
* * Neither the name of Kim Gräsman nor the names of contributors may be used | |||||
* to endorse or promote products derived from this software without specific | |||||
* prior written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
* ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, | |||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
#include "getopt.h" | |||||
#include <stddef.h> | |||||
#include <string.h> | |||||
const int no_argument = 0; | |||||
const int required_argument = 1; | |||||
const int optional_argument = 2; | |||||
char* optarg; | |||||
int optopt; | |||||
/* The variable optind [...] shall be initialized to 1 by the system. */ | |||||
int optind = 1; | |||||
int opterr; | |||||
static char* optcursor = NULL; | |||||
/* Implemented based on [1] and [2] for optional arguments. | |||||
optopt is handled FreeBSD-style, per [3]. | |||||
Other GNU and FreeBSD extensions are purely accidental. | |||||
[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html | |||||
[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html | |||||
[3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE | |||||
*/ | |||||
int getopt(int argc, char* const argv[], const char* optstring) { | |||||
int optchar = -1; | |||||
const char* optdecl = NULL; | |||||
optarg = NULL; | |||||
opterr = 0; | |||||
optopt = 0; | |||||
/* Unspecified, but we need it to avoid overrunning the argv bounds. */ | |||||
if (optind >= argc) | |||||
goto no_more_optchars; | |||||
/* If, when getopt() is called argv[optind] is a null pointer, getopt() | |||||
shall return -1 without changing optind. */ | |||||
if (argv[optind] == NULL) | |||||
goto no_more_optchars; | |||||
/* If, when getopt() is called *argv[optind] is not the character '-', | |||||
getopt() shall return -1 without changing optind. */ | |||||
if (*argv[optind] != '-') | |||||
goto no_more_optchars; | |||||
/* If, when getopt() is called argv[optind] points to the string "-", | |||||
getopt() shall return -1 without changing optind. */ | |||||
if (strcmp(argv[optind], "-") == 0) | |||||
goto no_more_optchars; | |||||
/* If, when getopt() is called argv[optind] points to the string "--", | |||||
getopt() shall return -1 after incrementing optind. */ | |||||
if (strcmp(argv[optind], "--") == 0) { | |||||
++optind; | |||||
goto no_more_optchars; | |||||
} | |||||
if (optcursor == NULL || *optcursor == '\0') | |||||
optcursor = argv[optind] + 1; | |||||
optchar = *optcursor; | |||||
/* FreeBSD: The variable optopt saves the last known option character | |||||
returned by getopt(). */ | |||||
optopt = optchar; | |||||
/* The getopt() function shall return the next option character (if one is | |||||
found) from argv that matches a character in optstring, if there is | |||||
one that matches. */ | |||||
optdecl = strchr(optstring, optchar); | |||||
if (optdecl) { | |||||
/* [I]f a character is followed by a colon, the option takes an | |||||
argument. */ | |||||
if (optdecl[1] == ':') { | |||||
optarg = ++optcursor; | |||||
if (*optarg == '\0') { | |||||
/* GNU extension: Two colons mean an option takes an | |||||
optional arg; if there is text in the current argv-element | |||||
(i.e., in the same word as the option name itself, for example, | |||||
"-oarg"), then it is returned in optarg, otherwise optarg is set | |||||
to zero. */ | |||||
if (optdecl[2] != ':') { | |||||
/* If the option was the last character in the string pointed to by | |||||
an element of argv, then optarg shall contain the next element | |||||
of argv, and optind shall be incremented by 2. If the resulting | |||||
value of optind is greater than argc, this indicates a missing | |||||
option-argument, and getopt() shall return an error indication. | |||||
Otherwise, optarg shall point to the string following the | |||||
option character in that element of argv, and optind shall be | |||||
incremented by 1. | |||||
*/ | |||||
if (++optind < argc) { | |||||
optarg = argv[optind]; | |||||
} else { | |||||
/* If it detects a missing option-argument, it shall return the | |||||
colon character ( ':' ) if the first character of optstring | |||||
was a colon, or a question-mark character ( '?' ) otherwise. | |||||
*/ | |||||
optarg = NULL; | |||||
optchar = (optstring[0] == ':') ? ':' : '?'; | |||||
} | |||||
} else { | |||||
optarg = NULL; | |||||
} | |||||
} | |||||
optcursor = NULL; | |||||
} | |||||
} else { | |||||
/* If getopt() encounters an option character that is not contained in | |||||
optstring, it shall return the question-mark ( '?' ) character. */ | |||||
optchar = '?'; | |||||
} | |||||
if (optcursor == NULL || *++optcursor == '\0') | |||||
++optind; | |||||
return optchar; | |||||
no_more_optchars: | |||||
optcursor = NULL; | |||||
return -1; | |||||
} | |||||
/* Implementation based on [1]. | |||||
[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html | |||||
*/ | |||||
int getopt_long(int argc, char* const argv[], const char* optstring, | |||||
const struct option* longopts, int* longindex) { | |||||
const struct option* o = longopts; | |||||
const struct option* match = NULL; | |||||
int num_matches = 0; | |||||
size_t argument_name_length = 0; | |||||
const char* current_argument = NULL; | |||||
int retval = -1; | |||||
optarg = NULL; | |||||
optopt = 0; | |||||
if (optind >= argc) | |||||
return -1; | |||||
if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) | |||||
return getopt(argc, argv, optstring); | |||||
/* It's an option; starts with -- and is longer than two chars. */ | |||||
current_argument = argv[optind] + 2; | |||||
argument_name_length = strcspn(current_argument, "="); | |||||
for (; o->name; ++o) { | |||||
if (strncmp(o->name, current_argument, argument_name_length) == 0) { | |||||
match = o; | |||||
++num_matches; | |||||
} | |||||
} | |||||
if (num_matches == 1) { | |||||
/* If longindex is not NULL, it points to a variable which is set to the | |||||
index of the long option relative to longopts. */ | |||||
if (longindex) | |||||
*longindex = (int) (match - longopts); | |||||
/* If flag is NULL, then getopt_long() shall return val. | |||||
Otherwise, getopt_long() returns 0, and flag shall point to a variable | |||||
which shall be set to val if the option is found, but left unchanged if | |||||
the option is not found. */ | |||||
if (match->flag) | |||||
*(match->flag) = match->val; | |||||
retval = match->flag ? 0 : match->val; | |||||
if (match->has_arg != no_argument) { | |||||
optarg = strchr(argv[optind], '='); | |||||
if (optarg != NULL) | |||||
++optarg; | |||||
if (match->has_arg == required_argument) { | |||||
/* Only scan the next argv for required arguments. Behavior is not | |||||
specified, but has been observed with Ubuntu and Mac OSX. */ | |||||
if (optarg == NULL && ++optind < argc) { | |||||
optarg = argv[optind]; | |||||
} | |||||
if (optarg == NULL) | |||||
retval = ':'; | |||||
} | |||||
} else if (strchr(argv[optind], '=')) { | |||||
/* An argument was provided to a non-argument option. | |||||
I haven't seen this specified explicitly, but both GNU and BSD-based | |||||
implementations show this behavior. | |||||
*/ | |||||
retval = '?'; | |||||
} | |||||
} else { | |||||
/* Unknown option or ambiguous match. */ | |||||
retval = '?'; | |||||
} | |||||
++optind; | |||||
return retval; | |||||
} |
@ -1,57 +0,0 @@ | |||||
/* Copyright (c) 2012, Kim Gräsman | |||||
* All rights reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions are met: | |||||
* * Redistributions of source code must retain the above copyright notice, | |||||
* this list of conditions and the following disclaimer. | |||||
* * Redistributions in binary form must reproduce the above copyright notice, | |||||
* this list of conditions and the following disclaimer in the documentation | |||||
* and/or other materials provided with the distribution. | |||||
* * Neither the name of Kim Gräsman nor the names of contributors may be used | |||||
* to endorse or promote products derived from this software without specific | |||||
* prior written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
* ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, | |||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*/ | |||||
#ifndef INCLUDED_GETOPT_PORT_H | |||||
#define INCLUDED_GETOPT_PORT_H | |||||
#if defined(__cplusplus) | |||||
extern "C" { | |||||
#endif | |||||
extern const int no_argument; | |||||
extern const int required_argument; | |||||
extern const int optional_argument; | |||||
extern char* optarg; | |||||
extern int optind, opterr, optopt; | |||||
struct option { | |||||
const char* name; | |||||
int has_arg; | |||||
int* flag; | |||||
int val; | |||||
}; | |||||
int getopt(int argc, char* const argv[], const char* optstring); | |||||
int getopt_long(int argc, char* const argv[], | |||||
const char* optstring, const struct option* longopts, int* longindex); | |||||
#if defined(__cplusplus) | |||||
} | |||||
#endif | |||||
#endif // INCLUDED_GETOPT_PORT_H |
@ -1,574 +0,0 @@ | |||||
#ifndef LINMATH_H | |||||
#define LINMATH_H | |||||
#include <math.h> | |||||
#ifdef _MSC_VER | |||||
#define inline __inline | |||||
#endif | |||||
#define LINMATH_H_DEFINE_VEC(n) \ | |||||
typedef float vec##n[n]; \ | |||||
static inline void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \ | |||||
{ \ | |||||
int i; \ | |||||
for(i=0; i<n; ++i) \ | |||||
r[i] = a[i] + b[i]; \ | |||||
} \ | |||||
static inline void vec##n##_sub(vec##n r, vec##n const a, vec##n const b) \ | |||||
{ \ | |||||
int i; \ | |||||
for(i=0; i<n; ++i) \ | |||||
r[i] = a[i] - b[i]; \ | |||||
} \ | |||||
static inline void vec##n##_scale(vec##n r, vec##n const v, float const s) \ | |||||
{ \ | |||||
int i; \ | |||||
for(i=0; i<n; ++i) \ | |||||
r[i] = v[i] * s; \ | |||||
} \ | |||||
static inline float vec##n##_mul_inner(vec##n const a, vec##n const b) \ | |||||
{ \ | |||||
float p = 0.; \ | |||||
int i; \ | |||||
for(i=0; i<n; ++i) \ | |||||
p += b[i]*a[i]; \ | |||||
return p; \ | |||||
} \ | |||||
static inline float vec##n##_len(vec##n const v) \ | |||||
{ \ | |||||
return (float) sqrt(vec##n##_mul_inner(v,v)); \ | |||||
} \ | |||||
static inline void vec##n##_norm(vec##n r, vec##n const v) \ | |||||
{ \ | |||||
float k = 1.f / vec##n##_len(v); \ | |||||
vec##n##_scale(r, v, k); \ | |||||
} | |||||
LINMATH_H_DEFINE_VEC(2) | |||||
LINMATH_H_DEFINE_VEC(3) | |||||
LINMATH_H_DEFINE_VEC(4) | |||||
static inline void vec3_mul_cross(vec3 r, vec3 const a, vec3 const b) | |||||
{ | |||||
r[0] = a[1]*b[2] - a[2]*b[1]; | |||||
r[1] = a[2]*b[0] - a[0]*b[2]; | |||||
r[2] = a[0]*b[1] - a[1]*b[0]; | |||||
} | |||||
static inline void vec3_reflect(vec3 r, vec3 const v, vec3 const n) | |||||
{ | |||||
float p = 2.f*vec3_mul_inner(v, n); | |||||
int i; | |||||
for(i=0;i<3;++i) | |||||
r[i] = v[i] - p*n[i]; | |||||
} | |||||
static inline void vec4_mul_cross(vec4 r, vec4 a, vec4 b) | |||||
{ | |||||
r[0] = a[1]*b[2] - a[2]*b[1]; | |||||
r[1] = a[2]*b[0] - a[0]*b[2]; | |||||
r[2] = a[0]*b[1] - a[1]*b[0]; | |||||
r[3] = 1.f; | |||||
} | |||||
static inline void vec4_reflect(vec4 r, vec4 v, vec4 n) | |||||
{ | |||||
float p = 2.f*vec4_mul_inner(v, n); | |||||
int i; | |||||
for(i=0;i<4;++i) | |||||
r[i] = v[i] - p*n[i]; | |||||
} | |||||
typedef vec4 mat4x4[4]; | |||||
static inline void mat4x4_identity(mat4x4 M) | |||||
{ | |||||
int i, j; | |||||
for(i=0; i<4; ++i) | |||||
for(j=0; j<4; ++j) | |||||
M[i][j] = i==j ? 1.f : 0.f; | |||||
} | |||||
static inline void mat4x4_dup(mat4x4 M, mat4x4 N) | |||||
{ | |||||
int i, j; | |||||
for(i=0; i<4; ++i) | |||||
for(j=0; j<4; ++j) | |||||
M[i][j] = N[i][j]; | |||||
} | |||||
static inline void mat4x4_row(vec4 r, mat4x4 M, int i) | |||||
{ | |||||
int k; | |||||
for(k=0; k<4; ++k) | |||||
r[k] = M[k][i]; | |||||
} | |||||
static inline void mat4x4_col(vec4 r, mat4x4 M, int i) | |||||
{ | |||||
int k; | |||||
for(k=0; k<4; ++k) | |||||
r[k] = M[i][k]; | |||||
} | |||||
static inline void mat4x4_transpose(mat4x4 M, mat4x4 N) | |||||
{ | |||||
int i, j; | |||||
for(j=0; j<4; ++j) | |||||
for(i=0; i<4; ++i) | |||||
M[i][j] = N[j][i]; | |||||
} | |||||
static inline void mat4x4_add(mat4x4 M, mat4x4 a, mat4x4 b) | |||||
{ | |||||
int i; | |||||
for(i=0; i<4; ++i) | |||||
vec4_add(M[i], a[i], b[i]); | |||||
} | |||||
static inline void mat4x4_sub(mat4x4 M, mat4x4 a, mat4x4 b) | |||||
{ | |||||
int i; | |||||
for(i=0; i<4; ++i) | |||||
vec4_sub(M[i], a[i], b[i]); | |||||
} | |||||
static inline void mat4x4_scale(mat4x4 M, mat4x4 a, float k) | |||||
{ | |||||
int i; | |||||
for(i=0; i<4; ++i) | |||||
vec4_scale(M[i], a[i], k); | |||||
} | |||||
static inline void mat4x4_scale_aniso(mat4x4 M, mat4x4 a, float x, float y, float z) | |||||
{ | |||||
int i; | |||||
vec4_scale(M[0], a[0], x); | |||||
vec4_scale(M[1], a[1], y); | |||||
vec4_scale(M[2], a[2], z); | |||||
for(i = 0; i < 4; ++i) { | |||||
M[3][i] = a[3][i]; | |||||
} | |||||
} | |||||
static inline void mat4x4_mul(mat4x4 M, mat4x4 a, mat4x4 b) | |||||
{ | |||||
mat4x4 temp; | |||||
int k, r, c; | |||||
for(c=0; c<4; ++c) for(r=0; r<4; ++r) { | |||||
temp[c][r] = 0.f; | |||||
for(k=0; k<4; ++k) | |||||
temp[c][r] += a[k][r] * b[c][k]; | |||||
} | |||||
mat4x4_dup(M, temp); | |||||
} | |||||
static inline void mat4x4_mul_vec4(vec4 r, mat4x4 M, vec4 v) | |||||
{ | |||||
int i, j; | |||||
for(j=0; j<4; ++j) { | |||||
r[j] = 0.f; | |||||
for(i=0; i<4; ++i) | |||||
r[j] += M[i][j] * v[i]; | |||||
} | |||||
} | |||||
static inline void mat4x4_translate(mat4x4 T, float x, float y, float z) | |||||
{ | |||||
mat4x4_identity(T); | |||||
T[3][0] = x; | |||||
T[3][1] = y; | |||||
T[3][2] = z; | |||||
} | |||||
static inline void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z) | |||||
{ | |||||
vec4 t = {x, y, z, 0}; | |||||
vec4 r; | |||||
int i; | |||||
for (i = 0; i < 4; ++i) { | |||||
mat4x4_row(r, M, i); | |||||
M[3][i] += vec4_mul_inner(r, t); | |||||
} | |||||
} | |||||
static inline void mat4x4_from_vec3_mul_outer(mat4x4 M, vec3 a, vec3 b) | |||||
{ | |||||
int i, j; | |||||
for(i=0; i<4; ++i) for(j=0; j<4; ++j) | |||||
M[i][j] = i<3 && j<3 ? a[i] * b[j] : 0.f; | |||||
} | |||||
static inline void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z, float angle) | |||||
{ | |||||
float s = sinf(angle); | |||||
float c = cosf(angle); | |||||
vec3 u = {x, y, z}; | |||||
if(vec3_len(u) > 1e-4) { | |||||
mat4x4 T, C, S = {{0}}; | |||||
vec3_norm(u, u); | |||||
mat4x4_from_vec3_mul_outer(T, u, u); | |||||
S[1][2] = u[0]; | |||||
S[2][1] = -u[0]; | |||||
S[2][0] = u[1]; | |||||
S[0][2] = -u[1]; | |||||
S[0][1] = u[2]; | |||||
S[1][0] = -u[2]; | |||||
mat4x4_scale(S, S, s); | |||||
mat4x4_identity(C); | |||||
mat4x4_sub(C, C, T); | |||||
mat4x4_scale(C, C, c); | |||||
mat4x4_add(T, T, C); | |||||
mat4x4_add(T, T, S); | |||||
T[3][3] = 1.; | |||||
mat4x4_mul(R, M, T); | |||||
} else { | |||||
mat4x4_dup(R, M); | |||||
} | |||||
} | |||||
static inline void mat4x4_rotate_X(mat4x4 Q, mat4x4 M, float angle) | |||||
{ | |||||
float s = sinf(angle); | |||||
float c = cosf(angle); | |||||
mat4x4 R = { | |||||
{1.f, 0.f, 0.f, 0.f}, | |||||
{0.f, c, s, 0.f}, | |||||
{0.f, -s, c, 0.f}, | |||||
{0.f, 0.f, 0.f, 1.f} | |||||
}; | |||||
mat4x4_mul(Q, M, R); | |||||
} | |||||
static inline void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle) | |||||
{ | |||||
float s = sinf(angle); | |||||
float c = cosf(angle); | |||||
mat4x4 R = { | |||||
{ c, 0.f, s, 0.f}, | |||||
{ 0.f, 1.f, 0.f, 0.f}, | |||||
{ -s, 0.f, c, 0.f}, | |||||
{ 0.f, 0.f, 0.f, 1.f} | |||||
}; | |||||
mat4x4_mul(Q, M, R); | |||||
} | |||||
static inline void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle) | |||||
{ | |||||
float s = sinf(angle); | |||||
float c = cosf(angle); | |||||
mat4x4 R = { | |||||
{ c, s, 0.f, 0.f}, | |||||
{ -s, c, 0.f, 0.f}, | |||||
{ 0.f, 0.f, 1.f, 0.f}, | |||||
{ 0.f, 0.f, 0.f, 1.f} | |||||
}; | |||||
mat4x4_mul(Q, M, R); | |||||
} | |||||
static inline void mat4x4_invert(mat4x4 T, mat4x4 M) | |||||
{ | |||||
float idet; | |||||
float s[6]; | |||||
float c[6]; | |||||
s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1]; | |||||
s[1] = M[0][0]*M[1][2] - M[1][0]*M[0][2]; | |||||
s[2] = M[0][0]*M[1][3] - M[1][0]*M[0][3]; | |||||
s[3] = M[0][1]*M[1][2] - M[1][1]*M[0][2]; | |||||
s[4] = M[0][1]*M[1][3] - M[1][1]*M[0][3]; | |||||
s[5] = M[0][2]*M[1][3] - M[1][2]*M[0][3]; | |||||
c[0] = M[2][0]*M[3][1] - M[3][0]*M[2][1]; | |||||
c[1] = M[2][0]*M[3][2] - M[3][0]*M[2][2]; | |||||
c[2] = M[2][0]*M[3][3] - M[3][0]*M[2][3]; | |||||
c[3] = M[2][1]*M[3][2] - M[3][1]*M[2][2]; | |||||
c[4] = M[2][1]*M[3][3] - M[3][1]*M[2][3]; | |||||
c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3]; | |||||
/* Assumes it is invertible */ | |||||
idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] ); | |||||
T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet; | |||||
T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet; | |||||
T[0][2] = ( M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet; | |||||
T[0][3] = (-M[2][1] * s[5] + M[2][2] * s[4] - M[2][3] * s[3]) * idet; | |||||
T[1][0] = (-M[1][0] * c[5] + M[1][2] * c[2] - M[1][3] * c[1]) * idet; | |||||
T[1][1] = ( M[0][0] * c[5] - M[0][2] * c[2] + M[0][3] * c[1]) * idet; | |||||
T[1][2] = (-M[3][0] * s[5] + M[3][2] * s[2] - M[3][3] * s[1]) * idet; | |||||
T[1][3] = ( M[2][0] * s[5] - M[2][2] * s[2] + M[2][3] * s[1]) * idet; | |||||
T[2][0] = ( M[1][0] * c[4] - M[1][1] * c[2] + M[1][3] * c[0]) * idet; | |||||
T[2][1] = (-M[0][0] * c[4] + M[0][1] * c[2] - M[0][3] * c[0]) * idet; | |||||
T[2][2] = ( M[3][0] * s[4] - M[3][1] * s[2] + M[3][3] * s[0]) * idet; | |||||
T[2][3] = (-M[2][0] * s[4] + M[2][1] * s[2] - M[2][3] * s[0]) * idet; | |||||
T[3][0] = (-M[1][0] * c[3] + M[1][1] * c[1] - M[1][2] * c[0]) * idet; | |||||
T[3][1] = ( M[0][0] * c[3] - M[0][1] * c[1] + M[0][2] * c[0]) * idet; | |||||
T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet; | |||||
T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet; | |||||
} | |||||
static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M) | |||||
{ | |||||
float s = 1.; | |||||
vec3 h; | |||||
mat4x4_dup(R, M); | |||||
vec3_norm(R[2], R[2]); | |||||
s = vec3_mul_inner(R[1], R[2]); | |||||
vec3_scale(h, R[2], s); | |||||
vec3_sub(R[1], R[1], h); | |||||
vec3_norm(R[2], R[2]); | |||||
s = vec3_mul_inner(R[1], R[2]); | |||||
vec3_scale(h, R[2], s); | |||||
vec3_sub(R[1], R[1], h); | |||||
vec3_norm(R[1], R[1]); | |||||
s = vec3_mul_inner(R[0], R[1]); | |||||
vec3_scale(h, R[1], s); | |||||
vec3_sub(R[0], R[0], h); | |||||
vec3_norm(R[0], R[0]); | |||||
} | |||||
static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f) | |||||
{ | |||||
M[0][0] = 2.f*n/(r-l); | |||||
M[0][1] = M[0][2] = M[0][3] = 0.f; | |||||
M[1][1] = 2.f*n/(t-b); | |||||
M[1][0] = M[1][2] = M[1][3] = 0.f; | |||||
M[2][0] = (r+l)/(r-l); | |||||
M[2][1] = (t+b)/(t-b); | |||||
M[2][2] = -(f+n)/(f-n); | |||||
M[2][3] = -1.f; | |||||
M[3][2] = -2.f*(f*n)/(f-n); | |||||
M[3][0] = M[3][1] = M[3][3] = 0.f; | |||||
} | |||||
static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f) | |||||
{ | |||||
M[0][0] = 2.f/(r-l); | |||||
M[0][1] = M[0][2] = M[0][3] = 0.f; | |||||
M[1][1] = 2.f/(t-b); | |||||
M[1][0] = M[1][2] = M[1][3] = 0.f; | |||||
M[2][2] = -2.f/(f-n); | |||||
M[2][0] = M[2][1] = M[2][3] = 0.f; | |||||
M[3][0] = -(r+l)/(r-l); | |||||
M[3][1] = -(t+b)/(t-b); | |||||
M[3][2] = -(f+n)/(f-n); | |||||
M[3][3] = 1.f; | |||||
} | |||||
static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f) | |||||
{ | |||||
/* NOTE: Degrees are an unhandy unit to work with. | |||||
* linmath.h uses radians for everything! */ | |||||
float const a = 1.f / (float) tan(y_fov / 2.f); | |||||
m[0][0] = a / aspect; | |||||
m[0][1] = 0.f; | |||||
m[0][2] = 0.f; | |||||
m[0][3] = 0.f; | |||||
m[1][0] = 0.f; | |||||
m[1][1] = a; | |||||
m[1][2] = 0.f; | |||||
m[1][3] = 0.f; | |||||
m[2][0] = 0.f; | |||||
m[2][1] = 0.f; | |||||
m[2][2] = -((f + n) / (f - n)); | |||||
m[2][3] = -1.f; | |||||
m[3][0] = 0.f; | |||||
m[3][1] = 0.f; | |||||
m[3][2] = -((2.f * f * n) / (f - n)); | |||||
m[3][3] = 0.f; | |||||
} | |||||
static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up) | |||||
{ | |||||
/* Adapted from Android's OpenGL Matrix.java. */ | |||||
/* See the OpenGL GLUT documentation for gluLookAt for a description */ | |||||
/* of the algorithm. We implement it in a straightforward way: */ | |||||
/* TODO: The negation of of can be spared by swapping the order of | |||||
* operands in the following cross products in the right way. */ | |||||
vec3 f; | |||||
vec3 s; | |||||
vec3 t; | |||||
vec3_sub(f, center, eye); | |||||
vec3_norm(f, f); | |||||
vec3_mul_cross(s, f, up); | |||||
vec3_norm(s, s); | |||||
vec3_mul_cross(t, s, f); | |||||
m[0][0] = s[0]; | |||||
m[0][1] = t[0]; | |||||
m[0][2] = -f[0]; | |||||
m[0][3] = 0.f; | |||||
m[1][0] = s[1]; | |||||
m[1][1] = t[1]; | |||||
m[1][2] = -f[1]; | |||||
m[1][3] = 0.f; | |||||
m[2][0] = s[2]; | |||||
m[2][1] = t[2]; | |||||
m[2][2] = -f[2]; | |||||
m[2][3] = 0.f; | |||||
m[3][0] = 0.f; | |||||
m[3][1] = 0.f; | |||||
m[3][2] = 0.f; | |||||
m[3][3] = 1.f; | |||||
mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]); | |||||
} | |||||
typedef float quat[4]; | |||||
static inline void quat_identity(quat q) | |||||
{ | |||||
q[0] = q[1] = q[2] = 0.f; | |||||
q[3] = 1.f; | |||||
} | |||||
static inline void quat_add(quat r, quat a, quat b) | |||||
{ | |||||
int i; | |||||
for(i=0; i<4; ++i) | |||||
r[i] = a[i] + b[i]; | |||||
} | |||||
static inline void quat_sub(quat r, quat a, quat b) | |||||
{ | |||||
int i; | |||||
for(i=0; i<4; ++i) | |||||
r[i] = a[i] - b[i]; | |||||
} | |||||
static inline void quat_mul(quat r, quat p, quat q) | |||||
{ | |||||
vec3 w; | |||||
vec3_mul_cross(r, p, q); | |||||
vec3_scale(w, p, q[3]); | |||||
vec3_add(r, r, w); | |||||
vec3_scale(w, q, p[3]); | |||||
vec3_add(r, r, w); | |||||
r[3] = p[3]*q[3] - vec3_mul_inner(p, q); | |||||
} | |||||
static inline void quat_scale(quat r, quat v, float s) | |||||
{ | |||||
int i; | |||||
for(i=0; i<4; ++i) | |||||
r[i] = v[i] * s; | |||||
} | |||||
static inline float quat_inner_product(quat a, quat b) | |||||
{ | |||||
float p = 0.f; | |||||
int i; | |||||
for(i=0; i<4; ++i) | |||||
p += b[i]*a[i]; | |||||
return p; | |||||
} | |||||
static inline void quat_conj(quat r, quat q) | |||||
{ | |||||
int i; | |||||
for(i=0; i<3; ++i) | |||||
r[i] = -q[i]; | |||||
r[3] = q[3]; | |||||
} | |||||
static inline void quat_rotate(quat r, float angle, vec3 axis) { | |||||
int i; | |||||
vec3 v; | |||||
vec3_scale(v, axis, sinf(angle / 2)); | |||||
for(i=0; i<3; ++i) | |||||
r[i] = v[i]; | |||||
r[3] = cosf(angle / 2); | |||||
} | |||||
#define quat_norm vec4_norm | |||||
static inline void quat_mul_vec3(vec3 r, quat q, vec3 v) | |||||
{ | |||||
/* | |||||
* Method by Fabian 'ryg' Giessen (of Farbrausch) | |||||
t = 2 * cross(q.xyz, v) | |||||
v' = v + q.w * t + cross(q.xyz, t) | |||||
*/ | |||||
vec3 t = {q[0], q[1], q[2]}; | |||||
vec3 u = {q[0], q[1], q[2]}; | |||||
vec3_mul_cross(t, t, v); | |||||
vec3_scale(t, t, 2); | |||||
vec3_mul_cross(u, u, t); | |||||
vec3_scale(t, t, q[3]); | |||||
vec3_add(r, v, t); | |||||
vec3_add(r, r, u); | |||||
} | |||||
static inline void mat4x4_from_quat(mat4x4 M, quat q) | |||||
{ | |||||
float a = q[3]; | |||||
float b = q[0]; | |||||
float c = q[1]; | |||||
float d = q[2]; | |||||
float a2 = a*a; | |||||
float b2 = b*b; | |||||
float c2 = c*c; | |||||
float d2 = d*d; | |||||
M[0][0] = a2 + b2 - c2 - d2; | |||||
M[0][1] = 2.f*(b*c + a*d); | |||||
M[0][2] = 2.f*(b*d - a*c); | |||||
M[0][3] = 0.f; | |||||
M[1][0] = 2*(b*c - a*d); | |||||
M[1][1] = a2 - b2 + c2 - d2; | |||||
M[1][2] = 2.f*(c*d + a*b); | |||||
M[1][3] = 0.f; | |||||
M[2][0] = 2.f*(b*d + a*c); | |||||
M[2][1] = 2.f*(c*d - a*b); | |||||
M[2][2] = a2 - b2 - c2 + d2; | |||||
M[2][3] = 0.f; | |||||
M[3][0] = M[3][1] = M[3][2] = 0.f; | |||||
M[3][3] = 1.f; | |||||
} | |||||
static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q) | |||||
{ | |||||
/* XXX: The way this is written only works for othogonal matrices. */ | |||||
/* TODO: Take care of non-orthogonal case. */ | |||||
quat_mul_vec3(R[0], q, M[0]); | |||||
quat_mul_vec3(R[1], q, M[1]); | |||||
quat_mul_vec3(R[2], q, M[2]); | |||||
R[3][0] = R[3][1] = R[3][2] = 0.f; | |||||
R[3][3] = 1.f; | |||||
} | |||||
static inline void quat_from_mat4x4(quat q, mat4x4 M) | |||||
{ | |||||
float r=0.f; | |||||
int i; | |||||
int perm[] = { 0, 1, 2, 0, 1 }; | |||||
int *p = perm; | |||||
for(i = 0; i<3; i++) { | |||||
float m = M[i][i]; | |||||
if( m < r ) | |||||
continue; | |||||
m = r; | |||||
p = &perm[i]; | |||||
} | |||||
r = (float) sqrt(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]] ); | |||||
if(r < 1e-6) { | |||||
q[0] = 1.f; | |||||
q[1] = q[2] = q[3] = 0.f; | |||||
return; | |||||
} | |||||
q[0] = r/2.f; | |||||
q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]])/(2.f*r); | |||||
q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]])/(2.f*r); | |||||
q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]])/(2.f*r); | |||||
} | |||||
#endif |
@ -1,372 +0,0 @@ | |||||
/* | |||||
* Nuklear - v1.32.0 - public domain | |||||
* no warrenty implied; use at your own risk. | |||||
* authored from 2015-2017 by Micha Mettke | |||||
*/ | |||||
/* | |||||
* ============================================================== | |||||
* | |||||
* API | |||||
* | |||||
* =============================================================== | |||||
*/ | |||||
#ifndef NK_GLFW_GL2_H_ | |||||
#define NK_GLFW_GL2_H_ | |||||
#include <GLFW/glfw3.h> | |||||
enum nk_glfw_init_state{ | |||||
NK_GLFW3_DEFAULT = 0, | |||||
NK_GLFW3_INSTALL_CALLBACKS | |||||
}; | |||||
NK_API struct nk_context* nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state); | |||||
NK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas); | |||||
NK_API void nk_glfw3_font_stash_end(void); | |||||
NK_API void nk_glfw3_new_frame(void); | |||||
NK_API void nk_glfw3_render(enum nk_anti_aliasing); | |||||
NK_API void nk_glfw3_shutdown(void); | |||||
NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint); | |||||
NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff); | |||||
#endif | |||||
/* | |||||
* ============================================================== | |||||
* | |||||
* IMPLEMENTATION | |||||
* | |||||
* =============================================================== | |||||
*/ | |||||
#ifdef NK_GLFW_GL2_IMPLEMENTATION | |||||
#ifndef NK_GLFW_TEXT_MAX | |||||
#define NK_GLFW_TEXT_MAX 256 | |||||
#endif | |||||
#ifndef NK_GLFW_DOUBLE_CLICK_LO | |||||
#define NK_GLFW_DOUBLE_CLICK_LO 0.02 | |||||
#endif | |||||
#ifndef NK_GLFW_DOUBLE_CLICK_HI | |||||
#define NK_GLFW_DOUBLE_CLICK_HI 0.2 | |||||
#endif | |||||
struct nk_glfw_device { | |||||
struct nk_buffer cmds; | |||||
struct nk_draw_null_texture null; | |||||
GLuint font_tex; | |||||
}; | |||||
struct nk_glfw_vertex { | |||||
float position[2]; | |||||
float uv[2]; | |||||
nk_byte col[4]; | |||||
}; | |||||
static struct nk_glfw { | |||||
GLFWwindow *win; | |||||
int width, height; | |||||
int display_width, display_height; | |||||
struct nk_glfw_device ogl; | |||||
struct nk_context ctx; | |||||
struct nk_font_atlas atlas; | |||||
struct nk_vec2 fb_scale; | |||||
unsigned int text[NK_GLFW_TEXT_MAX]; | |||||
int text_len; | |||||
struct nk_vec2 scroll; | |||||
double last_button_click; | |||||
} glfw; | |||||
NK_INTERN void | |||||
nk_glfw3_device_upload_atlas(const void *image, int width, int height) | |||||
{ | |||||
struct nk_glfw_device *dev = &glfw.ogl; | |||||
glGenTextures(1, &dev->font_tex); | |||||
glBindTexture(GL_TEXTURE_2D, dev->font_tex); | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, | |||||
GL_RGBA, GL_UNSIGNED_BYTE, image); | |||||
} | |||||
NK_API void | |||||
nk_glfw3_render(enum nk_anti_aliasing AA) | |||||
{ | |||||
/* setup global state */ | |||||
struct nk_glfw_device *dev = &glfw.ogl; | |||||
glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT); | |||||
glDisable(GL_CULL_FACE); | |||||
glDisable(GL_DEPTH_TEST); | |||||
glEnable(GL_SCISSOR_TEST); | |||||
glEnable(GL_BLEND); | |||||
glEnable(GL_TEXTURE_2D); | |||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
/* setup viewport/project */ | |||||
glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height); | |||||
glMatrixMode(GL_PROJECTION); | |||||
glPushMatrix(); | |||||
glLoadIdentity(); | |||||
glOrtho(0.0f, glfw.width, glfw.height, 0.0f, -1.0f, 1.0f); | |||||
glMatrixMode(GL_MODELVIEW); | |||||
glPushMatrix(); | |||||
glLoadIdentity(); | |||||
glEnableClientState(GL_VERTEX_ARRAY); | |||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |||||
glEnableClientState(GL_COLOR_ARRAY); | |||||
{ | |||||
GLsizei vs = sizeof(struct nk_glfw_vertex); | |||||
size_t vp = offsetof(struct nk_glfw_vertex, position); | |||||
size_t vt = offsetof(struct nk_glfw_vertex, uv); | |||||
size_t vc = offsetof(struct nk_glfw_vertex, col); | |||||
/* convert from command queue into draw list and draw to screen */ | |||||
const struct nk_draw_command *cmd; | |||||
const nk_draw_index *offset = NULL; | |||||
struct nk_buffer vbuf, ebuf; | |||||
/* fill convert configuration */ | |||||
struct nk_convert_config config; | |||||
static const struct nk_draw_vertex_layout_element vertex_layout[] = { | |||||
{NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)}, | |||||
{NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)}, | |||||
{NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)}, | |||||
{NK_VERTEX_LAYOUT_END} | |||||
}; | |||||
NK_MEMSET(&config, 0, sizeof(config)); | |||||
config.vertex_layout = vertex_layout; | |||||
config.vertex_size = sizeof(struct nk_glfw_vertex); | |||||
config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex); | |||||
config.null = dev->null; | |||||
config.circle_segment_count = 22; | |||||
config.curve_segment_count = 22; | |||||
config.arc_segment_count = 22; | |||||
config.global_alpha = 1.0f; | |||||
config.shape_AA = AA; | |||||
config.line_AA = AA; | |||||
/* convert shapes into vertexes */ | |||||
nk_buffer_init_default(&vbuf); | |||||
nk_buffer_init_default(&ebuf); | |||||
nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config); | |||||
/* setup vertex buffer pointer */ | |||||
{const void *vertices = nk_buffer_memory_const(&vbuf); | |||||
glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp)); | |||||
glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt)); | |||||
glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));} | |||||
/* iterate over and execute each draw command */ | |||||
offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf); | |||||
nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds) | |||||
{ | |||||
if (!cmd->elem_count) continue; | |||||
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); | |||||
glScissor( | |||||
(GLint)(cmd->clip_rect.x * glfw.fb_scale.x), | |||||
(GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y), | |||||
(GLint)(cmd->clip_rect.w * glfw.fb_scale.x), | |||||
(GLint)(cmd->clip_rect.h * glfw.fb_scale.y)); | |||||
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); | |||||
offset += cmd->elem_count; | |||||
} | |||||
nk_clear(&glfw.ctx); | |||||
nk_buffer_free(&vbuf); | |||||
nk_buffer_free(&ebuf); | |||||
} | |||||
/* default OpenGL state */ | |||||
glDisableClientState(GL_VERTEX_ARRAY); | |||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY); | |||||
glDisableClientState(GL_COLOR_ARRAY); | |||||
glDisable(GL_CULL_FACE); | |||||
glDisable(GL_DEPTH_TEST); | |||||
glDisable(GL_SCISSOR_TEST); | |||||
glDisable(GL_BLEND); | |||||
glDisable(GL_TEXTURE_2D); | |||||
glBindTexture(GL_TEXTURE_2D, 0); | |||||
glMatrixMode(GL_MODELVIEW); | |||||
glPopMatrix(); | |||||
glMatrixMode(GL_PROJECTION); | |||||
glPopMatrix(); | |||||
glPopAttrib(); | |||||
} | |||||
NK_API void | |||||
nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint) | |||||
{ | |||||
(void)win; | |||||
if (glfw.text_len < NK_GLFW_TEXT_MAX) | |||||
glfw.text[glfw.text_len++] = codepoint; | |||||
} | |||||
NK_API void | |||||
nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff) | |||||
{ | |||||
(void)win; (void)xoff; | |||||
glfw.scroll.x += (float)xoff; | |||||
glfw.scroll.y += (float)yoff; | |||||
} | |||||
NK_API void | |||||
nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) | |||||
{ | |||||
double x, y; | |||||
if (button != GLFW_MOUSE_BUTTON_LEFT) return; | |||||
glfwGetCursorPos(window, &x, &y); | |||||
if (action == GLFW_PRESS) { | |||||
double dt = glfwGetTime() - glfw.last_button_click; | |||||
if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) | |||||
nk_input_button(&glfw.ctx, NK_BUTTON_DOUBLE, (int)x, (int)y, nk_true); | |||||
glfw.last_button_click = glfwGetTime(); | |||||
} else nk_input_button(&glfw.ctx, NK_BUTTON_DOUBLE, (int)x, (int)y, nk_false); | |||||
} | |||||
NK_INTERN void | |||||
nk_glfw3_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) | |||||
{ | |||||
const char *text = glfwGetClipboardString(glfw.win); | |||||
if (text) nk_textedit_paste(edit, text, nk_strlen(text)); | |||||
(void)usr; | |||||
} | |||||
NK_INTERN void | |||||
nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len) | |||||
{ | |||||
char *str = 0; | |||||
(void)usr; | |||||
if (!len) return; | |||||
str = (char*)malloc((size_t)len+1); | |||||
if (!str) return; | |||||
NK_MEMCPY(str, text, (size_t)len); | |||||
str[len] = '\0'; | |||||
glfwSetClipboardString(glfw.win, str); | |||||
free(str); | |||||
} | |||||
NK_API struct nk_context* | |||||
nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state) | |||||
{ | |||||
glfw.win = win; | |||||
if (init_state == NK_GLFW3_INSTALL_CALLBACKS) { | |||||
glfwSetScrollCallback(win, nk_gflw3_scroll_callback); | |||||
glfwSetCharCallback(win, nk_glfw3_char_callback); | |||||
glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback); | |||||
} | |||||
nk_init_default(&glfw.ctx, 0); | |||||
glfw.ctx.clip.copy = nk_glfw3_clipbard_copy; | |||||
glfw.ctx.clip.paste = nk_glfw3_clipbard_paste; | |||||
glfw.ctx.clip.userdata = nk_handle_ptr(0); | |||||
nk_buffer_init_default(&glfw.ogl.cmds); | |||||
return &glfw.ctx; | |||||
} | |||||
NK_API void | |||||
nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas) | |||||
{ | |||||
nk_font_atlas_init_default(&glfw.atlas); | |||||
nk_font_atlas_begin(&glfw.atlas); | |||||
*atlas = &glfw.atlas; | |||||
} | |||||
NK_API void | |||||
nk_glfw3_font_stash_end(void) | |||||
{ | |||||
const void *image; int w, h; | |||||
image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); | |||||
nk_glfw3_device_upload_atlas(image, w, h); | |||||
nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.null); | |||||
if (glfw.atlas.default_font) | |||||
nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle); | |||||
} | |||||
NK_API void | |||||
nk_glfw3_new_frame(void) | |||||
{ | |||||
int i; | |||||
double x, y; | |||||
struct nk_context *ctx = &glfw.ctx; | |||||
struct GLFWwindow *win = glfw.win; | |||||
glfwGetWindowSize(win, &glfw.width, &glfw.height); | |||||
glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height); | |||||
glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width; | |||||
glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height; | |||||
nk_input_begin(ctx); | |||||
for (i = 0; i < glfw.text_len; ++i) | |||||
nk_input_unicode(ctx, glfw.text[i]); | |||||
/* optional grabbing behavior */ | |||||
if (ctx->input.mouse.grab) | |||||
glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); | |||||
else if (ctx->input.mouse.ungrab) | |||||
glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); | |||||
nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_SCROLL_DOWN, glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_SCROLL_UP, glfwGetKey(win, GLFW_KEY_PAGE_UP) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS|| | |||||
glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS); | |||||
if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || | |||||
glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) { | |||||
nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_V) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS); | |||||
} else { | |||||
nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); | |||||
nk_input_key(ctx, NK_KEY_COPY, 0); | |||||
nk_input_key(ctx, NK_KEY_PASTE, 0); | |||||
nk_input_key(ctx, NK_KEY_CUT, 0); | |||||
nk_input_key(ctx, NK_KEY_SHIFT, 0); | |||||
} | |||||
glfwGetCursorPos(win, &x, &y); | |||||
nk_input_motion(ctx, (int)x, (int)y); | |||||
if (ctx->input.mouse.grabbed) { | |||||
glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y); | |||||
ctx->input.mouse.pos.x = ctx->input.mouse.prev.x; | |||||
ctx->input.mouse.pos.y = ctx->input.mouse.prev.y; | |||||
} | |||||
nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); | |||||
nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); | |||||
nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); | |||||
nk_input_scroll(ctx, glfw.scroll); | |||||
nk_input_end(&glfw.ctx); | |||||
glfw.text_len = 0; | |||||
glfw.scroll = nk_vec2(0,0); | |||||
} | |||||
NK_API | |||||
void nk_glfw3_shutdown(void) | |||||
{ | |||||
struct nk_glfw_device *dev = &glfw.ogl; | |||||
nk_font_atlas_clear(&glfw.atlas); | |||||
nk_free(&glfw.ctx); | |||||
glDeleteTextures(1, &dev->font_tex); | |||||
nk_buffer_free(&dev->cmds); | |||||
NK_MEMSET(&glfw, 0, sizeof(glfw)); | |||||
} | |||||
#endif |
@ -1,594 +0,0 @@ | |||||
/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- | |||||
Copyright (c) 2012 Marcus Geelnard | |||||
This software is provided 'as-is', without any express or implied | |||||
warranty. In no event will the authors be held liable for any damages | |||||
arising from the use of this software. | |||||
Permission is granted to anyone to use this software for any purpose, | |||||
including commercial applications, and to alter it and redistribute it | |||||
freely, subject to the following restrictions: | |||||
1. The origin of this software must not be misrepresented; you must not | |||||
claim that you wrote the original software. If you use this software | |||||
in a product, an acknowledgment in the product documentation would be | |||||
appreciated but is not required. | |||||
2. Altered source versions must be plainly marked as such, and must not be | |||||
misrepresented as being the original software. | |||||
3. This notice may not be removed or altered from any source | |||||
distribution. | |||||
*/ | |||||
/* 2013-01-06 Camilla Löwy <elmindreda@glfw.org> | |||||
* | |||||
* Added casts from time_t to DWORD to avoid warnings on VC++. | |||||
* Fixed time retrieval on POSIX systems. | |||||
*/ | |||||
#include "tinycthread.h" | |||||
#include <stdlib.h> | |||||
/* Platform specific includes */ | |||||
#if defined(_TTHREAD_POSIX_) | |||||
#include <signal.h> | |||||
#include <sched.h> | |||||
#include <unistd.h> | |||||
#include <sys/time.h> | |||||
#include <errno.h> | |||||
#elif defined(_TTHREAD_WIN32_) | |||||
#include <process.h> | |||||
#include <sys/timeb.h> | |||||
#endif | |||||
/* Standard, good-to-have defines */ | |||||
#ifndef NULL | |||||
#define NULL (void*)0 | |||||
#endif | |||||
#ifndef TRUE | |||||
#define TRUE 1 | |||||
#endif | |||||
#ifndef FALSE | |||||
#define FALSE 0 | |||||
#endif | |||||
int mtx_init(mtx_t *mtx, int type) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
mtx->mAlreadyLocked = FALSE; | |||||
mtx->mRecursive = type & mtx_recursive; | |||||
InitializeCriticalSection(&mtx->mHandle); | |||||
return thrd_success; | |||||
#else | |||||
int ret; | |||||
pthread_mutexattr_t attr; | |||||
pthread_mutexattr_init(&attr); | |||||
if (type & mtx_recursive) | |||||
{ | |||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); | |||||
} | |||||
ret = pthread_mutex_init(mtx, &attr); | |||||
pthread_mutexattr_destroy(&attr); | |||||
return ret == 0 ? thrd_success : thrd_error; | |||||
#endif | |||||
} | |||||
void mtx_destroy(mtx_t *mtx) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
DeleteCriticalSection(&mtx->mHandle); | |||||
#else | |||||
pthread_mutex_destroy(mtx); | |||||
#endif | |||||
} | |||||
int mtx_lock(mtx_t *mtx) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
EnterCriticalSection(&mtx->mHandle); | |||||
if (!mtx->mRecursive) | |||||
{ | |||||
while(mtx->mAlreadyLocked) Sleep(1000); /* Simulate deadlock... */ | |||||
mtx->mAlreadyLocked = TRUE; | |||||
} | |||||
return thrd_success; | |||||
#else | |||||
return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; | |||||
#endif | |||||
} | |||||
int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) | |||||
{ | |||||
/* FIXME! */ | |||||
(void)mtx; | |||||
(void)ts; | |||||
return thrd_error; | |||||
} | |||||
int mtx_trylock(mtx_t *mtx) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy; | |||||
if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked) | |||||
{ | |||||
LeaveCriticalSection(&mtx->mHandle); | |||||
ret = thrd_busy; | |||||
} | |||||
return ret; | |||||
#else | |||||
return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; | |||||
#endif | |||||
} | |||||
int mtx_unlock(mtx_t *mtx) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
mtx->mAlreadyLocked = FALSE; | |||||
LeaveCriticalSection(&mtx->mHandle); | |||||
return thrd_success; | |||||
#else | |||||
return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;; | |||||
#endif | |||||
} | |||||
#if defined(_TTHREAD_WIN32_) | |||||
#define _CONDITION_EVENT_ONE 0 | |||||
#define _CONDITION_EVENT_ALL 1 | |||||
#endif | |||||
int cnd_init(cnd_t *cond) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
cond->mWaitersCount = 0; | |||||
/* Init critical section */ | |||||
InitializeCriticalSection(&cond->mWaitersCountLock); | |||||
/* Init events */ | |||||
cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); | |||||
if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL) | |||||
{ | |||||
cond->mEvents[_CONDITION_EVENT_ALL] = NULL; | |||||
return thrd_error; | |||||
} | |||||
cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); | |||||
if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL) | |||||
{ | |||||
CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); | |||||
cond->mEvents[_CONDITION_EVENT_ONE] = NULL; | |||||
return thrd_error; | |||||
} | |||||
return thrd_success; | |||||
#else | |||||
return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error; | |||||
#endif | |||||
} | |||||
void cnd_destroy(cnd_t *cond) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL) | |||||
{ | |||||
CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); | |||||
} | |||||
if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL) | |||||
{ | |||||
CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]); | |||||
} | |||||
DeleteCriticalSection(&cond->mWaitersCountLock); | |||||
#else | |||||
pthread_cond_destroy(cond); | |||||
#endif | |||||
} | |||||
int cnd_signal(cnd_t *cond) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
int haveWaiters; | |||||
/* Are there any waiters? */ | |||||
EnterCriticalSection(&cond->mWaitersCountLock); | |||||
haveWaiters = (cond->mWaitersCount > 0); | |||||
LeaveCriticalSection(&cond->mWaitersCountLock); | |||||
/* If we have any waiting threads, send them a signal */ | |||||
if(haveWaiters) | |||||
{ | |||||
if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0) | |||||
{ | |||||
return thrd_error; | |||||
} | |||||
} | |||||
return thrd_success; | |||||
#else | |||||
return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; | |||||
#endif | |||||
} | |||||
int cnd_broadcast(cnd_t *cond) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
int haveWaiters; | |||||
/* Are there any waiters? */ | |||||
EnterCriticalSection(&cond->mWaitersCountLock); | |||||
haveWaiters = (cond->mWaitersCount > 0); | |||||
LeaveCriticalSection(&cond->mWaitersCountLock); | |||||
/* If we have any waiting threads, send them a signal */ | |||||
if(haveWaiters) | |||||
{ | |||||
if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) | |||||
{ | |||||
return thrd_error; | |||||
} | |||||
} | |||||
return thrd_success; | |||||
#else | |||||
return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; | |||||
#endif | |||||
} | |||||
#if defined(_TTHREAD_WIN32_) | |||||
static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) | |||||
{ | |||||
int result, lastWaiter; | |||||
/* Increment number of waiters */ | |||||
EnterCriticalSection(&cond->mWaitersCountLock); | |||||
++ cond->mWaitersCount; | |||||
LeaveCriticalSection(&cond->mWaitersCountLock); | |||||
/* Release the mutex while waiting for the condition (will decrease | |||||
the number of waiters when done)... */ | |||||
mtx_unlock(mtx); | |||||
/* Wait for either event to become signaled due to cnd_signal() or | |||||
cnd_broadcast() being called */ | |||||
result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout); | |||||
if (result == WAIT_TIMEOUT) | |||||
{ | |||||
return thrd_timeout; | |||||
} | |||||
else if (result == (int)WAIT_FAILED) | |||||
{ | |||||
return thrd_error; | |||||
} | |||||
/* Check if we are the last waiter */ | |||||
EnterCriticalSection(&cond->mWaitersCountLock); | |||||
-- cond->mWaitersCount; | |||||
lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && | |||||
(cond->mWaitersCount == 0); | |||||
LeaveCriticalSection(&cond->mWaitersCountLock); | |||||
/* If we are the last waiter to be notified to stop waiting, reset the event */ | |||||
if (lastWaiter) | |||||
{ | |||||
if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) | |||||
{ | |||||
return thrd_error; | |||||
} | |||||
} | |||||
/* Re-acquire the mutex */ | |||||
mtx_lock(mtx); | |||||
return thrd_success; | |||||
} | |||||
#endif | |||||
int cnd_wait(cnd_t *cond, mtx_t *mtx) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
return _cnd_timedwait_win32(cond, mtx, INFINITE); | |||||
#else | |||||
return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; | |||||
#endif | |||||
} | |||||
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
struct timespec now; | |||||
if (clock_gettime(CLOCK_REALTIME, &now) == 0) | |||||
{ | |||||
DWORD delta = (DWORD) ((ts->tv_sec - now.tv_sec) * 1000 + | |||||
(ts->tv_nsec - now.tv_nsec + 500000) / 1000000); | |||||
return _cnd_timedwait_win32(cond, mtx, delta); | |||||
} | |||||
else | |||||
return thrd_error; | |||||
#else | |||||
int ret; | |||||
ret = pthread_cond_timedwait(cond, mtx, ts); | |||||
if (ret == ETIMEDOUT) | |||||
{ | |||||
return thrd_timeout; | |||||
} | |||||
return ret == 0 ? thrd_success : thrd_error; | |||||
#endif | |||||
} | |||||
/** Information to pass to the new thread (what to run). */ | |||||
typedef struct { | |||||
thrd_start_t mFunction; /**< Pointer to the function to be executed. */ | |||||
void * mArg; /**< Function argument for the thread function. */ | |||||
} _thread_start_info; | |||||
/* Thread wrapper function. */ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
static unsigned WINAPI _thrd_wrapper_function(void * aArg) | |||||
#elif defined(_TTHREAD_POSIX_) | |||||
static void * _thrd_wrapper_function(void * aArg) | |||||
#endif | |||||
{ | |||||
thrd_start_t fun; | |||||
void *arg; | |||||
int res; | |||||
#if defined(_TTHREAD_POSIX_) | |||||
void *pres; | |||||
#endif | |||||
/* Get thread startup information */ | |||||
_thread_start_info *ti = (_thread_start_info *) aArg; | |||||
fun = ti->mFunction; | |||||
arg = ti->mArg; | |||||
/* The thread is responsible for freeing the startup information */ | |||||
free((void *)ti); | |||||
/* Call the actual client thread function */ | |||||
res = fun(arg); | |||||
#if defined(_TTHREAD_WIN32_) | |||||
return res; | |||||
#else | |||||
pres = malloc(sizeof(int)); | |||||
if (pres != NULL) | |||||
{ | |||||
*(int*)pres = res; | |||||
} | |||||
return pres; | |||||
#endif | |||||
} | |||||
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) | |||||
{ | |||||
/* Fill out the thread startup information (passed to the thread wrapper, | |||||
which will eventually free it) */ | |||||
_thread_start_info* ti = (_thread_start_info*)malloc(sizeof(_thread_start_info)); | |||||
if (ti == NULL) | |||||
{ | |||||
return thrd_nomem; | |||||
} | |||||
ti->mFunction = func; | |||||
ti->mArg = arg; | |||||
/* Create the thread */ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
*thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL); | |||||
#elif defined(_TTHREAD_POSIX_) | |||||
if(pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0) | |||||
{ | |||||
*thr = 0; | |||||
} | |||||
#endif | |||||
/* Did we fail to create the thread? */ | |||||
if(!*thr) | |||||
{ | |||||
free(ti); | |||||
return thrd_error; | |||||
} | |||||
return thrd_success; | |||||
} | |||||
thrd_t thrd_current(void) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
return GetCurrentThread(); | |||||
#else | |||||
return pthread_self(); | |||||
#endif | |||||
} | |||||
int thrd_detach(thrd_t thr) | |||||
{ | |||||
/* FIXME! */ | |||||
(void)thr; | |||||
return thrd_error; | |||||
} | |||||
int thrd_equal(thrd_t thr0, thrd_t thr1) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
return thr0 == thr1; | |||||
#else | |||||
return pthread_equal(thr0, thr1); | |||||
#endif | |||||
} | |||||
void thrd_exit(int res) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
ExitThread(res); | |||||
#else | |||||
void *pres = malloc(sizeof(int)); | |||||
if (pres != NULL) | |||||
{ | |||||
*(int*)pres = res; | |||||
} | |||||
pthread_exit(pres); | |||||
#endif | |||||
} | |||||
int thrd_join(thrd_t thr, int *res) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED) | |||||
{ | |||||
return thrd_error; | |||||
} | |||||
if (res != NULL) | |||||
{ | |||||
DWORD dwRes; | |||||
GetExitCodeThread(thr, &dwRes); | |||||
*res = dwRes; | |||||
} | |||||
#elif defined(_TTHREAD_POSIX_) | |||||
void *pres; | |||||
int ires = 0; | |||||
if (pthread_join(thr, &pres) != 0) | |||||
{ | |||||
return thrd_error; | |||||
} | |||||
if (pres != NULL) | |||||
{ | |||||
ires = *(int*)pres; | |||||
free(pres); | |||||
} | |||||
if (res != NULL) | |||||
{ | |||||
*res = ires; | |||||
} | |||||
#endif | |||||
return thrd_success; | |||||
} | |||||
int thrd_sleep(const struct timespec *time_point, struct timespec *remaining) | |||||
{ | |||||
struct timespec now; | |||||
#if defined(_TTHREAD_WIN32_) | |||||
DWORD delta; | |||||
#else | |||||
long delta; | |||||
#endif | |||||
/* Get the current time */ | |||||
if (clock_gettime(CLOCK_REALTIME, &now) != 0) | |||||
return -2; // FIXME: Some specific error code? | |||||
#if defined(_TTHREAD_WIN32_) | |||||
/* Delta in milliseconds */ | |||||
delta = (DWORD) ((time_point->tv_sec - now.tv_sec) * 1000 + | |||||
(time_point->tv_nsec - now.tv_nsec + 500000) / 1000000); | |||||
if (delta > 0) | |||||
{ | |||||
Sleep(delta); | |||||
} | |||||
#else | |||||
/* Delta in microseconds */ | |||||
delta = (time_point->tv_sec - now.tv_sec) * 1000000L + | |||||
(time_point->tv_nsec - now.tv_nsec + 500L) / 1000L; | |||||
/* On some systems, the usleep argument must be < 1000000 */ | |||||
while (delta > 999999L) | |||||
{ | |||||
usleep(999999); | |||||
delta -= 999999L; | |||||
} | |||||
if (delta > 0L) | |||||
{ | |||||
usleep((useconds_t)delta); | |||||
} | |||||
#endif | |||||
/* We don't support waking up prematurely (yet) */ | |||||
if (remaining) | |||||
{ | |||||
remaining->tv_sec = 0; | |||||
remaining->tv_nsec = 0; | |||||
} | |||||
return 0; | |||||
} | |||||
void thrd_yield(void) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
Sleep(0); | |||||
#else | |||||
sched_yield(); | |||||
#endif | |||||
} | |||||
int tss_create(tss_t *key, tss_dtor_t dtor) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
/* FIXME: The destructor function is not supported yet... */ | |||||
if (dtor != NULL) | |||||
{ | |||||
return thrd_error; | |||||
} | |||||
*key = TlsAlloc(); | |||||
if (*key == TLS_OUT_OF_INDEXES) | |||||
{ | |||||
return thrd_error; | |||||
} | |||||
#else | |||||
if (pthread_key_create(key, dtor) != 0) | |||||
{ | |||||
return thrd_error; | |||||
} | |||||
#endif | |||||
return thrd_success; | |||||
} | |||||
void tss_delete(tss_t key) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
TlsFree(key); | |||||
#else | |||||
pthread_key_delete(key); | |||||
#endif | |||||
} | |||||
void *tss_get(tss_t key) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
return TlsGetValue(key); | |||||
#else | |||||
return pthread_getspecific(key); | |||||
#endif | |||||
} | |||||
int tss_set(tss_t key, void *val) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
if (TlsSetValue(key, val) == 0) | |||||
{ | |||||
return thrd_error; | |||||
} | |||||
#else | |||||
if (pthread_setspecific(key, val) != 0) | |||||
{ | |||||
return thrd_error; | |||||
} | |||||
#endif | |||||
return thrd_success; | |||||
} | |||||
#if defined(_TTHREAD_EMULATE_CLOCK_GETTIME_) | |||||
int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts) | |||||
{ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
struct _timeb tb; | |||||
_ftime(&tb); | |||||
ts->tv_sec = (time_t)tb.time; | |||||
ts->tv_nsec = 1000000L * (long)tb.millitm; | |||||
#else | |||||
struct timeval tv; | |||||
gettimeofday(&tv, NULL); | |||||
ts->tv_sec = (time_t)tv.tv_sec; | |||||
ts->tv_nsec = 1000L * (long)tv.tv_usec; | |||||
#endif | |||||
return 0; | |||||
} | |||||
#endif // _TTHREAD_EMULATE_CLOCK_GETTIME_ | |||||
@ -1,443 +0,0 @@ | |||||
/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- | |||||
Copyright (c) 2012 Marcus Geelnard | |||||
This software is provided 'as-is', without any express or implied | |||||
warranty. In no event will the authors be held liable for any damages | |||||
arising from the use of this software. | |||||
Permission is granted to anyone to use this software for any purpose, | |||||
including commercial applications, and to alter it and redistribute it | |||||
freely, subject to the following restrictions: | |||||
1. The origin of this software must not be misrepresented; you must not | |||||
claim that you wrote the original software. If you use this software | |||||
in a product, an acknowledgment in the product documentation would be | |||||
appreciated but is not required. | |||||
2. Altered source versions must be plainly marked as such, and must not be | |||||
misrepresented as being the original software. | |||||
3. This notice may not be removed or altered from any source | |||||
distribution. | |||||
*/ | |||||
#ifndef _TINYCTHREAD_H_ | |||||
#define _TINYCTHREAD_H_ | |||||
/** | |||||
* @file | |||||
* @mainpage TinyCThread API Reference | |||||
* | |||||
* @section intro_sec Introduction | |||||
* TinyCThread is a minimal, portable implementation of basic threading | |||||
* classes for C. | |||||
* | |||||
* They closely mimic the functionality and naming of the C11 standard, and | |||||
* should be easily replaceable with the corresponding standard variants. | |||||
* | |||||
* @section port_sec Portability | |||||
* The Win32 variant uses the native Win32 API for implementing the thread | |||||
* classes, while for other systems, the POSIX threads API (pthread) is used. | |||||
* | |||||
* @section misc_sec Miscellaneous | |||||
* The following special keywords are available: #_Thread_local. | |||||
* | |||||
* For more detailed information, browse the different sections of this | |||||
* documentation. A good place to start is: | |||||
* tinycthread.h. | |||||
*/ | |||||
/* Which platform are we on? */ | |||||
#if !defined(_TTHREAD_PLATFORM_DEFINED_) | |||||
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) | |||||
#define _TTHREAD_WIN32_ | |||||
#else | |||||
#define _TTHREAD_POSIX_ | |||||
#endif | |||||
#define _TTHREAD_PLATFORM_DEFINED_ | |||||
#endif | |||||
/* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */ | |||||
#if defined(_TTHREAD_POSIX_) | |||||
#undef _FEATURES_H | |||||
#if !defined(_GNU_SOURCE) | |||||
#define _GNU_SOURCE | |||||
#endif | |||||
#if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) | |||||
#undef _POSIX_C_SOURCE | |||||
#define _POSIX_C_SOURCE 199309L | |||||
#endif | |||||
#if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) | |||||
#undef _XOPEN_SOURCE | |||||
#define _XOPEN_SOURCE 500 | |||||
#endif | |||||
#endif | |||||
/* Generic includes */ | |||||
#include <time.h> | |||||
/* Platform specific includes */ | |||||
#if defined(_TTHREAD_POSIX_) | |||||
#include <sys/time.h> | |||||
#include <pthread.h> | |||||
#elif defined(_TTHREAD_WIN32_) | |||||
#ifndef WIN32_LEAN_AND_MEAN | |||||
#define WIN32_LEAN_AND_MEAN | |||||
#define __UNDEF_LEAN_AND_MEAN | |||||
#endif | |||||
#include <windows.h> | |||||
#ifdef __UNDEF_LEAN_AND_MEAN | |||||
#undef WIN32_LEAN_AND_MEAN | |||||
#undef __UNDEF_LEAN_AND_MEAN | |||||
#endif | |||||
#endif | |||||
/* Workaround for missing TIME_UTC: If time.h doesn't provide TIME_UTC, | |||||
it's quite likely that libc does not support it either. Hence, fall back to | |||||
the only other supported time specifier: CLOCK_REALTIME (and if that fails, | |||||
we're probably emulating clock_gettime anyway, so anything goes). */ | |||||
#ifndef TIME_UTC | |||||
#ifdef CLOCK_REALTIME | |||||
#define TIME_UTC CLOCK_REALTIME | |||||
#else | |||||
#define TIME_UTC 0 | |||||
#endif | |||||
#endif | |||||
/* Workaround for missing clock_gettime (most Windows compilers, afaik) */ | |||||
#if defined(_TTHREAD_WIN32_) || defined(__APPLE_CC__) | |||||
#define _TTHREAD_EMULATE_CLOCK_GETTIME_ | |||||
/* Emulate struct timespec */ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
struct _ttherad_timespec { | |||||
time_t tv_sec; | |||||
long tv_nsec; | |||||
}; | |||||
#define timespec _ttherad_timespec | |||||
#endif | |||||
/* Emulate clockid_t */ | |||||
typedef int _tthread_clockid_t; | |||||
#define clockid_t _tthread_clockid_t | |||||
/* Emulate clock_gettime */ | |||||
int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); | |||||
#define clock_gettime _tthread_clock_gettime | |||||
#ifndef CLOCK_REALTIME | |||||
#define CLOCK_REALTIME 0 | |||||
#endif | |||||
#endif | |||||
/** TinyCThread version (major number). */ | |||||
#define TINYCTHREAD_VERSION_MAJOR 1 | |||||
/** TinyCThread version (minor number). */ | |||||
#define TINYCTHREAD_VERSION_MINOR 1 | |||||
/** TinyCThread version (full version). */ | |||||
#define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR) | |||||
/** | |||||
* @def _Thread_local | |||||
* Thread local storage keyword. | |||||
* A variable that is declared with the @c _Thread_local keyword makes the | |||||
* value of the variable local to each thread (known as thread-local storage, | |||||
* or TLS). Example usage: | |||||
* @code | |||||
* // This variable is local to each thread. | |||||
* _Thread_local int variable; | |||||
* @endcode | |||||
* @note The @c _Thread_local keyword is a macro that maps to the corresponding | |||||
* compiler directive (e.g. @c __declspec(thread)). | |||||
* @note This directive is currently not supported on Mac OS X (it will give | |||||
* a compiler error), since compile-time TLS is not supported in the Mac OS X | |||||
* executable format. Also, some older versions of MinGW (before GCC 4.x) do | |||||
* not support this directive. | |||||
* @hideinitializer | |||||
*/ | |||||
/* FIXME: Check for a PROPER value of __STDC_VERSION__ to know if we have C11 */ | |||||
#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local) | |||||
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) | |||||
#define _Thread_local __thread | |||||
#else | |||||
#define _Thread_local __declspec(thread) | |||||
#endif | |||||
#endif | |||||
/* Macros */ | |||||
#define TSS_DTOR_ITERATIONS 0 | |||||
/* Function return values */ | |||||
#define thrd_error 0 /**< The requested operation failed */ | |||||
#define thrd_success 1 /**< The requested operation succeeded */ | |||||
#define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ | |||||
#define thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ | |||||
#define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ | |||||
/* Mutex types */ | |||||
#define mtx_plain 1 | |||||
#define mtx_timed 2 | |||||
#define mtx_try 4 | |||||
#define mtx_recursive 8 | |||||
/* Mutex */ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
typedef struct { | |||||
CRITICAL_SECTION mHandle; /* Critical section handle */ | |||||
int mAlreadyLocked; /* TRUE if the mutex is already locked */ | |||||
int mRecursive; /* TRUE if the mutex is recursive */ | |||||
} mtx_t; | |||||
#else | |||||
typedef pthread_mutex_t mtx_t; | |||||
#endif | |||||
/** Create a mutex object. | |||||
* @param mtx A mutex object. | |||||
* @param type Bit-mask that must have one of the following six values: | |||||
* @li @c mtx_plain for a simple non-recursive mutex | |||||
* @li @c mtx_timed for a non-recursive mutex that supports timeout | |||||
* @li @c mtx_try for a non-recursive mutex that supports test and return | |||||
* @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) | |||||
* @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) | |||||
* @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) | |||||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||||
* not be honored. | |||||
*/ | |||||
int mtx_init(mtx_t *mtx, int type); | |||||
/** Release any resources used by the given mutex. | |||||
* @param mtx A mutex object. | |||||
*/ | |||||
void mtx_destroy(mtx_t *mtx); | |||||
/** Lock the given mutex. | |||||
* Blocks until the given mutex can be locked. If the mutex is non-recursive, and | |||||
* the calling thread already has a lock on the mutex, this call will block | |||||
* forever. | |||||
* @param mtx A mutex object. | |||||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||||
* not be honored. | |||||
*/ | |||||
int mtx_lock(mtx_t *mtx); | |||||
/** NOT YET IMPLEMENTED. | |||||
*/ | |||||
int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); | |||||
/** Try to lock the given mutex. | |||||
* The specified mutex shall support either test and return or timeout. If the | |||||
* mutex is already locked, the function returns without blocking. | |||||
* @param mtx A mutex object. | |||||
* @return @ref thrd_success on success, or @ref thrd_busy if the resource | |||||
* requested is already in use, or @ref thrd_error if the request could not be | |||||
* honored. | |||||
*/ | |||||
int mtx_trylock(mtx_t *mtx); | |||||
/** Unlock the given mutex. | |||||
* @param mtx A mutex object. | |||||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||||
* not be honored. | |||||
*/ | |||||
int mtx_unlock(mtx_t *mtx); | |||||
/* Condition variable */ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
typedef struct { | |||||
HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ | |||||
unsigned int mWaitersCount; /* Count of the number of waiters. */ | |||||
CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ | |||||
} cnd_t; | |||||
#else | |||||
typedef pthread_cond_t cnd_t; | |||||
#endif | |||||
/** Create a condition variable object. | |||||
* @param cond A condition variable object. | |||||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||||
* not be honored. | |||||
*/ | |||||
int cnd_init(cnd_t *cond); | |||||
/** Release any resources used by the given condition variable. | |||||
* @param cond A condition variable object. | |||||
*/ | |||||
void cnd_destroy(cnd_t *cond); | |||||
/** Signal a condition variable. | |||||
* Unblocks one of the threads that are blocked on the given condition variable | |||||
* at the time of the call. If no threads are blocked on the condition variable | |||||
* at the time of the call, the function does nothing and return success. | |||||
* @param cond A condition variable object. | |||||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||||
* not be honored. | |||||
*/ | |||||
int cnd_signal(cnd_t *cond); | |||||
/** Broadcast a condition variable. | |||||
* Unblocks all of the threads that are blocked on the given condition variable | |||||
* at the time of the call. If no threads are blocked on the condition variable | |||||
* at the time of the call, the function does nothing and return success. | |||||
* @param cond A condition variable object. | |||||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||||
* not be honored. | |||||
*/ | |||||
int cnd_broadcast(cnd_t *cond); | |||||
/** Wait for a condition variable to become signaled. | |||||
* The function atomically unlocks the given mutex and endeavors to block until | |||||
* the given condition variable is signaled by a call to cnd_signal or to | |||||
* cnd_broadcast. When the calling thread becomes unblocked it locks the mutex | |||||
* before it returns. | |||||
* @param cond A condition variable object. | |||||
* @param mtx A mutex object. | |||||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||||
* not be honored. | |||||
*/ | |||||
int cnd_wait(cnd_t *cond, mtx_t *mtx); | |||||
/** Wait for a condition variable to become signaled. | |||||
* The function atomically unlocks the given mutex and endeavors to block until | |||||
* the given condition variable is signaled by a call to cnd_signal or to | |||||
* cnd_broadcast, or until after the specified time. When the calling thread | |||||
* becomes unblocked it locks the mutex before it returns. | |||||
* @param cond A condition variable object. | |||||
* @param mtx A mutex object. | |||||
* @param xt A point in time at which the request will time out (absolute time). | |||||
* @return @ref thrd_success upon success, or @ref thrd_timeout if the time | |||||
* specified in the call was reached without acquiring the requested resource, or | |||||
* @ref thrd_error if the request could not be honored. | |||||
*/ | |||||
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); | |||||
/* Thread */ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
typedef HANDLE thrd_t; | |||||
#else | |||||
typedef pthread_t thrd_t; | |||||
#endif | |||||
/** Thread start function. | |||||
* Any thread that is started with the @ref thrd_create() function must be | |||||
* started through a function of this type. | |||||
* @param arg The thread argument (the @c arg argument of the corresponding | |||||
* @ref thrd_create() call). | |||||
* @return The thread return value, which can be obtained by another thread | |||||
* by using the @ref thrd_join() function. | |||||
*/ | |||||
typedef int (*thrd_start_t)(void *arg); | |||||
/** Create a new thread. | |||||
* @param thr Identifier of the newly created thread. | |||||
* @param func A function pointer to the function that will be executed in | |||||
* the new thread. | |||||
* @param arg An argument to the thread function. | |||||
* @return @ref thrd_success on success, or @ref thrd_nomem if no memory could | |||||
* be allocated for the thread requested, or @ref thrd_error if the request | |||||
* could not be honored. | |||||
* @note A thread’s identifier may be reused for a different thread once the | |||||
* original thread has exited and either been detached or joined to another | |||||
* thread. | |||||
*/ | |||||
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); | |||||
/** Identify the calling thread. | |||||
* @return The identifier of the calling thread. | |||||
*/ | |||||
thrd_t thrd_current(void); | |||||
/** NOT YET IMPLEMENTED. | |||||
*/ | |||||
int thrd_detach(thrd_t thr); | |||||
/** Compare two thread identifiers. | |||||
* The function determines if two thread identifiers refer to the same thread. | |||||
* @return Zero if the two thread identifiers refer to different threads. | |||||
* Otherwise a nonzero value is returned. | |||||
*/ | |||||
int thrd_equal(thrd_t thr0, thrd_t thr1); | |||||
/** Terminate execution of the calling thread. | |||||
* @param res Result code of the calling thread. | |||||
*/ | |||||
void thrd_exit(int res); | |||||
/** Wait for a thread to terminate. | |||||
* The function joins the given thread with the current thread by blocking | |||||
* until the other thread has terminated. | |||||
* @param thr The thread to join with. | |||||
* @param res If this pointer is not NULL, the function will store the result | |||||
* code of the given thread in the integer pointed to by @c res. | |||||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||||
* not be honored. | |||||
*/ | |||||
int thrd_join(thrd_t thr, int *res); | |||||
/** Put the calling thread to sleep. | |||||
* Suspend execution of the calling thread. | |||||
* @param time_point A point in time at which the thread will resume (absolute time). | |||||
* @param remaining If non-NULL, this parameter will hold the remaining time until | |||||
* time_point upon return. This will typically be zero, but if | |||||
* the thread was woken up by a signal that is not ignored before | |||||
* time_point was reached @c remaining will hold a positive | |||||
* time. | |||||
* @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. | |||||
*/ | |||||
int thrd_sleep(const struct timespec *time_point, struct timespec *remaining); | |||||
/** Yield execution to another thread. | |||||
* Permit other threads to run, even if the current thread would ordinarily | |||||
* continue to run. | |||||
*/ | |||||
void thrd_yield(void); | |||||
/* Thread local storage */ | |||||
#if defined(_TTHREAD_WIN32_) | |||||
typedef DWORD tss_t; | |||||
#else | |||||
typedef pthread_key_t tss_t; | |||||
#endif | |||||
/** Destructor function for a thread-specific storage. | |||||
* @param val The value of the destructed thread-specific storage. | |||||
*/ | |||||
typedef void (*tss_dtor_t)(void *val); | |||||
/** Create a thread-specific storage. | |||||
* @param key The unique key identifier that will be set if the function is | |||||
* successful. | |||||
* @param dtor Destructor function. This can be NULL. | |||||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||||
* not be honored. | |||||
* @note The destructor function is not supported under Windows. If @c dtor is | |||||
* not NULL when calling this function under Windows, the function will fail | |||||
* and return @ref thrd_error. | |||||
*/ | |||||
int tss_create(tss_t *key, tss_dtor_t dtor); | |||||
/** Delete a thread-specific storage. | |||||
* The function releases any resources used by the given thread-specific | |||||
* storage. | |||||
* @param key The key that shall be deleted. | |||||
*/ | |||||
void tss_delete(tss_t key); | |||||
/** Get the value for a thread-specific storage. | |||||
* @param key The thread-specific storage identifier. | |||||
* @return The value for the current thread held in the given thread-specific | |||||
* storage. | |||||
*/ | |||||
void *tss_get(tss_t key); | |||||
/** Set the value for a thread-specific storage. | |||||
* @param key The thread-specific storage identifier. | |||||
* @param val The value of the thread-specific storage to set for the current | |||||
* thread. | |||||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||||
* not be honored. | |||||
*/ | |||||
int tss_set(tss_t key, void *val); | |||||
#endif /* _TINYTHREAD_H_ */ | |||||
@ -1,120 +0,0 @@ | |||||
// | |||||
// File: vk_platform.h | |||||
// | |||||
/* | |||||
** Copyright (c) 2014-2015 The Khronos Group Inc. | |||||
** | |||||
** Licensed under the Apache License, Version 2.0 (the "License"); | |||||
** you may not use this file except in compliance with the License. | |||||
** You may obtain a copy of the License at | |||||
** | |||||
** http://www.apache.org/licenses/LICENSE-2.0 | |||||
** | |||||
** Unless required by applicable law or agreed to in writing, software | |||||
** distributed under the License is distributed on an "AS IS" BASIS, | |||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
** See the License for the specific language governing permissions and | |||||
** limitations under the License. | |||||
*/ | |||||
#ifndef VK_PLATFORM_H_ | |||||
#define VK_PLATFORM_H_ | |||||
#ifdef __cplusplus | |||||
extern "C" | |||||
{ | |||||
#endif // __cplusplus | |||||
/* | |||||
*************************************************************************************************** | |||||
* Platform-specific directives and type declarations | |||||
*************************************************************************************************** | |||||
*/ | |||||
/* Platform-specific calling convention macros. | |||||
* | |||||
* Platforms should define these so that Vulkan clients call Vulkan commands | |||||
* with the same calling conventions that the Vulkan implementation expects. | |||||
* | |||||
* VKAPI_ATTR - Placed before the return type in function declarations. | |||||
* Useful for C++11 and GCC/Clang-style function attribute syntax. | |||||
* VKAPI_CALL - Placed after the return type in function declarations. | |||||
* Useful for MSVC-style calling convention syntax. | |||||
* VKAPI_PTR - Placed between the '(' and '*' in function pointer types. | |||||
* | |||||
* Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); | |||||
* Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); | |||||
*/ | |||||
#if defined(_WIN32) | |||||
// On Windows, Vulkan commands use the stdcall convention | |||||
#define VKAPI_ATTR | |||||
#define VKAPI_CALL __stdcall | |||||
#define VKAPI_PTR VKAPI_CALL | |||||
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 | |||||
#error "Vulkan isn't supported for the 'armeabi' NDK ABI" | |||||
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) | |||||
// On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" | |||||
// calling convention, i.e. float parameters are passed in registers. This | |||||
// is true even if the rest of the application passes floats on the stack, | |||||
// as it does by default when compiling for the armeabi-v7a NDK ABI. | |||||
#define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) | |||||
#define VKAPI_CALL | |||||
#define VKAPI_PTR VKAPI_ATTR | |||||
#else | |||||
// On other platforms, use the default calling convention | |||||
#define VKAPI_ATTR | |||||
#define VKAPI_CALL | |||||
#define VKAPI_PTR | |||||
#endif | |||||
#include <stddef.h> | |||||
#if !defined(VK_NO_STDINT_H) | |||||
#if defined(_MSC_VER) && (_MSC_VER < 1600) | |||||
typedef signed __int8 int8_t; | |||||
typedef unsigned __int8 uint8_t; | |||||
typedef signed __int16 int16_t; | |||||
typedef unsigned __int16 uint16_t; | |||||
typedef signed __int32 int32_t; | |||||
typedef unsigned __int32 uint32_t; | |||||
typedef signed __int64 int64_t; | |||||
typedef unsigned __int64 uint64_t; | |||||
#else | |||||
#include <stdint.h> | |||||
#endif | |||||
#endif // !defined(VK_NO_STDINT_H) | |||||
#ifdef __cplusplus | |||||
} // extern "C" | |||||
#endif // __cplusplus | |||||
// Platform-specific headers required by platform window system extensions. | |||||
// These are enabled prior to #including "vulkan.h". The same enable then | |||||
// controls inclusion of the extension interfaces in vulkan.h. | |||||
#ifdef VK_USE_PLATFORM_ANDROID_KHR | |||||
#include <android/native_window.h> | |||||
#endif | |||||
#ifdef VK_USE_PLATFORM_MIR_KHR | |||||
#include <mir_toolkit/client_types.h> | |||||
#endif | |||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR | |||||
#include <wayland-client.h> | |||||
#endif | |||||
#ifdef VK_USE_PLATFORM_WIN32_KHR | |||||
#include <windows.h> | |||||
#endif | |||||
#ifdef VK_USE_PLATFORM_XLIB_KHR | |||||
#include <X11/Xlib.h> | |||||
#endif | |||||
#ifdef VK_USE_PLATFORM_XCB_KHR | |||||
#include <xcb/xcb.h> | |||||
#endif | |||||
#endif |