commit cb7368c138395c7d84030b6b57b6b94e9ec63b1c Author: Gero Müller Date: Tue Jan 4 18:11:59 2011 +0100 initial commit diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..47a5acd --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required (VERSION 2.6) +project (GREMLIN C CXX) + +add_subdirectory (libs/glfw) +add_subdirectory (libs/enet) +add_subdirectory (src) diff --git a/libs/enet/CMakeLists.txt b/libs/enet/CMakeLists.txt new file mode 100644 index 0000000..0edd72e --- /dev/null +++ b/libs/enet/CMakeLists.txt @@ -0,0 +1,12 @@ +include_directories (include) + +add_library (enet callbacks.c + compress.c + host.c + list.c + packet.c + peer.c + protocol.c + unix.c + win32.c +) \ No newline at end of file diff --git a/libs/enet/ChangeLog b/libs/enet/ChangeLog new file mode 100644 index 0000000..45f14db --- /dev/null +++ b/libs/enet/ChangeLog @@ -0,0 +1,86 @@ +ENet 1.3.0 (June 5, 2010): + +* enet_host_create() now requires the channel limit to be specified as +a parameter +* enet_host_connect() now accepts a data parameter which is supplied +to the receiving receiving host in the event data field for a connect event +* added an adaptive order-2 PPM range coder as a built-in compressor option +which can be set with enet_host_compress_with_range_coder() +* added support for packet compression configurable with a callback +* improved session number handling to not rely on the packet checksum +field, saving 4 bytes per packet unless the checksum option is used +* removed the dependence on the rand callback for session number handling + +Caveats: This version is not protocol compatible with the 1.2 series or +earlier. The enet_host_connect and enet_host_create API functions require +supplying additional parameters. + +ENet 1.2.2 (June 5, 2010): + +* checksum functionality is now enabled by setting a checksum callback +inside ENetHost instead of being a configure script option +* added totalSentData, totalSentPackets, totalReceivedData, and +totalReceivedPackets counters inside ENetHost for getting usage +statistics +* added enet_host_channel_limit() for limiting the maximum number of +channels allowed by connected peers +* now uses dispatch queues for event dispatch rather than potentially +unscalable array walking +* added no_memory callback that is called when a malloc attempt fails, +such that if no_memory returns rather than aborts (the default behavior), +then the error is propagated to the return value of the API calls +* now uses packed attribute for protocol structures on platforms with +strange alignment rules +* improved autoconf build system contributed by Nathan Brink allowing +for easier building as a shared library + +Caveats: If you were using the compile-time option that enabled checksums, +make sure to set the checksum callback inside ENetHost to enet_crc32 to +regain the old behavior. The ENetCallbacks structure has added new fields, +so make sure to clear the structure to zero before use if +using enet_initialize_with_callbacks(). + +ENet 1.2.1 (November 12, 2009): + +* fixed bug that could cause disconnect events to be dropped +* added thin wrapper around select() for portable usage +* added ENET_SOCKOPT_REUSEADDR socket option +* factored enet_socket_bind()/enet_socket_listen() out of enet_socket_create() +* added contributed Code::Blocks build file + +ENet 1.2 (February 12, 2008): + +* fixed bug in VERIFY_CONNECT acknowledgement that could cause connect +attempts to occasionally timeout +* fixed acknowledgements to check both the outgoing and sent queues +when removing acknowledged packets +* fixed accidental bit rot in the MSVC project file +* revised sequence number overflow handling to address some possible +disconnect bugs +* added enet_host_check_events() for getting only local queued events +* factored out socket option setting into enet_socket_set_option() so +that socket options are now set separately from enet_socket_create() + +Caveats: While this release is superficially protocol compatible with 1.1, +differences in the sequence number overflow handling can potentially cause +random disconnects. + +ENet 1.1 (June 6, 2007): + +* optional CRC32 just in case someone needs a stronger checksum than UDP +provides (--enable-crc32 configure option) +* the size of packet headers are half the size they used to be (so less +overhead when sending small packets) +* enet_peer_disconnect_later() that waits till all queued outgoing +packets get sent before issuing an actual disconnect +* freeCallback field in individual packets for notification of when a +packet is about to be freed +* ENET_PACKET_FLAG_NO_ALLOCATE for supplying pre-allocated data to a +packet (can be used in concert with freeCallback to support some custom +allocation schemes that the normal memory allocation callbacks would +normally not allow) +* enet_address_get_host_ip() for printing address numbers +* promoted the enet_socket_*() functions to be part of the API now +* a few stability/crash fixes + + diff --git a/libs/enet/LICENSE b/libs/enet/LICENSE new file mode 100644 index 0000000..df0f91e --- /dev/null +++ b/libs/enet/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2002-2010 Lee Salzman + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 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 Software. + +THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/libs/enet/README b/libs/enet/README new file mode 100644 index 0000000..7f7a0ad --- /dev/null +++ b/libs/enet/README @@ -0,0 +1,15 @@ +Please visit the ENet homepage at http://enet.bespin.org for installation +and usage instructions. + +If you obtained this package from CVS, the quick description on how to build +is: + +# Generate the build system. + +autoreconf -vfi + +# Compile and install the library. + +./configure && make && make install + + diff --git a/libs/enet/callbacks.c b/libs/enet/callbacks.c new file mode 100644 index 0000000..f941282 --- /dev/null +++ b/libs/enet/callbacks.c @@ -0,0 +1,47 @@ +/** + @file callbacks.c + @brief ENet callback functions +*/ +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +static ENetCallbacks callbacks = { malloc, free, abort }; + +int +enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits) +{ + if (version < ENET_VERSION_CREATE (1, 3, 0)) + return -1; + + if (inits -> malloc != NULL || inits -> free != NULL) + { + if (inits -> malloc == NULL || inits -> free == NULL) + return -1; + + callbacks.malloc = inits -> malloc; + callbacks.free = inits -> free; + } + + if (inits -> no_memory != NULL) + callbacks.no_memory = inits -> no_memory; + + return enet_initialize (); +} + +void * +enet_malloc (size_t size) +{ + void * memory = callbacks.malloc (size); + + if (memory == NULL) + callbacks.no_memory (); + + return memory; +} + +void +enet_free (void * memory) +{ + callbacks.free (memory); +} + diff --git a/libs/enet/compress.c b/libs/enet/compress.c new file mode 100644 index 0000000..784489a --- /dev/null +++ b/libs/enet/compress.c @@ -0,0 +1,654 @@ +/** + @file compress.c + @brief An adaptive order-2 PPM range coder +*/ +#define ENET_BUILDING_LIB 1 +#include +#include "enet/enet.h" + +typedef struct _ENetSymbol +{ + /* binary indexed tree of symbols */ + enet_uint8 value; + enet_uint8 count; + enet_uint16 under; + enet_uint16 left, right; + + /* context defined by this symbol */ + enet_uint16 symbols; + enet_uint16 escapes; + enet_uint16 total; + enet_uint16 parent; +} ENetSymbol; + +/* adaptation constants tuned aggressively for small packet sizes rather than large file compression */ +enum +{ + ENET_RANGE_CODER_TOP = 1<<24, + ENET_RANGE_CODER_BOTTOM = 1<<16, + + ENET_CONTEXT_SYMBOL_DELTA = 3, + ENET_CONTEXT_SYMBOL_MINIMUM = 1, + ENET_CONTEXT_ESCAPE_MINIMUM = 1, + + ENET_SUBCONTEXT_ORDER = 2, + ENET_SUBCONTEXT_SYMBOL_DELTA = 2, + ENET_SUBCONTEXT_ESCAPE_DELTA = 5 +}; + +/* context exclusion roughly halves compression speed, so disable for now */ +#undef ENET_CONTEXT_EXCLUSION + +typedef struct _ENetRangeCoder +{ + /* only allocate enough symbols for reasonable MTUs, would need to be larger for large file compression */ + ENetSymbol symbols[4096]; +} ENetRangeCoder; + +void * +enet_range_coder_create (void) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) enet_malloc (sizeof (ENetRangeCoder)); + if (rangeCoder == NULL) + return NULL; + + return rangeCoder; +} + +void +enet_range_coder_destroy (void * context) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; + if (rangeCoder == NULL) + return; + + enet_free (rangeCoder); +} + +#define ENET_SYMBOL_CREATE(symbol, value_, count_) \ +{ \ + symbol = & rangeCoder -> symbols [nextSymbol ++]; \ + symbol -> value = value_; \ + symbol -> count = count_; \ + symbol -> under = count_; \ + symbol -> left = 0; \ + symbol -> right = 0; \ + symbol -> symbols = 0; \ + symbol -> escapes = 0; \ + symbol -> total = 0; \ + symbol -> parent = 0; \ +} + +#define ENET_CONTEXT_CREATE(context, escapes_, minimum) \ +{ \ + ENET_SYMBOL_CREATE (context, 0, 0); \ + (context) -> escapes = escapes_; \ + (context) -> total = escapes_ + 256*minimum; \ + (context) -> symbols = 0; \ +} + +static enet_uint16 +enet_symbol_rescale (ENetSymbol * symbol) +{ + enet_uint16 total = 0; + for (;;) + { + symbol -> count -= symbol->count >> 1; + symbol -> under = symbol -> count; + if (symbol -> left) + symbol -> under += enet_symbol_rescale (symbol + symbol -> left); + total += symbol -> under; + if (! symbol -> right) break; + symbol += symbol -> right; + } + return total; +} + +#define ENET_CONTEXT_RESCALE(context, minimum) \ +{ \ + (context) -> total = (context) -> symbols ? enet_symbol_rescale ((context) + (context) -> symbols) : 0; \ + (context) -> escapes -= (context) -> escapes >> 1; \ + (context) -> total += (context) -> escapes + 256*minimum; \ +} + +#define ENET_RANGE_CODER_OUTPUT(value) \ +{ \ + if (outData >= outEnd) \ + return 0; \ + * outData ++ = value; \ +} + +#define ENET_RANGE_CODER_ENCODE(under, count, total) \ +{ \ + encodeRange /= (total); \ + encodeLow += (under) * encodeRange; \ + encodeRange *= (count); \ + for (;;) \ + { \ + if((encodeLow ^ (encodeLow + encodeRange)) >= ENET_RANGE_CODER_TOP) \ + { \ + if(encodeRange >= ENET_RANGE_CODER_BOTTOM) break; \ + encodeRange = -encodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \ + } \ + ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \ + encodeRange <<= 8; \ + encodeLow <<= 8; \ + } \ +} + +#define ENET_RANGE_CODER_FLUSH \ +{ \ + while (encodeLow) \ + { \ + ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \ + encodeLow <<= 8; \ + } \ +} + +#define ENET_RANGE_CODER_FREE_SYMBOLS \ +{ \ + if (nextSymbol >= sizeof (rangeCoder -> symbols) / sizeof (ENetSymbol) - ENET_SUBCONTEXT_ORDER ) \ + { \ + nextSymbol = 0; \ + ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); \ + predicted = 0; \ + order = 0; \ + } \ +} + +#define ENET_CONTEXT_ENCODE(context, symbol_, value_, under_, count_, update, minimum) \ +{ \ + under_ = value*minimum; \ + count_ = minimum; \ + if (! (context) -> symbols) \ + { \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + (context) -> symbols = symbol_ - (context); \ + } \ + else \ + { \ + ENetSymbol * node = (context) + (context) -> symbols; \ + for (;;) \ + { \ + if (value_ < node -> value) \ + { \ + node -> under += update; \ + if (node -> left) { node += node -> left; continue; } \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> left = symbol_ - node; \ + } \ + else \ + if (value_ > node -> value) \ + { \ + under_ += node -> under; \ + if (node -> right) { node += node -> right; continue; } \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> right = symbol_ - node; \ + } \ + else \ + { \ + count_ += node -> count; \ + under_ += node -> under - node -> count; \ + node -> under += update; \ + node -> count += update; \ + symbol_ = node; \ + } \ + break; \ + } \ + } \ +} + +#ifdef ENET_CONTEXT_EXCLUSION +static const ENetSymbol emptyContext = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +#define ENET_CONTEXT_WALK(context, body) \ +{ \ + const ENetSymbol * node = (context) + (context) -> symbols; \ + const ENetSymbol * stack [256]; \ + size_t stackSize = 0; \ + while (node -> left) \ + { \ + stack [stackSize ++] = node; \ + node += node -> left; \ + } \ + for (;;) \ + { \ + body; \ + if (node -> right) \ + { \ + node += node -> right; \ + while (node -> left) \ + { \ + stack [stackSize ++] = node; \ + node += node -> left; \ + } \ + } \ + else \ + if (stackSize <= 0) \ + break; \ + else \ + node = stack [-- stackSize]; \ + } \ +} + +#define ENET_CONTEXT_ENCODE_EXCLUDE(context, value_, under, total, minimum) \ +ENET_CONTEXT_WALK(context, { \ + if (node -> value != value_) \ + { \ + enet_uint16 parentCount = rangeCoder -> symbols [node -> parent].count + minimum; \ + if (node -> value < value_) \ + under -= parentCount; \ + total -= parentCount; \ + } \ +}) +#endif + +size_t +enet_range_coder_compress (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; + enet_uint8 * outStart = outData, * outEnd = & outData [outLimit]; + const enet_uint8 * inData, * inEnd; + enet_uint32 encodeLow = 0, encodeRange = ~0; + ENetSymbol * root; + enet_uint16 predicted = 0; + size_t order = 0, nextSymbol = 0; + + if (rangeCoder == NULL || inBufferCount <= 0 || inLimit <= 0) + return 0; + + inData = (const enet_uint8 *) inBuffers -> data; + inEnd = & inData [inBuffers -> dataLength]; + inBuffers ++; + inBufferCount --; + + ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); + + for (;;) + { + ENetSymbol * subcontext, * symbol; +#ifdef ENET_CONTEXT_EXCLUSION + const ENetSymbol * childContext = & emptyContext; +#endif + enet_uint8 value; + enet_uint16 count, under, * parent = & predicted, total; + if (inData >= inEnd) + { + if (inBufferCount <= 0) + break; + inData = (const enet_uint8 *) inBuffers -> data; + inEnd = & inData [inBuffers -> dataLength]; + inBuffers ++; + inBufferCount --; + } + value = * inData ++; + + for (subcontext = & rangeCoder -> symbols [predicted]; + subcontext != root; +#ifdef ENET_CONTEXT_EXCLUSION + childContext = subcontext, +#endif + subcontext = & rangeCoder -> symbols [subcontext -> parent]) + { + ENET_CONTEXT_ENCODE (subcontext, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0); + * parent = symbol - rangeCoder -> symbols; + parent = & symbol -> parent; + total = subcontext -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA) + ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, 0); +#endif + if (count > 0) + { + ENET_RANGE_CODER_ENCODE (subcontext -> escapes + under, count, total); + } + else + { + if (subcontext -> escapes > 0 && subcontext -> escapes < total) + ENET_RANGE_CODER_ENCODE (0, subcontext -> escapes, total); + subcontext -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA; + subcontext -> total += ENET_SUBCONTEXT_ESCAPE_DELTA; + } + subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (subcontext, 0); + if (count > 0) goto nextInput; + } + + ENET_CONTEXT_ENCODE (root, symbol, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM); + * parent = symbol - rangeCoder -> symbols; + parent = & symbol -> parent; + total = root -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA) + ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, ENET_CONTEXT_SYMBOL_MINIMUM); +#endif + ENET_RANGE_CODER_ENCODE (root -> escapes + under, count, total); + root -> total += ENET_CONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM); + + nextInput: + if (order >= ENET_SUBCONTEXT_ORDER) + predicted = rangeCoder -> symbols [predicted].parent; + else + order ++; + ENET_RANGE_CODER_FREE_SYMBOLS; + } + + ENET_RANGE_CODER_FLUSH; + + return (size_t) (outData - outStart); +} + +#define ENET_RANGE_CODER_SEED \ +{ \ + if (inData < inEnd) decodeCode |= * inData ++ << 24; \ + if (inData < inEnd) decodeCode |= * inData ++ << 16; \ + if (inData < inEnd) decodeCode |= * inData ++ << 8; \ + if (inData < inEnd) decodeCode |= * inData ++; \ +} + +#define ENET_RANGE_CODER_READ(total) ((decodeCode - decodeLow) / (decodeRange /= (total))) + +#define ENET_RANGE_CODER_DECODE(under, count, total) \ +{ \ + decodeLow += (under) * decodeRange; \ + decodeRange *= (count); \ + for (;;) \ + { \ + if((decodeLow ^ (decodeLow + decodeRange)) >= ENET_RANGE_CODER_TOP) \ + { \ + if(decodeRange >= ENET_RANGE_CODER_BOTTOM) break; \ + decodeRange = -decodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \ + } \ + decodeCode <<= 8; \ + if (inData < inEnd) \ + decodeCode |= * inData ++; \ + decodeRange <<= 8; \ + decodeLow <<= 8; \ + } \ +} + +#define ENET_CONTEXT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, createRoot, visitNode, createRight, createLeft) \ +{ \ + under_ = 0; \ + count_ = minimum; \ + if (! (context) -> symbols) \ + { \ + createRoot; \ + } \ + else \ + { \ + ENetSymbol * node = (context) + (context) -> symbols; \ + for (;;) \ + { \ + enet_uint16 after = under_ + node -> under + (node -> value + 1)*minimum, before = node -> count + minimum; \ + visitNode; \ + if (code >= after) \ + { \ + under_ += node -> under; \ + if (node -> right) { node += node -> right; continue; } \ + createRight; \ + } \ + else \ + if (code < after - before) \ + { \ + node -> under += update; \ + if (node -> left) { node += node -> left; continue; } \ + createLeft; \ + } \ + else \ + { \ + value_ = node -> value; \ + count_ += node -> count; \ + under_ = after - before; \ + node -> under += update; \ + node -> count += update; \ + symbol_ = node; \ + } \ + break; \ + } \ + } \ +} + +#define ENET_CONTEXT_TRY_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \ +ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, return 0, exclude (node -> value, after, before), return 0, return 0) + +#define ENET_CONTEXT_ROOT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \ +ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, \ + { \ + value_ = code / minimum; \ + under_ = code - code%minimum; \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + (context) -> symbols = symbol_ - (context); \ + }, \ + exclude (node -> value, after, before), \ + { \ + value_ = node->value + 1 + (code - after)/minimum; \ + under_ = code - (code - after)%minimum; \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> right = symbol_ - node; \ + }, \ + { \ + value_ = node->value - 1 - (after - before - code - 1)/minimum; \ + under_ = code - (after - before - code - 1)%minimum; \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> left = symbol_ - node; \ + }) \ + +#ifdef ENET_CONTEXT_EXCLUSION +typedef struct _ENetExclude +{ + enet_uint8 value; + enet_uint16 under; +} ENetExclude; + +#define ENET_CONTEXT_DECODE_EXCLUDE(context, total, minimum) \ +{ \ + enet_uint16 under = 0; \ + nextExclude = excludes; \ + ENET_CONTEXT_WALK (context, { \ + under += rangeCoder -> symbols [node -> parent].count + minimum; \ + nextExclude -> value = node -> value; \ + nextExclude -> under = under; \ + nextExclude ++; \ + }); \ + total -= under; \ +} + +#define ENET_CONTEXT_EXCLUDED(value_, after, before) \ +{ \ + size_t low = 0, high = nextExclude - excludes; \ + for(;;) \ + { \ + size_t mid = (low + high) >> 1; \ + const ENetExclude * exclude = & excludes [mid]; \ + if (value_ < exclude -> value) \ + { \ + if (low + 1 < high) \ + { \ + high = mid; \ + continue; \ + } \ + if (exclude > excludes) \ + after -= exclude [-1].under; \ + } \ + else \ + { \ + if (value_ > exclude -> value) \ + { \ + if (low + 1 < high) \ + { \ + low = mid; \ + continue; \ + } \ + } \ + else \ + before = 0; \ + after -= exclude -> under; \ + } \ + break; \ + } \ +} +#endif + +#define ENET_CONTEXT_NOT_EXCLUDED(value_, after, before) + +size_t +enet_range_coder_decompress (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; + enet_uint8 * outStart = outData, * outEnd = & outData [outLimit]; + const enet_uint8 * inEnd = & inData [inLimit]; + enet_uint32 decodeLow = 0, decodeCode = 0, decodeRange = ~0; + ENetSymbol * root; + enet_uint16 predicted = 0; + size_t order = 0, nextSymbol = 0; +#ifdef ENET_CONTEXT_EXCLUSION + ENetExclude excludes [256]; + ENetExclude * nextExclude = excludes; +#endif + + if (rangeCoder == NULL || inLimit <= 0) + return 0; + + ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); + + ENET_RANGE_CODER_SEED; + + for (;;) + { + ENetSymbol * subcontext, * symbol, * patch; +#ifdef ENET_CONTEXT_EXCLUSION + const ENetSymbol * childContext = & emptyContext; +#endif + enet_uint8 value = 0; + enet_uint16 code, under, count, bottom, * parent = & predicted, total; + + for (subcontext = & rangeCoder -> symbols [predicted]; + subcontext != root; +#ifdef ENET_CONTEXT_EXCLUSION + childContext = subcontext, +#endif + subcontext = & rangeCoder -> symbols [subcontext -> parent]) + { + if (subcontext -> escapes <= 0) + continue; + total = subcontext -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, 0); +#endif + if (subcontext -> escapes >= total) + continue; + code = ENET_RANGE_CODER_READ (total); + if (code < subcontext -> escapes) + { + ENET_RANGE_CODER_DECODE (0, subcontext -> escapes, total); + continue; + } + code -= subcontext -> escapes; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + { + ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_EXCLUDED); + } + else +#endif + { + ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_NOT_EXCLUDED); + } + bottom = symbol - rangeCoder -> symbols; + ENET_RANGE_CODER_DECODE (subcontext -> escapes + under, count, total); + subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (subcontext, 0); + goto patchContexts; + } + + total = root -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, ENET_CONTEXT_SYMBOL_MINIMUM); +#endif + code = ENET_RANGE_CODER_READ (total); + if (code < root -> escapes) + { + ENET_RANGE_CODER_DECODE (0, root -> escapes, total); + break; + } + code -= root -> escapes; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + { + ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_EXCLUDED); + } + else +#endif + { + ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_NOT_EXCLUDED); + } + bottom = symbol - rangeCoder -> symbols; + ENET_RANGE_CODER_DECODE (root -> escapes + under, count, total); + root -> total += ENET_CONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM); + + patchContexts: + for (patch = & rangeCoder -> symbols [predicted]; + patch != subcontext; + patch = & rangeCoder -> symbols [patch -> parent]) + { + ENET_CONTEXT_ENCODE (patch, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0); + * parent = symbol - rangeCoder -> symbols; + parent = & symbol -> parent; + if (count <= 0) + { + patch -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA; + patch -> total += ENET_SUBCONTEXT_ESCAPE_DELTA; + } + patch -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || patch -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (patch, 0); + } + * parent = bottom; + + ENET_RANGE_CODER_OUTPUT (value); + + if (order >= ENET_SUBCONTEXT_ORDER) + predicted = rangeCoder -> symbols [predicted].parent; + else + order ++; + ENET_RANGE_CODER_FREE_SYMBOLS; + } + + return (size_t) (outData - outStart); +} + +/** @defgroup host ENet host functions + @{ +*/ + +/** Sets the packet compressor the host should use to the default range coder. + @param host host to enable the range coder for + @returns 0 on success, < 0 on failure +*/ +int +enet_host_compress_with_range_coder (ENetHost * host) +{ + ENetCompressor compressor; + memset (& compressor, 0, sizeof (compressor)); + compressor.context = enet_range_coder_create(); + if (compressor.context == NULL) + return -1; + compressor.compress = enet_range_coder_compress; + compressor.decompress = enet_range_coder_decompress; + compressor.destroy = enet_range_coder_destroy; + enet_host_compress (host, & compressor); + return 0; +} + +/** @} */ + + diff --git a/libs/enet/host.c b/libs/enet/host.c new file mode 100644 index 0000000..8bb2433 --- /dev/null +++ b/libs/enet/host.c @@ -0,0 +1,479 @@ +/** + @file host.c + @brief ENet host management functions +*/ +#define ENET_BUILDING_LIB 1 +#include +#include +#include "enet/enet.h" + +/** @defgroup host ENet host functions + @{ +*/ + +/** Creates a host for communicating to peers. + + @param address the address at which other peers may connect to this host. If NULL, then no peers may connect to the host. + @param peerCount the maximum number of peers that should be allocated for the host. + @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT + @param incomingBandwidth downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. + @param outgoingBandwidth upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. + + @returns the host on success and NULL on failure + + @remarks ENet will strategically drop packets on specific sides of a connection between hosts + to ensure the host's bandwidth is not overwhelmed. The bandwidth parameters also determine + the window size of a connection which limits the amount of reliable packets that may be in transit + at any given time. +*/ +ENetHost * +enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) +{ + ENetHost * host; + ENetPeer * currentPeer; + + if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID) + return NULL; + + host = (ENetHost *) enet_malloc (sizeof (ENetHost)); + if (host == NULL) + return NULL; + + host -> peers = (ENetPeer *) enet_malloc (peerCount * sizeof (ENetPeer)); + if (host -> peers == NULL) + { + enet_free (host); + + return NULL; + } + memset (host -> peers, 0, peerCount * sizeof (ENetPeer)); + + host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM); + if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0)) + { + if (host -> socket != ENET_SOCKET_NULL) + enet_socket_destroy (host -> socket); + + enet_free (host -> peers); + enet_free (host); + + return NULL; + } + + enet_socket_set_option (host -> socket, ENET_SOCKOPT_NONBLOCK, 1); + enet_socket_set_option (host -> socket, ENET_SOCKOPT_BROADCAST, 1); + enet_socket_set_option (host -> socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE); + enet_socket_set_option (host -> socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE); + + if (address != NULL) + host -> address = * address; + + if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) + channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; + else + if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) + channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; + + host -> randomSeed = (enet_uint32) time(NULL) + (enet_uint32) (size_t) host; + host -> randomSeed = (host -> randomSeed << 16) | (host -> randomSeed >> 16); + host -> channelLimit = channelLimit; + host -> incomingBandwidth = incomingBandwidth; + host -> outgoingBandwidth = outgoingBandwidth; + host -> bandwidthThrottleEpoch = 0; + host -> recalculateBandwidthLimits = 0; + host -> mtu = ENET_HOST_DEFAULT_MTU; + host -> peerCount = peerCount; + host -> commandCount = 0; + host -> bufferCount = 0; + host -> checksum = NULL; + host -> receivedAddress.host = ENET_HOST_ANY; + host -> receivedAddress.port = 0; + host -> receivedData = NULL; + host -> receivedDataLength = 0; + + host -> totalSentData = 0; + host -> totalSentPackets = 0; + host -> totalReceivedData = 0; + host -> totalReceivedPackets = 0; + + host -> compressor.context = NULL; + host -> compressor.compress = NULL; + host -> compressor.decompress = NULL; + host -> compressor.destroy = NULL; + + enet_list_clear (& host -> dispatchQueue); + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + currentPeer -> host = host; + currentPeer -> incomingPeerID = currentPeer - host -> peers; + currentPeer -> outgoingSessionID = currentPeer -> incomingSessionID = 0xFF; + currentPeer -> data = NULL; + + enet_list_clear (& currentPeer -> acknowledgements); + enet_list_clear (& currentPeer -> sentReliableCommands); + enet_list_clear (& currentPeer -> sentUnreliableCommands); + enet_list_clear (& currentPeer -> outgoingReliableCommands); + enet_list_clear (& currentPeer -> outgoingUnreliableCommands); + enet_list_clear (& currentPeer -> dispatchedCommands); + + enet_peer_reset (currentPeer); + } + + return host; +} + +/** Destroys the host and all resources associated with it. + @param host pointer to the host to destroy +*/ +void +enet_host_destroy (ENetHost * host) +{ + ENetPeer * currentPeer; + + enet_socket_destroy (host -> socket); + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + enet_peer_reset (currentPeer); + } + + if (host -> compressor.context != NULL && host -> compressor.destroy) + (* host -> compressor.destroy) (host -> compressor.context); + + enet_free (host -> peers); + enet_free (host); +} + +/** Initiates a connection to a foreign host. + @param host host seeking the connection + @param address destination for the connection + @param channelCount number of channels to allocate + @param data user data supplied to the receiving host + @returns a peer representing the foreign host on success, NULL on failure + @remarks The peer returned will have not completed the connection until enet_host_service() + notifies of an ENET_EVENT_TYPE_CONNECT event for the peer. +*/ +ENetPeer * +enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelCount, enet_uint32 data) +{ + ENetPeer * currentPeer; + ENetChannel * channel; + ENetProtocol command; + + if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) + channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; + else + if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) + channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED) + break; + } + + if (currentPeer >= & host -> peers [host -> peerCount]) + return NULL; + + currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); + if (currentPeer -> channels == NULL) + return NULL; + currentPeer -> channelCount = channelCount; + currentPeer -> state = ENET_PEER_STATE_CONNECTING; + currentPeer -> address = * address; + currentPeer -> connectID = ++ host -> randomSeed; + + if (host -> outgoingBandwidth == 0) + currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + else + currentPeer -> windowSize = (host -> outgoingBandwidth / + ENET_PEER_WINDOW_SIZE_SCALE) * + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (currentPeer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + currentPeer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + if (currentPeer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + for (channel = currentPeer -> channels; + channel < & currentPeer -> channels [channelCount]; + ++ channel) + { + channel -> outgoingReliableSequenceNumber = 0; + channel -> outgoingUnreliableSequenceNumber = 0; + channel -> incomingReliableSequenceNumber = 0; + + enet_list_clear (& channel -> incomingReliableCommands); + enet_list_clear (& channel -> incomingUnreliableCommands); + + channel -> usedReliableWindows = 0; + memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows)); + } + + command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + command.connect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID); + command.connect.incomingSessionID = currentPeer -> incomingSessionID; + command.connect.outgoingSessionID = currentPeer -> outgoingSessionID; + command.connect.mtu = ENET_HOST_TO_NET_32 (currentPeer -> mtu); + command.connect.windowSize = ENET_HOST_TO_NET_32 (currentPeer -> windowSize); + command.connect.channelCount = ENET_HOST_TO_NET_32 (channelCount); + command.connect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth); + command.connect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); + command.connect.packetThrottleInterval = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleInterval); + command.connect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleAcceleration); + command.connect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleDeceleration); + command.connect.connectID = currentPeer -> connectID; + command.connect.data = ENET_HOST_TO_NET_32 (data); + + enet_peer_queue_outgoing_command (currentPeer, & command, NULL, 0, 0); + + return currentPeer; +} + +/** Queues a packet to be sent to all peers associated with the host. + @param host host on which to broadcast the packet + @param channelID channel on which to broadcast + @param packet packet to broadcast +*/ +void +enet_host_broadcast (ENetHost * host, enet_uint8 channelID, ENetPacket * packet) +{ + ENetPeer * currentPeer; + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state != ENET_PEER_STATE_CONNECTED) + continue; + + enet_peer_send (currentPeer, channelID, packet); + } + + if (packet -> referenceCount == 0) + enet_packet_destroy (packet); +} + +/** Sets the packet compressor the host should use to compress and decompress packets. + @param host host to enable or disable compression for + @param compressor callbacks for for the packet compressor; if NULL, then compression is disabled +*/ +void +enet_host_compress (ENetHost * host, const ENetCompressor * compressor) +{ + if (host -> compressor.context != NULL && host -> compressor.destroy) + (* host -> compressor.destroy) (host -> compressor.context); + + if (compressor) + host -> compressor = * compressor; + else + host -> compressor.context = NULL; +} + +/** Limits the maximum allowed channels of future incoming connections. + @param host host to limit + @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT +*/ +void +enet_host_channel_limit (ENetHost * host, size_t channelLimit) +{ + if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) + channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; + else + if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) + channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; + + host -> channelLimit = channelLimit; +} + + +/** Adjusts the bandwidth limits of a host. + @param host host to adjust + @param incomingBandwidth new incoming bandwidth + @param outgoingBandwidth new outgoing bandwidth + @remarks the incoming and outgoing bandwidth parameters are identical in function to those + specified in enet_host_create(). +*/ +void +enet_host_bandwidth_limit (ENetHost * host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) +{ + host -> incomingBandwidth = incomingBandwidth; + host -> outgoingBandwidth = outgoingBandwidth; + host -> recalculateBandwidthLimits = 1; +} + +void +enet_host_bandwidth_throttle (ENetHost * host) +{ + enet_uint32 timeCurrent = enet_time_get (), + elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch, + peersTotal = 0, + dataTotal = 0, + peersRemaining, + bandwidth, + throttle = 0, + bandwidthLimit = 0; + int needsAdjustment; + ENetPeer * peer; + ENetProtocol command; + + if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) + return; + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) + continue; + + ++ peersTotal; + dataTotal += peer -> outgoingDataTotal; + } + + if (peersTotal == 0) + return; + + peersRemaining = peersTotal; + needsAdjustment = 1; + + if (host -> outgoingBandwidth == 0) + bandwidth = ~0; + else + bandwidth = (host -> outgoingBandwidth * elapsedTime) / 1000; + + while (peersRemaining > 0 && needsAdjustment != 0) + { + needsAdjustment = 0; + + if (dataTotal < bandwidth) + throttle = ENET_PEER_PACKET_THROTTLE_SCALE; + else + throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + enet_uint32 peerBandwidth; + + if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || + peer -> incomingBandwidth == 0 || + peer -> outgoingBandwidthThrottleEpoch == timeCurrent) + continue; + + peerBandwidth = (peer -> incomingBandwidth * elapsedTime) / 1000; + if ((throttle * peer -> outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth) + continue; + + peer -> packetThrottleLimit = (peerBandwidth * + ENET_PEER_PACKET_THROTTLE_SCALE) / peer -> outgoingDataTotal; + + if (peer -> packetThrottleLimit == 0) + peer -> packetThrottleLimit = 1; + + if (peer -> packetThrottle > peer -> packetThrottleLimit) + peer -> packetThrottle = peer -> packetThrottleLimit; + + peer -> outgoingBandwidthThrottleEpoch = timeCurrent; + + + needsAdjustment = 1; + -- peersRemaining; + bandwidth -= peerBandwidth; + dataTotal -= peerBandwidth; + } + } + + if (peersRemaining > 0) + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || + peer -> outgoingBandwidthThrottleEpoch == timeCurrent) + continue; + + peer -> packetThrottleLimit = throttle; + + if (peer -> packetThrottle > peer -> packetThrottleLimit) + peer -> packetThrottle = peer -> packetThrottleLimit; + } + + if (host -> recalculateBandwidthLimits) + { + host -> recalculateBandwidthLimits = 0; + + peersRemaining = peersTotal; + bandwidth = host -> incomingBandwidth; + needsAdjustment = 1; + + if (bandwidth == 0) + bandwidthLimit = 0; + else + while (peersRemaining > 0 && needsAdjustment != 0) + { + needsAdjustment = 0; + bandwidthLimit = bandwidth / peersRemaining; + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || + peer -> incomingBandwidthThrottleEpoch == timeCurrent) + continue; + + if (peer -> outgoingBandwidth > 0 && + peer -> outgoingBandwidth >= bandwidthLimit) + continue; + + peer -> incomingBandwidthThrottleEpoch = timeCurrent; + + needsAdjustment = 1; + -- peersRemaining; + bandwidth -= peer -> outgoingBandwidth; + } + } + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) + continue; + + command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); + + if (peer -> incomingBandwidthThrottleEpoch == timeCurrent) + command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (peer -> outgoingBandwidth); + else + command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (bandwidthLimit); + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); + } + } + + host -> bandwidthThrottleEpoch = timeCurrent; + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + peer -> incomingDataTotal = 0; + peer -> outgoingDataTotal = 0; + } +} + +/** @} */ diff --git a/libs/enet/include/enet/callbacks.h b/libs/enet/include/enet/callbacks.h new file mode 100644 index 0000000..340a4a9 --- /dev/null +++ b/libs/enet/include/enet/callbacks.h @@ -0,0 +1,27 @@ +/** + @file callbacks.h + @brief ENet callbacks +*/ +#ifndef __ENET_CALLBACKS_H__ +#define __ENET_CALLBACKS_H__ + +#include + +typedef struct _ENetCallbacks +{ + void * (ENET_CALLBACK * malloc) (size_t size); + void (ENET_CALLBACK * free) (void * memory); + void (ENET_CALLBACK * no_memory) (void); +} ENetCallbacks; + +/** @defgroup callbacks ENet internal callbacks + @{ + @ingroup private +*/ +extern void * enet_malloc (size_t); +extern void enet_free (void *); + +/** @} */ + +#endif /* __ENET_CALLBACKS_H__ */ + diff --git a/libs/enet/include/enet/enet.h b/libs/enet/include/enet/enet.h new file mode 100644 index 0000000..2f656d6 --- /dev/null +++ b/libs/enet/include/enet/enet.h @@ -0,0 +1,540 @@ +/** + @file enet.h + @brief ENet public header file +*/ +#ifndef __ENET_ENET_H__ +#define __ENET_ENET_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#ifdef WIN32 +#include "enet/win32.h" +#else +#include "enet/unix.h" +#endif + +#include "enet/types.h" +#include "enet/protocol.h" +#include "enet/list.h" +#include "enet/callbacks.h" + +#define ENET_VERSION_MAJOR 1 +#define ENET_VERSION_MINOR 3 +#define ENET_VERSION_PATCH 0 +#define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch)) +#define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH) + +typedef enet_uint32 ENetVersion; + +typedef enum _ENetSocketType +{ + ENET_SOCKET_TYPE_STREAM = 1, + ENET_SOCKET_TYPE_DATAGRAM = 2 +} ENetSocketType; + +typedef enum _ENetSocketWait +{ + ENET_SOCKET_WAIT_NONE = 0, + ENET_SOCKET_WAIT_SEND = (1 << 0), + ENET_SOCKET_WAIT_RECEIVE = (1 << 1) +} ENetSocketWait; + +typedef enum _ENetSocketOption +{ + ENET_SOCKOPT_NONBLOCK = 1, + ENET_SOCKOPT_BROADCAST = 2, + ENET_SOCKOPT_RCVBUF = 3, + ENET_SOCKOPT_SNDBUF = 4, + ENET_SOCKOPT_REUSEADDR = 5 +} ENetSocketOption; + +enum +{ + ENET_HOST_ANY = 0, /**< specifies the default server host */ + ENET_HOST_BROADCAST = 0xFFFFFFFF, /**< specifies a subnet-wide broadcast */ + + ENET_PORT_ANY = 0 /**< specifies that a port should be automatically chosen */ +}; + +/** + * Portable internet address structure. + * + * The host must be specified in network byte-order, and the port must be in host + * byte-order. The constant ENET_HOST_ANY may be used to specify the default + * server host. The constant ENET_HOST_BROADCAST may be used to specify the + * broadcast address (255.255.255.255). This makes sense for enet_host_connect, + * but not for enet_host_create. Once a server responds to a broadcast, the + * address is updated from ENET_HOST_BROADCAST to the server's actual IP address. + */ +typedef struct _ENetAddress +{ + enet_uint32 host; + enet_uint16 port; +} ENetAddress; + +/** + * Packet flag bit constants. + * + * The host must be specified in network byte-order, and the port must be in + * host byte-order. The constant ENET_HOST_ANY may be used to specify the + * default server host. + + @sa ENetPacket +*/ +typedef enum _ENetPacketFlag +{ + /** packet must be received by the target peer and resend attempts should be + * made until the packet is delivered */ + ENET_PACKET_FLAG_RELIABLE = (1 << 0), + /** packet will not be sequenced with other packets + * not supported for reliable packets + */ + ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1), + /** packet will not allocate data, and user must supply it instead */ + ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2) +} ENetPacketFlag; + +struct _ENetPacket; +typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *); + +/** + * ENet packet structure. + * + * An ENet data packet that may be sent to or received from a peer. The shown + * fields should only be read and never modified. The data field contains the + * allocated data for the packet. The dataLength fields specifies the length + * of the allocated data. The flags field is either 0 (specifying no flags), + * or a bitwise-or of any combination of the following flags: + * + * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer + * and resend attempts should be made until the packet is delivered + * + * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets + * (not supported for reliable packets) + * + * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead + + @sa ENetPacketFlag + */ +typedef struct _ENetPacket +{ + size_t referenceCount; /**< internal use only */ + enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */ + enet_uint8 * data; /**< allocated data for packet */ + size_t dataLength; /**< length of data */ + ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */ +} ENetPacket; + +typedef struct _ENetAcknowledgement +{ + ENetListNode acknowledgementList; + enet_uint32 sentTime; + ENetProtocol command; +} ENetAcknowledgement; + +typedef struct _ENetOutgoingCommand +{ + ENetListNode outgoingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + enet_uint32 sentTime; + enet_uint32 roundTripTimeout; + enet_uint32 roundTripTimeoutLimit; + enet_uint32 fragmentOffset; + enet_uint16 fragmentLength; + enet_uint16 sendAttempts; + ENetProtocol command; + ENetPacket * packet; +} ENetOutgoingCommand; + +typedef struct _ENetIncomingCommand +{ + ENetListNode incomingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + ENetProtocol command; + enet_uint32 fragmentCount; + enet_uint32 fragmentsRemaining; + enet_uint32 * fragments; + ENetPacket * packet; +} ENetIncomingCommand; + +typedef enum _ENetPeerState +{ + ENET_PEER_STATE_DISCONNECTED = 0, + ENET_PEER_STATE_CONNECTING = 1, + ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2, + ENET_PEER_STATE_CONNECTION_PENDING = 3, + ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, + ENET_PEER_STATE_CONNECTED = 5, + ENET_PEER_STATE_DISCONNECT_LATER = 6, + ENET_PEER_STATE_DISCONNECTING = 7, + ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, + ENET_PEER_STATE_ZOMBIE = 9 +} ENetPeerState; + +#ifndef ENET_BUFFER_MAXIMUM +#define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS) +#endif + +enum +{ + ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024, + ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024, + ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000, + ENET_HOST_DEFAULT_MTU = 1400, + + ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 500, + ENET_PEER_DEFAULT_PACKET_THROTTLE = 32, + ENET_PEER_PACKET_THROTTLE_SCALE = 32, + ENET_PEER_PACKET_THROTTLE_COUNTER = 7, + ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2, + ENET_PEER_PACKET_THROTTLE_DECELERATION = 2, + ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000, + ENET_PEER_PACKET_LOSS_SCALE = (1 << 16), + ENET_PEER_PACKET_LOSS_INTERVAL = 10000, + ENET_PEER_WINDOW_SIZE_SCALE = 64 * 1024, + ENET_PEER_TIMEOUT_LIMIT = 32, + ENET_PEER_TIMEOUT_MINIMUM = 5000, + ENET_PEER_TIMEOUT_MAXIMUM = 30000, + ENET_PEER_PING_INTERVAL = 500, + ENET_PEER_UNSEQUENCED_WINDOWS = 64, + ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 1024, + ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32, + ENET_PEER_RELIABLE_WINDOWS = 16, + ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000, + ENET_PEER_FREE_RELIABLE_WINDOWS = 8 +}; + +typedef struct _ENetChannel +{ + enet_uint16 outgoingReliableSequenceNumber; + enet_uint16 outgoingUnreliableSequenceNumber; + enet_uint16 usedReliableWindows; + enet_uint16 reliableWindows [ENET_PEER_RELIABLE_WINDOWS]; + enet_uint16 incomingReliableSequenceNumber; + ENetList incomingReliableCommands; + ENetList incomingUnreliableCommands; +} ENetChannel; + +/** + * An ENet peer which data packets may be sent or received from. + * + * No fields should be modified unless otherwise specified. + */ +typedef struct _ENetPeer +{ + ENetListNode dispatchList; + struct _ENetHost * host; + enet_uint16 outgoingPeerID; + enet_uint16 incomingPeerID; + enet_uint32 connectID; + enet_uint8 outgoingSessionID; + enet_uint8 incomingSessionID; + ENetAddress address; /**< Internet address of the peer */ + void * data; /**< Application private data, may be freely modified */ + ENetPeerState state; + ENetChannel * channels; + size_t channelCount; /**< Number of channels allocated for communication with peer */ + enet_uint32 incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ + enet_uint32 outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ + enet_uint32 incomingBandwidthThrottleEpoch; + enet_uint32 outgoingBandwidthThrottleEpoch; + enet_uint32 incomingDataTotal; + enet_uint32 outgoingDataTotal; + enet_uint32 lastSendTime; + enet_uint32 lastReceiveTime; + enet_uint32 nextTimeout; + enet_uint32 earliestTimeout; + enet_uint32 packetLossEpoch; + enet_uint32 packetsSent; + enet_uint32 packetsLost; + enet_uint32 packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ + enet_uint32 packetLossVariance; + enet_uint32 packetThrottle; + enet_uint32 packetThrottleLimit; + enet_uint32 packetThrottleCounter; + enet_uint32 packetThrottleEpoch; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 packetThrottleInterval; + enet_uint32 lastRoundTripTime; + enet_uint32 lowestRoundTripTime; + enet_uint32 lastRoundTripTimeVariance; + enet_uint32 highestRoundTripTimeVariance; + enet_uint32 roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */ + enet_uint32 roundTripTimeVariance; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 reliableDataInTransit; + enet_uint16 outgoingReliableSequenceNumber; + ENetList acknowledgements; + ENetList sentReliableCommands; + ENetList sentUnreliableCommands; + ENetList outgoingReliableCommands; + ENetList outgoingUnreliableCommands; + ENetList dispatchedCommands; + int needsDispatch; + enet_uint16 incomingUnsequencedGroup; + enet_uint16 outgoingUnsequencedGroup; + enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; + enet_uint32 eventData; +} ENetPeer; + +/** An ENet packet compressor for compressing UDP packets before socket sends or receives. + */ +typedef struct _ENetCompressor +{ + /** Context data for the compressor. Must be non-NULL. */ + void * context; + /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ + size_t (ENET_CALLBACK * compress) (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit); + /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ + size_t (ENET_CALLBACK * decompress) (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit); + /** Destroys the context when compression is disabled or the host is destroyed. May be NULL. */ + void (ENET_CALLBACK * destroy) (void * context); +} ENetCompressor; + +/** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */ +typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * buffers, size_t bufferCount); + +/** An ENet host for communicating with peers. + * + * No fields should be modified unless otherwise stated. + + @sa enet_host_create() + @sa enet_host_destroy() + @sa enet_host_connect() + @sa enet_host_service() + @sa enet_host_flush() + @sa enet_host_broadcast() + @sa enet_host_compress() + @sa enet_host_compress_with_range_coder() + @sa enet_host_channel_limit() + @sa enet_host_bandwidth_limit() + @sa enet_host_bandwidth_throttle() + */ +typedef struct _ENetHost +{ + ENetSocket socket; + ENetAddress address; /**< Internet address of the host */ + enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ + enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ + enet_uint32 bandwidthThrottleEpoch; + enet_uint32 mtu; + enet_uint32 randomSeed; + int recalculateBandwidthLimits; + ENetPeer * peers; /**< array of peers allocated for this host */ + size_t peerCount; /**< number of peers allocated for this host */ + size_t channelLimit; /**< maximum number of channels allowed for connected peers */ + enet_uint32 serviceTime; + ENetList dispatchQueue; + int continueSending; + size_t packetSize; + enet_uint16 headerFlags; + ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS]; + size_t commandCount; + ENetBuffer buffers [ENET_BUFFER_MAXIMUM]; + size_t bufferCount; + ENetChecksumCallback checksum; /**< callback the user can set to enable packet checksums for this host */ + ENetCompressor compressor; + enet_uint8 packetData [2][ENET_PROTOCOL_MAXIMUM_MTU]; + ENetAddress receivedAddress; + enet_uint8 * receivedData; + size_t receivedDataLength; + enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalSentPackets; /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedData; /**< total data received, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedPackets; /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */ +} ENetHost; + +/** + * An ENet event type, as specified in @ref ENetEvent. + */ +typedef enum _ENetEventType +{ + /** no event occurred within the specified time limit */ + ENET_EVENT_TYPE_NONE = 0, + + /** a connection request initiated by enet_host_connect has completed. + * The peer field contains the peer which successfully connected. + */ + ENET_EVENT_TYPE_CONNECT = 1, + + /** a peer has disconnected. This event is generated on a successful + * completion of a disconnect initiated by enet_pper_disconnect, if + * a peer has timed out, or if a connection request intialized by + * enet_host_connect has timed out. The peer field contains the peer + * which disconnected. The data field contains user supplied data + * describing the disconnection, or 0, if none is available. + */ + ENET_EVENT_TYPE_DISCONNECT = 2, + + /** a packet has been received from a peer. The peer field specifies the + * peer which sent the packet. The channelID field specifies the channel + * number upon which the packet was received. The packet field contains + * the packet that was received; this packet must be destroyed with + * enet_packet_destroy after use. + */ + ENET_EVENT_TYPE_RECEIVE = 3 +} ENetEventType; + +/** + * An ENet event as returned by enet_host_service(). + + @sa enet_host_service + */ +typedef struct _ENetEvent +{ + ENetEventType type; /**< type of the event */ + ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */ + enet_uint8 channelID; /**< channel on the peer that generated the event, if appropriate */ + enet_uint32 data; /**< data associated with the event, if appropriate */ + ENetPacket * packet; /**< packet associated with the event, if appropriate */ +} ENetEvent; + +/** @defgroup global ENet global functions + @{ +*/ + +/** + Initializes ENet globally. Must be called prior to using any functions in + ENet. + @returns 0 on success, < 0 on failure +*/ +ENET_API int enet_initialize (void); + +/** + Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in ENet. Do not use enet_initialize() if you use this variant. Make sure the ENetCallbacks structure is zeroed out so that any additional callbacks added in future versions will be properly ignored. + + @param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use + @param inits user-overriden callbacks where any NULL callbacks will use ENet's defaults + @returns 0 on success, < 0 on failure +*/ +ENET_API int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits); + +/** + Shuts down ENet globally. Should be called when a program that has + initialized ENet exits. +*/ +ENET_API void enet_deinitialize (void); + +/** @} */ + +/** @defgroup private ENet private implementation functions */ + +/** + Returns the wall-time in milliseconds. Its initial value is unspecified + unless otherwise set. + */ +ENET_API enet_uint32 enet_time_get (void); +/** + Sets the current wall-time in milliseconds. + */ +ENET_API void enet_time_set (enet_uint32); + +/** @defgroup socket ENet socket functions + @{ +*/ +ENET_API ENetSocket enet_socket_create (ENetSocketType); +ENET_API int enet_socket_bind (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_listen (ENetSocket, int); +ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *); +ENET_API int enet_socket_connect (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t); +ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t); +ENET_API int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32); +ENET_API int enet_socket_set_option (ENetSocket, ENetSocketOption, int); +ENET_API void enet_socket_destroy (ENetSocket); +ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32); + +/** @} */ + +/** @defgroup Address ENet address functions + @{ +*/ +/** Attempts to resolve the host named by the parameter hostName and sets + the host field in the address parameter if successful. + @param address destination to store resolved address + @param hostName host name to lookup + @retval 0 on success + @retval < 0 on failure + @returns the address of the given hostName in address on success +*/ +ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName); + +/** Gives the printable form of the ip address specified in the address parameter. + @param address address printed + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host_ip (const ENetAddress * address, char * hostName, size_t nameLength); + +/** Attempts to do a reverse lookup of the host field in the address parameter. + @param address address used for reverse lookup + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength); + +/** @} */ + +ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32); +ENET_API void enet_packet_destroy (ENetPacket *); +ENET_API int enet_packet_resize (ENetPacket *, size_t); +extern enet_uint32 enet_crc32 (const ENetBuffer *, size_t); + +ENET_API ENetHost * enet_host_create (const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32); +ENET_API void enet_host_destroy (ENetHost *); +ENET_API ENetPeer * enet_host_connect (ENetHost *, const ENetAddress *, size_t, enet_uint32); +ENET_API int enet_host_check_events (ENetHost *, ENetEvent *); +ENET_API int enet_host_service (ENetHost *, ENetEvent *, enet_uint32); +ENET_API void enet_host_flush (ENetHost *); +ENET_API void enet_host_broadcast (ENetHost *, enet_uint8, ENetPacket *); +ENET_API void enet_host_compress (ENetHost *, const ENetCompressor *); +ENET_API int enet_host_compress_with_range_coder (ENetHost * host); +ENET_API void enet_host_channel_limit (ENetHost *, size_t); +ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32); +extern void enet_host_bandwidth_throttle (ENetHost *); + +ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *); +ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID); +ENET_API void enet_peer_ping (ENetPeer *); +ENET_API void enet_peer_reset (ENetPeer *); +ENET_API void enet_peer_disconnect (ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_now (ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_later (ENetPeer *, enet_uint32); +ENET_API void enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); +extern int enet_peer_throttle (ENetPeer *, enet_uint32); +extern void enet_peer_reset_queues (ENetPeer *); +extern void enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *); +extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16); +extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32); +extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const ENetProtocol *, enet_uint16); +extern void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer *, ENetChannel *); +extern void enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *); + +ENET_API void * enet_range_coder_create (void); +ENET_API void enet_range_coder_destroy (void *); +ENET_API size_t enet_range_coder_compress (void *, const ENetBuffer *, size_t, size_t, enet_uint8 *, size_t); +ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, enet_uint8 *, size_t); + +extern size_t enet_protocol_command_size (enet_uint8); + +#ifdef __cplusplus +} +#endif + +#endif /* __ENET_ENET_H__ */ + diff --git a/libs/enet/include/enet/list.h b/libs/enet/include/enet/list.h new file mode 100644 index 0000000..d7b2600 --- /dev/null +++ b/libs/enet/include/enet/list.h @@ -0,0 +1,43 @@ +/** + @file list.h + @brief ENet list management +*/ +#ifndef __ENET_LIST_H__ +#define __ENET_LIST_H__ + +#include + +typedef struct _ENetListNode +{ + struct _ENetListNode * next; + struct _ENetListNode * previous; +} ENetListNode; + +typedef ENetListNode * ENetListIterator; + +typedef struct _ENetList +{ + ENetListNode sentinel; +} ENetList; + +extern void enet_list_clear (ENetList *); + +extern ENetListIterator enet_list_insert (ENetListIterator, void *); +extern void * enet_list_remove (ENetListIterator); +extern ENetListIterator enet_list_move (ENetListIterator, void *, void *); + +extern size_t enet_list_size (ENetList *); + +#define enet_list_begin(list) ((list) -> sentinel.next) +#define enet_list_end(list) (& (list) -> sentinel) + +#define enet_list_empty(list) (enet_list_begin (list) == enet_list_end (list)) + +#define enet_list_next(iterator) ((iterator) -> next) +#define enet_list_previous(iterator) ((iterator) -> previous) + +#define enet_list_front(list) ((void *) (list) -> sentinel.next) +#define enet_list_back(list) ((void *) (list) -> sentinel.previous) + +#endif /* __ENET_LIST_H__ */ + diff --git a/libs/enet/include/enet/protocol.h b/libs/enet/include/enet/protocol.h new file mode 100644 index 0000000..19f7e45 --- /dev/null +++ b/libs/enet/include/enet/protocol.h @@ -0,0 +1,196 @@ +/** + @file protocol.h + @brief ENet protocol +*/ +#ifndef __ENET_PROTOCOL_H__ +#define __ENET_PROTOCOL_H__ + +#include "enet/types.h" + +enum +{ + ENET_PROTOCOL_MINIMUM_MTU = 576, + ENET_PROTOCOL_MAXIMUM_MTU = 4096, + ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32, + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096, + ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 32768, + ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1, + ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255, + ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF +}; + +typedef enum _ENetProtocolCommand +{ + ENET_PROTOCOL_COMMAND_NONE = 0, + ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, + ENET_PROTOCOL_COMMAND_CONNECT = 2, + ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, + ENET_PROTOCOL_COMMAND_DISCONNECT = 4, + ENET_PROTOCOL_COMMAND_PING = 5, + ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, + ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, + ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, + ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, + ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, + ENET_PROTOCOL_COMMAND_COUNT = 12, + + ENET_PROTOCOL_COMMAND_MASK = 0x0F +} ENetProtocolCommand; + +typedef enum _ENetProtocolFlag +{ + ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7), + ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6), + + ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14), + ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15), + ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME, + + ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12), + ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12 +} ENetProtocolFlag; + +#ifdef _MSC_VER_ +#pragma pack(push, 1) +#define ENET_PACKED +#elif defined(__GNUC__) +#define ENET_PACKED __attribute__ ((packed)) +#else +#define ENET_PACKED +#endif + +typedef struct _ENetProtocolHeader +{ + enet_uint16 peerID; + enet_uint16 sentTime; +} ENET_PACKED ENetProtocolHeader; + +typedef struct _ENetProtocolCommandHeader +{ + enet_uint8 command; + enet_uint8 channelID; + enet_uint16 reliableSequenceNumber; +} ENET_PACKED ENetProtocolCommandHeader; + +typedef struct _ENetProtocolAcknowledge +{ + ENetProtocolCommandHeader header; + enet_uint16 receivedReliableSequenceNumber; + enet_uint16 receivedSentTime; +} ENET_PACKED ENetProtocolAcknowledge; + +typedef struct _ENetProtocolConnect +{ + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 connectID; + enet_uint32 data; +} ENET_PACKED ENetProtocolConnect; + +typedef struct _ENetProtocolVerifyConnect +{ + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 connectID; +} ENET_PACKED ENetProtocolVerifyConnect; + +typedef struct _ENetProtocolBandwidthLimit +{ + ENetProtocolCommandHeader header; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; +} ENET_PACKED ENetProtocolBandwidthLimit; + +typedef struct _ENetProtocolThrottleConfigure +{ + ENetProtocolCommandHeader header; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; +} ENET_PACKED ENetProtocolThrottleConfigure; + +typedef struct _ENetProtocolDisconnect +{ + ENetProtocolCommandHeader header; + enet_uint32 data; +} ENET_PACKED ENetProtocolDisconnect; + +typedef struct _ENetProtocolPing +{ + ENetProtocolCommandHeader header; +} ENET_PACKED ENetProtocolPing; + +typedef struct _ENetProtocolSendReliable +{ + ENetProtocolCommandHeader header; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendReliable; + +typedef struct _ENetProtocolSendUnreliable +{ + ENetProtocolCommandHeader header; + enet_uint16 unreliableSequenceNumber; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnreliable; + +typedef struct _ENetProtocolSendUnsequenced +{ + ENetProtocolCommandHeader header; + enet_uint16 unsequencedGroup; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnsequenced; + +typedef struct _ENetProtocolSendFragment +{ + ENetProtocolCommandHeader header; + enet_uint16 startSequenceNumber; + enet_uint16 dataLength; + enet_uint32 fragmentCount; + enet_uint32 fragmentNumber; + enet_uint32 totalLength; + enet_uint32 fragmentOffset; +} ENET_PACKED ENetProtocolSendFragment; + +typedef union _ENetProtocol +{ + ENetProtocolCommandHeader header; + ENetProtocolAcknowledge acknowledge; + ENetProtocolConnect connect; + ENetProtocolVerifyConnect verifyConnect; + ENetProtocolDisconnect disconnect; + ENetProtocolPing ping; + ENetProtocolSendReliable sendReliable; + ENetProtocolSendUnreliable sendUnreliable; + ENetProtocolSendUnsequenced sendUnsequenced; + ENetProtocolSendFragment sendFragment; + ENetProtocolBandwidthLimit bandwidthLimit; + ENetProtocolThrottleConfigure throttleConfigure; +} ENET_PACKED ENetProtocol; + +#ifdef _MSC_VER_ +#pragma pack(pop) +#endif + +#endif /* __ENET_PROTOCOL_H__ */ + diff --git a/libs/enet/include/enet/time.h b/libs/enet/include/enet/time.h new file mode 100644 index 0000000..c82a546 --- /dev/null +++ b/libs/enet/include/enet/time.h @@ -0,0 +1,18 @@ +/** + @file time.h + @brief ENet time constants and macros +*/ +#ifndef __ENET_TIME_H__ +#define __ENET_TIME_H__ + +#define ENET_TIME_OVERFLOW 86400000 + +#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) +#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) + +#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) + +#endif /* __ENET_TIME_H__ */ + diff --git a/libs/enet/include/enet/types.h b/libs/enet/include/enet/types.h new file mode 100644 index 0000000..ab010a4 --- /dev/null +++ b/libs/enet/include/enet/types.h @@ -0,0 +1,13 @@ +/** + @file types.h + @brief type definitions for ENet +*/ +#ifndef __ENET_TYPES_H__ +#define __ENET_TYPES_H__ + +typedef unsigned char enet_uint8; /**< unsigned 8-bit type */ +typedef unsigned short enet_uint16; /**< unsigned 16-bit type */ +typedef unsigned int enet_uint32; /**< unsigned 32-bit type */ + +#endif /* __ENET_TYPES_H__ */ + diff --git a/libs/enet/include/enet/unix.h b/libs/enet/include/enet/unix.h new file mode 100644 index 0000000..087015e --- /dev/null +++ b/libs/enet/include/enet/unix.h @@ -0,0 +1,45 @@ +/** + @file unix.h + @brief ENet Unix header +*/ +#ifndef __ENET_UNIX_H__ +#define __ENET_UNIX_H__ + +#include +#include +#include +#include +#include + +typedef int ENetSocket; + +enum +{ + ENET_SOCKET_NULL = -1 +}; + +#define ENET_HOST_TO_NET_16(value) (htons (value)) /**< macro that converts host to net byte-order of a 16-bit value */ +#define ENET_HOST_TO_NET_32(value) (htonl (value)) /**< macro that converts host to net byte-order of a 32-bit value */ + +#define ENET_NET_TO_HOST_16(value) (ntohs (value)) /**< macro that converts net to host byte-order of a 16-bit value */ +#define ENET_NET_TO_HOST_32(value) (ntohl (value)) /**< macro that converts net to host byte-order of a 32-bit value */ + +typedef struct +{ + void * data; + size_t dataLength; +} ENetBuffer; + +#define ENET_CALLBACK + +#define ENET_API extern + +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLEAR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_UNIX_H__ */ + diff --git a/libs/enet/include/enet/utility.h b/libs/enet/include/enet/utility.h new file mode 100644 index 0000000..e48a476 --- /dev/null +++ b/libs/enet/include/enet/utility.h @@ -0,0 +1,12 @@ +/** + @file utility.h + @brief ENet utility header +*/ +#ifndef __ENET_UTILITY_H__ +#define __ENET_UTILITY_H__ + +#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#endif /* __ENET_UTILITY_H__ */ + diff --git a/libs/enet/include/enet/win32.h b/libs/enet/include/enet/win32.h new file mode 100644 index 0000000..0e1cf0c --- /dev/null +++ b/libs/enet/include/enet/win32.h @@ -0,0 +1,58 @@ +/** + @file win32.h + @brief ENet Win32 header +*/ +#ifndef __ENET_WIN32_H__ +#define __ENET_WIN32_H__ + +#ifdef ENET_BUILDING_LIB +#pragma warning (disable: 4996) // 'strncpy' was declared deprecated +#pragma warning (disable: 4267) // size_t to int conversion +#pragma warning (disable: 4244) // 64bit to 32bit int +#pragma warning (disable: 4018) // signed/unsigned mismatch +#endif + +#include +#include + +typedef SOCKET ENetSocket; + +enum +{ + ENET_SOCKET_NULL = INVALID_SOCKET +}; + +#define ENET_HOST_TO_NET_16(value) (htons (value)) +#define ENET_HOST_TO_NET_32(value) (htonl (value)) + +#define ENET_NET_TO_HOST_16(value) (ntohs (value)) +#define ENET_NET_TO_HOST_32(value) (ntohl (value)) + +typedef struct +{ + size_t dataLength; + void * data; +} ENetBuffer; + +#define ENET_CALLBACK __cdecl + +#if defined ENET_DLL +#if defined ENET_BUILDING_LIB +#define ENET_API __declspec( dllexport ) +#else +#define ENET_API __declspec( dllimport ) +#endif /* ENET_BUILDING_LIB */ +#else /* !ENET_DLL */ +#define ENET_API extern +#endif /* ENET_DLL */ + +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLEAR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_WIN32_H__ */ + + diff --git a/libs/enet/list.c b/libs/enet/list.c new file mode 100644 index 0000000..8487200 --- /dev/null +++ b/libs/enet/list.c @@ -0,0 +1,75 @@ +/** + @file list.c + @brief ENet linked list functions +*/ +#define ENET_BUILDING_LIB 1 +#include "enet/list.h" + +/** + @defgroup list ENet linked list utility functions + @ingroup private + @{ +*/ +void +enet_list_clear (ENetList * list) +{ + list -> sentinel.next = & list -> sentinel; + list -> sentinel.previous = & list -> sentinel; +} + +ENetListIterator +enet_list_insert (ENetListIterator position, void * data) +{ + ENetListIterator result = (ENetListIterator) data; + + result -> previous = position -> previous; + result -> next = position; + + result -> previous -> next = result; + position -> previous = result; + + return result; +} + +void * +enet_list_remove (ENetListIterator position) +{ + position -> previous -> next = position -> next; + position -> next -> previous = position -> previous; + + return position; +} + +ENetListIterator +enet_list_move (ENetListIterator position, void * dataFirst, void * dataLast) +{ + ENetListIterator first = (ENetListIterator) dataFirst, + last = (ENetListIterator) dataLast; + + first -> previous -> next = last -> next; + last -> next -> previous = first -> previous; + + first -> previous = position -> previous; + last -> next = position; + + first -> previous -> next = first; + position -> previous = last; + + return first; +} + +size_t +enet_list_size (ENetList * list) +{ + size_t size = 0; + ENetListIterator position; + + for (position = enet_list_begin (list); + position != enet_list_end (list); + position = enet_list_next (position)) + ++ size; + + return size; +} + +/** @} */ diff --git a/libs/enet/packet.c b/libs/enet/packet.c new file mode 100644 index 0000000..2fc9a10 --- /dev/null +++ b/libs/enet/packet.c @@ -0,0 +1,157 @@ +/** + @file packet.c + @brief ENet packet management functions +*/ +#include +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +/** @defgroup Packet ENet packet functions + @{ +*/ + +/** Creates a packet that may be sent to a peer. + @param dataContents initial contents of the packet's data; the packet's data will remain uninitialized if dataContents is NULL. + @param dataLength size of the data allocated for this packet + @param flags flags for this packet as described for the ENetPacket structure. + @returns the packet on success, NULL on failure +*/ +ENetPacket * +enet_packet_create (const void * data, size_t dataLength, enet_uint32 flags) +{ + ENetPacket * packet = (ENetPacket *) enet_malloc (sizeof (ENetPacket)); + if (packet == NULL) + return NULL; + + if (flags & ENET_PACKET_FLAG_NO_ALLOCATE) + packet -> data = (enet_uint8 *) data; + else + { + packet -> data = (enet_uint8 *) enet_malloc (dataLength); + if (packet -> data == NULL) + { + enet_free (packet); + return NULL; + } + + if (data != NULL) + memcpy (packet -> data, data, dataLength); + } + + packet -> referenceCount = 0; + packet -> flags = flags; + packet -> dataLength = dataLength; + packet -> freeCallback = NULL; + + return packet; +} + +/** Destroys the packet and deallocates its data. + @param packet packet to be destroyed +*/ +void +enet_packet_destroy (ENetPacket * packet) +{ + if (packet -> freeCallback != NULL) + (* packet -> freeCallback) (packet); + if (! (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE)) + enet_free (packet -> data); + enet_free (packet); +} + +/** Attempts to resize the data in the packet to length specified in the + dataLength parameter + @param packet packet to resize + @param dataLength new size for the packet data + @returns 0 on success, < 0 on failure +*/ +int +enet_packet_resize (ENetPacket * packet, size_t dataLength) +{ + enet_uint8 * newData; + + if (dataLength <= packet -> dataLength || (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE)) + { + packet -> dataLength = dataLength; + + return 0; + } + + newData = (enet_uint8 *) enet_malloc (dataLength); + if (newData == NULL) + return -1; + + memcpy (newData, packet -> data, packet -> dataLength); + enet_free (packet -> data); + + packet -> data = newData; + packet -> dataLength = dataLength; + + return 0; +} + +static int initializedCRC32 = 0; +static enet_uint32 crcTable [256]; + +static enet_uint32 +reflect_crc (int val, int bits) +{ + int result = 0, bit; + + for (bit = 0; bit < bits; bit ++) + { + if(val & 1) result |= 1 << (bits - 1 - bit); + val >>= 1; + } + + return result; +} + +static void +initialize_crc32 () +{ + int byte; + + for (byte = 0; byte < 256; ++ byte) + { + enet_uint32 crc = reflect_crc (byte, 8) << 24; + int offset; + + for(offset = 0; offset < 8; ++ offset) + { + if (crc & 0x80000000) + crc = (crc << 1) ^ 0x04c11db7; + else + crc <<= 1; + } + + crcTable [byte] = reflect_crc (crc, 32); + } + + initializedCRC32 = 1; +} + +enet_uint32 +enet_crc32 (const ENetBuffer * buffers, size_t bufferCount) +{ + enet_uint32 crc = 0xFFFFFFFF; + + if (! initializedCRC32) initialize_crc32 (); + + while (bufferCount -- > 0) + { + const enet_uint8 * data = (const enet_uint8 *) buffers -> data, + * dataEnd = & data [buffers -> dataLength]; + + while (data < dataEnd) + { + crc = (crc >> 8) ^ crcTable [(crc & 0xFF) ^ *data++]; + } + + ++ buffers; + } + + return ENET_HOST_TO_NET_32 (~ crc); +} + +/** @} */ diff --git a/libs/enet/peer.c b/libs/enet/peer.c new file mode 100644 index 0000000..d778ce1 --- /dev/null +++ b/libs/enet/peer.c @@ -0,0 +1,816 @@ +/** + @file peer.c + @brief ENet peer management functions +*/ +#include +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +/** @defgroup peer ENet peer functions + @{ +*/ + +/** Configures throttle parameter for a peer. + + Unreliable packets are dropped by ENet in response to the varying conditions + of the Internet connection to the peer. The throttle represents a probability + that an unreliable packet should not be dropped and thus sent by ENet to the peer. + The lowest mean round trip time from the sending of a reliable packet to the + receipt of its acknowledgement is measured over an amount of time specified by + the interval parameter in milliseconds. If a measured round trip time happens to + be significantly less than the mean round trip time measured over the interval, + then the throttle probability is increased to allow more traffic by an amount + specified in the acceleration parameter, which is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE + constant. If a measured round trip time happens to be significantly greater than + the mean round trip time measured over the interval, then the throttle probability + is decreased to limit traffic by an amount specified in the deceleration parameter, which + is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE constant. When the throttle has + a value of ENET_PEER_PACKET_THROTTLE_SCALE, on unreliable packets are dropped by + ENet, and so 100% of all unreliable packets will be sent. When the throttle has a + value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable + packets will be sent. Intermediate values for the throttle represent intermediate + probabilities between 0% and 100% of unreliable packets being sent. The bandwidth + limits of the local and foreign hosts are taken into account to determine a + sensible limit for the throttle probability above which it should not raise even in + the best of conditions. + + @param peer peer to configure + @param interval interval, in milliseconds, over which to measure lowest mean RTT; the default value is ENET_PEER_PACKET_THROTTLE_INTERVAL. + @param acceleration rate at which to increase the throttle probability as mean RTT declines + @param deceleration rate at which to decrease the throttle probability as mean RTT increases +*/ +void +enet_peer_throttle_configure (ENetPeer * peer, enet_uint32 interval, enet_uint32 acceleration, enet_uint32 deceleration) +{ + ENetProtocol command; + + peer -> packetThrottleInterval = interval; + peer -> packetThrottleAcceleration = acceleration; + peer -> packetThrottleDeceleration = deceleration; + + command.header.command = ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + + command.throttleConfigure.packetThrottleInterval = ENET_HOST_TO_NET_32 (interval); + command.throttleConfigure.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (acceleration); + command.throttleConfigure.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (deceleration); + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); +} + +int +enet_peer_throttle (ENetPeer * peer, enet_uint32 rtt) +{ + if (peer -> lastRoundTripTime <= peer -> lastRoundTripTimeVariance) + { + peer -> packetThrottle = peer -> packetThrottleLimit; + } + else + if (rtt < peer -> lastRoundTripTime) + { + peer -> packetThrottle += peer -> packetThrottleAcceleration; + + if (peer -> packetThrottle > peer -> packetThrottleLimit) + peer -> packetThrottle = peer -> packetThrottleLimit; + + return 1; + } + else + if (rtt > peer -> lastRoundTripTime + 2 * peer -> lastRoundTripTimeVariance) + { + if (peer -> packetThrottle > peer -> packetThrottleDeceleration) + peer -> packetThrottle -= peer -> packetThrottleDeceleration; + else + peer -> packetThrottle = 0; + + return -1; + } + + return 0; +} + +/** Queues a packet to be sent. + @param peer destination for the packet + @param channelID channel on which to send + @param packet packet to send + @retval 0 on success + @retval < 0 on failure +*/ +int +enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet) +{ + ENetChannel * channel = & peer -> channels [channelID]; + ENetProtocol command; + size_t fragmentLength; + + if (peer -> state != ENET_PEER_STATE_CONNECTED || + channelID >= peer -> channelCount) + return -1; + + fragmentLength = peer -> mtu - sizeof (ENetProtocolHeader) - sizeof (ENetProtocolSendFragment); + + if (packet -> dataLength > fragmentLength) + { + enet_uint16 startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingReliableSequenceNumber + 1); + enet_uint32 fragmentCount = ENET_HOST_TO_NET_32 ((packet -> dataLength + fragmentLength - 1) / fragmentLength), + fragmentNumber, + fragmentOffset; + ENetList fragments; + ENetOutgoingCommand * fragment; + + enet_list_clear (& fragments); + + for (fragmentNumber = 0, + fragmentOffset = 0; + fragmentOffset < packet -> dataLength; + ++ fragmentNumber, + fragmentOffset += fragmentLength) + { + if (packet -> dataLength - fragmentOffset < fragmentLength) + fragmentLength = packet -> dataLength - fragmentOffset; + + fragment = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand)); + if (fragment == NULL) + { + while (! enet_list_empty (& fragments)) + { + fragment = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& fragments)); + + enet_free (fragment); + } + + return -1; + } + + fragment -> fragmentOffset = fragmentOffset; + fragment -> fragmentLength = fragmentLength; + fragment -> packet = packet; + fragment -> command.header.command = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + fragment -> command.header.channelID = channelID; + fragment -> command.sendFragment.startSequenceNumber = startSequenceNumber; + fragment -> command.sendFragment.dataLength = ENET_HOST_TO_NET_16 (fragmentLength); + fragment -> command.sendFragment.fragmentCount = fragmentCount; + fragment -> command.sendFragment.fragmentNumber = ENET_HOST_TO_NET_32 (fragmentNumber); + fragment -> command.sendFragment.totalLength = ENET_HOST_TO_NET_32 (packet -> dataLength); + fragment -> command.sendFragment.fragmentOffset = ENET_NET_TO_HOST_32 (fragmentOffset); + + enet_list_insert (enet_list_end (& fragments), fragment); + } + + packet -> referenceCount += fragmentNumber; + + while (! enet_list_empty (& fragments)) + { + fragment = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& fragments)); + + enet_peer_setup_outgoing_command (peer, fragment); + } + + return 0; + } + + command.header.channelID = channelID; + + if (packet -> flags & ENET_PACKET_FLAG_RELIABLE) + { + command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.sendReliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); + } + else + if (packet -> flags & ENET_PACKET_FLAG_UNSEQUENCED) + { + command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; + command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup + 1); + command.sendUnsequenced.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); + } + else + if (channel -> outgoingUnreliableSequenceNumber >= 0xFFFF) + { + command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.sendReliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); + } + else + { + command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE; + command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingUnreliableSequenceNumber + 1); + command.sendUnreliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); + } + + if (enet_peer_queue_outgoing_command (peer, & command, packet, 0, packet -> dataLength) == NULL) + return -1; + + return 0; +} + +/** Attempts to dequeue any incoming queued packet. + @param peer peer to dequeue packets from + @param channelID holds the channel ID of the channel the packet was received on success + @returns a pointer to the packet, or NULL if there are no available incoming queued packets +*/ +ENetPacket * +enet_peer_receive (ENetPeer * peer, enet_uint8 * channelID) +{ + ENetIncomingCommand * incomingCommand; + ENetPacket * packet; + + if (enet_list_empty (& peer -> dispatchedCommands)) + return NULL; + + incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (& peer -> dispatchedCommands)); + + if (channelID != NULL) + * channelID = incomingCommand -> command.header.channelID; + + packet = incomingCommand -> packet; + + -- packet -> referenceCount; + + if (incomingCommand -> fragments != NULL) + enet_free (incomingCommand -> fragments); + + enet_free (incomingCommand); + + return packet; +} + +static void +enet_peer_reset_outgoing_commands (ENetList * queue) +{ + ENetOutgoingCommand * outgoingCommand; + + while (! enet_list_empty (queue)) + { + outgoingCommand = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (queue)); + + if (outgoingCommand -> packet != NULL) + { + -- outgoingCommand -> packet -> referenceCount; + + if (outgoingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (outgoingCommand -> packet); + } + + enet_free (outgoingCommand); + } +} + +static void +enet_peer_reset_incoming_commands (ENetList * queue) +{ + ENetIncomingCommand * incomingCommand; + + while (! enet_list_empty (queue)) + { + incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (queue)); + + if (incomingCommand -> packet != NULL) + { + -- incomingCommand -> packet -> referenceCount; + + if (incomingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (incomingCommand -> packet); + } + + if (incomingCommand -> fragments != NULL) + enet_free (incomingCommand -> fragments); + + enet_free (incomingCommand); + } +} + +void +enet_peer_reset_queues (ENetPeer * peer) +{ + ENetChannel * channel; + + if (peer -> needsDispatch) + { + enet_list_remove (& peer -> dispatchList); + + peer -> needsDispatch = 0; + } + + while (! enet_list_empty (& peer -> acknowledgements)) + enet_free (enet_list_remove (enet_list_begin (& peer -> acknowledgements))); + + enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands); + enet_peer_reset_outgoing_commands (& peer -> sentUnreliableCommands); + enet_peer_reset_outgoing_commands (& peer -> outgoingReliableCommands); + enet_peer_reset_outgoing_commands (& peer -> outgoingUnreliableCommands); + enet_peer_reset_incoming_commands (& peer -> dispatchedCommands); + + if (peer -> channels != NULL && peer -> channelCount > 0) + { + for (channel = peer -> channels; + channel < & peer -> channels [peer -> channelCount]; + ++ channel) + { + enet_peer_reset_incoming_commands (& channel -> incomingReliableCommands); + enet_peer_reset_incoming_commands (& channel -> incomingUnreliableCommands); + } + + enet_free (peer -> channels); + } + + peer -> channels = NULL; + peer -> channelCount = 0; +} + +/** Forcefully disconnects a peer. + @param peer peer to forcefully disconnect + @remarks The foreign host represented by the peer is not notified of the disconnection and will timeout + on its connection to the local host. +*/ +void +enet_peer_reset (ENetPeer * peer) +{ + peer -> outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID; + peer -> connectID = 0; + + peer -> state = ENET_PEER_STATE_DISCONNECTED; + + peer -> incomingBandwidth = 0; + peer -> outgoingBandwidth = 0; + peer -> incomingBandwidthThrottleEpoch = 0; + peer -> outgoingBandwidthThrottleEpoch = 0; + peer -> incomingDataTotal = 0; + peer -> outgoingDataTotal = 0; + peer -> lastSendTime = 0; + peer -> lastReceiveTime = 0; + peer -> nextTimeout = 0; + peer -> earliestTimeout = 0; + peer -> packetLossEpoch = 0; + peer -> packetsSent = 0; + peer -> packetsLost = 0; + peer -> packetLoss = 0; + peer -> packetLossVariance = 0; + peer -> packetThrottle = ENET_PEER_DEFAULT_PACKET_THROTTLE; + peer -> packetThrottleLimit = ENET_PEER_PACKET_THROTTLE_SCALE; + peer -> packetThrottleCounter = 0; + peer -> packetThrottleEpoch = 0; + peer -> packetThrottleAcceleration = ENET_PEER_PACKET_THROTTLE_ACCELERATION; + peer -> packetThrottleDeceleration = ENET_PEER_PACKET_THROTTLE_DECELERATION; + peer -> packetThrottleInterval = ENET_PEER_PACKET_THROTTLE_INTERVAL; + peer -> lastRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; + peer -> lowestRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; + peer -> lastRoundTripTimeVariance = 0; + peer -> highestRoundTripTimeVariance = 0; + peer -> roundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; + peer -> roundTripTimeVariance = 0; + peer -> mtu = peer -> host -> mtu; + peer -> reliableDataInTransit = 0; + peer -> outgoingReliableSequenceNumber = 0; + peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + peer -> incomingUnsequencedGroup = 0; + peer -> outgoingUnsequencedGroup = 0; + peer -> eventData = 0; + + memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow)); + + enet_peer_reset_queues (peer); +} + +/** Sends a ping request to a peer. + @param peer destination for the ping request + @remarks ping requests factor into the mean round trip time as designated by the + roundTripTime field in the ENetPeer structure. Enet automatically pings all connected + peers at regular intervals, however, this function may be called to ensure more + frequent ping requests. +*/ +void +enet_peer_ping (ENetPeer * peer) +{ + ENetProtocol command; + + if (peer -> state != ENET_PEER_STATE_CONNECTED) + return; + + command.header.command = ENET_PROTOCOL_COMMAND_PING | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); +} + +/** Force an immediate disconnection from a peer. + @param peer peer to disconnect + @param data data describing the disconnection + @remarks No ENET_EVENT_DISCONNECT event will be generated. The foreign peer is not + guarenteed to receive the disconnect notification, and is reset immediately upon + return from this function. +*/ +void +enet_peer_disconnect_now (ENetPeer * peer, enet_uint32 data) +{ + ENetProtocol command; + + if (peer -> state == ENET_PEER_STATE_DISCONNECTED) + return; + + if (peer -> state != ENET_PEER_STATE_ZOMBIE && + peer -> state != ENET_PEER_STATE_DISCONNECTING) + { + enet_peer_reset_queues (peer); + + command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; + command.header.channelID = 0xFF; + command.disconnect.data = ENET_HOST_TO_NET_32 (data); + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); + + enet_host_flush (peer -> host); + } + + enet_peer_reset (peer); +} + +/** Request a disconnection from a peer. + @param peer peer to request a disconnection + @param data data describing the disconnection + @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() + once the disconnection is complete. +*/ +void +enet_peer_disconnect (ENetPeer * peer, enet_uint32 data) +{ + ENetProtocol command; + + if (peer -> state == ENET_PEER_STATE_DISCONNECTING || + peer -> state == ENET_PEER_STATE_DISCONNECTED || + peer -> state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT || + peer -> state == ENET_PEER_STATE_ZOMBIE) + return; + + enet_peer_reset_queues (peer); + + command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT; + command.header.channelID = 0xFF; + command.disconnect.data = ENET_HOST_TO_NET_32 (data); + + if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) + command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + else + command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); + + if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) + peer -> state = ENET_PEER_STATE_DISCONNECTING; + else + { + enet_host_flush (peer -> host); + enet_peer_reset (peer); + } +} + +/** Request a disconnection from a peer, but only after all queued outgoing packets are sent. + @param peer peer to request a disconnection + @param data data describing the disconnection + @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() + once the disconnection is complete. +*/ +void +enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data) +{ + if ((peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) && + ! (enet_list_empty (& peer -> outgoingReliableCommands) && + enet_list_empty (& peer -> outgoingUnreliableCommands) && + enet_list_empty (& peer -> sentReliableCommands))) + { + peer -> state = ENET_PEER_STATE_DISCONNECT_LATER; + peer -> eventData = data; + } + else + enet_peer_disconnect (peer, data); +} + +ENetAcknowledgement * +enet_peer_queue_acknowledgement (ENetPeer * peer, const ENetProtocol * command, enet_uint16 sentTime) +{ + ENetAcknowledgement * acknowledgement; + + if (command -> header.channelID < peer -> channelCount) + { + ENetChannel * channel = & peer -> channels [command -> header.channelID]; + enet_uint16 reliableWindow = command -> header.reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE, + currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (command -> header.reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + reliableWindow += ENET_PEER_RELIABLE_WINDOWS; + + if (reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1 && reliableWindow <= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS) + return NULL; + } + + acknowledgement = (ENetAcknowledgement *) enet_malloc (sizeof (ENetAcknowledgement)); + if (acknowledgement == NULL) + return NULL; + + peer -> outgoingDataTotal += sizeof (ENetProtocolAcknowledge); + + acknowledgement -> sentTime = sentTime; + acknowledgement -> command = * command; + + enet_list_insert (enet_list_end (& peer -> acknowledgements), acknowledgement); + + return acknowledgement; +} + +void +enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoingCommand) +{ + ENetChannel * channel = & peer -> channels [outgoingCommand -> command.header.channelID]; + + peer -> outgoingDataTotal += enet_protocol_command_size (outgoingCommand -> command.header.command) + outgoingCommand -> fragmentLength; + + if (outgoingCommand -> command.header.channelID == 0xFF) + { + ++ peer -> outgoingReliableSequenceNumber; + + outgoingCommand -> reliableSequenceNumber = peer -> outgoingReliableSequenceNumber; + outgoingCommand -> unreliableSequenceNumber = 0; + } + else + if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) + { + ++ channel -> outgoingReliableSequenceNumber; + channel -> outgoingUnreliableSequenceNumber = 0; + + outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; + outgoingCommand -> unreliableSequenceNumber = 0; + } + else + if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED) + { + ++ peer -> outgoingUnsequencedGroup; + + outgoingCommand -> reliableSequenceNumber = 0; + outgoingCommand -> unreliableSequenceNumber = 0; + } + else + { + ++ channel -> outgoingUnreliableSequenceNumber; + + outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; + outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber; + } + + outgoingCommand -> sendAttempts = 0; + outgoingCommand -> sentTime = 0; + outgoingCommand -> roundTripTimeout = 0; + outgoingCommand -> roundTripTimeoutLimit = 0; + outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> reliableSequenceNumber); + + if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) + enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand); + else + enet_list_insert (enet_list_end (& peer -> outgoingUnreliableCommands), outgoingCommand); +} + +ENetOutgoingCommand * +enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command, ENetPacket * packet, enet_uint32 offset, enet_uint16 length) +{ + ENetOutgoingCommand * outgoingCommand = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand)); + if (outgoingCommand == NULL) + return NULL; + + outgoingCommand -> command = * command; + outgoingCommand -> fragmentOffset = offset; + outgoingCommand -> fragmentLength = length; + outgoingCommand -> packet = packet; + if (packet != NULL) + ++ packet -> referenceCount; + + enet_peer_setup_outgoing_command (peer, outgoingCommand); + + return outgoingCommand; +} + +void +enet_peer_dispatch_incoming_unreliable_commands (ENetPeer * peer, ENetChannel * channel) +{ + ENetListIterator currentCommand; + + for (currentCommand = enet_list_begin (& channel -> incomingUnreliableCommands); + currentCommand != enet_list_end (& channel -> incomingUnreliableCommands); + currentCommand = enet_list_next (currentCommand)) + { + ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; + + if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE && + incomingCommand -> reliableSequenceNumber != channel -> incomingReliableSequenceNumber) + break; + } + + if (currentCommand == enet_list_begin (& channel -> incomingUnreliableCommands)) + return; + + enet_list_move (enet_list_end (& peer -> dispatchedCommands), enet_list_begin (& channel -> incomingUnreliableCommands), enet_list_previous (currentCommand)); + + if (! peer -> needsDispatch) + { + enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); + + peer -> needsDispatch = 1; + } +} + +void +enet_peer_dispatch_incoming_reliable_commands (ENetPeer * peer, ENetChannel * channel) +{ + ENetListIterator currentCommand; + + for (currentCommand = enet_list_begin (& channel -> incomingReliableCommands); + currentCommand != enet_list_end (& channel -> incomingReliableCommands); + currentCommand = enet_list_next (currentCommand)) + { + ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; + + if (incomingCommand -> fragmentsRemaining > 0 || + incomingCommand -> reliableSequenceNumber != (enet_uint16) (channel -> incomingReliableSequenceNumber + 1)) + break; + + channel -> incomingReliableSequenceNumber = incomingCommand -> reliableSequenceNumber; + + if (incomingCommand -> fragmentCount > 0) + channel -> incomingReliableSequenceNumber += incomingCommand -> fragmentCount - 1; + } + + if (currentCommand == enet_list_begin (& channel -> incomingReliableCommands)) + return; + + enet_list_move (enet_list_end (& peer -> dispatchedCommands), enet_list_begin (& channel -> incomingReliableCommands), enet_list_previous (currentCommand)); + + if (! peer -> needsDispatch) + { + enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); + + peer -> needsDispatch = 1; + } + + enet_peer_dispatch_incoming_unreliable_commands (peer, channel); +} + +ENetIncomingCommand * +enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, ENetPacket * packet, enet_uint32 fragmentCount) +{ + static ENetIncomingCommand dummyCommand; + + ENetChannel * channel = & peer -> channels [command -> header.channelID]; + enet_uint32 unreliableSequenceNumber = 0, reliableSequenceNumber; + enet_uint16 reliableWindow, currentWindow; + ENetIncomingCommand * incomingCommand; + ENetListIterator currentCommand; + + if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) + goto freePacket; + + if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) + { + reliableSequenceNumber = command -> header.reliableSequenceNumber; + reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + reliableWindow += ENET_PEER_RELIABLE_WINDOWS; + + if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) + goto freePacket; + } + + switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK) + { + case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: + case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: + if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber) + goto freePacket; + + for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands)); + currentCommand != enet_list_end (& channel -> incomingReliableCommands); + currentCommand = enet_list_previous (currentCommand)) + { + incomingCommand = (ENetIncomingCommand *) currentCommand; + + if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber <= reliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber) + break; + + goto freePacket; + } + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: + unreliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendUnreliable.unreliableSequenceNumber); + + for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands)); + currentCommand != enet_list_end (& channel -> incomingUnreliableCommands); + currentCommand = enet_list_previous (currentCommand)) + { + incomingCommand = (ENetIncomingCommand *) currentCommand; + + if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE) + continue; + + if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber > reliableSequenceNumber) + continue; + + if (incomingCommand -> unreliableSequenceNumber <= unreliableSequenceNumber) + { + if (incomingCommand -> unreliableSequenceNumber < unreliableSequenceNumber) + break; + + goto freePacket; + } + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: + currentCommand = enet_list_end (& channel -> incomingUnreliableCommands); + break; + + default: + goto freePacket; + } + + incomingCommand = (ENetIncomingCommand *) enet_malloc (sizeof (ENetIncomingCommand)); + if (incomingCommand == NULL) + goto notifyError; + + incomingCommand -> reliableSequenceNumber = command -> header.reliableSequenceNumber; + incomingCommand -> unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF; + incomingCommand -> command = * command; + incomingCommand -> fragmentCount = fragmentCount; + incomingCommand -> fragmentsRemaining = fragmentCount; + incomingCommand -> packet = packet; + incomingCommand -> fragments = NULL; + + if (fragmentCount > 0) + { + incomingCommand -> fragments = (enet_uint32 *) enet_malloc ((fragmentCount + 31) / 32 * sizeof (enet_uint32)); + if (incomingCommand -> fragments == NULL) + { + enet_free (incomingCommand); + + goto notifyError; + } + memset (incomingCommand -> fragments, 0, (fragmentCount + 31) / 32 * sizeof (enet_uint32)); + } + + if (packet != NULL) + ++ packet -> referenceCount; + + enet_list_insert (enet_list_next (currentCommand), incomingCommand); + + switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK) + { + case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: + case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: + enet_peer_dispatch_incoming_reliable_commands (peer, channel); + break; + + default: + enet_peer_dispatch_incoming_unreliable_commands (peer, channel); + break; + } + + return incomingCommand; + +freePacket: + if (fragmentCount > 0) + goto notifyError; + + if (packet != NULL && packet -> referenceCount == 0) + enet_packet_destroy (packet); + + return & dummyCommand; + +notifyError: + if (packet != NULL && packet -> referenceCount == 0) + enet_packet_destroy (packet); + + return NULL; +} + +/** @} */ diff --git a/libs/enet/protocol.c b/libs/enet/protocol.c new file mode 100644 index 0000000..8e26dfb --- /dev/null +++ b/libs/enet/protocol.c @@ -0,0 +1,1671 @@ +/** + @file protocol.c + @brief ENet protocol functions +*/ +#include +#include +#define ENET_BUILDING_LIB 1 +#include "enet/utility.h" +#include "enet/time.h" +#include "enet/enet.h" + +static size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] = +{ + 0, + sizeof (ENetProtocolAcknowledge), + sizeof (ENetProtocolConnect), + sizeof (ENetProtocolVerifyConnect), + sizeof (ENetProtocolDisconnect), + sizeof (ENetProtocolPing), + sizeof (ENetProtocolSendReliable), + sizeof (ENetProtocolSendUnreliable), + sizeof (ENetProtocolSendFragment), + sizeof (ENetProtocolSendUnsequenced), + sizeof (ENetProtocolBandwidthLimit), + sizeof (ENetProtocolThrottleConfigure), +}; + +size_t +enet_protocol_command_size (enet_uint8 commandNumber) +{ + return commandSizes [commandNumber & ENET_PROTOCOL_COMMAND_MASK]; +} + +static int +enet_protocol_dispatch_incoming_commands (ENetHost * host, ENetEvent * event) +{ + while (! enet_list_empty (& host -> dispatchQueue)) + { + ENetPeer * peer = (ENetPeer *) enet_list_remove (enet_list_begin (& host -> dispatchQueue)); + + peer -> needsDispatch = 0; + + switch (peer -> state) + { + case ENET_PEER_STATE_CONNECTION_PENDING: + case ENET_PEER_STATE_CONNECTION_SUCCEEDED: + peer -> state = ENET_PEER_STATE_CONNECTED; + + event -> type = ENET_EVENT_TYPE_CONNECT; + event -> peer = peer; + event -> data = peer -> eventData; + + return 1; + + case ENET_PEER_STATE_ZOMBIE: + host -> recalculateBandwidthLimits = 1; + + event -> type = ENET_EVENT_TYPE_DISCONNECT; + event -> peer = peer; + event -> data = peer -> eventData; + + enet_peer_reset (peer); + + return 1; + + case ENET_PEER_STATE_CONNECTED: + if (enet_list_empty (& peer -> dispatchedCommands)) + continue; + + event -> packet = enet_peer_receive (peer, & event -> channelID); + if (event -> packet == NULL) + continue; + + event -> type = ENET_EVENT_TYPE_RECEIVE; + event -> peer = peer; + + if (! enet_list_empty (& peer -> dispatchedCommands)) + { + peer -> needsDispatch = 1; + + enet_list_insert (enet_list_end (& host -> dispatchQueue), & peer -> dispatchList); + } + + return 1; + } + } + + return 0; +} + +static void +enet_protocol_dispatch_state (ENetHost * host, ENetPeer * peer, ENetPeerState state) +{ + peer -> state = state; + + if (! peer -> needsDispatch) + { + enet_list_insert (enet_list_end (& host -> dispatchQueue), & peer -> dispatchList); + + peer -> needsDispatch = 1; + } +} + +static void +enet_protocol_notify_connect (ENetHost * host, ENetPeer * peer, ENetEvent * event) +{ + host -> recalculateBandwidthLimits = 1; + + if (event != NULL) + { + peer -> state = ENET_PEER_STATE_CONNECTED; + + event -> type = ENET_EVENT_TYPE_CONNECT; + event -> peer = peer; + event -> data = peer -> eventData; + } + else + enet_protocol_dispatch_state (host, peer, peer -> state == ENET_PEER_STATE_CONNECTING ? ENET_PEER_STATE_CONNECTION_SUCCEEDED : ENET_PEER_STATE_CONNECTION_PENDING); +} + +static void +enet_protocol_notify_disconnect (ENetHost * host, ENetPeer * peer, ENetEvent * event) +{ + if (peer -> state >= ENET_PEER_STATE_CONNECTION_PENDING) + host -> recalculateBandwidthLimits = 1; + + if (peer -> state != ENET_PEER_STATE_CONNECTING && peer -> state < ENET_PEER_STATE_CONNECTION_SUCCEEDED) + enet_peer_reset (peer); + else + if (event != NULL) + { + event -> type = ENET_EVENT_TYPE_DISCONNECT; + event -> peer = peer; + event -> data = 0; + + enet_peer_reset (peer); + } + else + { + peer -> eventData = 0; + + enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); + } +} + +static void +enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer) +{ + ENetOutgoingCommand * outgoingCommand; + + while (! enet_list_empty (& peer -> sentUnreliableCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) enet_list_front (& peer -> sentUnreliableCommands); + + enet_list_remove (& outgoingCommand -> outgoingCommandList); + + if (outgoingCommand -> packet != NULL) + { + -- outgoingCommand -> packet -> referenceCount; + + if (outgoingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (outgoingCommand -> packet); + } + + enet_free (outgoingCommand); + } +} + +static ENetProtocolCommand +enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliableSequenceNumber, enet_uint8 channelID) +{ + ENetOutgoingCommand * outgoingCommand; + ENetListIterator currentCommand; + ENetProtocolCommand commandNumber; + + for (currentCommand = enet_list_begin (& peer -> sentReliableCommands); + currentCommand != enet_list_end (& peer -> sentReliableCommands); + currentCommand = enet_list_next (currentCommand)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber && + outgoingCommand -> command.header.channelID == channelID) + break; + } + + if (currentCommand == enet_list_end (& peer -> sentReliableCommands)) + { + for (currentCommand = enet_list_begin (& peer -> outgoingReliableCommands); + currentCommand != enet_list_end (& peer -> outgoingReliableCommands); + currentCommand = enet_list_next (currentCommand)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + if (outgoingCommand -> sendAttempts < 1) return ENET_PROTOCOL_COMMAND_NONE; + + if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber && + outgoingCommand -> command.header.channelID == channelID) + break; + } + + if (currentCommand == enet_list_end (& peer -> outgoingReliableCommands)) + return ENET_PROTOCOL_COMMAND_NONE; + } + + if (channelID < peer -> channelCount) + { + ENetChannel * channel = & peer -> channels [channelID]; + enet_uint16 reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + if (channel -> reliableWindows [reliableWindow] > 0) + { + -- channel -> reliableWindows [reliableWindow]; + if (! channel -> reliableWindows [reliableWindow]) + channel -> usedReliableWindows &= ~ (1 << reliableWindow); + } + } + + commandNumber = (ENetProtocolCommand) (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK); + + enet_list_remove (& outgoingCommand -> outgoingCommandList); + + if (outgoingCommand -> packet != NULL) + { + peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength; + + -- outgoingCommand -> packet -> referenceCount; + + if (outgoingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (outgoingCommand -> packet); + } + + enet_free (outgoingCommand); + + if (enet_list_empty (& peer -> sentReliableCommands)) + return commandNumber; + + outgoingCommand = (ENetOutgoingCommand *) enet_list_front (& peer -> sentReliableCommands); + + peer -> nextTimeout = outgoingCommand -> sentTime + outgoingCommand -> roundTripTimeout; + + return commandNumber; +} + +static ENetPeer * +enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENetProtocol * command) +{ + enet_uint8 incomingSessionID, outgoingSessionID; + enet_uint32 mtu, windowSize; + ENetChannel * channel; + size_t channelCount; + ENetPeer * currentPeer; + ENetProtocol verifyCommand; + + channelCount = ENET_NET_TO_HOST_32 (command -> connect.channelCount); + + if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || + channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) + return NULL; + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state != ENET_PEER_STATE_DISCONNECTED && + currentPeer -> address.host == host -> receivedAddress.host && + currentPeer -> address.port == host -> receivedAddress.port && + currentPeer -> connectID == command -> connect.connectID) + return NULL; + } + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED) + break; + } + + if (currentPeer >= & host -> peers [host -> peerCount]) + return NULL; + + if (channelCount > host -> channelLimit) + channelCount = host -> channelLimit; + currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); + if (currentPeer -> channels == NULL) + return NULL; + currentPeer -> channelCount = channelCount; + currentPeer -> state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT; + currentPeer -> connectID = command -> connect.connectID; + currentPeer -> address = host -> receivedAddress; + currentPeer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> connect.outgoingPeerID); + currentPeer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.incomingBandwidth); + currentPeer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.outgoingBandwidth); + currentPeer -> packetThrottleInterval = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleInterval); + currentPeer -> packetThrottleAcceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleAcceleration); + currentPeer -> packetThrottleDeceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleDeceleration); + currentPeer -> eventData = ENET_NET_TO_HOST_32 (command -> connect.data); + + incomingSessionID = command -> connect.incomingSessionID == 0xFF ? currentPeer -> outgoingSessionID : command -> connect.incomingSessionID; + incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + if (incomingSessionID == currentPeer -> outgoingSessionID) + incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + currentPeer -> outgoingSessionID = incomingSessionID; + + outgoingSessionID = command -> connect.outgoingSessionID == 0xFF ? currentPeer -> incomingSessionID : command -> connect.outgoingSessionID; + outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + if (outgoingSessionID == currentPeer -> incomingSessionID) + outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + currentPeer -> incomingSessionID = outgoingSessionID; + + for (channel = currentPeer -> channels; + channel < & currentPeer -> channels [channelCount]; + ++ channel) + { + channel -> outgoingReliableSequenceNumber = 0; + channel -> outgoingUnreliableSequenceNumber = 0; + channel -> incomingReliableSequenceNumber = 0; + + enet_list_clear (& channel -> incomingReliableCommands); + enet_list_clear (& channel -> incomingUnreliableCommands); + + channel -> usedReliableWindows = 0; + memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows)); + } + + mtu = ENET_NET_TO_HOST_32 (command -> connect.mtu); + + if (mtu < ENET_PROTOCOL_MINIMUM_MTU) + mtu = ENET_PROTOCOL_MINIMUM_MTU; + else + if (mtu > ENET_PROTOCOL_MAXIMUM_MTU) + mtu = ENET_PROTOCOL_MAXIMUM_MTU; + + currentPeer -> mtu = mtu; + + if (host -> outgoingBandwidth == 0 && + currentPeer -> incomingBandwidth == 0) + currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + else + if (host -> outgoingBandwidth == 0 || + currentPeer -> incomingBandwidth == 0) + currentPeer -> windowSize = (ENET_MAX (host -> outgoingBandwidth, currentPeer -> incomingBandwidth) / + ENET_PEER_WINDOW_SIZE_SCALE) * + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + currentPeer -> windowSize = (ENET_MIN (host -> outgoingBandwidth, currentPeer -> incomingBandwidth) / + ENET_PEER_WINDOW_SIZE_SCALE) * + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (currentPeer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + currentPeer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + if (currentPeer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + if (host -> incomingBandwidth == 0) + windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + else + windowSize = (host -> incomingBandwidth / ENET_PEER_WINDOW_SIZE_SCALE) * + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (windowSize > ENET_NET_TO_HOST_32 (command -> connect.windowSize)) + windowSize = ENET_NET_TO_HOST_32 (command -> connect.windowSize); + + if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + verifyCommand.header.command = ENET_PROTOCOL_COMMAND_VERIFY_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + verifyCommand.header.channelID = 0xFF; + verifyCommand.verifyConnect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID); + verifyCommand.verifyConnect.incomingSessionID = incomingSessionID; + verifyCommand.verifyConnect.outgoingSessionID = outgoingSessionID; + verifyCommand.verifyConnect.mtu = ENET_HOST_TO_NET_16 (currentPeer -> mtu); + verifyCommand.verifyConnect.windowSize = ENET_HOST_TO_NET_32 (windowSize); + verifyCommand.verifyConnect.channelCount = ENET_HOST_TO_NET_32 (channelCount); + verifyCommand.verifyConnect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth); + verifyCommand.verifyConnect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); + verifyCommand.verifyConnect.packetThrottleInterval = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleInterval); + verifyCommand.verifyConnect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleAcceleration); + verifyCommand.verifyConnect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleDeceleration); + verifyCommand.verifyConnect.connectID = currentPeer -> connectID; + + enet_peer_queue_outgoing_command (currentPeer, & verifyCommand, NULL, 0, 0); + + return currentPeer; +} + +static int +enet_protocol_handle_send_reliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + ENetPacket * packet; + size_t dataLength; + + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; + + dataLength = ENET_NET_TO_HOST_16 (command -> sendReliable.dataLength); + * currentData += dataLength; + if (* currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + packet = enet_packet_create ((const enet_uint8 *) command + sizeof (ENetProtocolSendReliable), + dataLength, + ENET_PACKET_FLAG_RELIABLE); + if (packet == NULL || + enet_peer_queue_incoming_command (peer, command, packet, 0) == NULL) + return -1; + + return 0; +} + +static int +enet_protocol_handle_send_unsequenced (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + ENetPacket * packet; + enet_uint32 unsequencedGroup, index; + size_t dataLength; + + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; + + dataLength = ENET_NET_TO_HOST_16 (command -> sendUnsequenced.dataLength); + * currentData += dataLength; + if (* currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + unsequencedGroup = ENET_NET_TO_HOST_16 (command -> sendUnsequenced.unsequencedGroup); + index = unsequencedGroup % ENET_PEER_UNSEQUENCED_WINDOW_SIZE; + + if (unsequencedGroup < peer -> incomingUnsequencedGroup) + unsequencedGroup += 0x10000; + + if (unsequencedGroup >= (enet_uint32) peer -> incomingUnsequencedGroup + ENET_PEER_FREE_UNSEQUENCED_WINDOWS * ENET_PEER_UNSEQUENCED_WINDOW_SIZE) + return 0; + + unsequencedGroup &= 0xFFFF; + + if (unsequencedGroup - index != peer -> incomingUnsequencedGroup) + { + peer -> incomingUnsequencedGroup = unsequencedGroup - index; + + memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow)); + } + else + if (peer -> unsequencedWindow [index / 32] & (1 << (index % 32))) + return 0; + + packet = enet_packet_create ((const enet_uint8 *) command + sizeof (ENetProtocolSendUnsequenced), + dataLength, + ENET_PACKET_FLAG_UNSEQUENCED); + if (packet == NULL || + enet_peer_queue_incoming_command (peer, command, packet, 0) == NULL) + return -1; + + peer -> unsequencedWindow [index / 32] |= 1 << (index % 32); + + return 0; +} + +static int +enet_protocol_handle_send_unreliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + ENetPacket * packet; + size_t dataLength; + + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; + + dataLength = ENET_NET_TO_HOST_16 (command -> sendUnreliable.dataLength); + * currentData += dataLength; + if (* currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + packet = enet_packet_create ((const enet_uint8 *) command + sizeof (ENetProtocolSendUnreliable), + dataLength, + 0); + if (packet == NULL || + enet_peer_queue_incoming_command (peer, command, packet, 0) == NULL) + return -1; + + return 0; +} + +static int +enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + enet_uint32 fragmentNumber, + fragmentCount, + fragmentOffset, + fragmentLength, + startSequenceNumber, + totalLength; + ENetChannel * channel; + enet_uint16 startWindow, currentWindow; + ENetListIterator currentCommand; + ENetIncomingCommand * startCommand = NULL; + + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; + + fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength); + * currentData += fragmentLength; + if (* currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + channel = & peer -> channels [command -> header.channelID]; + startSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendFragment.startSequenceNumber); + startWindow = startSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (startSequenceNumber < channel -> incomingReliableSequenceNumber) + startWindow += ENET_PEER_RELIABLE_WINDOWS; + + if (startWindow < currentWindow || startWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) + return 0; + + fragmentNumber = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentNumber); + fragmentCount = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentCount); + fragmentOffset = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentOffset); + totalLength = ENET_NET_TO_HOST_32 (command -> sendFragment.totalLength); + + if (fragmentOffset >= totalLength || + fragmentOffset + fragmentLength > totalLength || + fragmentNumber >= fragmentCount) + return -1; + + for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands)); + currentCommand != enet_list_end (& channel -> incomingReliableCommands); + currentCommand = enet_list_previous (currentCommand)) + { + ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; + + if (startSequenceNumber >= channel -> incomingReliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber <= startSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < startSequenceNumber) + break; + + if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_FRAGMENT || + totalLength != incomingCommand -> packet -> dataLength || + fragmentCount != incomingCommand -> fragmentCount) + return -1; + + startCommand = incomingCommand; + break; + } + } + + if (startCommand == NULL) + { + ENetProtocol hostCommand = * command; + ENetPacket * packet = enet_packet_create (NULL, totalLength, ENET_PACKET_FLAG_RELIABLE); + if (packet == NULL) + return -1; + + hostCommand.header.reliableSequenceNumber = startSequenceNumber; + hostCommand.sendFragment.startSequenceNumber = startSequenceNumber; + hostCommand.sendFragment.dataLength = fragmentLength; + hostCommand.sendFragment.fragmentNumber = fragmentNumber; + hostCommand.sendFragment.fragmentCount = fragmentCount; + hostCommand.sendFragment.fragmentOffset = fragmentOffset; + hostCommand.sendFragment.totalLength = totalLength; + + startCommand = enet_peer_queue_incoming_command (peer, & hostCommand, packet, fragmentCount); + if (startCommand == NULL) + return -1; + } + + if ((startCommand -> fragments [fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) + { + -- startCommand -> fragmentsRemaining; + + startCommand -> fragments [fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); + + if (fragmentOffset + fragmentLength > startCommand -> packet -> dataLength) + fragmentLength = startCommand -> packet -> dataLength - fragmentOffset; + + memcpy (startCommand -> packet -> data + fragmentOffset, + (enet_uint8 *) command + sizeof (ENetProtocolSendFragment), + fragmentLength); + + if (startCommand -> fragmentsRemaining <= 0) + enet_peer_dispatch_incoming_reliable_commands (peer, channel); + } + + return 0; +} + +static int +enet_protocol_handle_ping (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +{ + return 0; +} + +static int +enet_protocol_handle_bandwidth_limit (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +{ + peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> bandwidthLimit.incomingBandwidth); + peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> bandwidthLimit.outgoingBandwidth); + + if (peer -> incomingBandwidth == 0 && host -> outgoingBandwidth == 0) + peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + else + peer -> windowSize = (ENET_MIN (peer -> incomingBandwidth, host -> outgoingBandwidth) / + ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (peer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + peer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + if (peer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + return 0; +} + +static int +enet_protocol_handle_throttle_configure (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +{ + peer -> packetThrottleInterval = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleInterval); + peer -> packetThrottleAcceleration = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleAcceleration); + peer -> packetThrottleDeceleration = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleDeceleration); + + return 0; +} + +static int +enet_protocol_handle_disconnect (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +{ + if (peer -> state == ENET_PEER_STATE_ZOMBIE || peer -> state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT) + return 0; + + enet_peer_reset_queues (peer); + + if (peer -> state == ENET_PEER_STATE_CONNECTION_SUCCEEDED) + enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); + else + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) + { + if (peer -> state == ENET_PEER_STATE_CONNECTION_PENDING) host -> recalculateBandwidthLimits = 1; + + enet_peer_reset (peer); + } + else + if (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) + peer -> state = ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT; + else + enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); + + if (peer -> state != ENET_PEER_STATE_DISCONNECTED) + peer -> eventData = ENET_NET_TO_HOST_32 (command -> disconnect.data); + + return 0; +} + +static int +enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer * peer, const ENetProtocol * command) +{ + enet_uint32 roundTripTime, + receivedSentTime, + receivedReliableSequenceNumber; + ENetProtocolCommand commandNumber; + + receivedSentTime = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedSentTime); + receivedSentTime |= host -> serviceTime & 0xFFFF0000; + if ((receivedSentTime & 0x8000) > (host -> serviceTime & 0x8000)) + receivedSentTime -= 0x10000; + + if (ENET_TIME_LESS (host -> serviceTime, receivedSentTime)) + return 0; + + peer -> lastReceiveTime = host -> serviceTime; + peer -> earliestTimeout = 0; + + roundTripTime = ENET_TIME_DIFFERENCE (host -> serviceTime, receivedSentTime); + + enet_peer_throttle (peer, roundTripTime); + + peer -> roundTripTimeVariance -= peer -> roundTripTimeVariance / 4; + + if (roundTripTime >= peer -> roundTripTime) + { + peer -> roundTripTime += (roundTripTime - peer -> roundTripTime) / 8; + peer -> roundTripTimeVariance += (roundTripTime - peer -> roundTripTime) / 4; + } + else + { + peer -> roundTripTime -= (peer -> roundTripTime - roundTripTime) / 8; + peer -> roundTripTimeVariance += (peer -> roundTripTime - roundTripTime) / 4; + } + + if (peer -> roundTripTime < peer -> lowestRoundTripTime) + peer -> lowestRoundTripTime = peer -> roundTripTime; + + if (peer -> roundTripTimeVariance > peer -> highestRoundTripTimeVariance) + peer -> highestRoundTripTimeVariance = peer -> roundTripTimeVariance; + + if (peer -> packetThrottleEpoch == 0 || + ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> packetThrottleEpoch) >= peer -> packetThrottleInterval) + { + peer -> lastRoundTripTime = peer -> lowestRoundTripTime; + peer -> lastRoundTripTimeVariance = peer -> highestRoundTripTimeVariance; + peer -> lowestRoundTripTime = peer -> roundTripTime; + peer -> highestRoundTripTimeVariance = peer -> roundTripTimeVariance; + peer -> packetThrottleEpoch = host -> serviceTime; + } + + receivedReliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedReliableSequenceNumber); + + commandNumber = enet_protocol_remove_sent_reliable_command (peer, receivedReliableSequenceNumber, command -> header.channelID); + + switch (peer -> state) + { + case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT: + if (commandNumber != ENET_PROTOCOL_COMMAND_VERIFY_CONNECT) + return -1; + + enet_protocol_notify_connect (host, peer, event); + break; + + case ENET_PEER_STATE_DISCONNECTING: + if (commandNumber != ENET_PROTOCOL_COMMAND_DISCONNECT) + return -1; + + enet_protocol_notify_disconnect (host, peer, event); + break; + + case ENET_PEER_STATE_DISCONNECT_LATER: + if (enet_list_empty (& peer -> outgoingReliableCommands) && + enet_list_empty (& peer -> outgoingUnreliableCommands) && + enet_list_empty (& peer -> sentReliableCommands)) + enet_peer_disconnect (peer, peer -> eventData); + break; + } + + return 0; +} + +static int +enet_protocol_handle_verify_connect (ENetHost * host, ENetEvent * event, ENetPeer * peer, const ENetProtocol * command) +{ + enet_uint32 mtu, windowSize; + size_t channelCount; + + if (peer -> state != ENET_PEER_STATE_CONNECTING) + return 0; + + channelCount = ENET_NET_TO_HOST_32 (command -> verifyConnect.channelCount); + + if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT || + ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleInterval) != peer -> packetThrottleInterval || + ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleAcceleration) != peer -> packetThrottleAcceleration || + ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleDeceleration) != peer -> packetThrottleDeceleration || + command -> verifyConnect.connectID != peer -> connectID) + { + peer -> eventData = 0; + + enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); + + return -1; + } + + enet_protocol_remove_sent_reliable_command (peer, 1, 0xFF); + + if (channelCount < peer -> channelCount) + peer -> channelCount = channelCount; + + peer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> verifyConnect.outgoingPeerID); + peer -> incomingSessionID = command -> verifyConnect.incomingSessionID; + peer -> outgoingSessionID = command -> verifyConnect.outgoingSessionID; + + mtu = ENET_NET_TO_HOST_32 (command -> verifyConnect.mtu); + + if (mtu < ENET_PROTOCOL_MINIMUM_MTU) + mtu = ENET_PROTOCOL_MINIMUM_MTU; + else + if (mtu > ENET_PROTOCOL_MAXIMUM_MTU) + mtu = ENET_PROTOCOL_MAXIMUM_MTU; + + if (mtu < peer -> mtu) + peer -> mtu = mtu; + + windowSize = ENET_NET_TO_HOST_32 (command -> verifyConnect.windowSize); + + if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + if (windowSize < peer -> windowSize) + peer -> windowSize = windowSize; + + peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> verifyConnect.incomingBandwidth); + peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> verifyConnect.outgoingBandwidth); + + enet_protocol_notify_connect (host, peer, event); + return 0; +} + +static int +enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event) +{ + ENetProtocolHeader * header; + ENetProtocol * command; + ENetPeer * peer; + enet_uint8 * currentData; + size_t headerSize; + enet_uint16 peerID, flags; + enet_uint8 sessionID; + + if (host -> receivedDataLength < (size_t) & ((ENetProtocolHeader *) 0) -> sentTime) + return 0; + + header = (ENetProtocolHeader *) host -> receivedData; + + peerID = ENET_NET_TO_HOST_16 (header -> peerID); + sessionID = (peerID & ENET_PROTOCOL_HEADER_SESSION_MASK) >> ENET_PROTOCOL_HEADER_SESSION_SHIFT; + flags = peerID & ENET_PROTOCOL_HEADER_FLAG_MASK; + peerID &= ~ (ENET_PROTOCOL_HEADER_FLAG_MASK | ENET_PROTOCOL_HEADER_SESSION_MASK); + + headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof (ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *) 0) -> sentTime); + if (host -> checksum != NULL) + headerSize += sizeof (enet_uint32); + + if (peerID == ENET_PROTOCOL_MAXIMUM_PEER_ID) + peer = NULL; + else + if (peerID >= host -> peerCount) + return 0; + else + { + peer = & host -> peers [peerID]; + + if (peer -> state == ENET_PEER_STATE_DISCONNECTED || + peer -> state == ENET_PEER_STATE_ZOMBIE || + (host -> receivedAddress.host != peer -> address.host && + peer -> address.host != ENET_HOST_BROADCAST) || + (peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID && + sessionID != peer -> incomingSessionID)) + return 0; + } + + if (flags & ENET_PROTOCOL_HEADER_FLAG_COMPRESSED) + { + size_t originalSize; + if (host -> compressor.context == NULL || host -> compressor.decompress == NULL) + return 0; + + originalSize = host -> compressor.decompress (host -> compressor.context, + host -> receivedData + headerSize, + host -> receivedDataLength - headerSize, + host -> packetData [1] + headerSize, + sizeof (host -> packetData [1]) - headerSize); + if (originalSize <= 0 || originalSize > sizeof (host -> packetData [1]) - headerSize) + return 0; + + memcpy (host -> packetData [1], header, headerSize); + host -> receivedData = host -> packetData [1]; + host -> receivedDataLength = headerSize + originalSize; + } + + if (host -> checksum != NULL) + { + enet_uint32 * checksum = (enet_uint32 *) & host -> receivedData [headerSize - sizeof (enet_uint32)], + desiredChecksum = * checksum; + ENetBuffer buffer; + + * checksum = peer != NULL ? peer -> connectID : 0; + + buffer.data = host -> receivedData; + buffer.dataLength = host -> receivedDataLength; + + if (host -> checksum (& buffer, 1) != desiredChecksum) + return 0; + } + + if (peer != NULL) + { + peer -> address.host = host -> receivedAddress.host; + peer -> address.port = host -> receivedAddress.port; + peer -> incomingDataTotal += host -> receivedDataLength; + } + + currentData = host -> receivedData + headerSize; + + while (currentData < & host -> receivedData [host -> receivedDataLength]) + { + enet_uint8 commandNumber; + size_t commandSize; + + command = (ENetProtocol *) currentData; + + if (currentData + sizeof (ENetProtocolCommandHeader) > & host -> receivedData [host -> receivedDataLength]) + break; + + commandNumber = command -> header.command & ENET_PROTOCOL_COMMAND_MASK; + if (commandNumber >= ENET_PROTOCOL_COMMAND_COUNT) + break; + + commandSize = commandSizes [commandNumber]; + if (commandSize == 0 || currentData + commandSize > & host -> receivedData [host -> receivedDataLength]) + break; + + currentData += commandSize; + + if (peer == NULL && commandNumber != ENET_PROTOCOL_COMMAND_CONNECT) + break; + + command -> header.reliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> header.reliableSequenceNumber); + + switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK) + { + case ENET_PROTOCOL_COMMAND_ACKNOWLEDGE: + if (enet_protocol_handle_acknowledge (host, event, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_CONNECT: + peer = enet_protocol_handle_connect (host, header, command); + if (peer == NULL) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_VERIFY_CONNECT: + if (enet_protocol_handle_verify_connect (host, event, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_DISCONNECT: + if (enet_protocol_handle_disconnect (host, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_PING: + if (enet_protocol_handle_ping (host, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: + if (enet_protocol_handle_send_reliable (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: + if (enet_protocol_handle_send_unreliable (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: + if (enet_protocol_handle_send_unsequenced (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: + if (enet_protocol_handle_send_fragment (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT: + if (enet_protocol_handle_bandwidth_limit (host, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE: + if (enet_protocol_handle_throttle_configure (host, peer, command)) + goto commandError; + break; + + default: + goto commandError; + } + + if (peer != NULL && + (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) != 0) + { + enet_uint16 sentTime; + + if (! (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME)) + break; + + sentTime = ENET_NET_TO_HOST_16 (header -> sentTime); + + switch (peer -> state) + { + case ENET_PEER_STATE_DISCONNECTING: + case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT: + break; + + case ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT: + if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) + enet_peer_queue_acknowledgement (peer, command, sentTime); + break; + + default: + enet_peer_queue_acknowledgement (peer, command, sentTime); + break; + } + } + } + +commandError: + if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE) + return 1; + + return 0; +} + +static int +enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event) +{ + for (;;) + { + int receivedLength; + ENetBuffer buffer; + + buffer.data = host -> packetData [0]; + buffer.dataLength = sizeof (host -> packetData [0]); + + receivedLength = enet_socket_receive (host -> socket, + & host -> receivedAddress, + & buffer, + 1); + + if (receivedLength < 0) + return -1; + + if (receivedLength == 0) + return 0; + + host -> receivedData = host -> packetData [0]; + host -> receivedDataLength = receivedLength; + + host -> totalReceivedData += receivedLength; + host -> totalReceivedPackets ++; + + switch (enet_protocol_handle_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: + return -1; + + default: + break; + } + } + + return -1; +} + +static void +enet_protocol_send_acknowledgements (ENetHost * host, ENetPeer * peer) +{ + ENetProtocol * command = & host -> commands [host -> commandCount]; + ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; + ENetAcknowledgement * acknowledgement; + ENetListIterator currentAcknowledgement; + + currentAcknowledgement = enet_list_begin (& peer -> acknowledgements); + + while (currentAcknowledgement != enet_list_end (& peer -> acknowledgements)) + { + if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || + buffer >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || + peer -> mtu - host -> packetSize < sizeof (ENetProtocolAcknowledge)) + { + host -> continueSending = 1; + + break; + } + + acknowledgement = (ENetAcknowledgement *) currentAcknowledgement; + + currentAcknowledgement = enet_list_next (currentAcknowledgement); + + buffer -> data = command; + buffer -> dataLength = sizeof (ENetProtocolAcknowledge); + + host -> packetSize += buffer -> dataLength; + + command -> header.command = ENET_PROTOCOL_COMMAND_ACKNOWLEDGE; + command -> header.channelID = acknowledgement -> command.header.channelID; + command -> acknowledge.receivedReliableSequenceNumber = ENET_HOST_TO_NET_16 (acknowledgement -> command.header.reliableSequenceNumber); + command -> acknowledge.receivedSentTime = ENET_HOST_TO_NET_16 (acknowledgement -> sentTime); + + if ((acknowledgement -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) + enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); + + enet_list_remove (& acknowledgement -> acknowledgementList); + enet_free (acknowledgement); + + ++ command; + ++ buffer; + } + + host -> commandCount = command - host -> commands; + host -> bufferCount = buffer - host -> buffers; +} + +static void +enet_protocol_send_unreliable_outgoing_commands (ENetHost * host, ENetPeer * peer) +{ + ENetProtocol * command = & host -> commands [host -> commandCount]; + ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; + ENetOutgoingCommand * outgoingCommand; + ENetListIterator currentCommand; + + currentCommand = enet_list_begin (& peer -> outgoingUnreliableCommands); + + while (currentCommand != enet_list_end (& peer -> outgoingUnreliableCommands)) + { + size_t commandSize; + + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + commandSize = commandSizes [outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK]; + + if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || + buffer + 1 >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || + peer -> mtu - host -> packetSize < commandSize || + (outgoingCommand -> packet != NULL && + peer -> mtu - host -> packetSize < commandSize + outgoingCommand -> packet -> dataLength)) + { + host -> continueSending = 1; + + break; + } + + currentCommand = enet_list_next (currentCommand); + + if (outgoingCommand -> packet != NULL) + { + peer -> packetThrottleCounter += ENET_PEER_PACKET_THROTTLE_COUNTER; + peer -> packetThrottleCounter %= ENET_PEER_PACKET_THROTTLE_SCALE; + + if (peer -> packetThrottleCounter > peer -> packetThrottle) + { + -- outgoingCommand -> packet -> referenceCount; + + if (outgoingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (outgoingCommand -> packet); + + enet_list_remove (& outgoingCommand -> outgoingCommandList); + enet_free (outgoingCommand); + + continue; + } + } + + buffer -> data = command; + buffer -> dataLength = commandSize; + + host -> packetSize += buffer -> dataLength; + + * command = outgoingCommand -> command; + + enet_list_remove (& outgoingCommand -> outgoingCommandList); + + if (outgoingCommand -> packet != NULL) + { + ++ buffer; + + buffer -> data = outgoingCommand -> packet -> data; + buffer -> dataLength = outgoingCommand -> packet -> dataLength; + + host -> packetSize += buffer -> dataLength; + + enet_list_insert (enet_list_end (& peer -> sentUnreliableCommands), outgoingCommand); + } + else + enet_free (outgoingCommand); + + ++ command; + ++ buffer; + } + + host -> commandCount = command - host -> commands; + host -> bufferCount = buffer - host -> buffers; + + if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER && + enet_list_empty (& peer -> outgoingReliableCommands) && + enet_list_empty (& peer -> outgoingUnreliableCommands) && + enet_list_empty (& peer -> sentReliableCommands)) + enet_peer_disconnect (peer, peer -> eventData); +} + +static int +enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * event) +{ + ENetOutgoingCommand * outgoingCommand; + ENetListIterator currentCommand, insertPosition; + + currentCommand = enet_list_begin (& peer -> sentReliableCommands); + insertPosition = enet_list_begin (& peer -> outgoingReliableCommands); + + while (currentCommand != enet_list_end (& peer -> sentReliableCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + currentCommand = enet_list_next (currentCommand); + + if (ENET_TIME_DIFFERENCE (host -> serviceTime, outgoingCommand -> sentTime) < outgoingCommand -> roundTripTimeout) + continue; + + if (peer -> earliestTimeout == 0 || + ENET_TIME_LESS (outgoingCommand -> sentTime, peer -> earliestTimeout)) + peer -> earliestTimeout = outgoingCommand -> sentTime; + + if (peer -> earliestTimeout != 0 && + (ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= ENET_PEER_TIMEOUT_MAXIMUM || + (outgoingCommand -> roundTripTimeout >= outgoingCommand -> roundTripTimeoutLimit && + ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= ENET_PEER_TIMEOUT_MINIMUM))) + { + enet_protocol_notify_disconnect (host, peer, event); + + return 1; + } + + if (outgoingCommand -> packet != NULL) + peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength; + + ++ peer -> packetsLost; + + outgoingCommand -> roundTripTimeout *= 2; + + enet_list_insert (insertPosition, enet_list_remove (& outgoingCommand -> outgoingCommandList)); + + if (currentCommand == enet_list_begin (& peer -> sentReliableCommands) && + ! enet_list_empty (& peer -> sentReliableCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + peer -> nextTimeout = outgoingCommand -> sentTime + outgoingCommand -> roundTripTimeout; + } + } + + return 0; +} + +static void +enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer) +{ + ENetProtocol * command = & host -> commands [host -> commandCount]; + ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; + ENetOutgoingCommand * outgoingCommand; + ENetListIterator currentCommand; + ENetChannel *channel; + enet_uint16 reliableWindow; + size_t commandSize; + + currentCommand = enet_list_begin (& peer -> outgoingReliableCommands); + + while (currentCommand != enet_list_end (& peer -> outgoingReliableCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + channel = outgoingCommand -> command.header.channelID < peer -> channelCount ? & peer -> channels [outgoingCommand -> command.header.channelID] : NULL; + reliableWindow = outgoingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + if (channel != NULL && + outgoingCommand -> sendAttempts < 1 && + ! (outgoingCommand -> reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) && + (channel -> reliableWindows [(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE || + channel -> usedReliableWindows & ((((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) << reliableWindow) | + (((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) >> (ENET_PEER_RELIABLE_WINDOW_SIZE - reliableWindow))))) + break; + + commandSize = commandSizes [outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK]; + if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || + buffer + 1 >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || + peer -> mtu - host -> packetSize < commandSize) + { + host -> continueSending = 1; + + break; + } + + if (outgoingCommand -> packet != NULL) + { + if (peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > peer -> windowSize) + break; + + if ((enet_uint16) (peer -> mtu - host -> packetSize) < (enet_uint16) (commandSize + outgoingCommand -> fragmentLength)) + { + host -> continueSending = 1; + + break; + } + } + + currentCommand = enet_list_next (currentCommand); + + if (channel != NULL && outgoingCommand -> sendAttempts < 1) + { + channel -> usedReliableWindows |= 1 << reliableWindow; + ++ channel -> reliableWindows [reliableWindow]; + } + + ++ outgoingCommand -> sendAttempts; + + if (outgoingCommand -> roundTripTimeout == 0) + { + outgoingCommand -> roundTripTimeout = peer -> roundTripTime + 4 * peer -> roundTripTimeVariance; + outgoingCommand -> roundTripTimeoutLimit = ENET_PEER_TIMEOUT_LIMIT * outgoingCommand -> roundTripTimeout; + } + + if (enet_list_empty (& peer -> sentReliableCommands)) + peer -> nextTimeout = host -> serviceTime + outgoingCommand -> roundTripTimeout; + + enet_list_insert (enet_list_end (& peer -> sentReliableCommands), + enet_list_remove (& outgoingCommand -> outgoingCommandList)); + + outgoingCommand -> sentTime = host -> serviceTime; + + buffer -> data = command; + buffer -> dataLength = commandSize; + + host -> packetSize += buffer -> dataLength; + host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_SENT_TIME; + + * command = outgoingCommand -> command; + + if (outgoingCommand -> packet != NULL) + { + ++ buffer; + + buffer -> data = outgoingCommand -> packet -> data + outgoingCommand -> fragmentOffset; + buffer -> dataLength = outgoingCommand -> fragmentLength; + + host -> packetSize += outgoingCommand -> fragmentLength; + + peer -> reliableDataInTransit += outgoingCommand -> fragmentLength; + } + + ++ peer -> packetsSent; + + ++ command; + ++ buffer; + } + + host -> commandCount = command - host -> commands; + host -> bufferCount = buffer - host -> buffers; +} + +static int +enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int checkForTimeouts) +{ + enet_uint8 headerData [sizeof (ENetProtocolHeader) + sizeof (enet_uint32)]; + ENetProtocolHeader * header = (ENetProtocolHeader *) headerData; + ENetPeer * currentPeer; + int sentLength; + size_t shouldCompress = 0; + + host -> continueSending = 1; + + while (host -> continueSending) + for (host -> continueSending = 0, + currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED || + currentPeer -> state == ENET_PEER_STATE_ZOMBIE) + continue; + + host -> headerFlags = 0; + host -> commandCount = 0; + host -> bufferCount = 1; + host -> packetSize = sizeof (ENetProtocolHeader); + + if (! enet_list_empty (& currentPeer -> acknowledgements)) + enet_protocol_send_acknowledgements (host, currentPeer); + + if (checkForTimeouts != 0 && + ! enet_list_empty (& currentPeer -> sentReliableCommands) && + ENET_TIME_GREATER_EQUAL (host -> serviceTime, currentPeer -> nextTimeout) && + enet_protocol_check_timeouts (host, currentPeer, event) == 1) + return 1; + + if (! enet_list_empty (& currentPeer -> outgoingReliableCommands)) + enet_protocol_send_reliable_outgoing_commands (host, currentPeer); + else + if (enet_list_empty (& currentPeer -> sentReliableCommands) && + ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastReceiveTime) >= ENET_PEER_PING_INTERVAL && + currentPeer -> mtu - host -> packetSize >= sizeof (ENetProtocolPing)) + { + enet_peer_ping (currentPeer); + enet_protocol_send_reliable_outgoing_commands (host, currentPeer); + } + + if (! enet_list_empty (& currentPeer -> outgoingUnreliableCommands)) + enet_protocol_send_unreliable_outgoing_commands (host, currentPeer); + + if (host -> commandCount == 0) + continue; + + if (currentPeer -> packetLossEpoch == 0) + currentPeer -> packetLossEpoch = host -> serviceTime; + else + if (ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> packetLossEpoch) >= ENET_PEER_PACKET_LOSS_INTERVAL && + currentPeer -> packetsSent > 0) + { + enet_uint32 packetLoss = currentPeer -> packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer -> packetsSent; + +#ifdef ENET_DEBUG +#ifdef WIN32 + printf ( +#else + fprintf (stderr, +#endif + "peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u/%u outgoing, %u/%u incoming\n", currentPeer -> incomingPeerID, currentPeer -> packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> roundTripTime, currentPeer -> roundTripTimeVariance, currentPeer -> packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size (& currentPeer -> outgoingReliableCommands), enet_list_size (& currentPeer -> outgoingUnreliableCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands) : 0); +#endif + + currentPeer -> packetLossVariance -= currentPeer -> packetLossVariance / 4; + + if (packetLoss >= currentPeer -> packetLoss) + { + currentPeer -> packetLoss += (packetLoss - currentPeer -> packetLoss) / 8; + currentPeer -> packetLossVariance += (packetLoss - currentPeer -> packetLoss) / 4; + } + else + { + currentPeer -> packetLoss -= (currentPeer -> packetLoss - packetLoss) / 8; + currentPeer -> packetLossVariance += (currentPeer -> packetLoss - packetLoss) / 4; + } + + currentPeer -> packetLossEpoch = host -> serviceTime; + currentPeer -> packetsSent = 0; + currentPeer -> packetsLost = 0; + } + + host -> buffers -> data = headerData; + if (host -> headerFlags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME) + { + header -> sentTime = ENET_HOST_TO_NET_16 (host -> serviceTime & 0xFFFF); + + host -> buffers -> dataLength = sizeof (ENetProtocolHeader); + } + else + host -> buffers -> dataLength = (size_t) & ((ENetProtocolHeader *) 0) -> sentTime; + + shouldCompress = 0; + if (host -> compressor.context != NULL && host -> compressor.compress != NULL) + { + size_t originalSize = host -> packetSize - sizeof(ENetProtocolHeader), + compressedSize = host -> compressor.compress (host -> compressor.context, + & host -> buffers [1], host -> bufferCount - 1, + originalSize, + host -> packetData [1], + originalSize); + if (compressedSize > 0 && compressedSize < originalSize) + { + host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_COMPRESSED; + shouldCompress = compressedSize; +#ifdef ENET_DEBUG_COMPRESS +#ifdef WIN32 + printf ( +#else + fprintf (stderr, +#endif + "peer %u: compressed %u -> %u (%u%%)\n", currentPeer -> incomingPeerID, originalSize, compressedSize, (compressedSize * 100) / originalSize); +#endif + } + } + + if (currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID) + host -> headerFlags |= currentPeer -> outgoingSessionID << ENET_PROTOCOL_HEADER_SESSION_SHIFT; + header -> peerID = ENET_HOST_TO_NET_16 (currentPeer -> outgoingPeerID | host -> headerFlags); + if (host -> checksum != NULL) + { + enet_uint32 * checksum = (enet_uint32 *) & headerData [host -> buffers -> dataLength]; + * checksum = currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer -> connectID : 0; + host -> buffers -> dataLength += sizeof (enet_uint32); + * checksum = host -> checksum (host -> buffers, host -> bufferCount); + } + + if (shouldCompress > 0) + { + host -> buffers [1].data = host -> packetData [1]; + host -> buffers [1].dataLength = shouldCompress; + host -> bufferCount = 2; + } + + currentPeer -> lastSendTime = host -> serviceTime; + + sentLength = enet_socket_send (host -> socket, & currentPeer -> address, host -> buffers, host -> bufferCount); + + enet_protocol_remove_sent_unreliable_commands (currentPeer); + + if (sentLength < 0) + return -1; + + host -> totalSentData += sentLength; + host -> totalSentPackets ++; + } + + return 0; +} + +/** Sends any queued packets on the host specified to its designated peers. + + @param host host to flush + @remarks this function need only be used in circumstances where one wishes to send queued packets earlier than in a call to enet_host_service(). + @ingroup host +*/ +void +enet_host_flush (ENetHost * host) +{ + host -> serviceTime = enet_time_get (); + + enet_protocol_send_outgoing_commands (host, NULL, 0); +} + +/** Checks for any queued events on the host and dispatches one if available. + + @param host host to check for events + @param event an event structure where event details will be placed if available + @retval > 0 if an event was dispatched + @retval 0 if no events are available + @retval < 0 on failure + @ingroup host +*/ +int +enet_host_check_events (ENetHost * host, ENetEvent * event) +{ + if (event == NULL) return -1; + + event -> type = ENET_EVENT_TYPE_NONE; + event -> peer = NULL; + event -> packet = NULL; + + return enet_protocol_dispatch_incoming_commands (host, event); +} + +/** Waits for events on the host specified and shuttles packets between + the host and its peers. + + @param host host to service + @param event an event structure where event details will be placed if one occurs + if event == NULL then no events will be delivered + @param timeout number of milliseconds that ENet should wait for events + @retval > 0 if an event occurred within the specified time limit + @retval 0 if no event occurred + @retval < 0 on failure + @remarks enet_host_service should be called fairly regularly for adequate performance + @ingroup host +*/ +int +enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout) +{ + enet_uint32 waitCondition; + + if (event != NULL) + { + event -> type = ENET_EVENT_TYPE_NONE; + event -> peer = NULL; + event -> packet = NULL; + + switch (enet_protocol_dispatch_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: + perror ("Error dispatching incoming packets"); + + return -1; + + default: + break; + } + } + + host -> serviceTime = enet_time_get (); + + timeout += host -> serviceTime; + + do + { + if (ENET_TIME_DIFFERENCE (host -> serviceTime, host -> bandwidthThrottleEpoch) >= ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) + enet_host_bandwidth_throttle (host); + + switch (enet_protocol_send_outgoing_commands (host, event, 1)) + { + case 1: + return 1; + + case -1: + perror ("Error sending outgoing packets"); + + return -1; + + default: + break; + } + + switch (enet_protocol_receive_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: + perror ("Error receiving incoming packets"); + + return -1; + + default: + break; + } + + switch (enet_protocol_send_outgoing_commands (host, event, 1)) + { + case 1: + return 1; + + case -1: + perror ("Error sending outgoing packets"); + + return -1; + + default: + break; + } + + if (event != NULL) + { + switch (enet_protocol_dispatch_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: + perror ("Error dispatching incoming packets"); + + return -1; + + default: + break; + } + } + + host -> serviceTime = enet_time_get (); + + if (ENET_TIME_GREATER_EQUAL (host -> serviceTime, timeout)) + return 0; + + waitCondition = ENET_SOCKET_WAIT_RECEIVE; + + if (enet_socket_wait (host -> socket, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime)) != 0) + return -1; + + host -> serviceTime = enet_time_get (); + } while (waitCondition == ENET_SOCKET_WAIT_RECEIVE); + + return 0; +} + diff --git a/libs/enet/unix.c b/libs/enet/unix.c new file mode 100644 index 0000000..5c0f4e9 --- /dev/null +++ b/libs/enet/unix.c @@ -0,0 +1,439 @@ +/** + @file unix.c + @brief ENet Unix system specific functions +*/ +#ifndef WIN32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HAS_SOCKLEN_T +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +#ifdef HAS_FCNTL +#include +#endif + +#ifdef __APPLE__ +#undef HAS_POLL +#endif + +#ifdef HAS_POLL +#include +#endif + +#ifndef HAS_SOCKLEN_T +typedef int socklen_t; +#endif + +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + +static enet_uint32 timeBase = 0; + +int +enet_initialize (void) +{ + return 0; +} + +void +enet_deinitialize (void) +{ +} + +enet_uint32 +enet_time_get (void) +{ + struct timeval timeVal; + + gettimeofday (& timeVal, NULL); + + return timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - timeBase; +} + +void +enet_time_set (enet_uint32 newTimeBase) +{ + struct timeval timeVal; + + gettimeofday (& timeVal, NULL); + + timeBase = timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - newTimeBase; +} + +int +enet_address_set_host (ENetAddress * address, const char * name) +{ + struct hostent * hostEntry = NULL; +#ifdef HAS_GETHOSTBYNAME_R + struct hostent hostData; + char buffer [2048]; + int errnum; + +#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); +#else + hostEntry = gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & errnum); +#endif +#else + hostEntry = gethostbyname (name); +#endif + + if (hostEntry == NULL || + hostEntry -> h_addrtype != AF_INET) + { +#ifdef HAS_INET_PTON + if (! inet_pton (AF_INET, name, & address -> host)) +#else + if (! inet_aton (name, (struct in_addr *) & address -> host)) +#endif + return -1; + return 0; + } + + address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0]; + + return 0; +} + +int +enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength) +{ +#ifdef HAS_INET_NTOP + if (inet_ntop (AF_INET, & address -> host, name, nameLength) == NULL) +#else + char * addr = inet_ntoa (* (struct in_addr *) & address -> host); + if (addr != NULL) + strncpy (name, addr, nameLength); + else +#endif + return -1; + return 0; +} + +int +enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength) +{ + struct in_addr in; + struct hostent * hostEntry = NULL; +#ifdef HAS_GETHOSTBYADDR_R + struct hostent hostData; + char buffer [2048]; + int errnum; + + in.s_addr = address -> host; + +#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); +#else + hostEntry = gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & errnum); +#endif +#else + in.s_addr = address -> host; + + hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET); +#endif + + if (hostEntry == NULL) + return enet_address_get_host_ip (address, name, nameLength); + + strncpy (name, hostEntry -> h_name, nameLength); + + return 0; +} + +int +enet_socket_bind (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + + if (address != NULL) + { + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + else + { + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + } + + return bind (socket, + (struct sockaddr *) & sin, + sizeof (struct sockaddr_in)); +} + +int +enet_socket_listen (ENetSocket socket, int backlog) +{ + return listen (socket, backlog < 0 ? SOMAXCONN : backlog); +} + +ENetSocket +enet_socket_create (ENetSocketType type) +{ + return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); +} + +int +enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value) +{ + int result = -1; + switch (option) + { + case ENET_SOCKOPT_NONBLOCK: +#ifdef HAS_FCNTL + result = fcntl (socket, F_SETFL, O_NONBLOCK | fcntl (socket, F_GETFL)); +#else + result = ioctl (socket, FIONBIO, & value); +#endif + break; + + case ENET_SOCKOPT_BROADCAST: + result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_REUSEADDR: + result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_RCVBUF: + result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_SNDBUF: + result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int)); + break; + + default: + break; + } + return result == -1 ? -1 : 0; +} + +int +enet_socket_connect (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + + return connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in)); +} + +ENetSocket +enet_socket_accept (ENetSocket socket, ENetAddress * address) +{ + int result; + struct sockaddr_in sin; + socklen_t sinLength = sizeof (struct sockaddr_in); + + result = accept (socket, + address != NULL ? (struct sockaddr *) & sin : NULL, + address != NULL ? & sinLength : NULL); + + if (result == -1) + return ENET_SOCKET_NULL; + + if (address != NULL) + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return result; +} + +void +enet_socket_destroy (ENetSocket socket) +{ + close (socket); +} + +int +enet_socket_send (ENetSocket socket, + const ENetAddress * address, + const ENetBuffer * buffers, + size_t bufferCount) +{ + struct msghdr msgHdr; + struct sockaddr_in sin; + int sentLength; + + memset (& msgHdr, 0, sizeof (struct msghdr)); + + if (address != NULL) + { + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + + msgHdr.msg_name = & sin; + msgHdr.msg_namelen = sizeof (struct sockaddr_in); + } + + msgHdr.msg_iov = (struct iovec *) buffers; + msgHdr.msg_iovlen = bufferCount; + + sentLength = sendmsg (socket, & msgHdr, MSG_NOSIGNAL); + + if (sentLength == -1) + { + if (errno == EWOULDBLOCK) + return 0; + + return -1; + } + + return sentLength; +} + +int +enet_socket_receive (ENetSocket socket, + ENetAddress * address, + ENetBuffer * buffers, + size_t bufferCount) +{ + struct msghdr msgHdr; + struct sockaddr_in sin; + int recvLength; + + memset (& msgHdr, 0, sizeof (struct msghdr)); + + if (address != NULL) + { + msgHdr.msg_name = & sin; + msgHdr.msg_namelen = sizeof (struct sockaddr_in); + } + + msgHdr.msg_iov = (struct iovec *) buffers; + msgHdr.msg_iovlen = bufferCount; + + recvLength = recvmsg (socket, & msgHdr, MSG_NOSIGNAL); + + if (recvLength == -1) + { + if (errno == EWOULDBLOCK) + return 0; + + return -1; + } + +#ifdef HAS_MSGHDR_FLAGS + if (msgHdr.msg_flags & MSG_TRUNC) + return -1; +#endif + + if (address != NULL) + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return recvLength; +} + +int +enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout) +{ + struct timeval timeVal; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal); +} + +int +enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout) +{ +#ifdef HAS_POLL + struct pollfd pollSocket; + int pollCount; + + pollSocket.fd = socket; + pollSocket.events = 0; + + if (* condition & ENET_SOCKET_WAIT_SEND) + pollSocket.events |= POLLOUT; + + if (* condition & ENET_SOCKET_WAIT_RECEIVE) + pollSocket.events |= POLLIN; + + pollCount = poll (& pollSocket, 1, timeout); + + if (pollCount < 0) + return -1; + + * condition = ENET_SOCKET_WAIT_NONE; + + if (pollCount == 0) + return 0; + + if (pollSocket.revents & POLLOUT) + * condition |= ENET_SOCKET_WAIT_SEND; + + if (pollSocket.revents & POLLIN) + * condition |= ENET_SOCKET_WAIT_RECEIVE; + + return 0; +#else + fd_set readSet, writeSet; + struct timeval timeVal; + int selectCount; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + FD_ZERO (& readSet); + FD_ZERO (& writeSet); + + if (* condition & ENET_SOCKET_WAIT_SEND) + FD_SET (socket, & writeSet); + + if (* condition & ENET_SOCKET_WAIT_RECEIVE) + FD_SET (socket, & readSet); + + selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal); + + if (selectCount < 0) + return -1; + + * condition = ENET_SOCKET_WAIT_NONE; + + if (selectCount == 0) + return 0; + + if (FD_ISSET (socket, & writeSet)) + * condition |= ENET_SOCKET_WAIT_SEND; + + if (FD_ISSET (socket, & readSet)) + * condition |= ENET_SOCKET_WAIT_RECEIVE; + + return 0; +#endif +} + +#endif + diff --git a/libs/enet/win32.c b/libs/enet/win32.c new file mode 100644 index 0000000..e1fae23 --- /dev/null +++ b/libs/enet/win32.c @@ -0,0 +1,348 @@ +/** + @file win32.c + @brief ENet Win32 system specific functions +*/ +#ifdef WIN32 + +#include +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +static enet_uint32 timeBase = 0; + +int +enet_initialize (void) +{ + WORD versionRequested = MAKEWORD (1, 1); + WSADATA wsaData; + + if (WSAStartup (versionRequested, & wsaData)) + return -1; + + if (LOBYTE (wsaData.wVersion) != 1|| + HIBYTE (wsaData.wVersion) != 1) + { + WSACleanup (); + + return -1; + } + + timeBeginPeriod (1); + + return 0; +} + +void +enet_deinitialize (void) +{ + timeEndPeriod (1); + + WSACleanup (); +} + +enet_uint32 +enet_time_get (void) +{ + return (enet_uint32) timeGetTime () - timeBase; +} + +void +enet_time_set (enet_uint32 newTimeBase) +{ + timeBase = (enet_uint32) timeGetTime () - newTimeBase; +} + +int +enet_address_set_host (ENetAddress * address, const char * name) +{ + struct hostent * hostEntry; + + hostEntry = gethostbyname (name); + if (hostEntry == NULL || + hostEntry -> h_addrtype != AF_INET) + { + unsigned long host = inet_addr (name); + if (host == INADDR_NONE) + return -1; + address -> host = host; + return 0; + } + + address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0]; + + return 0; +} + +int +enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength) +{ + char * addr = inet_ntoa (* (struct in_addr *) & address -> host); + if (addr == NULL) + return -1; + strncpy (name, addr, nameLength); + return 0; +} + +int +enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength) +{ + struct in_addr in; + struct hostent * hostEntry; + + in.s_addr = address -> host; + + hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET); + if (hostEntry == NULL) + return enet_address_get_host_ip (address, name, nameLength); + + strncpy (name, hostEntry -> h_name, nameLength); + + return 0; +} + +int +enet_socket_bind (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + + if (address != NULL) + { + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + else + { + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + } + + return bind (socket, + (struct sockaddr *) & sin, + sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0; +} + +int +enet_socket_listen (ENetSocket socket, int backlog) +{ + return listen (socket, backlog < 0 ? SOMAXCONN : backlog) == SOCKET_ERROR ? -1 : 0; +} + +ENetSocket +enet_socket_create (ENetSocketType type) +{ + return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); +} + +int +enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value) +{ + int result = SOCKET_ERROR; + switch (option) + { + case ENET_SOCKOPT_NONBLOCK: + { + u_long nonBlocking = (u_long) value; + result = ioctlsocket (socket, FIONBIO, & nonBlocking); + break; + } + + case ENET_SOCKOPT_BROADCAST: + result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_REUSEADDR: + result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_RCVBUF: + result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_SNDBUF: + result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int)); + break; + + default: + break; + } + return result == SOCKET_ERROR ? -1 : 0; +} + +int +enet_socket_connect (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + + return connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0; +} + +ENetSocket +enet_socket_accept (ENetSocket socket, ENetAddress * address) +{ + SOCKET result; + struct sockaddr_in sin; + int sinLength = sizeof (struct sockaddr_in); + + result = accept (socket, + address != NULL ? (struct sockaddr *) & sin : NULL, + address != NULL ? & sinLength : NULL); + + if (result == INVALID_SOCKET) + return ENET_SOCKET_NULL; + + if (address != NULL) + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return result; +} + +void +enet_socket_destroy (ENetSocket socket) +{ + closesocket (socket); +} + +int +enet_socket_send (ENetSocket socket, + const ENetAddress * address, + const ENetBuffer * buffers, + size_t bufferCount) +{ + struct sockaddr_in sin; + DWORD sentLength; + + if (address != NULL) + { + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + + if (WSASendTo (socket, + (LPWSABUF) buffers, + (DWORD) bufferCount, + & sentLength, + 0, + address != NULL ? (struct sockaddr *) & sin : 0, + address != NULL ? sizeof (struct sockaddr_in) : 0, + NULL, + NULL) == SOCKET_ERROR) + { + if (WSAGetLastError () == WSAEWOULDBLOCK) + return 0; + + return -1; + } + + return (int) sentLength; +} + +int +enet_socket_receive (ENetSocket socket, + ENetAddress * address, + ENetBuffer * buffers, + size_t bufferCount) +{ + INT sinLength = sizeof (struct sockaddr_in); + DWORD flags = 0, + recvLength; + struct sockaddr_in sin; + + if (WSARecvFrom (socket, + (LPWSABUF) buffers, + (DWORD) bufferCount, + & recvLength, + & flags, + address != NULL ? (struct sockaddr *) & sin : NULL, + address != NULL ? & sinLength : NULL, + NULL, + NULL) == SOCKET_ERROR) + { + switch (WSAGetLastError ()) + { + case WSAEWOULDBLOCK: + case WSAECONNRESET: + return 0; + } + + return -1; + } + + if (flags & MSG_PARTIAL) + return -1; + + if (address != NULL) + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return (int) recvLength; +} + +int +enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout) +{ + struct timeval timeVal; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal); +} + +int +enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout) +{ + fd_set readSet, writeSet; + struct timeval timeVal; + int selectCount; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + FD_ZERO (& readSet); + FD_ZERO (& writeSet); + + if (* condition & ENET_SOCKET_WAIT_SEND) + FD_SET (socket, & writeSet); + + if (* condition & ENET_SOCKET_WAIT_RECEIVE) + FD_SET (socket, & readSet); + + selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal); + + if (selectCount < 0) + return -1; + + * condition = ENET_SOCKET_WAIT_NONE; + + if (selectCount == 0) + return 0; + + if (FD_ISSET (socket, & writeSet)) + * condition |= ENET_SOCKET_WAIT_SEND; + + if (FD_ISSET (socket, & readSet)) + * condition |= ENET_SOCKET_WAIT_RECEIVE; + + return 0; +} + +#endif + diff --git a/libs/glfw/CMakeLists.txt b/libs/glfw/CMakeLists.txt new file mode 100644 index 0000000..a58e382 --- /dev/null +++ b/libs/glfw/CMakeLists.txt @@ -0,0 +1,60 @@ +include_directories (include) +include_directories (lib) +SET(commonSources + lib/enable.c + lib/fullscreen.c + lib/glext.c + lib/image.c + lib/init.c + lib/input.c + lib/joystick.c + lib/stream.c + lib/tga.c + lib/thread.c + lib/time.c + lib/window.c +) +IF(APPLE) + SET(platformSources + lib/macosx/macosx_enable.c + lib/macosx/macosx_fullscreen.c + lib/macosx/macosx_glext.c + lib/macosx/macosx_init.c + lib/macosx/macosx_joystick.c + lib/macosx/macosx_thread.c + lib/macosx/macosx_time.c + lib/macosx/macosx_window.c + ) + include_directories (lib/macosx) +ELSE() + IF(WIN32) + SET(platformSources + lib/win32/win32_dllmain.c + lib/win32/win32_enable.c + lib/win32/win32_fullscreen.c + lib/win32/win32_glext.c + lib/win32/win32_init.c + lib/win32/win32_joystick.c + lib/win32/win32_thread.c + lib/win32/win32_time.c + lib/win32/win32_window.c + ) + include_directories (lib/win32) + ELSE() + SET(platformSources + lib/x11/x11_enable.c + lib/x11/x11_fullscreen.c + lib/x11/x11_glext.c + lib/x11/x11_init.c + lib/x11/x11_joystick.c + lib/x11/x11_keysym2unicode.c + lib/x11/x11_thread.c + lib/x11/x11_time.c + lib/x11/x11_window.c + ) + include_directories (lib/x11) + add_definitions(-D_GLFW_HAS_PTHREAD) + ENDIF() +ENDIF() + +add_library (glfw ${commonSources} ${platformSources}) \ No newline at end of file diff --git a/libs/glfw/include/GL/glfw.h b/libs/glfw/include/GL/glfw.h new file mode 100644 index 0000000..a77629d --- /dev/null +++ b/libs/glfw/include/GL/glfw.h @@ -0,0 +1,486 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: glfw.h +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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 __glfw_h_ +#define __glfw_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +//======================================================================== +// Global definitions +//======================================================================== + +// We need a NULL pointer from time to time +#ifndef NULL + #ifdef __cplusplus + #define NULL 0 + #else + #define NULL ((void *)0) + #endif +#endif // NULL + + +// ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- + +// Please report any probles that you find with your compiler, which may +// be solved in this section! There are several compilers that I have not +// been able to test this file with yet. + +// First: If we are we on Windows, we want a single define for it (_WIN32) +// (Note: For Cygwin the compiler flag -mwin32 should be used, but to +// make sure that things run smoothly for Cygwin users, we add __CYGWIN__ +// to the list of "valid Win32 identifiers", which removes the need for +// -mwin32) +#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)) + #define _WIN32 +#endif // _WIN32 + +// In order for extension support to be portable, we need to define an +// OpenGL function call method. We use the keyword APIENTRY, which is +// defined for Win32. (Note: Windows also needs this for ) +#ifndef APIENTRY + #ifdef _WIN32 + #define APIENTRY __stdcall + #else + #define APIENTRY + #endif + #define GL_APIENTRY_DEFINED +#endif // APIENTRY + + +// The following three defines are here solely to make some Windows-based +// files happy. Theoretically we could include , but +// it has the major drawback of severely polluting our namespace. + +// Under Windows, we need WINGDIAPI defined +#if !defined(WINGDIAPI) && defined(_WIN32) + #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__) + // Microsoft Visual C++, Borland C++ Builder and Pelles C + #define WINGDIAPI __declspec(dllimport) + #elif defined(__LCC__) + // LCC-Win32 + #define WINGDIAPI __stdcall + #else + // Others (e.g. MinGW, Cygwin) + #define WINGDIAPI extern + #endif + #define GL_WINGDIAPI_DEFINED +#endif // WINGDIAPI + +// Some files also need CALLBACK defined +#if !defined(CALLBACK) && defined(_WIN32) + #if defined(_MSC_VER) + // Microsoft Visual C++ + #if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) + #define CALLBACK __stdcall + #else + #define CALLBACK + #endif + #else + // Other Windows compilers + #define CALLBACK __stdcall + #endif + #define GLU_CALLBACK_DEFINED +#endif // CALLBACK + +// Microsoft Visual C++, Borland C++ and Pelles C needs wchar_t +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__)) && !defined(_WCHAR_T_DEFINED) + typedef unsigned short wchar_t; + #define _WCHAR_T_DEFINED +#endif // _WCHAR_T_DEFINED + + +// ---------------- GLFW related system specific defines ----------------- + +#if defined(_WIN32) && defined(GLFW_BUILD_DLL) + + // We are building a Win32 DLL + #define GLFWAPI __declspec(dllexport) + #define GLFWAPIENTRY __stdcall + #define GLFWCALL __stdcall + +#elif defined(_WIN32) && defined(GLFW_DLL) + + // We are calling a Win32 DLL + #if defined(__LCC__) + #define GLFWAPI extern + #else + #define GLFWAPI __declspec(dllimport) + #endif + #define GLFWAPIENTRY __stdcall + #define GLFWCALL __stdcall + +#else + + // We are either building/calling a static lib or we are non-win32 + #define GLFWAPIENTRY + #define GLFWAPI + #define GLFWCALL + +#endif + +// -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- + +// Include standard OpenGL headers: GLFW uses GL_FALSE/GL_TRUE, and it is +// convenient for the user to only have to include . This also +// solves the problem with Windows and needing some +// special defines which normally requires the user to include +// (which is not a nice solution for portable programs). +#if defined(__APPLE_CC__) + #include + #include +#else + #include + #include +#endif + + +//======================================================================== +// GLFW version +//======================================================================== + +#define GLFW_VERSION_MAJOR 2 +#define GLFW_VERSION_MINOR 6 +#define GLFW_VERSION_REVISION 0 + + +//======================================================================== +// Input handling definitions +//======================================================================== + +// Key and button state/action definitions +#define GLFW_RELEASE 0 +#define GLFW_PRESS 1 + +// Keyboard key definitions: 8-bit ISO-8859-1 (Latin 1) encoding is used +// for printable keys (such as A-Z, 0-9 etc), and values above 256 +// represent special (non-printable) keys (e.g. F1, Page Up etc). +#define GLFW_KEY_UNKNOWN -1 +#define GLFW_KEY_SPACE 32 +#define GLFW_KEY_SPECIAL 256 +#define GLFW_KEY_ESC (GLFW_KEY_SPECIAL+1) +#define GLFW_KEY_F1 (GLFW_KEY_SPECIAL+2) +#define GLFW_KEY_F2 (GLFW_KEY_SPECIAL+3) +#define GLFW_KEY_F3 (GLFW_KEY_SPECIAL+4) +#define GLFW_KEY_F4 (GLFW_KEY_SPECIAL+5) +#define GLFW_KEY_F5 (GLFW_KEY_SPECIAL+6) +#define GLFW_KEY_F6 (GLFW_KEY_SPECIAL+7) +#define GLFW_KEY_F7 (GLFW_KEY_SPECIAL+8) +#define GLFW_KEY_F8 (GLFW_KEY_SPECIAL+9) +#define GLFW_KEY_F9 (GLFW_KEY_SPECIAL+10) +#define GLFW_KEY_F10 (GLFW_KEY_SPECIAL+11) +#define GLFW_KEY_F11 (GLFW_KEY_SPECIAL+12) +#define GLFW_KEY_F12 (GLFW_KEY_SPECIAL+13) +#define GLFW_KEY_F13 (GLFW_KEY_SPECIAL+14) +#define GLFW_KEY_F14 (GLFW_KEY_SPECIAL+15) +#define GLFW_KEY_F15 (GLFW_KEY_SPECIAL+16) +#define GLFW_KEY_F16 (GLFW_KEY_SPECIAL+17) +#define GLFW_KEY_F17 (GLFW_KEY_SPECIAL+18) +#define GLFW_KEY_F18 (GLFW_KEY_SPECIAL+19) +#define GLFW_KEY_F19 (GLFW_KEY_SPECIAL+20) +#define GLFW_KEY_F20 (GLFW_KEY_SPECIAL+21) +#define GLFW_KEY_F21 (GLFW_KEY_SPECIAL+22) +#define GLFW_KEY_F22 (GLFW_KEY_SPECIAL+23) +#define GLFW_KEY_F23 (GLFW_KEY_SPECIAL+24) +#define GLFW_KEY_F24 (GLFW_KEY_SPECIAL+25) +#define GLFW_KEY_F25 (GLFW_KEY_SPECIAL+26) +#define GLFW_KEY_UP (GLFW_KEY_SPECIAL+27) +#define GLFW_KEY_DOWN (GLFW_KEY_SPECIAL+28) +#define GLFW_KEY_LEFT (GLFW_KEY_SPECIAL+29) +#define GLFW_KEY_RIGHT (GLFW_KEY_SPECIAL+30) +#define GLFW_KEY_LSHIFT (GLFW_KEY_SPECIAL+31) +#define GLFW_KEY_RSHIFT (GLFW_KEY_SPECIAL+32) +#define GLFW_KEY_LCTRL (GLFW_KEY_SPECIAL+33) +#define GLFW_KEY_RCTRL (GLFW_KEY_SPECIAL+34) +#define GLFW_KEY_LALT (GLFW_KEY_SPECIAL+35) +#define GLFW_KEY_RALT (GLFW_KEY_SPECIAL+36) +#define GLFW_KEY_TAB (GLFW_KEY_SPECIAL+37) +#define GLFW_KEY_ENTER (GLFW_KEY_SPECIAL+38) +#define GLFW_KEY_BACKSPACE (GLFW_KEY_SPECIAL+39) +#define GLFW_KEY_INSERT (GLFW_KEY_SPECIAL+40) +#define GLFW_KEY_DEL (GLFW_KEY_SPECIAL+41) +#define GLFW_KEY_PAGEUP (GLFW_KEY_SPECIAL+42) +#define GLFW_KEY_PAGEDOWN (GLFW_KEY_SPECIAL+43) +#define GLFW_KEY_HOME (GLFW_KEY_SPECIAL+44) +#define GLFW_KEY_END (GLFW_KEY_SPECIAL+45) +#define GLFW_KEY_KP_0 (GLFW_KEY_SPECIAL+46) +#define GLFW_KEY_KP_1 (GLFW_KEY_SPECIAL+47) +#define GLFW_KEY_KP_2 (GLFW_KEY_SPECIAL+48) +#define GLFW_KEY_KP_3 (GLFW_KEY_SPECIAL+49) +#define GLFW_KEY_KP_4 (GLFW_KEY_SPECIAL+50) +#define GLFW_KEY_KP_5 (GLFW_KEY_SPECIAL+51) +#define GLFW_KEY_KP_6 (GLFW_KEY_SPECIAL+52) +#define GLFW_KEY_KP_7 (GLFW_KEY_SPECIAL+53) +#define GLFW_KEY_KP_8 (GLFW_KEY_SPECIAL+54) +#define GLFW_KEY_KP_9 (GLFW_KEY_SPECIAL+55) +#define GLFW_KEY_KP_DIVIDE (GLFW_KEY_SPECIAL+56) +#define GLFW_KEY_KP_MULTIPLY (GLFW_KEY_SPECIAL+57) +#define GLFW_KEY_KP_SUBTRACT (GLFW_KEY_SPECIAL+58) +#define GLFW_KEY_KP_ADD (GLFW_KEY_SPECIAL+59) +#define GLFW_KEY_KP_DECIMAL (GLFW_KEY_SPECIAL+60) +#define GLFW_KEY_KP_EQUAL (GLFW_KEY_SPECIAL+61) +#define GLFW_KEY_KP_ENTER (GLFW_KEY_SPECIAL+62) +#define GLFW_KEY_LAST GLFW_KEY_KP_ENTER + +// Mouse button definitions +#define GLFW_MOUSE_BUTTON_1 0 +#define GLFW_MOUSE_BUTTON_2 1 +#define GLFW_MOUSE_BUTTON_3 2 +#define GLFW_MOUSE_BUTTON_4 3 +#define GLFW_MOUSE_BUTTON_5 4 +#define GLFW_MOUSE_BUTTON_6 5 +#define GLFW_MOUSE_BUTTON_7 6 +#define GLFW_MOUSE_BUTTON_8 7 +#define GLFW_MOUSE_BUTTON_LAST GLFW_MOUSE_BUTTON_8 + +// Mouse button aliases +#define GLFW_MOUSE_BUTTON_LEFT GLFW_MOUSE_BUTTON_1 +#define GLFW_MOUSE_BUTTON_RIGHT GLFW_MOUSE_BUTTON_2 +#define GLFW_MOUSE_BUTTON_MIDDLE GLFW_MOUSE_BUTTON_3 + + +// Joystick identifiers +#define GLFW_JOYSTICK_1 0 +#define GLFW_JOYSTICK_2 1 +#define GLFW_JOYSTICK_3 2 +#define GLFW_JOYSTICK_4 3 +#define GLFW_JOYSTICK_5 4 +#define GLFW_JOYSTICK_6 5 +#define GLFW_JOYSTICK_7 6 +#define GLFW_JOYSTICK_8 7 +#define GLFW_JOYSTICK_9 8 +#define GLFW_JOYSTICK_10 9 +#define GLFW_JOYSTICK_11 10 +#define GLFW_JOYSTICK_12 11 +#define GLFW_JOYSTICK_13 12 +#define GLFW_JOYSTICK_14 13 +#define GLFW_JOYSTICK_15 14 +#define GLFW_JOYSTICK_16 15 +#define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16 + + +//======================================================================== +// Other definitions +//======================================================================== + +// glfwOpenWindow modes +#define GLFW_WINDOW 0x00010001 +#define GLFW_FULLSCREEN 0x00010002 + +// glfwGetWindowParam tokens +#define GLFW_OPENED 0x00020001 +#define GLFW_ACTIVE 0x00020002 +#define GLFW_ICONIFIED 0x00020003 +#define GLFW_ACCELERATED 0x00020004 +#define GLFW_RED_BITS 0x00020005 +#define GLFW_GREEN_BITS 0x00020006 +#define GLFW_BLUE_BITS 0x00020007 +#define GLFW_ALPHA_BITS 0x00020008 +#define GLFW_DEPTH_BITS 0x00020009 +#define GLFW_STENCIL_BITS 0x0002000A + +// The following constants are used for both glfwGetWindowParam +// and glfwOpenWindowHint +#define GLFW_REFRESH_RATE 0x0002000B +#define GLFW_ACCUM_RED_BITS 0x0002000C +#define GLFW_ACCUM_GREEN_BITS 0x0002000D +#define GLFW_ACCUM_BLUE_BITS 0x0002000E +#define GLFW_ACCUM_ALPHA_BITS 0x0002000F +#define GLFW_AUX_BUFFERS 0x00020010 +#define GLFW_STEREO 0x00020011 +#define GLFW_WINDOW_NO_RESIZE 0x00020012 +#define GLFW_FSAA_SAMPLES 0x00020013 + +// glfwEnable/glfwDisable tokens +#define GLFW_MOUSE_CURSOR 0x00030001 +#define GLFW_STICKY_KEYS 0x00030002 +#define GLFW_STICKY_MOUSE_BUTTONS 0x00030003 +#define GLFW_SYSTEM_KEYS 0x00030004 +#define GLFW_KEY_REPEAT 0x00030005 +#define GLFW_AUTO_POLL_EVENTS 0x00030006 + +// glfwWaitThread wait modes +#define GLFW_WAIT 0x00040001 +#define GLFW_NOWAIT 0x00040002 + +// glfwGetJoystickParam tokens +#define GLFW_PRESENT 0x00050001 +#define GLFW_AXES 0x00050002 +#define GLFW_BUTTONS 0x00050003 + +// glfwReadImage/glfwLoadTexture2D flags +#define GLFW_NO_RESCALE_BIT 0x00000001 // Only for glfwReadImage +#define GLFW_ORIGIN_UL_BIT 0x00000002 +#define GLFW_BUILD_MIPMAPS_BIT 0x00000004 // Only for glfwLoadTexture2D +#define GLFW_ALPHA_MAP_BIT 0x00000008 + +// Time spans longer than this (seconds) are considered to be infinity +#define GLFW_INFINITY 100000.0 + + +//======================================================================== +// Typedefs +//======================================================================== + +// The video mode structure used by glfwGetVideoModes() +typedef struct { + int Width, Height; + int RedBits, BlueBits, GreenBits; +} GLFWvidmode; + +// Image/texture information +typedef struct { + int Width, Height; + int Format; + int BytesPerPixel; + unsigned char *Data; +} GLFWimage; + +// Thread ID +typedef int GLFWthread; + +// Mutex object +typedef void * GLFWmutex; + +// Condition variable object +typedef void * GLFWcond; + +// Function pointer types +typedef void (GLFWCALL * GLFWwindowsizefun)(int,int); +typedef int (GLFWCALL * GLFWwindowclosefun)(void); +typedef void (GLFWCALL * GLFWwindowrefreshfun)(void); +typedef void (GLFWCALL * GLFWmousebuttonfun)(int,int); +typedef void (GLFWCALL * GLFWmouseposfun)(int,int); +typedef void (GLFWCALL * GLFWmousewheelfun)(int); +typedef void (GLFWCALL * GLFWkeyfun)(int,int); +typedef void (GLFWCALL * GLFWcharfun)(int,int); +typedef void (GLFWCALL * GLFWthreadfun)(void *); + + +//======================================================================== +// Prototypes +//======================================================================== + +/*! @file glfw.h + */ +// GLFW initialization, termination and version querying +/*! @fn glfwInit + */ +GLFWAPI int GLFWAPIENTRY glfwInit( void ); +GLFWAPI void GLFWAPIENTRY glfwTerminate( void ); +GLFWAPI void GLFWAPIENTRY glfwGetVersion( int *major, int *minor, int *rev ); + +// Window handling +GLFWAPI int GLFWAPIENTRY glfwOpenWindow( int width, int height, int redbits, int greenbits, int bluebits, int alphabits, int depthbits, int stencilbits, int mode ); +GLFWAPI void GLFWAPIENTRY glfwOpenWindowHint( int target, int hint ); +GLFWAPI void GLFWAPIENTRY glfwCloseWindow( void ); +GLFWAPI void GLFWAPIENTRY glfwSetWindowTitle( const char *title ); +GLFWAPI void GLFWAPIENTRY glfwGetWindowSize( int *width, int *height ); +GLFWAPI void GLFWAPIENTRY glfwSetWindowSize( int width, int height ); +GLFWAPI void GLFWAPIENTRY glfwSetWindowPos( int x, int y ); +GLFWAPI void GLFWAPIENTRY glfwIconifyWindow( void ); +GLFWAPI void GLFWAPIENTRY glfwRestoreWindow( void ); +GLFWAPI void GLFWAPIENTRY glfwSwapBuffers( void ); +GLFWAPI void GLFWAPIENTRY glfwSwapInterval( int interval ); +GLFWAPI int GLFWAPIENTRY glfwGetWindowParam( int param ); +GLFWAPI void GLFWAPIENTRY glfwSetWindowSizeCallback( GLFWwindowsizefun cbfun ); +GLFWAPI void GLFWAPIENTRY glfwSetWindowCloseCallback( GLFWwindowclosefun cbfun ); +GLFWAPI void GLFWAPIENTRY glfwSetWindowRefreshCallback( GLFWwindowrefreshfun cbfun ); + +// Video mode functions +GLFWAPI int GLFWAPIENTRY glfwGetVideoModes( GLFWvidmode *list, int maxcount ); +GLFWAPI void GLFWAPIENTRY glfwGetDesktopMode( GLFWvidmode *mode ); + +// Input handling +GLFWAPI void GLFWAPIENTRY glfwPollEvents( void ); +GLFWAPI void GLFWAPIENTRY glfwWaitEvents( void ); +GLFWAPI int GLFWAPIENTRY glfwGetKey( int key ); +GLFWAPI int GLFWAPIENTRY glfwGetMouseButton( int button ); +GLFWAPI void GLFWAPIENTRY glfwGetMousePos( int *xpos, int *ypos ); +GLFWAPI void GLFWAPIENTRY glfwSetMousePos( int xpos, int ypos ); +GLFWAPI int GLFWAPIENTRY glfwGetMouseWheel( void ); +GLFWAPI void GLFWAPIENTRY glfwSetMouseWheel( int pos ); +GLFWAPI void GLFWAPIENTRY glfwSetKeyCallback( GLFWkeyfun cbfun ); +GLFWAPI void GLFWAPIENTRY glfwSetCharCallback( GLFWcharfun cbfun ); +GLFWAPI void GLFWAPIENTRY glfwSetMouseButtonCallback( GLFWmousebuttonfun cbfun ); +GLFWAPI void GLFWAPIENTRY glfwSetMousePosCallback( GLFWmouseposfun cbfun ); +GLFWAPI void GLFWAPIENTRY glfwSetMouseWheelCallback( GLFWmousewheelfun cbfun ); + +// Joystick input +GLFWAPI int GLFWAPIENTRY glfwGetJoystickParam( int joy, int param ); +GLFWAPI int GLFWAPIENTRY glfwGetJoystickPos( int joy, float *pos, int numaxes ); +GLFWAPI int GLFWAPIENTRY glfwGetJoystickButtons( int joy, unsigned char *buttons, int numbuttons ); + +// Time +GLFWAPI double GLFWAPIENTRY glfwGetTime( void ); +GLFWAPI void GLFWAPIENTRY glfwSetTime( double time ); +GLFWAPI void GLFWAPIENTRY glfwSleep( double time ); + +// Extension support +GLFWAPI int GLFWAPIENTRY glfwExtensionSupported( const char *extension ); +GLFWAPI void* GLFWAPIENTRY glfwGetProcAddress( const char *procname ); +GLFWAPI void GLFWAPIENTRY glfwGetGLVersion( int *major, int *minor, int *rev ); + +// Threading support +GLFWAPI GLFWthread GLFWAPIENTRY glfwCreateThread( GLFWthreadfun fun, void *arg ); +GLFWAPI void GLFWAPIENTRY glfwDestroyThread( GLFWthread ID ); +GLFWAPI int GLFWAPIENTRY glfwWaitThread( GLFWthread ID, int waitmode ); +GLFWAPI GLFWthread GLFWAPIENTRY glfwGetThreadID( void ); +GLFWAPI GLFWmutex GLFWAPIENTRY glfwCreateMutex( void ); +GLFWAPI void GLFWAPIENTRY glfwDestroyMutex( GLFWmutex mutex ); +GLFWAPI void GLFWAPIENTRY glfwLockMutex( GLFWmutex mutex ); +GLFWAPI void GLFWAPIENTRY glfwUnlockMutex( GLFWmutex mutex ); +GLFWAPI GLFWcond GLFWAPIENTRY glfwCreateCond( void ); +GLFWAPI void GLFWAPIENTRY glfwDestroyCond( GLFWcond cond ); +GLFWAPI void GLFWAPIENTRY glfwWaitCond( GLFWcond cond, GLFWmutex mutex, double timeout ); +GLFWAPI void GLFWAPIENTRY glfwSignalCond( GLFWcond cond ); +GLFWAPI void GLFWAPIENTRY glfwBroadcastCond( GLFWcond cond ); +GLFWAPI int GLFWAPIENTRY glfwGetNumberOfProcessors( void ); + +// Enable/disable functions +GLFWAPI void GLFWAPIENTRY glfwEnable( int token ); +GLFWAPI void GLFWAPIENTRY glfwDisable( int token ); + +// Image/texture I/O support +GLFWAPI int GLFWAPIENTRY glfwReadImage( const char *name, GLFWimage *img, int flags ); +GLFWAPI int GLFWAPIENTRY glfwReadMemoryImage( const void *data, long size, GLFWimage *img, int flags ); +GLFWAPI void GLFWAPIENTRY glfwFreeImage( GLFWimage *img ); +GLFWAPI int GLFWAPIENTRY glfwLoadTexture2D( const char *name, int flags ); +GLFWAPI int GLFWAPIENTRY glfwLoadMemoryTexture2D( const void *data, long size, int flags ); +GLFWAPI int GLFWAPIENTRY glfwLoadTextureImage2D( GLFWimage *img, int flags ); + + +#ifdef __cplusplus +} +#endif + +#endif // __glfw_h_ diff --git a/libs/glfw/lib/amigaos/Makefile.amigaos.gcc b/libs/glfw/lib/amigaos/Makefile.amigaos.gcc new file mode 100644 index 0000000..f7d7199 --- /dev/null +++ b/libs/glfw/lib/amigaos/Makefile.amigaos.gcc @@ -0,0 +1,128 @@ +########################################################################## +# Makefile for GLFW on AmigaOS using GCC. +#------------------------------------------------------------------------- +# To compile GLFW using this makefile, run: +# make -f Makefile.amigaos.gcc +########################################################################## + +########################################################################## +# Default: Build static library version of GLFW +########################################################################## +default: libglfw.a + + +########################################################################## +# GLFW version +########################################################################## +VERMAJOR = 2 +VERMINOR = 4 + + +########################################################################## +# Compiler settings +########################################################################## +CC = gcc +CFLAGS = -c -I. -I.. -Wall -Os -m68020 -m68881 + +# Some modules should be optimized for speed (e.g. image decoding) +CFLAGS_SPEED = -c -I. -I.. -Wall -O3 -ffast-math -m68020 -m68881 + + +########################################################################## +# Library builder settings +########################################################################## +MKLIB = ar +LIBFLAGS = -rcs + + +########################################################################## +# Object files which are part of the GLFW library +########################################################################## +OBJS = \ + enable.o \ + fullscreen.o \ + glext.o \ + image.o \ + init.o \ + input.o \ + joystick.o \ + tga.o \ + thread.o \ + time.o \ + window.o \ + amigaos_enable.o \ + amigaos_fullscreen.o \ + amigaos_glext.o \ + amigaos_init.o \ + amigaos_joystick.o \ + amigaos_thread.o \ + amigaos_time.o \ + amigaos_window.o + + +########################################################################## +# Rule for building library +########################################################################## +libglfw.a: $(OBJS) + $(MKLIB) $(LIBFLAGS) $@ $(OBJS) + + +########################################################################## +# Rules for building library object files +########################################################################## +enable.o: ../enable.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../enable.c + +fullscreen.o: ../fullscreen.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../fullscreen.c + +glext.o: ../glext.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../glext.c + +image.o: ../image.c ../internal.h platform.h + $(CC) $(CFLAGS_SPEED) -o $@ ../image.c + +init.o: ../init.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../init.c + +input.o: ../input.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../input.c + +joystick.o: ../joystick.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../joystick.c + +tga.o: ../tga.c ../internal.h platform.h + $(CC) $(CFLAGS_SPEED) -o $@ ../tga.c + +thread.o: ../thread.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../thread.c + +time.o: ../time.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../time.c + +window.o: ../window.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../window.c + +amigaos_enable.o: amigaos_enable.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_enable.c + +amigaos_fullscreen.o: amigaos_fullscreen.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_fullscreen.c + +amigaos_glext.o: amigaos_glext.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_glext.c + +amigaos_init.o: amigaos_init.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_init.c + +amigaos_joystick.o: amigaos_joystick.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_joystick.c + +amigaos_thread.o: amigaos_thread.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_thread.c + +amigaos_time.o: amigaos_time.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_time.c + +amigaos_window.o: amigaos_window.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_window.c diff --git a/libs/glfw/lib/amigaos/Makefile.amigaos.vbcc b/libs/glfw/lib/amigaos/Makefile.amigaos.vbcc new file mode 100644 index 0000000..8e48861 --- /dev/null +++ b/libs/glfw/lib/amigaos/Makefile.amigaos.vbcc @@ -0,0 +1,128 @@ +########################################################################## +# Makefile for GLFW on AmigaOS using VBCC. +#------------------------------------------------------------------------- +# To compile GLFW using this makefile, run: +# make -f Makefile.amigaos.vbcc +########################################################################## + +########################################################################## +# Default: Build static library version of GLFW +########################################################################## +default: glfw.lib + + +########################################################################## +# GLFW version +########################################################################## +VERMAJOR = 2 +VERMINOR = 4 + + +########################################################################## +# Compiler settings +########################################################################## +CC = vc +CFLAGS = -c -I. -I/ -c99 -cpu=68020 -fpu=68881 -O1 + +# Some modules should be optimized for speed (e.g. image decoding) +CFLAGS_SPEED = -c -I. -I/ -c99 -cpu=68020 -fpu=68881 -O1 + + +########################################################################## +# Library builder settings +########################################################################## +MKLIB = join +LIBFLAGS = as + + +########################################################################## +# Object files which are part of the GLFW library +########################################################################## +OBJS = \ + enable.o \ + fullscreen.o \ + glext.o \ + image.o \ + init.o \ + input.o \ + joystick.o \ + tga.o \ + thread.o \ + time.o \ + window.o \ + amigaos_enable.o \ + amigaos_fullscreen.o \ + amigaos_glext.o \ + amigaos_init.o \ + amigaos_joystick.o \ + amigaos_thread.o \ + amigaos_time.o \ + amigaos_window.o + + +########################################################################## +# Rule for building library +########################################################################## +glfw.lib: $(OBJS) + $(MKLIB) $(OBJS) $(LIBFLAGS) $@ + + +########################################################################## +# Rules for building library object files +########################################################################## +enable.o: /enable.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ /enable.c + +fullscreen.o: /fullscreen.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ /fullscreen.c + +glext.o: /glext.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ /glext.c + +image.o: /image.c /internal.h platform.h + $(CC) $(CFLAGS_SPEED) -o $@ /image.c + +init.o: /init.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ /init.c + +input.o: /input.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ /input.c + +joystick.o: /joystick.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ /joystick.c + +tga.o: /tga.c /internal.h platform.h + $(CC) $(CFLAGS_SPEED) -o $@ /tga.c + +thread.o: /thread.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ /thread.c + +time.o: /time.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ /time.c + +window.o: /window.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ /window.c + +amigaos_enable.o: amigaos_enable.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_enable.c + +amigaos_fullscreen.o: amigaos_fullscreen.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_fullscreen.c + +amigaos_glext.o: amigaos_glext.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_glext.c + +amigaos_init.o: amigaos_init.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_init.c + +amigaos_joystick.o: amigaos_joystick.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_joystick.c + +amigaos_thread.o: amigaos_thread.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_thread.c + +amigaos_time.o: amigaos_time.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_time.c + +amigaos_window.o: amigaos_window.c /internal.h platform.h + $(CC) $(CFLAGS) -o $@ amigaos_window.c diff --git a/libs/glfw/lib/amigaos/SDI_compiler.h b/libs/glfw/lib/amigaos/SDI_compiler.h new file mode 100644 index 0000000..5add3b8 --- /dev/null +++ b/libs/glfw/lib/amigaos/SDI_compiler.h @@ -0,0 +1,94 @@ +#ifndef SDI_COMPILER_H +#define SDI_COMPILER_H + +/* Includeheader + + Name: SDI_compiler.h + Versionstring: $VER: SDI_compiler.h 1.5 (29.07.2000) + Author: SDI + Distribution: PD + Description: defines to hide compiler stuff + + 1.1 25.06.98 : created from data made by Gunter Nikl + 1.2 17.11.99 : added VBCC + 1.3 29.02.00 : fixed VBCC REG define + 1.4 30.03.00 : fixed SAVEDS for VBCC + 1.5 29.07.00 : added #undef statements (needed e.g. for AmiTCP together with vbcc) +*/ + +#ifdef ASM +#undef ASM +#endif +#ifdef REG +#undef REG +#endif +#ifdef LREG +#undef LREG +#endif +#ifdef CONST +#undef CONST +#endif +#ifdef SAVEDS +#undef SAVEDS +#endif +#ifdef INLINE +#undef INLINE +#endif +#ifdef REGARGS +#undef REGARGS +#endif +#ifdef STDARGS +#undef STDARGS +#endif + +/* first "exceptions" */ + +#if defined(__MAXON__) + #define STDARGS + #define REGARGS + #define SAVEDS + #define INLINE inline +#elif defined(__VBCC__) + #define STDARGS + #define REGARGS + #define INLINE + #define REG(reg,arg) __reg(#reg) arg +#elif defined(__STORM__) + #define STDARGS + #define REGARGS + #define INLINE inline +#elif defined(__SASC) + #define ASM(arg) arg __asm +#elif defined(__GNUC__) + #define REG(reg,arg) arg __asm(#reg) + #define LREG(reg,arg) register REG(reg,arg) +#endif + +/* then "common" ones */ + +#if !defined(ASM) + #define ASM(arg) arg +#endif +#if !defined(REG) + #define REG(reg,arg) register __##reg arg +#endif +#if !defined(LREG) + #define LREG(reg,arg) register arg +#endif +#if !defined(CONST) + #define CONST const +#endif +#if !defined(SAVEDS) + #define SAVEDS __saveds +#endif +#if !defined(INLINE) + #define INLINE __inline +#endif +#if !defined(REGARGS) + #define REGARGS __regargs +#endif +#if !defined(STDARGS) + #define STDARGS __stdargs +#endif + +#endif /* SDI_COMPILER_H */ diff --git a/libs/glfw/lib/amigaos/amigaos_enable.c b/libs/glfw/lib/amigaos/amigaos_enable.c new file mode 100644 index 0000000..581ce68 --- /dev/null +++ b/libs/glfw/lib/amigaos/amigaos_enable.c @@ -0,0 +1,51 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: amigaos_enable.c +// Platforms: AmigaOS, MorphOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformEnableSystemKeys() - Enable system keys +// _glfwPlatformDisableSystemKeys() - Disable system keys +//======================================================================== + +void _glfwPlatformEnableSystemKeys( void ) +{ + // Not supported under AmigaOS (yet) +} + +void _glfwPlatformDisableSystemKeys( void ) +{ + // Not supported under AmigaOS (yet) +} diff --git a/libs/glfw/lib/amigaos/amigaos_fullscreen.c b/libs/glfw/lib/amigaos/amigaos_fullscreen.c new file mode 100644 index 0000000..02b463e --- /dev/null +++ b/libs/glfw/lib/amigaos/amigaos_fullscreen.c @@ -0,0 +1,319 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: amigaos_fullscreen.c +// Platforms: AmigaOS, MorphOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwBPP2RGB() - Convert BPP to RGB bits (based on "best guess") +//======================================================================== + +static void _glfwBPP2RGB( int bpp, int *r, int *g, int *b ) +{ + int delta; + + // Special case: bpp = 32 + if( bpp == 32 ) bpp = 24; + + // Convert "bits per pixel" to red, green & blue sizes + *r = *g = *b = bpp / 3; + delta = bpp - (*r * 3); + if( delta >= 1 ) + { + *g = *g + 1; + } + if( delta == 2 ) + { + *r = *r + 1; + } +} + + +//======================================================================== +// _glfwGetModeIDInfo() - Return video mode information about a ModeID +//======================================================================== + +void _glfwGetModeIDInfo( ULONG ModeID, int *w, int *h, int *r, int *g, + int *b, int *refresh ) +{ + struct DimensionInfo dimsInfo; + struct DisplayInfo dispInfo; + struct MonitorInfo monInfo; + + // Get various display info + (void) GetDisplayInfoData( NULL, + (BYTE*) &dimsInfo, + sizeof(struct DimensionInfo), + DTAG_DIMS, + ModeID ); + (void) GetDisplayInfoData( NULL, + (BYTE*) &dispInfo, + sizeof(struct DisplayInfo), + DTAG_DISP, + ModeID ); + (void) GetDisplayInfoData( NULL, + (BYTE*) &monInfo, + sizeof(struct MonitorInfo), + DTAG_MNTR, + ModeID ); + + // Extract nominal width & height + if( w != NULL && h != NULL ) + { + *w = (int) (dimsInfo.Nominal.MaxX - dimsInfo.Nominal.MinX) + 1; + *h = (int) (dimsInfo.Nominal.MaxY - dimsInfo.Nominal.MinY) + 1; + } + + // Extract color bits + if( r != NULL && g != NULL && g != NULL ) + { + *r = (int) dispInfo.RedBits; + *g = (int) dispInfo.GreenBits; + *b = (int) dispInfo.BlueBits; + + // If depth < sum of RGB bits, we're probably not true color, + // which means that DisplayInfo red/green/blue bits do not refer + // to actual pixel color depth => use pixel depth info instead + if( dimsInfo.MaxDepth < (*r + *g + *b) ) + { + _glfwBPP2RGB( dimsInfo.MaxDepth, r, g, b ); + } + } + + // Extract refresh rate + if( refresh != NULL ) + { + *refresh = (int) (1.0 / ((double) monInfo.TotalRows * + (double) monInfo.TotalColorClocks * + 280.0e-9) + 0.5 ); + } +} + + +//======================================================================== +// _glfwGetClosestVideoMode() +//======================================================================== + +int _glfwGetClosestVideoMode( int *w, int *h, int *r, int *g, int *b, + int refresh ) +{ + int modeID; + + // Find best mode + modeID = BestModeID( + BIDTAG_NominalWidth, *w, + BIDTAG_NominalHeight, *h, + BIDTAG_Depth, *r + *g + *b, + BIDTAG_RedBits, *r, + BIDTAG_GreenBits, *g, + BIDTAG_BlueBits, *b, + TAG_DONE, 0 + ); + + // Did we get a proper mode? + if( !modeID ) + { + return 0; + } + + // Get actual display info + _glfwGetModeIDInfo( modeID, w, h, r, g, b, NULL ); + + return modeID; +} + + +//======================================================================== +// _glfwOpenScreen() - Open an AmigaOS screen +//======================================================================== + +int _glfwOpenScreen( int *width, int *height, int *r, int *g, int *b, + int refresh ) +{ + int bpp, modeID; + + // Calculate BPP + bpp = *r + *g + *b; + + // If colorbits < 8 (e.g. 0) or >= 24, default to 24 bpp + if( bpp < 8 || bpp >= 24 ) + { + *r = *g = *b = 8; + } + + // Find best matching video mode + modeID = _glfwGetClosestVideoMode( width, height, r, g, b, refresh ); + + // Open screen + _glfwWin.Screen = OpenScreenTags( + NULL, + SA_Width, *width, + SA_Height, *height, + SA_DisplayID, modeID, + SA_Type, CUSTOMSCREEN, + SA_SysFont, 1, + SA_ShowTitle, FALSE, + TAG_DONE, 0 + ); + + // Did we succeed? + if( !_glfwWin.Screen ) + { + printf( "Failed to open Amiga screen\n" ); + return GL_FALSE; + } + + // Remember Mode ID + _glfwWin.ModeID = modeID; + +/* + // Debugging information + printf( "Amiga Screen opened:\n" ); + printf( " ModeID: 0x%08X\n", modeID ); + printf( " Dimensions: %d x %d\n", *width, *height ); + printf( " Color bits: %d : %d : %d\n", *r, *g, *b ); +*/ + + return GL_TRUE; +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformGetVideoModes() - List available video modes +//======================================================================== + +int _glfwPlatformGetVideoModes( GLFWvidmode *list, int maxcount ) +{ + ULONG modeID; + int w, h, r, g, b, bpp, m1, m2, i, j, count; + + count = 0; + modeID = INVALID_ID; + do + { + // Enumarate all ModeIDs with NextDisplayInfo + modeID = NextDisplayInfo( modeID ); + if( modeID != INVALID_ID ) + { + // Get related video mode information + _glfwGetModeIDInfo( modeID, &w, &h, &r, &g, &b, NULL ); + + // Convert RGB to BPP + bpp = r + g + b; + + // We only support true-color modes, which means at least 15 + // bits per pixel (reasonable?) - Sorry, AGA users! + if( bpp >= 15 ) + { + // Mode "code" for this mode + m1 = (bpp << 25) | (w*h); + + // Insert mode in list (sorted), and avoid duplicates + for( i = 0; i < count; i ++ ) + { + // Mode "code" for already listed mode + bpp = list[i].RedBits + list[i].GreenBits + + list[i].BlueBits; + m2 = (bpp << 25) | (list[i].Width * list[i].Height); + if( m1 <= m2 ) + { + break; + } + } + + // New entry at the end of the list? + if( i >= count ) + { + list[count].Width = w; + list[count].Height = h; + list[count].RedBits = r; + list[count].GreenBits = g; + list[count].BlueBits = b; + count ++; + } + // Insert new entry in the list? + else if( m1 < m2 ) + { + for( j = count; j > i; j -- ) + { + list[j] = list[j-1]; + } + list[i].Width = w; + list[i].Height = h; + list[i].RedBits = r; + list[i].GreenBits = g; + list[i].BlueBits = b; + count ++; + } + } + } + } + while( modeID != INVALID_ID && count < maxcount ); + + return count; +} + + +//======================================================================== +// _glfwPlatformGetDesktopMode() - Get the desktop video mode +//======================================================================== + +void _glfwPlatformGetDesktopMode( GLFWvidmode *mode ) +{ + struct Screen *pubscreen; + ULONG modeID; + + // Get default public screen screen handle + pubscreen = LockPubScreen( NULL ); + + // Get screen width and height (use actual screen size rather than + // ModeID nominal size) + mode->Width = (int) pubscreen->Width; + mode->Height = (int) pubscreen->Height; + + // Get ModeID for public screen + modeID = GetVPModeID( &pubscreen->ViewPort ); + + // Release workbench screen + UnlockPubScreen( NULL, pubscreen ); + + // Get color bits information + _glfwGetModeIDInfo( modeID, NULL, NULL, &mode->RedBits, + &mode->GreenBits, &mode->BlueBits, NULL ); +} diff --git a/libs/glfw/lib/amigaos/amigaos_glext.c b/libs/glfw/lib/amigaos/amigaos_glext.c new file mode 100644 index 0000000..195558c --- /dev/null +++ b/libs/glfw/lib/amigaos/amigaos_glext.c @@ -0,0 +1,61 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: amigaos_glext.c +// Platforms: AmigaOS, MorphOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformExtensionSupported() - Check if an OpenGL extension is +// available at runtime +//======================================================================== + +int _glfwPlatformExtensionSupported( const char *extension ) +{ + // There are no AmigaOS specific ways to check for extensions + return GL_FALSE; +} + + +//======================================================================== +// _glfwPlatformGetProcAddress() - Get the function pointer to an OpenGL +// function +//======================================================================== + +void * _glfwPlatformGetProcAddress( const char *procname ) +{ +#ifdef _GLFW_STORMMESA + // StormMesa does not support this + return NULL; +#endif +} diff --git a/libs/glfw/lib/amigaos/amigaos_init.c b/libs/glfw/lib/amigaos/amigaos_init.c new file mode 100644 index 0000000..ef47849 --- /dev/null +++ b/libs/glfw/lib/amigaos/amigaos_init.c @@ -0,0 +1,284 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: amigaos_init.c +// Platforms: AmigaOS, MorphOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwInitLibraries() - Load shared libraries +//======================================================================== + +static int _glfwInitLibraries( void ) +{ + // Note: exec.library & dos.library are always opened (by C startup) + + // Start by clearing all handles + GfxBase = NULL; + IntuitionBase = NULL; + KeymapBase = NULL; + UtilityBase = NULL; + + // graphics.library + GfxBase = (struct GfxBase *) OpenLibrary( "graphics.library", 40 ); + if( !GfxBase ) + { + return 0; + } + + // intuition.library + IntuitionBase = (struct IntuitionBase *) OpenLibrary( "intuition.library", 40 ); + if( !IntuitionBase ) + { + return 0; + } + + // keymap.library + KeymapBase = OpenLibrary( "keymap.library", 40 ); + if( !KeymapBase ) + { + return 0; + } + + // Utility.library + UtilityBase = (struct UtilityBase *) OpenLibrary( "utility.library", 40 ); + if( !UtilityBase ) + { + return 0; + } + + return 1; +} + + +//======================================================================== +// _glfwTerminateLibraries() - Unload shared libraries +//======================================================================== + +static void _glfwTerminateLibraries( void ) +{ + // Close graphics.library + if( GfxBase ) + { + CloseLibrary( (struct Library *) GfxBase ); + GfxBase = NULL; + } + + // Close intuition.library + if( IntuitionBase ) + { + CloseLibrary( (struct Library *) IntuitionBase ); + IntuitionBase = NULL; + } + + // Close keymap.library + if( KeymapBase ) + { + CloseLibrary( KeymapBase ); + KeymapBase = NULL; + } + + // Close utility.library + if( UtilityBase ) + { + CloseLibrary( (struct Library *) UtilityBase ); + UtilityBase = NULL; + } +} + + +//======================================================================== +// _glfwInitThreads() - Initialize GLFW thread package +//======================================================================== + +static int _glfwInitThreads( void ) +{ + int waitSig; + + // Allocate a signal to use for waiting (glfwWaitThread and + // glfwWaitCond) + waitSig = AllocSignal( -1 ); + if( waitSig == -1 ) + { + return 0; + } + + // Initialize critical section handle + memset( &_glfwThrd.CriticalSection,0,sizeof(struct SignalSemaphore) ); + InitSemaphore( &_glfwThrd.CriticalSection ); + + // The first thread (the main thread) has ID 0 + _glfwThrd.NextID = 0; + + // The first condition variable has ID 0xFFFFFFFF + _glfwThrd.NextCondID = 0xFFFFFFFF; + + // Fill out information about the main thread (this thread) + _glfwThrd.First.Previous = NULL; + _glfwThrd.First.Next = NULL; + _glfwThrd.First.ID = _glfwThrd.NextID ++; + _glfwThrd.First.Function = NULL; + _glfwThrd.First.Arg = NULL; + _glfwThrd.First.AmiTask = FindTask( NULL ); + _glfwThrd.First.AmiProc = (struct Process *) _glfwThrd.First.AmiTask; + _glfwThrd.First.WaitFor = NULL; + _glfwThrd.First.WaitSig = waitSig; + + // Store GLFW thread struct pointer in task user data + _glfwThrd.First.AmiTask->tc_UserData = (APTR) &_glfwThrd.First; + + return 1; +} + + +//======================================================================== +// _glfwTerminateThreads() - Terminate GLFW thread package +//======================================================================== + +static void _glfwTerminateThreads( void ) +{ + _GLFWthread *t, *t_next; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Kill all threads (NOTE: THE USER SHOULD WAIT FOR ALL THREADS TO + // DIE, _BEFORE_ CALLING glfwTerminate()!!!) + t = _glfwThrd.First.Next; + while( t != NULL ) + { + // Get pointer to next thread + t_next = t->Next; + + // Simply murder the process, no mercy! + // ?? How about Process resources ?? + RemTask( t->AmiTask ); + + // Free memory allocated for this thread + free( (void *) t ); + + // Select next thread in list + t = t_next; + } + + // Free waiting signal for main thread + FreeSignal( _glfwThrd.First.WaitSig ); + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION +} + + +//======================================================================== +// _glfwTerminate_atexit() - Terminate GLFW when exiting application +//======================================================================== + +void _glfwTerminate_atexit( void ) +{ + glfwTerminate(); +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformInit() - Initialize various GLFW state +//======================================================================== + +int _glfwPlatformInit( void ) +{ + // Load shared libraries + if( !_glfwInitLibraries() ) + { + _glfwTerminateLibraries(); + return GL_FALSE; + } + + // Initialize thread package + if( !_glfwInitThreads() ) + { + _glfwTerminateLibraries(); + return GL_FALSE; + } + + // Start the timer + if( !_glfwInitTimer() ) + { + _glfwTerminateThreads(); + _glfwTerminateLibraries(); + return GL_FALSE; + } + + // Initialize joysticks + _glfwInitJoysticks(); + + // Install atexit() routine + atexit( _glfwTerminate_atexit ); + + return GL_TRUE; +} + + +//======================================================================== +// _glfwPlatformTerminate() - Close window and kill all threads +//======================================================================== + +int _glfwPlatformTerminate( void ) +{ + // Only the main thread is allowed to do this... + if( FindTask( NULL ) != _glfwThrd.First.AmiTask ) + { + return GL_FALSE; + } + + // Close OpenGL window + glfwCloseWindow(); + + // Terminate joysticks + _glfwTerminateJoysticks(); + + // Kill timer + _glfwTerminateTimer(); + + // Kill thread package + _glfwTerminateThreads(); + + // Unload shared libraries + _glfwTerminateLibraries(); + + return GL_TRUE; +} diff --git a/libs/glfw/lib/amigaos/amigaos_joystick.c b/libs/glfw/lib/amigaos/amigaos_joystick.c new file mode 100644 index 0000000..5473a89 --- /dev/null +++ b/libs/glfw/lib/amigaos/amigaos_joystick.c @@ -0,0 +1,359 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: amigaos_joystick.c +// Platforms: AmigaOS, MorphOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwSendJoyReadRequest() - Send joystick read request +//======================================================================== + +static void _glfwSendJoyReadRequest( void ) +{ + // Send read request + _glfwJoy.GameIO->io_Command = GPD_READEVENT; + _glfwJoy.GameIO->io_Flags = 0; + _glfwJoy.GameIO->io_Data = (APTR) &_glfwJoy.GameEvent; + _glfwJoy.GameIO->io_Length = sizeof(struct InputEvent); + SendIO( (struct IORequest *) _glfwJoy.GameIO ); +} + + +//======================================================================== +// _glfwInitJoysticks() - Initialize joystick interface +//======================================================================== + +void _glfwInitJoysticks( void ) +{ + unsigned char controller_type = 0; + struct GamePortTrigger game_trigger; + + // Start by clearing all handles + _glfwJoy.GameMP = NULL; + _glfwJoy.GameIO = NULL; + _glfwJoy.Present = 0; + _glfwJoy.GameDeviceOpen = 0; + + // Create gameport.device message port + if( !(_glfwJoy.GameMP = CreatePort( NULL, 0 )) ) + { + return; + } + + // Create gameport.device I/O request + if( !( _glfwJoy.GameIO = (struct IOStdReq *) + CreateExtIO(_glfwJoy.GameMP, sizeof(struct IOStdReq)) ) ) + { + _glfwTerminateJoysticks(); + return; + } + + // Open gameport.device (unit 1 = port 2) + _glfwJoy.GameIO->io_Message.mn_Node.ln_Type = NT_UNKNOWN; + if( OpenDevice( "gameport.device", 1, + (struct IORequest *)_glfwJoy.GameIO, 0 ) ) + { + _glfwTerminateJoysticks(); + return; + } + _glfwJoy.GameDeviceOpen = 1; + + // Start critical section + Forbid(); + + // Find out if anyone else is using the stick + _glfwJoy.GameIO->io_Command = GPD_ASKCTYPE; + _glfwJoy.GameIO->io_Flags = IOF_QUICK; + _glfwJoy.GameIO->io_Data = (APTR) &controller_type; + _glfwJoy.GameIO->io_Length = 1; + DoIO( (struct IORequest *) _glfwJoy.GameIO ); + + // Was it already allocated? + if( controller_type != GPCT_NOCONTROLLER ) + { + Permit(); + _glfwTerminateJoysticks(); + return; + } + + // Allocate joystick + controller_type = GPCT_ABSJOYSTICK; + _glfwJoy.GameIO->io_Command = GPD_SETCTYPE; + _glfwJoy.GameIO->io_Flags = IOF_QUICK; + _glfwJoy.GameIO->io_Data = (APTR) &controller_type; + _glfwJoy.GameIO->io_Length = 1; + DoIO( (struct IORequest *) _glfwJoy.GameIO ); + _glfwJoy.Present = 1; + + // End critical section + Permit(); + + // Set trigger conditions + game_trigger.gpt_Keys = GPTF_UPKEYS | GPTF_DOWNKEYS; + game_trigger.gpt_XDelta = 1; + game_trigger.gpt_YDelta = 1; + game_trigger.gpt_Timeout = (UWORD) 0xFFFF; // ~20 minutes + _glfwJoy.GameIO->io_Command = GPD_SETTRIGGER; + _glfwJoy.GameIO->io_Flags = IOF_QUICK; + _glfwJoy.GameIO->io_Data = (APTR) &game_trigger; + _glfwJoy.GameIO->io_Length = (LONG) sizeof(struct GamePortTrigger); + DoIO( (struct IORequest *) _glfwJoy.GameIO ); + + // Flush buffer + _glfwJoy.GameIO->io_Command = CMD_CLEAR; + _glfwJoy.GameIO->io_Flags = IOF_QUICK; + _glfwJoy.GameIO->io_Data = NULL; + _glfwJoy.GameIO->io_Length = 0; + DoIO( (struct IORequest *) _glfwJoy.GameIO ); + + // Send joystick read request (asynchronous) + _glfwSendJoyReadRequest(); +} + + +//======================================================================== +// _glfwTerminateJoysticks() - Close all opened joystick handles +//======================================================================== + +void _glfwTerminateJoysticks( void ) +{ + unsigned char controller_type; + + // Remove any remaining asynchronous messages + if( _glfwJoy.GameIO ) + { + if( !CheckIO( (struct IORequest *)_glfwJoy.GameIO ) ) + { + AbortIO( (struct IORequest *)_glfwJoy.GameIO ); + WaitIO( (struct IORequest *)_glfwJoy.GameIO ); + } + } + + // Deallocate joystick + if( _glfwJoy.Present ) + { + controller_type = GPCT_NOCONTROLLER; + _glfwJoy.GameIO->io_Command = GPD_SETCTYPE; + _glfwJoy.GameIO->io_Flags = IOF_QUICK; + _glfwJoy.GameIO->io_Data = (APTR) &controller_type; + _glfwJoy.GameIO->io_Length = 1; + DoIO( (struct IORequest *) _glfwJoy.GameIO ); + _glfwJoy.Present = 0; + } + + // Close gameport.device + if( _glfwJoy.GameDeviceOpen ) + { + CloseDevice( (struct IORequest *) _glfwJoy.GameIO ); + _glfwJoy.GameDeviceOpen = 0; + } + + // Delete I/O request + if( _glfwJoy.GameIO ) + { + DeleteExtIO( (struct IORequest *) _glfwJoy.GameIO ); + _glfwJoy.GameIO = NULL; + } + + // Delete message port + if( _glfwJoy.GameMP ) + { + DeletePort( _glfwJoy.GameMP ); + _glfwJoy.GameMP = NULL; + } +} + + +//======================================================================== +// _glfwPollJoystickEvents() - Empty joystick event queue +//======================================================================== + +static void _glfwPollJoystickEvents( void ) +{ + int got_event = 0; + + // Do we have a stick? + if( !_glfwJoy.Present ) + { + return; + } + + // Empty the message queue + while( GetMsg( _glfwJoy.GameMP ) != NULL ) + { + // Flag: we got an event + got_event = 1; + + switch( _glfwJoy.GameEvent.ie_Code ) + { + // Left button pressed + case IECODE_LBUTTON: + _glfwJoy.Button[ 0 ] = 1; + break; + + // Left button released + case (IECODE_LBUTTON | IECODE_UP_PREFIX): + _glfwJoy.Button[ 0 ] = 0; + break; + + // Right button pressed + case IECODE_RBUTTON: + _glfwJoy.Button[ 1 ] = 1; + break; + + // Right button released + case (IECODE_RBUTTON | IECODE_UP_PREFIX): + _glfwJoy.Button[ 1 ] = 0; + break; + + // Axis event + case IECODE_NOBUTTON: + _glfwJoy.Axis[ 0 ] = (float) _glfwJoy.GameEvent.ie_X; + _glfwJoy.Axis[ 1 ] = (float) -_glfwJoy.GameEvent.ie_Y; + break; + + default: + break; + } + } + + // Did we get any events? + if( got_event ) + { + // Send joystick read request (asynchronous) + _glfwSendJoyReadRequest(); + } +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformGetJoystickParam() - Determine joystick capabilities +//======================================================================== + +int _glfwPlatformGetJoystickParam( int joy, int param ) +{ + // Is joystick present? + if( joy != GLFW_JOYSTICK_1 || !_glfwJoy.Present ) + { + return 0; + } + + // We assume that the joystick is connected, and has two axes and two + // buttons (since there is no way of retrieving this information from + // AmigaOS) + switch( param ) + { + case GLFW_PRESENT: + return GL_TRUE; + + case GLFW_AXES: + return 2; + + case GLFW_BUTTONS: + return 2; + + default: + break; + } + + return 0; +} + + +//======================================================================== +// _glfwPlatformGetJoystickPos() - Get joystick axis positions +//======================================================================== + +int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes ) +{ + int k; + + // Is joystick present? + if( joy != GLFW_JOYSTICK_1 || !_glfwJoy.Present ) + { + return 0; + } + + // Update joystick state + _glfwPollJoystickEvents(); + + // Copy axis position information to output vector + if( numaxes > 2 ) + { + numaxes = 2; + } + for( k = 0; k < numaxes; ++ k ) + { + pos[ k ] = _glfwJoy.Axis[ k ]; + } + + return numaxes; +} + + +//======================================================================== +// _glfwPlatformGetJoystickButtons() - Get joystick button states +//======================================================================== + +int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, + int numbuttons ) +{ + int k; + + // Is joystick present? + if( joy != GLFW_JOYSTICK_1 || !_glfwJoy.Present ) + { + return 0; + } + + // Update joystick state + _glfwPollJoystickEvents(); + + // Copy button information to output vector + if( numbuttons > 2 ) + { + numbuttons = 2; + } + for( k = 0; k < numbuttons; ++ k ) + { + buttons[ k ] = _glfwJoy.Button[ k ]; + } + + return numbuttons; +} diff --git a/libs/glfw/lib/amigaos/amigaos_thread.c b/libs/glfw/lib/amigaos/amigaos_thread.c new file mode 100644 index 0000000..725a6ae --- /dev/null +++ b/libs/glfw/lib/amigaos/amigaos_thread.c @@ -0,0 +1,494 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: amigaos_thread.c +// Platforms: AmigaOS, MorphOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwNewThread() - This is simply a "wrapper" for calling the user +// thread function. +//======================================================================== + +int _glfwNewThread( void ) +{ + GLFWthreadfun threadfun; + void *arg; + _GLFWthread *t, *t_wait; + struct Task *amiTask; + int waitSig; + + // Allocate a signal to use for waiting (glfwWaitThread and + // glfwWaitCond) + waitSig = AllocSignal( -1 ); + if( waitSig == -1 ) + { + // If we could not get a signal (VERY UNLIKELY), exit immediately + return 0; + } + + // Get current task + amiTask = FindTask( NULL ); + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // The task's user data points to the GLFW thread struct + t = (_GLFWthread *) amiTask->tc_UserData; + + // Store wait signal handle + t->WaitSig = waitSig; + t->WaitFor = NULL; + + // Get user thread function pointer and argument + threadfun = t->Function; + arg = t->Arg; + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Call the user thread function + threadfun( arg ); + + ENTER_THREAD_CRITICAL_SECTION + + // Remove thread from thread list + _glfwRemoveThread( t ); + + // Signal any waiting threads that we have died + for( t_wait = &_glfwThrd.First; t_wait; t_wait = t_wait->Next ) + { + if( t_wait->WaitFor == (void *) t ) + { + Signal( t_wait->AmiTask, 1L<WaitSig ); + t_wait->WaitFor = NULL; + } + } + + LEAVE_THREAD_CRITICAL_SECTION + + // When the process function returns, the process will die... + return 0; +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformCreateThread() - Create a new thread +//======================================================================== + +GLFWthread _glfwPlatformCreateThread( GLFWthreadfun fun, void *arg ) +{ + GLFWthread ID; + _GLFWthread *t; + struct TagItem tagList[ 10 ]; + int tagNR; + + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Create a new thread information memory area + t = (_GLFWthread *) malloc( sizeof(_GLFWthread) ); + if( t == NULL ) + { + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + return -1; + } + + // Get a new unique thread id + ID = _glfwThrd.NextID ++; + + // Store thread information in the thread list + t->ID = ID; + t->Function = fun; + t->Arg = arg; + +#ifdef _GLFW_MORPHOS + // For MorphOS, we set up a 68k -> PPC switch trap instruction. + // CreateNewProc actually creates a 68k process (emulated), so we make + // sure that the first 68k instruction that is executed is a trap + // instruction that forces the execution model to change from emulated + // 68k to native PPC (and starts execution at _glfwNewThread). + t->mosEmulLibEntry.Trap = TRAP_LIB; + t->mosEmulLibEntry.Extension = 0; + t->mosEmulLibEntry.Func = _glfwNewThread; +#endif + + // Create new process + tagNR = 0; + tagList[ tagNR ].ti_Tag = NP_Entry; +#ifdef _GLFW_MORPHOS + tagList[ tagNR++ ].ti_Data = (ULONG) &t->mosEmulLibEntry; +#else + tagList[ tagNR++ ].ti_Data = (ULONG) _glfwNewThread; +#endif + tagList[ tagNR ].ti_Tag = NP_StackSize; + tagList[ tagNR++ ].ti_Data = _GLFW_TASK_STACK_SIZE; + tagList[ tagNR ].ti_Tag = NP_Input; + tagList[ tagNR++ ].ti_Data = (ULONG) Input(); + tagList[ tagNR ].ti_Tag = NP_Output; + tagList[ tagNR++ ].ti_Data = (ULONG) Output(); + tagList[ tagNR ].ti_Tag = NP_CloseInput; + tagList[ tagNR++ ].ti_Data = FALSE; + tagList[ tagNR ].ti_Tag = NP_CloseOutput; + tagList[ tagNR++ ].ti_Data = FALSE; + tagList[ tagNR ].ti_Tag = TAG_DONE; + t->AmiProc = CreateNewProc( tagList ); + + // Did the process creation fail? + if( !t->AmiProc ) + { + free( (void *) t ); + LEAVE_THREAD_CRITICAL_SECTION + return -1; + } + + // Get pointer to task structure + t->AmiTask = &(t->AmiProc->pr_Task); + + // Store GLFW thread struct pointer in task user data + t->AmiTask->tc_UserData = (APTR) t; + + // Append thread to thread list + _glfwAppendThread( t ); + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Return the GLFW thread ID + return ID; +} + + +//======================================================================== +// _glfwPlatformDestroyThread() - Kill a thread. NOTE: THIS IS A VERY +// DANGEROUS OPERATION, AND SHOULD NOT BE USED EXCEPT IN EXTREME +// SITUATIONS! +//======================================================================== + +void _glfwPlatformDestroyThread( GLFWthread ID ) +{ + _GLFWthread *t, *t_wait; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Get thread information pointer + t = _glfwGetThreadPointer( ID ); + if( t == NULL ) + { + LEAVE_THREAD_CRITICAL_SECTION + return; + } + + // Simply murder the process, no mercy! + // ?? How about Process resources ?? + RemTask( t->AmiTask ); + + // Remove thread from thread list + _glfwRemoveThread( t ); + + // Signal any waiting threads that the thread has died + for( t_wait = &_glfwThrd.First; t_wait; t_wait = t_wait->Next ) + { + if( t_wait->WaitFor == (void *) t ) + { + Signal( t_wait->AmiTask, 1L<WaitSig ); + t_wait->WaitFor = NULL; + } + } + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION +} + + +//======================================================================== +// _glfwPlatformWaitThread() - Wait for a thread to die +//======================================================================== + +int _glfwPlatformWaitThread( GLFWthread ID, int waitmode ) +{ + struct Task *amiTask; + _GLFWthread *t, *t_this; + int waitSig; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Get thread information pointer + t = _glfwGetThreadPointer( ID ); + + // Is the thread already dead? + if( t == NULL ) + { + LEAVE_THREAD_CRITICAL_SECTION + return GL_TRUE; + } + + // If got this far, the thread is alive => polling returns FALSE + if( waitmode == GLFW_NOWAIT ) + { + LEAVE_THREAD_CRITICAL_SECTION + return GL_FALSE; + } + + // Find pointer to this threads structure + amiTask = FindTask( NULL ); + t_this = (_GLFWthread *) amiTask->tc_UserData; + + // Store information in our thread structure that we want to wait for + // the specified thread to die + t_this->WaitFor = (void *) t; + waitSig = t_this->WaitSig; + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Wait for thread to die + Wait( 1L<tc_UserData; + + // Return the found GLFW thread identifier + return t->ID; +} + + +//======================================================================== +// _glfwPlatformCreateMutex() - Create a mutual exclusion object +//======================================================================== + +GLFWmutex _glfwPlatformCreateMutex( void ) +{ + struct SignalSemaphore *mutex; + + // Allocate memory for mutex + mutex = (struct SignalSemaphore *) malloc( sizeof(struct SignalSemaphore) ); + if( !mutex ) + { + return NULL; + } + + // Initialize mutex object + memset( mutex, 0, sizeof(struct SignalSemaphore) ); + InitSemaphore( mutex ); + + // Cast to GLFWmutex and return + return (GLFWmutex) mutex; +} + + +//======================================================================== +// _glfwPlatformDestroyMutex() - Destroy a mutual exclusion object +//======================================================================== + +void _glfwPlatformDestroyMutex( GLFWmutex mutex ) +{ + // Free memory for mutex object + free( (void *) mutex ); +} + + +//======================================================================== +// _glfwPlatformLockMutex() - Request access to a mutex +//======================================================================== + +void _glfwPlatformLockMutex( GLFWmutex mutex ) +{ + // Wait for mutex to be released + ObtainSemaphore( (struct SignalSemaphore *) mutex ); +} + + +//======================================================================== +// _glfwPlatformUnlockMutex() - Release a mutex +//======================================================================== + +void _glfwPlatformUnlockMutex( GLFWmutex mutex ) +{ + // Release mutex + ReleaseSemaphore( (struct SignalSemaphore *) mutex ); +} + + +//======================================================================== +// _glfwPlatformCreateCond() - Create a new condition variable object +//======================================================================== + +GLFWcond _glfwPlatformCreateCond( void ) +{ + unsigned int cond; + + // Generate a new unique cond ID + ENTER_THREAD_CRITICAL_SECTION + cond = _glfwThrd.NextCondID --; + LEAVE_THREAD_CRITICAL_SECTION + + // Cast to GLFWcond and return + return (GLFWcond) cond; +} + + +//======================================================================== +// _glfwPlatformDestroyCond() - Destroy a condition variable object +//======================================================================== + +void _glfwPlatformDestroyCond( GLFWcond cond ) +{ +} + + +//======================================================================== +// _glfwPlatformWaitCond() - Wait for a condition to be raised +//======================================================================== + +void _glfwPlatformWaitCond( GLFWcond cond, GLFWmutex mutex, + double timeout ) +{ + struct Task *amiTask; + _GLFWthread *t_this; + + // Do we need a limited timeout? + if( timeout < GLFW_INFINITY ) + { + // Oooops! Not implemented properly yet! + ReleaseSemaphore( (struct SignalSemaphore *) mutex ); + Delay( 1 ); + ObtainSemaphore( (struct SignalSemaphore *) mutex ); + return; + } + + // Find pointer to this threads structure + amiTask = FindTask( NULL ); + t_this = (_GLFWthread *) amiTask->tc_UserData; + + // Store information in our thread structure that we want to wait for + // the specified condition variable to be signaled + ENTER_THREAD_CRITICAL_SECTION + t_this->WaitFor = (void *) cond; + LEAVE_THREAD_CRITICAL_SECTION + + // Release the mutex + ReleaseSemaphore( (struct SignalSemaphore *) mutex ); + + // Wait for condition variable + Wait( 1L<<(t_this->WaitSig) ); + + // Reacquire the mutex + ObtainSemaphore( (struct SignalSemaphore *) mutex ); +} + + +//======================================================================== +// _glfwPlatformSignalCond() - Signal a condition to one waiting thread +//======================================================================== + +void _glfwPlatformSignalCond( GLFWcond cond ) +{ + _GLFWthread *t_wait; + + // Broadcast condition to one waiting thread + ENTER_THREAD_CRITICAL_SECTION + for( t_wait = &_glfwThrd.First; t_wait; t_wait = t_wait->Next ) + { + if( t_wait->WaitFor == (void *) cond ) + { + Signal( t_wait->AmiTask, 1L<WaitSig ); + t_wait->WaitFor = NULL; + break; + } + } + LEAVE_THREAD_CRITICAL_SECTION +} + + +//======================================================================== +// _glfwPlatformBroadcastCond() - Broadcast a condition to all waiting +// threads +//======================================================================== + +void _glfwPlatformBroadcastCond( GLFWcond cond ) +{ + _GLFWthread *t_wait; + + // Broadcast condition to any waiting threads + ENTER_THREAD_CRITICAL_SECTION + for( t_wait = &_glfwThrd.First; t_wait; t_wait = t_wait->Next ) + { + if( t_wait->WaitFor == (void *) cond ) + { + Signal( t_wait->AmiTask, 1L<WaitSig ); + t_wait->WaitFor = NULL; + } + } + LEAVE_THREAD_CRITICAL_SECTION +} + + +//======================================================================== +// _glfwPlatformGetNumberOfProcessors() - Return the number of processors +// in the system. +//======================================================================== + +int _glfwPlatformGetNumberOfProcessors( void ) +{ + // Return number of processors online (MorphOS has SMP support, so we + // should do something useful here...) + return 1; +} diff --git a/libs/glfw/lib/amigaos/amigaos_time.c b/libs/glfw/lib/amigaos/amigaos_time.c new file mode 100644 index 0000000..12d9960 --- /dev/null +++ b/libs/glfw/lib/amigaos/amigaos_time.c @@ -0,0 +1,206 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: amigaos_time.c +// Platforms: AmigaOS, MorphOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwInitTimer() - Initialize timer +//======================================================================== + +int _glfwInitTimer( void ) +{ + ULONG freq; + struct EClockVal t; + + // Start by clearing all handles + TimerBase = NULL; + _glfwTimer.TimerMP = NULL; + _glfwTimer.TimerIO = NULL; + + // Open timer.device (used as a library for ReadEClock) + if( (_glfwTimer.TimerMP = CreatePort( NULL, 0 )) ) + { + // Create the I/O request + if( (_glfwTimer.TimerIO = (struct timerequest *) + CreateExtIO(_glfwTimer.TimerMP, sizeof(struct timerequest))) ) + { + // Open the timer device + if( !( OpenDevice( "timer.device", UNIT_MICROHZ, + (struct IORequest *) _glfwTimer.TimerIO, + 0 ) ) ) + { + // Set up pointer for timer functions + TimerBase = + (struct Device *)_glfwTimer.TimerIO->tr_node.io_Device; + } + else + { + return 0; + } + } + else + { + return 0; + } + } + else + { + return 0; + } + + // Get current time + freq = ReadEClock( &t ); + + // Calculate resolution + _glfwTimer.Resolution = 1.0 / (double) freq; + + // Convert to 64-bit integer + _glfwTimer.t0 = (long long) t.ev_hi * (long long) 4294967296 + + (long long) t.ev_lo; + + return 1; +} + + +//======================================================================== +// _glfwTerminateTimer() - Terminate timer +//======================================================================== + +void _glfwTerminateTimer( void ) +{ + // Empty the timer.device message port queue + if( _glfwTimer.TimerMP ) + { + struct Message *msg; + while( NULL != (msg = GetMsg( _glfwTimer.TimerMP )) ) + { + ReplyMsg( msg ); + } + } + + // Close timer.device + if( TimerBase ) + { + CloseDevice( (struct IORequest *) _glfwTimer.TimerIO ); + TimerBase = NULL; + } + + // Delete timer.device I/O request + if( _glfwTimer.TimerIO ) + { + DeleteExtIO( (struct IORequest *) _glfwTimer.TimerIO ); + _glfwTimer.TimerIO = NULL; + } + + // Delete timer.device message port + if( _glfwTimer.TimerMP ) + { + DeletePort( _glfwTimer.TimerMP ); + _glfwTimer.TimerMP = NULL; + } +} + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformGetTime() - Return timer value in seconds +//======================================================================== + +double _glfwPlatformGetTime( void ) +{ + struct EClockVal t; + long long t64; + + // Get current time + (void) ReadEClock( &t ); + + // Convert to 64-bit integer + t64 = (long long) t.ev_hi * (long long) 4294967296 + + (long long) t.ev_lo; + + return (double)(t64 - _glfwTimer.t0) * _glfwTimer.Resolution; +} + + +//======================================================================== +// _glfwPlatformSetTime() - Set timer value in seconds +//======================================================================== + +void _glfwPlatformSetTime( double t ) +{ + struct EClockVal t0; + long long t64; + + // Get current time + (void) ReadEClock( &t0 ); + + // Convert to 64-bit integer + t64 = (long long) t0.ev_hi * (long long) 4294967296 + + (long long) t0.ev_lo; + + // Calulate new starting time + _glfwTimer.t0 = t64 - (long long)(t/_glfwTimer.Resolution); +} + + +//======================================================================== +// _glfwPlatformSleep() - Put a thread to sleep for a specified amount of +// time +//======================================================================== + +void _glfwPlatformSleep( double time ) +{ + ULONG ticks; + + // Too short time? + if( time <= 0.0 ) + { + return; + } + + // Calculate Delay ticks (should be 50 ticks per second) + ticks = (ULONG) ((double)TICKS_PER_SECOND * time + 0.5); + if( ticks == 0 ) + { + ticks = 1; + } + + // Put process to sleep + Delay( ticks ); +} diff --git a/libs/glfw/lib/amigaos/amigaos_window.c b/libs/glfw/lib/amigaos/amigaos_window.c new file mode 100644 index 0000000..5660b6a --- /dev/null +++ b/libs/glfw/lib/amigaos/amigaos_window.c @@ -0,0 +1,830 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: amigaos_window.c +// Platforms: AmigaOS, MorphOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwTranslateChar() - Translates an AmigaOS key to Unicode +//======================================================================== + +static int _glfwTranslateChar( struct IntuiMessage *msg ) +{ + struct InputEvent event; + unsigned char buffer[ 4 ]; + int character; + + // Create input event + event.ie_Class = IECLASS_RAWKEY; + event.ie_Code = msg->Code; + event.ie_Qualifier = msg->Qualifier; + event.ie_EventAddress = msg->IAddress; + + // Map key event to text string + if( MapRawKey( &event, buffer, 4, NULL ) > 0 ) + { + // Valid Unicode character? + character = (int) buffer[ 0 ]; + if( (character >= 32 && character <= 126) || + (character >= 160 && character <= 255) ) + { + return character; + } + } + + return -1; +} + + +//======================================================================== +// _glfwTranslateKey() - Translates an AmigaOS key to internal coding +//======================================================================== + +static int _glfwTranslateKey( struct IntuiMessage *msg ) +{ + int key = msg->Code & 0x7F; + ULONG old_qualifier; + + // Special (non printable) keys + switch( key ) + { + // Modifier keys + case 0x60: return GLFW_KEY_LSHIFT; + case 0x61: return GLFW_KEY_RSHIFT; + case 0x62: return GLFW_KEY_LCTRL; // ? + case 0x63: return GLFW_KEY_RCTRL; // ? + case 0x64: return GLFW_KEY_LALT; + case 0x65: return GLFW_KEY_RALT; + + // Function keys + case 0x50: return GLFW_KEY_F1; + case 0x51: return GLFW_KEY_F2; + case 0x52: return GLFW_KEY_F3; + case 0x53: return GLFW_KEY_F4; + case 0x54: return GLFW_KEY_F5; + case 0x55: return GLFW_KEY_F6; + case 0x56: return GLFW_KEY_F7; + case 0x57: return GLFW_KEY_F8; + case 0x58: return GLFW_KEY_F9; + case 0x59: return GLFW_KEY_F10; + + // Other control keys + case 0x45: return GLFW_KEY_ESC; + case 0x42: return GLFW_KEY_TAB; + case 0x44: return GLFW_KEY_ENTER; + case 0x46: return GLFW_KEY_DEL; + case 0x41: return GLFW_KEY_BACKSPACE; + case 0x66: return GLFW_KEY_INSERT; // ? + case 0x4F: return GLFW_KEY_LEFT; + case 0x4E: return GLFW_KEY_RIGHT; + case 0x4C: return GLFW_KEY_UP; + case 0x4D: return GLFW_KEY_DOWN; + + // Keypad keys + case 0x0F: return GLFW_KEY_KP_0; + case 0x1D: return GLFW_KEY_KP_1; + case 0x1E: return GLFW_KEY_KP_2; + case 0x1F: return GLFW_KEY_KP_3; + case 0x2D: return GLFW_KEY_KP_4; + case 0x2E: return GLFW_KEY_KP_5; + case 0x2F: return GLFW_KEY_KP_6; + case 0x3D: return GLFW_KEY_KP_7; + case 0x3E: return GLFW_KEY_KP_8; + case 0x3F: return GLFW_KEY_KP_9; + case 0x43: return GLFW_KEY_KP_ENTER; + case 0x5E: return GLFW_KEY_KP_ADD; + case 0x4A: return GLFW_KEY_KP_SUBTRACT; + case 0x5D: return GLFW_KEY_KP_MULTIPLY; + case 0x5C: return GLFW_KEY_KP_DIVIDE; + case 0x3C: return GLFW_KEY_KP_DECIMAL; + + default: break; + } + + // Printable keys (without modifiers!) + old_qualifier = msg->Qualifier; + msg->Qualifier = 0; + key = _glfwTranslateChar( msg ); + msg->Qualifier = old_qualifier; + if( key > 0 ) + { + // Make sure it is upper case + key = ToUpper( key ); + } + + return key; +} + + +//======================================================================== +// _glfwProcessEvents() - Process all pending AmigaOS events +//======================================================================== + +static int _glfwProcessEvents( void ) +{ + struct IntuiMessage message, *tmp_message = NULL; + struct MsgPort *msg_port; + int win_closed = GL_FALSE, action; + int x, y; + + // Examine pending messages + msg_port = _glfwWin.Window->UserPort; + while( (tmp_message = (struct IntuiMessage *) GetMsg( msg_port )) ) + { + // Copy contents of message structure + message = *tmp_message; + + // Now reply to the message (we don't need it anymore) + ReplyMsg( (struct Message *) tmp_message ); + + // Handle different messages + switch( message.Class ) + { + + // Was the window activated? + case IDCMP_ACTIVEWINDOW: + _glfwWin.Active = GL_TRUE; + break; + + // Was the window deactivated? + case IDCMP_INACTIVEWINDOW: + _glfwWin.Active = GL_FALSE; + _glfwInputDeactivation(); + break; + + // Did we get a keyboard press or release? + case IDCMP_RAWKEY: + action = (message.Code & 0x80) ? GLFW_RELEASE : GLFW_PRESS; + message.Code &= 0x7F; + _glfwInputKey( _glfwTranslateKey( &message ), action ); + _glfwInputChar( _glfwTranslateChar( &message ), action ); + break; + + // Was the mouse moved? + case IDCMP_MOUSEMOVE: + x = message.MouseX; + y = message.MouseY; + if( _glfwWin.PointerHidden ) + { + // When pointer is hidden, we get delta moves + x += _glfwInput.MousePosX; + y += _glfwInput.MousePosY; + } + else if( x < 0 || x >= _glfwWin.Width || + y < 0 || y >= _glfwWin.Height ) + { + // Only report mouse moves that are INSIDE client area + break; + } + if( x != _glfwInput.MousePosX || y != _glfwInput.MousePosY ) + { + _glfwInput.MousePosX = x; + _glfwInput.MousePosY = y; + if( _glfwWin.MousePosCallback ) + { + _glfwWin.MousePosCallback( x, y ); + } + } + break; + + // Did we get a mouse button event? + case IDCMP_MOUSEBUTTONS: + switch( message.Code ) + { + case SELECTUP: + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, + GLFW_RELEASE ); + break; + case SELECTDOWN: + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, + GLFW_PRESS ); + break; + case MENUUP: + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, + GLFW_RELEASE ); + break; + case MENUDOWN: + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, + GLFW_PRESS ); + break; + default: + break; + } + break; + + // Was the window size changed? + case IDCMP_NEWSIZE: + _glfwWin.Width = message.IDCMPWindow->GZZWidth; + _glfwWin.Height = message.IDCMPWindow->GZZHeight; + if( _glfwWin.WindowSizeCallback ) + { + _glfwWin.WindowSizeCallback( _glfwWin.Width, + _glfwWin.Height ); + } + break; + + // Was the window contents damaged? + case IDCMP_REFRESHWINDOW: + // Intuition wants us to do this... + BeginRefresh( _glfwWin.Window ); + EndRefresh( _glfwWin.Window, TRUE ); + + // Call user callback function + if( _glfwWin.WindowRefreshCallback ) + { + _glfwWin.WindowRefreshCallback(); + } + break; + + // Was the window closed? + case IDCMP_CLOSEWINDOW: + win_closed = GL_TRUE; + break; + + default: + break; + } + } + + // Return GL_TRUE if window was closed + return( win_closed ); +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformOpenWindow() - Here is where the window is created, and +// the OpenGL rendering context is created +//======================================================================== + +int _glfwPlatformOpenWindow( int width, int height, int redbits, + int greenbits, int bluebits, int alphabits, int depthbits, + int stencilbits, int mode, int accumredbits, int accumgreenbits, + int accumbluebits, int accumalphabits, int auxbuffers, int stereo, + int refreshrate ) +{ + struct TagItem tagList[ 25 ]; + int tagNR, accumbits; + + // Calculate sum of accumulator bits + accumbits = accumredbits + accumgreenbits + accumbluebits + + accumalphabits; + + // Clear window state + _glfwWin.Screen = NULL; + _glfwWin.Window = NULL; + _glfwWin.Context = NULL; + _glfwWin.PointerHidden = 0; + _glfwWin.PointerSprite = NULL; + _glfwWin.InputMP = NULL; + _glfwWin.InputIO = NULL; + + // Create input.device message port + if( !(_glfwWin.InputMP = CreatePort( NULL, 0 )) ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Create input.device I/O request + if( !(_glfwWin.InputIO = (struct IOStdReq *) + CreateExtIO( _glfwWin.InputMP, sizeof(struct IOStdReq) )) ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Open input.device (for pointer position manipulation) + if( OpenDevice( "input.device", 0, + (struct IORequest *)_glfwWin.InputIO, 0 ) ) + { + DeleteExtIO( (struct IORequest *) _glfwWin.InputIO ); + _glfwWin.InputIO = NULL; + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Do we want fullscreen? + if( _glfwWin.Fullscreen ) + { + // Open a new Amiga screen + if( !_glfwOpenScreen( &width, &height, &redbits, &greenbits, + &bluebits, refreshrate ) ) + { + _glfwWin.Fullscreen = GL_FALSE; + } + } + + // Select window properties + tagNR = 0; + tagList[ tagNR ].ti_Tag = WA_Left; + tagList[ tagNR++ ].ti_Data = 0; + tagList[ tagNR ].ti_Tag = WA_Top; + tagList[ tagNR++ ].ti_Data = 0; + tagList[ tagNR ].ti_Tag = WA_IDCMP; + tagList[ tagNR++ ].ti_Data = IDCMP_REFRESHWINDOW | + IDCMP_CLOSEWINDOW | + IDCMP_NEWSIZE | + IDCMP_ACTIVEWINDOW | + IDCMP_INACTIVEWINDOW | + IDCMP_RAWKEY | + IDCMP_MOUSEMOVE | + IDCMP_MOUSEBUTTONS; + tagList[ tagNR ].ti_Tag = WA_ReportMouse; + tagList[ tagNR++ ].ti_Data = TRUE; + tagList[ tagNR ].ti_Tag = WA_RMBTrap; + tagList[ tagNR++ ].ti_Data = TRUE; + tagList[ tagNR ].ti_Tag = WA_NoCareRefresh; + tagList[ tagNR++ ].ti_Data = FALSE; + tagList[ tagNR ].ti_Tag = WA_SimpleRefresh; + tagList[ tagNR++ ].ti_Data = TRUE; + tagList[ tagNR ].ti_Tag = WA_Activate; + tagList[ tagNR++ ].ti_Data = TRUE; + tagList[ tagNR ].ti_Tag = WA_CloseGadget; + tagList[ tagNR++ ].ti_Data = _glfwWin.Fullscreen ? FALSE : TRUE; + tagList[ tagNR ].ti_Tag = WA_SizeGadget; + tagList[ tagNR++ ].ti_Data = _glfwWin.Fullscreen ? FALSE : ( _glfwWinHints.WindowNoResize ? FALSE : TRUE ); + tagList[ tagNR ].ti_Tag = WA_DepthGadget; + tagList[ tagNR++ ].ti_Data = _glfwWin.Fullscreen ? FALSE : TRUE; + tagList[ tagNR ].ti_Tag = WA_DragBar; + tagList[ tagNR++ ].ti_Data = _glfwWin.Fullscreen ? FALSE : TRUE; + tagList[ tagNR ].ti_Tag = WA_Borderless; + tagList[ tagNR++ ].ti_Data = _glfwWin.Fullscreen ? TRUE : FALSE; + tagList[ tagNR ].ti_Tag = WA_Backdrop; + tagList[ tagNR++ ].ti_Data = _glfwWin.Fullscreen ? TRUE : FALSE; + if( _glfwWin.Fullscreen ) + { + tagList[ tagNR ].ti_Tag = WA_CustomScreen; + tagList[ tagNR++ ].ti_Data = (ULONG) _glfwWin.Screen; + tagList[ tagNR ].ti_Tag = WA_Width; + tagList[ tagNR++ ].ti_Data = width; + tagList[ tagNR ].ti_Tag = WA_Height; + tagList[ tagNR++ ].ti_Data = height; + } + else + { + tagList[ tagNR ].ti_Tag = WA_GimmeZeroZero; + tagList[ tagNR++ ].ti_Data = TRUE; + tagList[ tagNR ].ti_Tag = WA_InnerWidth; + tagList[ tagNR++ ].ti_Data = width; + tagList[ tagNR ].ti_Tag = WA_InnerHeight; + tagList[ tagNR++ ].ti_Data = height; + tagList[ tagNR ].ti_Tag = WA_MinWidth; + tagList[ tagNR++ ].ti_Data = 20; + tagList[ tagNR ].ti_Tag = WA_MinHeight; + tagList[ tagNR++ ].ti_Data = 20; + tagList[ tagNR ].ti_Tag = WA_MaxWidth; + tagList[ tagNR++ ].ti_Data = 9999; + tagList[ tagNR ].ti_Tag = WA_MaxHeight; + tagList[ tagNR++ ].ti_Data = 9999; + tagList[ tagNR ].ti_Tag = WA_Title; + tagList[ tagNR++ ].ti_Data = (ULONG) "GLFW Window"; + tagList[ tagNR ].ti_Tag = WA_ScreenTitle; + tagList[ tagNR++ ].ti_Data = (ULONG) "GLFW Application"; + } + tagList[ tagNR ].ti_Tag = TAG_DONE; + + // Open window + _glfwWin.Window = OpenWindowTagList( NULL, tagList ); + if( !_glfwWin.Window ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Fullscreen/windowed post fixups + if( _glfwWin.Fullscreen ) + { + // Don't show screen title + ShowTitle( _glfwWin.Screen, FALSE ); + + // Remember window size + _glfwWin.Width = _glfwWin.Window->Width; + _glfwWin.Height = _glfwWin.Window->Height; + } + else + { + // If we are not in fullscreen mode, get screen handle from window + _glfwWin.Screen = _glfwWin.Window->WScreen; + + // Get ModeID for the current video mode + _glfwWin.ModeID = GetVPModeID( &_glfwWin.Screen->ViewPort ); + + // Remember window size + _glfwWin.Width = _glfwWin.Window->GZZWidth; + _glfwWin.Height = _glfwWin.Window->GZZHeight; + } + + // Put window on top + WindowToFront( _glfwWin.Window ); + + // Create OpenGL context +#ifdef _GLFW_STORMMESA + tagNR = 0; + tagList[ tagNR ].ti_Tag = AMA_Window; + tagList[ tagNR++ ].ti_Data = (ULONG) _glfwWin.Window; + tagList[ tagNR ].ti_Tag = AMA_RastPort; + tagList[ tagNR++ ].ti_Data = (ULONG) _glfwWin.Window->RPort; + tagList[ tagNR ].ti_Tag = AMA_Screen; + tagList[ tagNR++ ].ti_Data = (ULONG) _glfwWin.Screen; + tagList[ tagNR ].ti_Tag = AMA_Left; + tagList[ tagNR++ ].ti_Data = 0; + tagList[ tagNR ].ti_Tag = AMA_Bottom; + tagList[ tagNR++ ].ti_Data = 0; + tagList[ tagNR ].ti_Tag = AMA_Width; + tagList[ tagNR++ ].ti_Data = _glfwWin.Width; + tagList[ tagNR ].ti_Tag = AMA_Height; + tagList[ tagNR++ ].ti_Data = _glfwWin.Height; + tagList[ tagNR ].ti_Tag = AMA_DoubleBuf; + tagList[ tagNR++ ].ti_Data = GL_TRUE; + tagList[ tagNR ].ti_Tag = AMA_RGBMode; + tagList[ tagNR++ ].ti_Data = GL_TRUE; + tagList[ tagNR ].ti_Tag = AMA_AlphaFlag; + tagList[ tagNR++ ].ti_Data = alphabits ? GL_TRUE : GL_FALSE; + tagList[ tagNR ].ti_Tag = AMA_NoDepth; + tagList[ tagNR++ ].ti_Data = depthbits ? GL_FALSE : GL_TRUE; + tagList[ tagNR ].ti_Tag = AMA_NoStencil; + tagList[ tagNR++ ].ti_Data = stencilbits ? GL_FALSE : GL_TRUE; + tagList[ tagNR ].ti_Tag = AMA_NoAccum; + tagList[ tagNR++ ].ti_Data = accumbits ? GL_FALSE : GL_TRUE; + tagList[ tagNR ].ti_Tag = AMA_DirectRender; + tagList[ tagNR++ ].ti_Data = GL_TRUE; + tagList[ tagNR ].ti_Tag = AMA_DrawMode; + tagList[ tagNR++ ].ti_Data = AMESA_AGA_C2P; + tagList[ tagNR ].ti_Tag = TAG_DONE; + _glfwWin.Context = AmigaMesaCreateContext( tagList ); +#endif + if( !_glfwWin.Context ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Make current +#ifdef _GLFW_STORMMESA + AmigaMesaMakeCurrent( _glfwWin.Context, _glfwWin.Context->buffer ); +#endif + + return GL_TRUE; +} + + +//======================================================================== +// _glfwPlatformCloseWindow() - Properly kill the window/video display +//======================================================================== + +void _glfwPlatformCloseWindow( void ) +{ + // Restore mouse pointer (if hidden) + _glfwPlatformShowMouseCursor(); + + // Destroy OpenGL context + if( _glfwWin.Context ) + { +#ifdef _GLFW_STORMMESA + AmigaMesaDestroyContext( _glfwWin.Context ); +#endif + _glfwWin.Context = NULL; + } + + // Close window + if( _glfwWin.Window ) + { + CloseWindow( _glfwWin.Window ); + _glfwWin.Window = NULL; + } + + // Close screen + if( _glfwWin.Fullscreen && _glfwWin.Screen ) + { + CloseScreen( _glfwWin.Screen ); + } + _glfwWin.Screen = NULL; + + // Close input device I/O request + if( _glfwWin.InputIO ) + { + CloseDevice( (struct IORequest *) _glfwWin.InputIO ); + DeleteExtIO( (struct IORequest *) _glfwWin.InputIO ); + _glfwWin.InputIO = NULL; + } + + // Close input device message port + if( _glfwWin.InputMP ) + { + DeletePort( _glfwWin.InputMP ); + _glfwWin.InputMP = NULL; + } + +} + + +//======================================================================== +// _glfwPlatformSetWindowTitle() - Set the window title. +//======================================================================== + +void _glfwPlatformSetWindowTitle( const char *title ) +{ + if( !_glfwWin.Fullscreen ) + { + SetWindowTitles( _glfwWin.Window, (char*) title, (char*) title ); + } +} + + +//======================================================================== +// _glfwPlatformSetWindowSize() - Set the window size. +//======================================================================== + +void _glfwPlatformSetWindowSize( int width, int height ) +{ + if( !_glfwWin.Fullscreen ) + { + SizeWindow( _glfwWin.Window, width-_glfwWin.Width, + height-_glfwWin.Height ); + } +} + + +//======================================================================== +// _glfwPlatformSetWindowPos() - Set the window position. +//======================================================================== + +void _glfwPlatformSetWindowPos( int x, int y ) +{ + if( !_glfwWin.Fullscreen ) + { + ChangeWindowBox( _glfwWin.Window, x, y, _glfwWin.Window->Width, + _glfwWin.Window->Height ); + } +} + + +//======================================================================== +// _glfwPlatformIconfyWindow() - Window iconification +//======================================================================== + +void _glfwPlatformIconifyWindow( void ) +{ + if( _glfwWin.Fullscreen ) + { + ScreenToBack( _glfwWin.Screen ); + WBenchToFront(); + _glfwWin.Iconified = GL_TRUE; + } +} + + +//======================================================================== +// _glfwPlatformRestoreWindow() - Window un-iconification +//======================================================================== + +void _glfwPlatformRestoreWindow( void ) +{ + if( _glfwWin.Fullscreen ) + { + ScreenToFront( _glfwWin.Screen ); + } + WindowToFront( _glfwWin.Window ); + ActivateWindow( _glfwWin.Window ); + _glfwWin.Iconified = GL_FALSE; +} + + +//======================================================================== +// _glfwPlatformSwapBuffers() - Swap buffers (double-buffering) and poll +// any new events. +//======================================================================== + +void _glfwPlatformSwapBuffers( void ) +{ +#ifdef _GLFW_STORMMESA + AmigaMesaSwapBuffers( _glfwWin.Context ); +#endif +} + + +//======================================================================== +// _glfwPlatformSwapInterval() - Set double buffering swap interval +//======================================================================== + +void _glfwPlatformSwapInterval( int interval ) +{ + // Not supported +} + + +//======================================================================== +// _glfwPlatformRefreshWindowParams() +//======================================================================== + +void _glfwPlatformRefreshWindowParams( void ) +{ + int refresh; + GLint x; + GLboolean b; + + // This function is not proerly implemented yet. We use OpenGL for + // getting framebuffer format information - we should use some + // alternate interface (such as glX under the X Window System), but + // StormMesa does not seem to provide this. + + // Fill out information + _glfwWin.Accelerated = GL_TRUE; + glGetIntegerv( GL_RED_BITS, &x ); + _glfwWin.RedBits = x; + glGetIntegerv( GL_GREEN_BITS, &x ); + _glfwWin.GreenBits = x; + glGetIntegerv( GL_BLUE_BITS, &x ); + _glfwWin.BlueBits = x; + glGetIntegerv( GL_ALPHA_BITS, &x ); + _glfwWin.AlphaBits = x; + glGetIntegerv( GL_DEPTH_BITS, &x ); + _glfwWin.DepthBits = x; + glGetIntegerv( GL_STENCIL_BITS, &x ); + _glfwWin.StencilBits = x; + glGetIntegerv( GL_ACCUM_RED_BITS, &x ); + _glfwWin.AccumRedBits = x; + glGetIntegerv( GL_ACCUM_GREEN_BITS, &x ); + _glfwWin.AccumGreenBits = x; + glGetIntegerv( GL_ACCUM_BLUE_BITS, &x ); + _glfwWin.AccumBlueBits = x; + glGetIntegerv( GL_ACCUM_ALPHA_BITS, &x ); + _glfwWin.AccumAlphaBits = x; + glGetIntegerv( GL_AUX_BUFFERS, &x ); + _glfwWin.AuxBuffers = x; + glGetBooleanv( GL_AUX_BUFFERS, &b ); + _glfwWin.Stereo = b ? GL_TRUE : GL_FALSE; + + // Get ModeID information (refresh rate) + _glfwGetModeIDInfo( _glfwWin.ModeID, NULL, NULL, NULL, NULL, NULL, + &refresh ); + _glfwWin.RefreshRate = refresh; +} + + +//======================================================================== +// _glfwPlatformPollEvents() - Poll for new window and input events +//======================================================================== + +void _glfwPlatformPollEvents( void ) +{ + int winclosed; + + // Process all pending window events + winclosed = GL_FALSE; + if( _glfwProcessEvents() ) + { + winclosed = GL_TRUE; + } + + // Was there a window close request? + if( winclosed && _glfwWin.WindowCloseCallback ) + { + // Check if the program wants us to close the window + winclosed = _glfwWin.WindowCloseCallback(); + } + if( winclosed ) + { + glfwCloseWindow(); + } +} + + +//======================================================================== +// _glfwPlatformWaitEvents() - Wait for new window and input events +//======================================================================== + +void _glfwPlatformWaitEvents( void ) +{ + // Wait for new events + Wait( 1L << _glfwWin.Window->UserPort->mp_SigBit ); + + // Poll new events + _glfwPlatformPollEvents(); +} + + +//======================================================================== +// _glfwPlatformHideMouseCursor() - Hide mouse cursor (lock it) +//======================================================================== + +void _glfwPlatformHideMouseCursor( void ) +{ + // We only allow this under fullscreen right now, since we can't rely + // on the pointer position in windowed mode! Perhaps it's possible to + // "steal" the mouse with input.device or something...? + if( !_glfwWin.PointerHidden && _glfwWin.Fullscreen ) + { + // Allocate chip memory for the blank mouse pointer + _glfwWin.PointerSprite = AllocVec( 128, MEMF_CHIP | MEMF_CLEAR ); + if( _glfwWin.PointerSprite ) + { + // Switch to blank/transparent pointer + SetPointer( _glfwWin.Window, (UWORD *) _glfwWin.PointerSprite, + 1, 1, 0, 0 ); + _glfwWin.PointerHidden = 1; + + // Switch to mouse delta movement + Forbid(); + _glfwWin.Window->IDCMPFlags |= IDCMP_DELTAMOVE; + Permit(); + } + } +} + + +//======================================================================== +// _glfwPlatformShowMouseCursor() - Show mouse cursor (unlock it) +//======================================================================== + +void _glfwPlatformShowMouseCursor( void ) +{ + if( _glfwWin.PointerHidden ) + { + // Switch to absolute mouse movement + Forbid(); + _glfwWin.Window->IDCMPFlags &= (0xFFFFFFFF^IDCMP_DELTAMOVE); + Permit(); + + // Change back to normal pointer + ClearPointer( _glfwWin.Window ); + if( _glfwWin.PointerSprite ) + { + FreeVec( _glfwWin.PointerSprite ); + _glfwWin.PointerSprite = NULL; + } + _glfwWin.PointerHidden = 0; + } +} + + +//======================================================================== +// _glfwPlatformSetMouseCursorPos() - Set physical mouse cursor position +//======================================================================== + +void _glfwPlatformSetMouseCursorPos( int x, int y ) +{ + struct IEPointerPixel ppxl; + struct InputEvent event; + + // Adjust coordinates to window client area upper left corner + x += _glfwWin.Window->LeftEdge; + y += _glfwWin.Window->TopEdge; + + /* Set up IEPointerPixel fields */ + ppxl.iepp_Screen = _glfwWin.Screen; + ppxl.iepp_Position.X = x; + ppxl.iepp_Position.Y = y; + + /* Set up InputEvent fields */ + event.ie_EventAddress = (APTR)&ppxl; /* IEPointerPixel */ + event.ie_NextEvent = NULL; + event.ie_Class = IECLASS_NEWPOINTERPOS; /* new mouse pos */ + event.ie_SubClass = IESUBCLASS_PIXEL; /* on pixel */ + event.ie_Code = IECODE_NOBUTTON; + event.ie_Qualifier = 0; /* absolute pos */ + + /* Set up I/O request */ + _glfwWin.InputIO->io_Data = (APTR)&event; + _glfwWin.InputIO->io_Length = sizeof(struct InputEvent); + _glfwWin.InputIO->io_Command = IND_WRITEEVENT; + + /* Perform I/O (move mouse cursor) */ + DoIO( (struct IORequest *)_glfwWin.InputIO ); +} diff --git a/libs/glfw/lib/amigaos/platform.h b/libs/glfw/lib/amigaos/platform.h new file mode 100644 index 0000000..a27b5fc --- /dev/null +++ b/libs/glfw/lib/amigaos/platform.h @@ -0,0 +1,337 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: platform.h +// Platforms: AmigaOS, MorphOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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 _platform_h_ +#define _platform_h_ + +// First of all: a file that hides compiler specific stuff +#include "SDI_compiler.h" + + +// This is the AmigaOS version of GLFW +#define _GLFW_AMIGAOS + +// Are we compiling for MorphOS? +#if defined(__MORPHOS__) || defined(MORPHOS) + #define _GLFW_MORPHOS +#endif + +// Mesa/OpenGL flavour (we only support StormMesa at the moment) +#if !defined(_GLFW_STORMMESA) + #define _GLFW_STORMMESA +#endif + + + +// Include files +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + + +// Amiga Mesa/OpenGL implementation dependent include +#ifdef _GLFW_STORMMESA + #include +#endif + +// MorphOS support +#ifdef _GLFW_MORPHOS + #include +#endif + +// GLFW+GL+GLU defines +#ifdef __GNUC__ + #include "../../include/GL/glfw.h" +#else + #include "//include/GL/glfw.h" +#endif + + +// Stack size for each thread (in bytes) +#define _GLFW_TASK_STACK_SIZE 50000 + + +//======================================================================== +// Global variables (GLFW internals) +//======================================================================== + +//------------------------------------------------------------------------ +// Shared libraries +//------------------------------------------------------------------------ + +#if defined( _init_c_ ) +struct GfxBase * GfxBase; +struct IntuitionBase * IntuitionBase; +struct Library * KeymapBase; +struct UtilityBase * UtilityBase; +struct Device * TimerBase; +#endif + + +//------------------------------------------------------------------------ +// Window structure +//------------------------------------------------------------------------ +typedef struct _GLFWwin_struct _GLFWwin; + +struct _GLFWwin_struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // User callback functions + GLFWwindowsizefun WindowSizeCallback; + GLFWwindowclosefun WindowCloseCallback; + GLFWwindowrefreshfun WindowRefreshCallback; + GLFWmousebuttonfun MouseButtonCallback; + GLFWmouseposfun MousePosCallback; + GLFWmousewheelfun MouseWheelCallback; + GLFWkeyfun KeyCallback; + GLFWcharfun CharCallback; + + // User selected window settings + int Fullscreen; // Fullscreen flag + int MouseLock; // Mouse-lock flag + int AutoPollEvents; // Auto polling flag + int SysKeysDisabled; // System keys disabled flag + int WindowNoResize; // Resize- and maximize gadgets disabled flag + + // Window status & parameters + int Opened; // Flag telling if window is opened or not + int Active; // Application active flag + int Iconified; // Window iconified flag + int Width, Height; // Window width and heigth + int Accelerated; // GL_TRUE if window is HW accelerated + int RedBits; + int GreenBits; + int BlueBits; + int AlphaBits; + int DepthBits; + int StencilBits; + int AccumRedBits; + int AccumGreenBits; + int AccumBlueBits; + int AccumAlphaBits; + int AuxBuffers; + int Stereo; + int RefreshRate; // Vertical monitor refresh rate + + // Extensions & OpenGL version + int Has_GL_SGIS_generate_mipmap; + int Has_GL_ARB_texture_non_power_of_two; + int GLVerMajor,GLVerMinor; + + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Platform specific window resources + struct Screen *Screen; // Screen handle + struct Window *Window; // Window handle + ULONG ModeID; // ModeID + APTR PointerSprite; // Memory for blank pointer sprite + int PointerHidden; // Is pointer hidden? + struct MsgPort *InputMP; // Message port (pointer movement) + struct IOStdReq *InputIO; // I/O request (pointer movement) + + // Mesa/OpenGL flavour specific +#ifdef _GLFW_STORMMESA + struct amigamesa_context *Context; // GL context handle +#endif + + // Platform specific extensions + + // Various platform specific internal variables + +}; + +GLFWGLOBAL _GLFWwin _glfwWin; + + +//------------------------------------------------------------------------ +// User input status (most of this should go in _GLFWwin) +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Mouse status + int MousePosX, MousePosY; + int WheelPos; + char MouseButton[ GLFW_MOUSE_BUTTON_LAST+1 ]; + + // Keyboard status + char Key[ GLFW_KEY_LAST+1 ]; + int LastChar; + + // User selected settings + int StickyKeys; + int StickyMouseButtons; + int KeyRepeat; + + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Platform specific internal variables + int MouseMoved, OldMouseX, OldMouseY; + +} _glfwInput; + + +//------------------------------------------------------------------------ +// Timer status +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + struct MsgPort *TimerMP; + struct timerequest *TimerIO; + double Resolution; + long long t0; +} _glfwTimer; + + +//------------------------------------------------------------------------ +// Thread record (one for each thread) +//------------------------------------------------------------------------ +typedef struct _GLFWthread_struct _GLFWthread; + +struct _GLFWthread_struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Pointer to previous and next threads in linked list + _GLFWthread *Previous, *Next; + + // GLFW user side thread information + GLFWthread ID; + +// ========= PLATFORM SPECIFIC PART ====================================== + + // System side thread information + GLFWthreadfun Function; + void *Arg; + struct Process *AmiProc; + struct Task *AmiTask; + + // "Wait for" object. Can be a thread, condition variable or NULL. + void *WaitFor; + int WaitSig; + + // MorphOS support +#ifdef _GLFW_MORPHOS + struct EmulLibEntry mosEmulLibEntry; +#endif +}; + + +//------------------------------------------------------------------------ +// General thread information +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Next thread ID to use (increments for every created thread) + GLFWthread NextID; + + // First thread in linked list (always the main thread) + _GLFWthread First; + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Critical section lock + struct SignalSemaphore CriticalSection; + + // Next condition variable ID (decrements for every created cond) + unsigned int NextCondID; + +} _glfwThrd; + + +//------------------------------------------------------------------------ +// Joystick information & state +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + int Present; + int GameDeviceOpen; + struct IOStdReq *GameIO; + struct MsgPort *GameMP; + struct InputEvent GameEvent; + float Axis[ 2 ]; + unsigned char Button[ 2 ]; +} _glfwJoy; + + +//======================================================================== +// Macros for encapsulating critical code sections (i.e. making parts +// of GLFW thread safe) +//======================================================================== + +// Thread list management +#define ENTER_THREAD_CRITICAL_SECTION ObtainSemaphore( &_glfwThrd.CriticalSection ); +#define LEAVE_THREAD_CRITICAL_SECTION ReleaseSemaphore( &_glfwThrd.CriticalSection ); + + +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +// Time +int _glfwInitTimer( void ); +void _glfwTerminateTimer( void ); + +// Fullscreen +int _glfwOpenScreen( int *width, int *height, int *r, int *g, int *b, + int refresh ); +int _glfwGetClosestVideoMode( int *w, int *h, int *r, int *g, int *b, + int refresh ); +void _glfwGetModeIDInfo( ULONG ModeID, int *w, int *h, int *r, int *g, + int *b, int *refresh ); +// Joystick +void _glfwInitJoysticks( void ); +void _glfwTerminateJoysticks( void ); + + +#endif // _platform_h_ diff --git a/libs/glfw/lib/dos/Makefile.dos.djgpp b/libs/glfw/lib/dos/Makefile.dos.djgpp new file mode 100644 index 0000000..506ef09 --- /dev/null +++ b/libs/glfw/lib/dos/Makefile.dos.djgpp @@ -0,0 +1,146 @@ +########################################################################## +# Makefile for GLFW on DOS using DJGPP. +#------------------------------------------------------------------------- +# To compile GLFW using this makefile, run: +# make -f Makefile.dos.djgpp +# NOTE: You need long filename support (e.g. compile under Windows9x or +# use a LFN driver such as DOSLFN) +########################################################################## + +########################################################################## +# Default: Build static library version of GLFW +########################################################################## +default: libglfw.a + + +########################################################################## +# GLFW version +########################################################################## +VERMAJOR = 2 +VERMINOR = 4 + + +########################################################################## +# Compiler settings +########################################################################## +CC = gcc +CFLAGS = -c -I. -I.. -Wall -Os + +# Some modules should be optimized for speed (e.g. image decoding) +CFLAGS_SPEED = -c -I. -I.. -Wall -O3 -ffast-math + + +########################################################################## +# Library builder settings +########################################################################## +MKLIB = ar +LIBFLAGS = -rcs + + +########################################################################## +# Object files which are part of the GLFW library +########################################################################## +OBJS = \ + enable.o \ + fullscreen.o \ + glext.o \ + image.o \ + init.o \ + input.o \ + joystick.o \ + tga.o \ + thread.o \ + time.o \ + window.o \ + dos_enable.o \ + dos_events.o \ + dos_fullscreen.o \ + dos_glext.o \ + dos_init.o \ + dos_irq.o \ + dos_joystick.o \ + dos_keyboard.o \ + dos_mouse.o \ + dos_thread.o \ + dos_time.o \ + dos_window.o + + +########################################################################## +# Rule for building library +########################################################################## +libglfw.a: $(OBJS) + $(MKLIB) $(LIBFLAGS) $@ $(OBJS) + + +########################################################################## +# Rules for building library object files +########################################################################## +enable.o: ..\\enable.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ ..\\enable.c + +fullscreen.o: ..\\fullscreen.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ ..\\fullscreen.c + +glext.o: ..\\glext.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ ..\\glext.c + +image.o: ..\\image.c ..\\internal.h platform.h + $(CC) $(CFLAGS_SPEED) -o $@ ..\\image.c + +init.o: ..\\init.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ ..\\init.c + +input.o: ..\\input.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ ..\\input.c + +joystick.o: ..\\joystick.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ ..\\joystick.c + +tga.o: ..\\tga.c ..\\internal.h platform.h + $(CC) $(CFLAGS_SPEED) -o $@ ..\\tga.c + +thread.o: ..\\thread.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ ..\\thread.c + +time.o: ..\\time.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ ..\\time.c + +window.o: ..\\window.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ ..\\window.c + +dos_enable.o: dos_enable.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ dos_enable.c + +dos_events.o: dos_events.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ dos_events.c + +dos_fullscreen.o: dos_fullscreen.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ dos_fullscreen.c + +dos_glext.o: dos_glext.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ dos_glext.c + +dos_init.o: dos_init.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ dos_init.c + +dos_irq.o: dos_irq.s ..\\internal.h platform.h + $(CC) $(CFLAGS) -x assembler-with-cpp -o $@ dos_irq.s + +dos_joystick.o: dos_joystick.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ dos_joystick.c + +dos_keyboard.o: dos_keyboard.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ dos_keyboard.c + +dos_mouse.o: dos_mouse.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ dos_mouse.c + +dos_thread.o: dos_thread.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ dos_thread.c + +dos_time.o: dos_time.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ dos_time.c + +dos_window.o: dos_window.c ..\\internal.h platform.h + $(CC) $(CFLAGS) -o $@ dos_window.c diff --git a/libs/glfw/lib/dos/dos_enable.c b/libs/glfw/lib/dos/dos_enable.c new file mode 100644 index 0000000..c50a43d --- /dev/null +++ b/libs/glfw/lib/dos/dos_enable.c @@ -0,0 +1,51 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: dos_enable.c +// Platform: DOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformEnableSystemKeys() - Enable system keys +// _glfwPlatformDisableSystemKeys() - Disable system keys +//======================================================================== + +void _glfwPlatformEnableSystemKeys( void ) +{ + // Not supported under DOS (yet) +} + +void _glfwPlatformDisableSystemKeys( void ) +{ + // Not supported under DOS (yet) +} diff --git a/libs/glfw/lib/dos/dos_events.c b/libs/glfw/lib/dos/dos_events.c new file mode 100644 index 0000000..17070e1 --- /dev/null +++ b/libs/glfw/lib/dos/dos_events.c @@ -0,0 +1,173 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: dos_events.c +// Platform: DOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//======================================================================== +// Global variables +//======================================================================== + +// Event buffer +#define _GLFW_EVENT_BUFFER_SIZE 1024 + +static volatile struct { + volatile int Start, End; + volatile _GLFWdosevent *Event; +} _glfwEventBuffer; + +static int _glfwEventsInitialized = 0; + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwWaitNextEvent() - Wait for an event to appear in the event FIFO +// NOTE: Must not be called from an interrupt routine +//======================================================================== + +void _glfwWaitNextEvent( void ) +{ + int noevent = 1; + + while( noevent ) + { + DISABLE(); + noevent = ( _glfwEventBuffer.Start == _glfwEventBuffer.End ); + ENABLE(); + // Wait for an interrupt to happen?... + } +} + + +//======================================================================== +// _glfwGetNextEvent() - Get an event from the event FIFO +// NOTE: Must not be called from an interrupt routine +//======================================================================== + +int _glfwGetNextEvent( _GLFWdosevent *event ) +{ + DISABLE(); + + if( _glfwEventBuffer.Start == _glfwEventBuffer.End ) + { + ENABLE(); + return 0; + } + + *event = _glfwEventBuffer.Event[ _glfwEventBuffer.Start ++ ]; + if( _glfwEventBuffer.Start >= _GLFW_EVENT_BUFFER_SIZE ) + { + _glfwEventBuffer.Start = 0; + } + + ENABLE(); + + return 1; +} + + +//======================================================================== +// _glfwPostDOSEvent() - Put an event onto the event FIFO +// NOTE: Must only be called from an interrupt routine +//======================================================================== + +void _glfwPostDOSEvent( _GLFWdosevent *event ) +{ + // Add event + _glfwEventBuffer.Event[ _glfwEventBuffer.End ++ ] = *event; + + // End of FIFO buffer? + if( _glfwEventBuffer.End >= _GLFW_EVENT_BUFFER_SIZE ) + _glfwEventBuffer.End = 0; + + // If the buffer is full, drop the oldest event + if( _glfwEventBuffer.End == _glfwEventBuffer.Start) + { + _glfwEventBuffer.Start ++; + if( _glfwEventBuffer.Start >= _GLFW_EVENT_BUFFER_SIZE ) + _glfwEventBuffer.Start = 0; + } +} ENDOFUNC(_glfwPostDOSEvent) + + +//======================================================================== +// _glfwInitEvents() - Initialize event management functions and the FIFO +//======================================================================== + +int _glfwInitEvents( void ) +{ + int fifosize; + + // Allocate memory for the event FIFO buffer + fifosize = _GLFW_EVENT_BUFFER_SIZE * sizeof(_GLFWdosevent); + _glfwEventBuffer.Event = malloc( fifosize ); + if( !_glfwEventBuffer.Event ) + { + return 0; + } + + // Lock data & functions + LOCKBUFF( _glfwEventBuffer.Event, fifosize ); + LOCKDATA( _glfwEventBuffer ); + LOCKFUNC( _glfwPostDOSEvent ); + + // Initialize event FIFO + _glfwEventBuffer.Start = _glfwEventBuffer.End = 0; + + _glfwEventsInitialized = 1; + + return 1; +} + + +//======================================================================== +// _glfwTerminateEvents() - Terminate event management +//======================================================================== + +void _glfwTerminateEvents( void ) +{ + if( !_glfwEventsInitialized ) + { + return; + } + + _glfwEventsInitialized = 0; + + // Free memory for the event FIFO buffer + if( _glfwEventBuffer.Event ) + { + free( (void *) _glfwEventBuffer.Event ); + _glfwEventBuffer.Event = NULL; + } +} diff --git a/libs/glfw/lib/dos/dos_fullscreen.c b/libs/glfw/lib/dos/dos_fullscreen.c new file mode 100644 index 0000000..941d013 --- /dev/null +++ b/libs/glfw/lib/dos/dos_fullscreen.c @@ -0,0 +1,101 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: dos_fullscreen.c +// Platform: DOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwBPP2RGB() - Convert BPP to RGB bits (based on "best guess") +//======================================================================== + +static void _glfwBPP2RGB( int bpp, int *r, int *g, int *b ) +{ + int delta; + int bpp2; + + // Special case: bpp = 32 + if( bpp == 32 ) bpp = 24; + + // Convert "bits per pixel" to red, green & blue sizes + *r = *g = *b = bpp / 3; + delta = bpp - (*r * 3); + if( delta >= 1 ) + { + *g = *g + 1; + } + if( delta == 2 ) + { + *r = *r + 1; + } +} + + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformGetVideoModes() - List available video modes +//======================================================================== + +int _glfwPlatformGetVideoModes( GLFWvidmode *list, int maxcount ) +{ + if( maxcount <= 0 ) return 0; + + // Dummy... + list[0].Width = 640; + list[0].Height = 480; + list[0].RedBits = 5; + list[0].GreenBits = 6; + list[0].BlueBits = 5; + + return 1; +} + + +//======================================================================== +// _glfwPlatformGetDesktopMode() - Get the desktop video mode +//======================================================================== + +void _glfwPlatformGetDesktopMode( GLFWvidmode *mode ) +{ + // Dummy... + mode->Width = 640; + mode->Height = 480; + mode->RedBits = 5; + mode->GreenBits = 6; + mode->BlueBits = 5; +} diff --git a/libs/glfw/lib/dos/dos_glext.c b/libs/glfw/lib/dos/dos_glext.c new file mode 100644 index 0000000..9000235 --- /dev/null +++ b/libs/glfw/lib/dos/dos_glext.c @@ -0,0 +1,59 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: dos_glext.c +// Platform: DOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformExtensionSupported() - Check if an OpenGL extension is +// available at runtime +//======================================================================== + +int _glfwPlatformExtensionSupported( const char *extension ) +{ + // TODO + return GL_FALSE; +} + + +//======================================================================== +// _glfwPlatformGetProcAddress() - Get the function pointer to an OpenGL +// function +//======================================================================== + +void * _glfwPlatformGetProcAddress( const char *procname ) +{ + // TODO + return NULL; +} diff --git a/libs/glfw/lib/dos/dos_init.c b/libs/glfw/lib/dos/dos_init.c new file mode 100644 index 0000000..4e02e9d --- /dev/null +++ b/libs/glfw/lib/dos/dos_init.c @@ -0,0 +1,105 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: dos_init.c +// Platform: DOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwTerminate_atexit() - Terminate GLFW when exiting application +//======================================================================== + +void _glfwTerminate_atexit( void ) +{ + glfwTerminate(); +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformInit() - Initialize various GLFW state +//======================================================================== + +int _glfwPlatformInit( void ) +{ + // Initialize thread package + if( !_glfwInitThreads() ) + { + return GL_FALSE; + } + + // Start the timer + if( !_glfwInitTimer() ) + { + _glfwTerminateThreads(); + return GL_FALSE; + } + + // Initialize joysticks + _glfwInitJoysticks(); + + // Install atexit() routine + atexit( _glfwTerminate_atexit ); + + return GL_TRUE; +} + + +//======================================================================== +// _glfwPlatformTerminate() - Close window and kill all threads +//======================================================================== + +int _glfwPlatformTerminate( void ) +{ + // Only the main thread is allowed to do this... + // TODO + + // Close OpenGL window + glfwCloseWindow(); + + // Terminate joysticks + _glfwTerminateJoysticks(); + + // Kill timer + _glfwTerminateTimer(); + + // Kill thread package + _glfwTerminateThreads(); + + return GL_TRUE; +} diff --git a/libs/glfw/lib/dos/dos_irq.s b/libs/glfw/lib/dos/dos_irq.s new file mode 100644 index 0000000..5ff80da --- /dev/null +++ b/libs/glfw/lib/dos/dos_irq.s @@ -0,0 +1,246 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: dos_irq.s +// Platform: DOS +// API version: 2.4 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2004 Camilla Berglund +// +// 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. +// +//======================================================================== + + .file "dos_irq.S" + + .text + + +#define IRQ_STACK_SIZE 16384 + +#define IRQ_WRAPPER_LEN (__irq_wrapper_1-__irq_wrapper_0) +#define IRQ_OLD (__irq_old_0-__irq_wrapper_0) +#define IRQ_HOOK (__irq_hook_0-__irq_wrapper_0) +#define IRQ_STACK (__irq_stack_0-__irq_wrapper_0) + + +//======================================================================== +// common +//======================================================================== + + .balign 4 +common: + movw $0x0400, %ax + int $0x31 + + movl %ss:8(%ebp), %ebx + cmpl $15, %ebx + jbe 0f +fail: + orl $-1, %eax + popl %edi + popl %ebx + leave + ret + + 0: + movl %ebx, %edi + imull $IRQ_WRAPPER_LEN, %edi + addl $__irq_wrapper_0, %edi + + cmpb $7, %bl + jbe 1f + movb %dl, %dh + subb $8, %dh + 1: + addb %dh, %bl + ret + + +//======================================================================== +// _glfwInstallDOSIrq() +//======================================================================== + + .balign 4 + .global __glfwInstallDOSIrq +__glfwInstallDOSIrq: + pushl %ebp + movl %esp, %ebp + pushl %ebx + pushl %edi + + call common + + cmpl $0, IRQ_HOOK(%edi) + jne fail + + pushl $IRQ_WRAPPER_LEN + pushl %edi + call __go32_dpmi_lock_code + addl $8, %esp + testl %eax, %eax + jnz fail + +/* OLD >> + pushl $IRQ_STACK_SIZE + call _pc_malloc + popl %edx + testl %eax, %eax + jz fail + addl %edx, %eax + movl %eax, IRQ_STACK(%edi) +<< OLD */ + +/* MG: NEW >> */ + pushl $IRQ_STACK_SIZE + call _malloc + popl %edx + testl %eax, %eax + jz fail + + pushl %edx + pushl %eax + call __go32_dpmi_lock_data + addl $8, %esp + testl %eax, %eax + jnz fail + subl $8, %esp + popl %eax + popl %edx + + addl %edx, %eax + movl %eax, IRQ_STACK(%edi) +/* << NEW */ + + movl ___djgpp_ds_alias, %eax + movl %eax, IRQ_STACK+4(%edi) + + movl %ss:12(%ebp), %eax + movl %eax, IRQ_HOOK(%edi) + + movw $0x0204, %ax + int $0x31 + movl %edx, IRQ_OLD(%edi) + movw %cx, IRQ_OLD+4(%edi) + movw $0x0205, %ax + movl %edi, %edx + movl %cs, %ecx + int $0x31 + +done: + xorl %eax, %eax + popl %edi + popl %ebx + leave + ret + + +//======================================================================== +// _glfwRemoveDOSIrq() +//======================================================================== + .balign 4 + .global __glfwRemoveDOSIrq +__glfwRemoveDOSIrq: + pushl %ebp + movl %esp, %ebp + pushl %ebx + pushl %edi + + call common + + cmpl $0, IRQ_HOOK(%edi) + je fail + + movl $0, IRQ_HOOK(%edi) + + movw $0x0205, %ax + movl IRQ_OLD(%edi), %edx + movl IRQ_OLD+4(%edi), %ecx + int $0x31 + + movl IRQ_STACK(%edi), %eax + subl $IRQ_STACK_SIZE, %eax + pushl %eax + call _free + popl %eax + + jmp done + + +//======================================================================== +// IRQ wrapper code for all 16 different IRQs +//======================================================================== + +#define WRAPPER(x) ; \ + .balign 4 ; \ +__irq_wrapper_##x: ; \ + pushal ; \ + pushl %ds ; \ + pushl %es ; \ + pushl %fs ; \ + pushl %gs ; \ + movl %ss, %ebx ; \ + movl %esp, %esi ; \ + lss %cs:__irq_stack_##x, %esp ; \ + pushl %ss ; \ + pushl %ss ; \ + popl %es ; \ + popl %ds ; \ + movl ___djgpp_dos_sel, %fs ; \ + pushl %fs ; \ + popl %gs ; \ + call *__irq_hook_##x ; \ + movl %ebx, %ss ; \ + movl %esi, %esp ; \ + testl %eax, %eax ; \ + popl %gs ; \ + popl %fs ; \ + popl %es ; \ + popl %ds ; \ + popal ; \ + jz __irq_ignore_##x ; \ +__irq_bypass_##x: ; \ + ljmp *%cs:__irq_old_##x ; \ +__irq_ignore_##x: ; \ + iret ; \ + .balign 4 ; \ +__irq_old_##x: ; \ + .long 0, 0 ; \ +__irq_hook_##x: ; \ + .long 0 ; \ +__irq_stack_##x: ; \ + .long 0, 0 + + WRAPPER(0); + WRAPPER(1); + WRAPPER(2); + WRAPPER(3); + WRAPPER(4); + WRAPPER(5); + WRAPPER(6); + WRAPPER(7); + WRAPPER(8); + WRAPPER(9); + WRAPPER(10); + WRAPPER(11); + WRAPPER(12); + WRAPPER(13); + WRAPPER(14); + WRAPPER(15); diff --git a/libs/glfw/lib/dos/dos_joystick.c b/libs/glfw/lib/dos/dos_joystick.c new file mode 100644 index 0000000..4cd5ed2 --- /dev/null +++ b/libs/glfw/lib/dos/dos_joystick.c @@ -0,0 +1,94 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: dos_joystick.c +// Platform: DOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwInitJoysticks() - Initialize joystick interface +//======================================================================== + +void _glfwInitJoysticks( void ) +{ + // TODO +} + + +//======================================================================== +// _glfwTerminateJoysticks() - Close all opened joystick handles +//======================================================================== + +void _glfwTerminateJoysticks( void ) +{ + // TODO +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformGetJoystickParam() - Determine joystick capabilities +//======================================================================== + +int _glfwPlatformGetJoystickParam( int joy, int param ) +{ + // TODO + return 0; +} + + +//======================================================================== +// _glfwPlatformGetJoystickPos() - Get joystick axis positions +//======================================================================== + +int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes ) +{ + // TODO + return 0; +} + + +//======================================================================== +// _glfwPlatformGetJoystickButtons() - Get joystick button states +//======================================================================== + +int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, + int numbuttons ) +{ + // TODO + return 0; +} diff --git a/libs/glfw/lib/dos/dos_keyboard.c b/libs/glfw/lib/dos/dos_keyboard.c new file mode 100644 index 0000000..071d626 --- /dev/null +++ b/libs/glfw/lib/dos/dos_keyboard.c @@ -0,0 +1,694 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: dos_keyboard.c +// Platform: DOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//======================================================================== +// Most of the code in this source file is based on two sources of +// information: +// 1) The Allegro DOS keyboard driver (allegro\src\dos\dkeybd.c) +// 2) The document "IBM PC KEYBOARD INFORMATION FOR SOFTWARE DEVELOPERS" +// by Chris Giese. +//======================================================================== + +//======================================================================== +// Unicode in GLFW for DOS +// ======================= +// +// Keyboard mapping tables in GLFW for DOS use Unicode encoding. The codes +// are 16-bit unsigned integers, and thus do not cover the entire Unicode +// standard (but a great deal is covered). +// +// Keys or characters that are not supported by GLFW (for instance the +// PrtScr or Windows keys that are found on most PC keyboards) are coded +// with 0xFFFF ("not a character" according to the Unicode standard). +// +// GLFW special keys, as defined in glfw.h (e.g. GLFW_KEY_LSHIFT) are +// encoded in the private area of the Unicode standard (i.e. codes in the +// range E000-F8FF). The encoding is as follows: +// +// unicode = 0xE000 + glfw_key - GLFW_KEY_SPECIAL; +// +// Every key in the keyboard matrix has a description consisting of four +// entries: Normal, Shift, Caps, and AltGr. +//======================================================================== + +//======================================================================== +// Definitions +//======================================================================== + +// Keyboard interrupt number +#define KEYB_IRQ 1 + +// Qualifier flags +#define QUAL_SCROLOCK 0x0001 // Same bits as for controller cmd 0xED +#define QUAL_NUMLOCK 0x0002 // (set leds) +#define QUAL_CAPSLOCK 0x0004 // --"-- +#define QUAL_LSHIFT 0x0008 +#define QUAL_RSHIFT 0x0010 +#define QUAL_LALT 0x0020 +#define QUAL_RALT 0x0040 +#define QUAL_LCTRL 0x0080 +#define QUAL_RCTRL 0x0100 + +// Qualifier groups +#define QUAL_MODIFIERS (QUAL_LSHIFT|QUAL_RSHIFT|QUAL_LALT|QUAL_RALT|\ + QUAL_LCTRL|QUAL_RCTRL) +#define QUAL_LEDS (QUAL_SCROLOCK|QUAL_NUMLOCK|QUAL_CAPSLOCK) + + +// Additional non-GLFW keys, defined here for internal processing only +#define GLFW_KEY_CAPSLOCK (GLFW_KEY_SPECIAL+0x0200) +#define GLFW_KEY_NUMLOCK (GLFW_KEY_SPECIAL+0x0201) +#define GLFW_KEY_SCROLOCK (GLFW_KEY_SPECIAL+0x0202) +#define GLFW_KEY_PAUSE (GLFW_KEY_SPECIAL+0x0203) + +// Keymap entry definition +struct key { + unsigned short Normal, Caps, Shift, AltGr; +}; + +// Keymap entry macros +#define NOCHAR(x) {x+0xDF00,x+0xDF00,x+0xDF00,x+0xDF00} +#define UNDEFINED {0xFFFF,0xFFFF,0xFFFF,0xFFFF} + + +//======================================================================== +// Global variables +//======================================================================== + +static struct { + int volatile KeyEnhanced, KeyPauseLoop, Qualifiers; + int LedsOK; + int Interrupt; +} _glfwKeyDrv; + +static int _glfwKeyboardInstalled = 0; + + + +//======================================================================== +// scancode_to_key_us[] - Mapping table for US keyboard layout (XT) +//======================================================================== + +static struct key scancode_to_key_us[256] = +{ +/* Standard hardware scancodes */ +/* 0x00 */ UNDEFINED, NOCHAR(GLFW_KEY_ESC), +/* 0x02 */ {'1','1','!',0xFFFF}, {'2','2','@',0xFFFF}, +/* 0x04 */ {'3','3','#',0xFFFF}, {'4','4','$',0xFFFF}, +/* 0x06 */ {'5','5','%',0xFFFF}, {'6','6','^',0xFFFF}, +/* 0x08 */ {'7','7','&',0xFFFF}, {'8','8','*',0xFFFF}, +/* 0x0A */ {'9','9','(',0xFFFF}, {'0','0',')',0xFFFF}, +/* 0x0C */ {'-','-','_',0xFFFF}, {'=','=','+',0xFFFF}, +/* 0x0E */ NOCHAR(GLFW_KEY_BACKSPACE), NOCHAR(GLFW_KEY_TAB), +/* 0x10 */ {'q','Q','Q',0xFFFF}, {'w','W','W',0xFFFF}, +/* 0x12 */ {'e','E','E',0xFFFF}, {'r','R','R',0xFFFF}, +/* 0x14 */ {'t','T','T',0xFFFF}, {'y','Y','Y',0xFFFF}, +/* 0x16 */ {'u','U','U',0xFFFF}, {'i','I','I',0xFFFF}, +/* 0x18 */ {'o','O','O',0xFFFF}, {'p','P','P',0xFFFF}, +/* 0x1A */ {'[','[','{',0xFFFF}, {']',']','}',0xFFFF}, +/* 0x1C */ NOCHAR(GLFW_KEY_ENTER), NOCHAR(GLFW_KEY_LCTRL), +/* 0x1E */ {'a','A','A',0xFFFF}, {'s','S','S',0xFFFF}, +/* 0x20 */ {'d','D','D',0xFFFF}, {'f','F','F',0xFFFF}, +/* 0x22 */ {'g','G','G',0xFFFF}, {'h','H','H',0xFFFF}, +/* 0x24 */ {'j','J','J',0xFFFF}, {'k','K','K',0xFFFF}, +/* 0x26 */ {'l','L','L',0xFFFF}, {';',';',':',0xFFFF}, +/* 0x28 */ {'\'','\'','"',0xFFFF}, {'\\','\\','|',0xFFFF}, +/* 0x2A */ NOCHAR(GLFW_KEY_LSHIFT), {'\\','\\','|',0xFFFF}, +/* 0x2C */ {'z','Z','Z',0xFFFF}, {'x','X','X',0xFFFF}, +/* 0x2E */ {'c','C','C',0xFFFF}, {'v','V','V',0xFFFF}, +/* 0x30 */ {'b','B','B',0xFFFF}, {'n','N','N',0xFFFF}, +/* 0x32 */ {'m','M','M',0xFFFF}, {',',',','<',0xFFFF}, +/* 0x34 */ {'.','.','>',0xFFFF}, {'/','/','?',0xFFFF}, +/* 0x36 */ NOCHAR(GLFW_KEY_RSHIFT), NOCHAR(GLFW_KEY_KP_MULTIPLY), +/* 0x38 */ NOCHAR(GLFW_KEY_LALT), {' ',' ',' ',0xFFFF}, +/* 0x3A */ NOCHAR(GLFW_KEY_CAPSLOCK), NOCHAR(GLFW_KEY_F1), +/* 0x3C */ NOCHAR(GLFW_KEY_F2), NOCHAR(GLFW_KEY_F3), +/* 0x3E */ NOCHAR(GLFW_KEY_F4), NOCHAR(GLFW_KEY_F5), +/* 0x40 */ NOCHAR(GLFW_KEY_F6), NOCHAR(GLFW_KEY_F7), +/* 0x42 */ NOCHAR(GLFW_KEY_F8), NOCHAR(GLFW_KEY_F9), +/* 0x44 */ NOCHAR(GLFW_KEY_F10), NOCHAR(GLFW_KEY_NUMLOCK), +/* 0x46 */ NOCHAR(GLFW_KEY_SCROLOCK), NOCHAR(GLFW_KEY_KP_7), +/* 0x48 */ NOCHAR(GLFW_KEY_KP_8), NOCHAR(GLFW_KEY_KP_9), +/* 0x4A */ NOCHAR(GLFW_KEY_KP_SUBTRACT), NOCHAR(GLFW_KEY_KP_4), +/* 0x4C */ NOCHAR(GLFW_KEY_KP_5), NOCHAR(GLFW_KEY_KP_6), +/* 0x4E */ NOCHAR(GLFW_KEY_KP_ADD), NOCHAR(GLFW_KEY_KP_1), +/* 0x50 */ NOCHAR(GLFW_KEY_KP_2), NOCHAR(GLFW_KEY_KP_3), +/* 0x52 */ NOCHAR(GLFW_KEY_KP_0), NOCHAR(GLFW_KEY_KP_DECIMAL), +/* 0x54 */ UNDEFINED, /* PRTSCR */ UNDEFINED, +/* 0x56 */ {'\\','\\','|',0xFFFF}, NOCHAR(GLFW_KEY_F11), +/* 0x58 */ NOCHAR(GLFW_KEY_F12), UNDEFINED, +/* 0x5A */ UNDEFINED, UNDEFINED, /* LWIN */ +/* 0x5C */ UNDEFINED, /* RWIN */ UNDEFINED, /* MENU */ +/* 0x5E */ UNDEFINED, UNDEFINED, +/* 0x60 */ UNDEFINED, UNDEFINED, +/* 0x62 */ UNDEFINED, UNDEFINED, +/* 0x64 */ UNDEFINED, UNDEFINED, +/* 0x66 */ UNDEFINED, UNDEFINED, +/* 0x68 */ UNDEFINED, UNDEFINED, +/* 0x6A */ UNDEFINED, UNDEFINED, +/* 0x6C */ UNDEFINED, UNDEFINED, +/* 0x6E */ UNDEFINED, UNDEFINED, +/* 0x70 */ UNDEFINED, /* KANA */ UNDEFINED, +/* 0x72 */ UNDEFINED, UNDEFINED, /* ABNT_C1 */ +/* 0x74 */ UNDEFINED, UNDEFINED, +/* 0x76 */ UNDEFINED, UNDEFINED, +/* 0x78 */ UNDEFINED, UNDEFINED, /* CONVERT */ +/* 0x7A */ UNDEFINED, UNDEFINED, /* NOCONVERT */ +/* 0x7C */ UNDEFINED, UNDEFINED, /* YEN */ +/* 0x7E */ UNDEFINED, UNDEFINED, + +/* Extended hardware scancodes (index=scancode+0x80) */ +/* 0xE000 */ UNDEFINED, NOCHAR(GLFW_KEY_ESC), +/* 0xE002 */ {'1','1','!',0xFFFF}, {'2','2','@',0xFFFF}, +/* 0xE004 */ {'3','3','#',0xFFFF}, {'4','4','$',0xFFFF}, +/* 0xE006 */ {'5','5','%',0xFFFF}, {'6','6','^',0xFFFF}, +/* 0xE008 */ {'7','7','&',0xFFFF}, {'8','8','*',0xFFFF}, +/* 0xE00A */ {'9','9','(',0xFFFF}, {'0','0',')',0xFFFF}, +/* 0xE00C */ {'-','-','_',0xFFFF}, {'=','=','+',0xFFFF}, +/* 0xE00E */ NOCHAR(GLFW_KEY_BACKSPACE), NOCHAR(GLFW_KEY_TAB), +/* 0xE010 */ UNDEFINED, /* CIRCUMFLEX */ UNDEFINED, /* AT */ +/* 0xE012 */ UNDEFINED, /* COLON2 */ {'r','R','R',0xFFFF}, +/* 0xE014 */ UNDEFINED, /* KANJI */ {'y','Y','Y',0xFFFF}, +/* 0xE016 */ {'u','U','U',0xFFFF}, {'i','I','I',0xFFFF}, +/* 0xE018 */ {'o','O','O',0xFFFF}, {'p','P','P',0xFFFF}, +/* 0xE01A */ {'[','[','{',0xFFFF}, {']',']','}',0xFFFF}, +/* 0xE01C */ NOCHAR(GLFW_KEY_KP_ENTER), NOCHAR(GLFW_KEY_RCTRL), +/* 0xE01E */ {'a','A','A',0xFFFF}, {'s','S','S',0xFFFF}, +/* 0xE020 */ {'d','D','D',0xFFFF}, {'f','F','F',0xFFFF}, +/* 0xE022 */ {'g','G','G',0xFFFF}, {'h','H','H',0xFFFF}, +/* 0xE024 */ {'j','J','J',0xFFFF}, {'k','K','K',0xFFFF}, +/* 0xE026 */ {'l','L','L',0xFFFF}, {';',';',':',0xFFFF}, +/* 0xE028 */ {'\'','\'','"',0xFFFF}, {'`','`','~',0xFFFF}, +/* 0xE02A */ UNDEFINED, {'\\','\\','|',0xFFFF}, +/* 0xE02C */ {'z','Z','Z',0xFFFF}, {'x','X','X',0xFFFF}, +/* 0xE02E */ {'c','C','C',0xFFFF}, {'v','V','V',0xFFFF}, +/* 0xE030 */ {'b','B','B',0xFFFF}, {'n','N','N',0xFFFF}, +/* 0xE032 */ {'m','M','M',0xFFFF}, {',',',','<',0xFFFF}, +/* 0xE034 */ {'.','.','>',0xFFFF}, NOCHAR(GLFW_KEY_KP_DIVIDE), +/* 0xE036 */ UNDEFINED, UNDEFINED, /* PRTSCR */ +/* 0xE038 */ NOCHAR(GLFW_KEY_RALT), {' ',' ',' ',0xFFFF}, +/* 0xE03A */ NOCHAR(GLFW_KEY_CAPSLOCK), NOCHAR(GLFW_KEY_F1), +/* 0xE03C */ NOCHAR(GLFW_KEY_F2), NOCHAR(GLFW_KEY_F3), +/* 0xE03E */ NOCHAR(GLFW_KEY_F4), NOCHAR(GLFW_KEY_F5), +/* 0xE040 */ NOCHAR(GLFW_KEY_F6), NOCHAR(GLFW_KEY_F7), +/* 0xE042 */ NOCHAR(GLFW_KEY_F8), NOCHAR(GLFW_KEY_F9), +/* 0xE044 */ NOCHAR(GLFW_KEY_F10), NOCHAR(GLFW_KEY_NUMLOCK), +/* 0xE046 */ NOCHAR(GLFW_KEY_PAUSE), NOCHAR(GLFW_KEY_HOME), +/* 0xE048 */ NOCHAR(GLFW_KEY_UP), NOCHAR(GLFW_KEY_PAGEUP), +/* 0xE04A */ NOCHAR(GLFW_KEY_KP_SUBTRACT), NOCHAR(GLFW_KEY_LEFT), +/* 0xE04C */ NOCHAR(GLFW_KEY_KP_5), NOCHAR(GLFW_KEY_RIGHT), +/* 0xE04E */ NOCHAR(GLFW_KEY_KP_ADD), NOCHAR(GLFW_KEY_END), +/* 0xE050 */ NOCHAR(GLFW_KEY_DOWN), NOCHAR(GLFW_KEY_PAGEDOWN), +/* 0xE052 */ NOCHAR(GLFW_KEY_INSERT), NOCHAR(GLFW_KEY_DEL), +/* 0xE054 */ UNDEFINED, /* PRTSCR */ UNDEFINED, +/* 0xE056 */ {'\\','\\','|',0xFFFF}, NOCHAR(GLFW_KEY_F11), +/* 0xE058 */ NOCHAR(GLFW_KEY_F12), UNDEFINED, +/* 0xE05A */ UNDEFINED, UNDEFINED, /* LWIN */ +/* 0xE05C */ UNDEFINED, /* RWIN */ UNDEFINED, /* MENU */ +/* 0xE05E */ UNDEFINED, UNDEFINED, +/* 0xE060 */ UNDEFINED, UNDEFINED, +/* 0xE062 */ UNDEFINED, UNDEFINED, +/* 0xE064 */ UNDEFINED, UNDEFINED, +/* 0xE066 */ UNDEFINED, UNDEFINED, +/* 0xE068 */ UNDEFINED, UNDEFINED, +/* 0xE06A */ UNDEFINED, UNDEFINED, +/* 0xE06C */ UNDEFINED, UNDEFINED, +/* 0xE06E */ UNDEFINED, UNDEFINED, +/* 0xE070 */ UNDEFINED, UNDEFINED, +/* 0xE072 */ UNDEFINED, UNDEFINED, +/* 0xE074 */ UNDEFINED, UNDEFINED, +/* 0xE076 */ UNDEFINED, UNDEFINED, +/* 0xE078 */ UNDEFINED, UNDEFINED, +/* 0xE07A */ UNDEFINED, UNDEFINED, +/* 0xE07C */ UNDEFINED, UNDEFINED, +/* 0xE07E */ UNDEFINED, UNDEFINED +}; + + + +//************************************************************************ +//**** Keyboard Decoding ************************************************* +//************************************************************************ + +//======================================================================== +// _glfwMapRawKey() - Map a raw scancode to a Unicode character +//======================================================================== + +static int _glfwMapRawKey( int scancode, int qualifiers ) +{ + struct key *keyvals; + int keycode; + + // Get possible key codings for this scancode + keyvals = &scancode_to_key_us[ scancode ]; + + // Select Unicode code depending on qualifiers + if( qualifiers & QUAL_RALT ) + { + keycode = keyvals->AltGr; + } + else if( qualifiers & (QUAL_LSHIFT|QUAL_RSHIFT) ) + { + if( (qualifiers & QUAL_CAPSLOCK) && + (keyvals->Normal != keyvals->Caps) ) + { + keycode = keyvals->Normal; + } + else + { + keycode = keyvals->Shift; + } + } + else if( qualifiers & QUAL_CAPSLOCK ) + { + keycode = keyvals->Caps; + } + else + { + keycode = keyvals->Normal; + } + + // Special interpretations + if( keycode >= 0xE000 && keycode <= 0xE8FF ) + { + keycode = -(keycode - 0xE000 + GLFW_KEY_SPECIAL); + } + else if( keycode == 0xFFFF ) + { + keycode = 0; + } + + return keycode; +} ENDOFUNC(_glfwMapRawKey) + + +//======================================================================== +// _glfwCreateKeyEvent() - Add a keyboard event to the event FIFO +//======================================================================== + +static void _glfwCreateKeyEvent( int scancode, int qualifiers, int action ) +{ + _GLFWdosevent event; + struct key_event *key = &event.Key; + + // Create event + key->Type = _GLFW_DOS_KEY_EVENT; + key->Key = _glfwMapRawKey( scancode, qualifiers ); + key->KeyNoMod = _glfwMapRawKey( scancode, QUAL_CAPSLOCK ); + key->Action = action; + + // Post event + _glfwPostDOSEvent( &event ); +} ENDOFUNC(_glfwCreateKeyEvent) + + + +//************************************************************************ +//**** Keyboard Communication ******************************************** +//************************************************************************ + +//======================================================================== +// _glfwWaitForReadReady() / _glfwWaitForWriteReady() +// Wait for the keyboard controller to set the ready-for-read/write bit +//======================================================================== + +static int _glfwWaitForReadReady( void ) +{ + int timeout = 16384; + while( (timeout>0) && (!(inportb(0x64)&1)) ) timeout--; + return timeout > 0; +} ENDOFUNC(_glfwWaitForReadReady) + +static int _glfwWaitForWriteReady( void ) +{ + int timeout = 4096; + while( (timeout>0) && (inportb(0x64)&2) ) timeout--; + return timeout > 0; +} ENDOFUNC(_glfwWaitForWriteReady) + + +//======================================================================== +// _glfwSendKeyboardByte() - Send a byte to the keyboard controller +//======================================================================== + +static int _glfwSendKeyboardByte( unsigned char data ) +{ + int resends = 4; + int timeout, ret; + + do + { + if( !_glfwWaitForWriteReady() ) return 0; + + outportb( 0x60, data ); + + timeout = 4096; + while( --timeout > 0 ) + { + if( !_glfwWaitForReadReady() ) return 0; + + ret = inportb( 0x60 ); + if( ret == 0xFA ) return 1; + if( ret == 0xFE ) break; + } + } + while( (resends-- > 0) && (timeout > 0) ); + + return 0; +} ENDOFUNC(_glfwSendKeyboardByte) + + +//======================================================================== +// _glfwSendKeyboardCommand() - Send a command sequence to the keyboard +//======================================================================== + +static int _glfwSendKeyboardCommand( unsigned char *cmd, int count ) +{ + int i, ok = 1; + + // Force atomic keyboard communication session + if( !_glfwKeyDrv.Interrupt ) DISABLE(); + + // Send command sequence + for( i = 0; i < count; ++ i ) + { + if( !_glfwSendKeyboardByte( cmd[i] ) ) + { + ok = 0; + break; + } + } + + // Send "clear output buffer, enable keyboard" + _glfwSendKeyboardByte( 0xF4 ); + + if( !_glfwKeyDrv.Interrupt ) ENABLE(); + + return ok; +} ENDOFUNC(_glfwSendKeyboardCommand) + + + +//************************************************************************ +//**** Miscellaneous Handling ******************************************** +//************************************************************************ + +//======================================================================== +// _glfwUpdateLeds() - Update keyboard leds +//======================================================================== + +static void _glfwUpdateLeds( int qualifiers ) +{ + unsigned char cmd[2]; + cmd[0] = 0xED; + cmd[1] = qualifiers & 7; + _glfwSendKeyboardCommand( cmd, 2 ); +} ENDOFUNC(_glfwUpdateLeds) + + + +//************************************************************************ +//**** Keyboard Interrupt Handler **************************************** +//************************************************************************ + +//======================================================================== +// _glfwHandleCode() - Handle new scancode event +//======================================================================== + +static void _glfwHandleCode( int scancode, int keypress ) +{ + if( scancode == GLFW_KEY_PAUSE && keypress ) + { + // Pause + _glfwCreateKeyEvent( GLFW_KEY_PAUSE, 0, GLFW_PRESS ); + } + else if( scancode ) + { + int tmp, qualifier; + + // Check if this is a qualifier key + tmp = scancode_to_key_us[scancode].Normal; + tmp += GLFW_KEY_SPECIAL - 0xE000; + if( tmp == GLFW_KEY_LSHIFT ) qualifier = QUAL_LSHIFT; + else if( tmp == GLFW_KEY_RSHIFT ) qualifier = QUAL_RSHIFT; + else if( tmp == GLFW_KEY_LCTRL ) qualifier = QUAL_LCTRL; + else if( tmp == GLFW_KEY_RCTRL ) qualifier = QUAL_RCTRL; + else if( tmp == GLFW_KEY_LALT ) qualifier = QUAL_LALT; + else if( tmp == GLFW_KEY_RALT ) qualifier = QUAL_RALT; + else if( tmp == GLFW_KEY_NUMLOCK ) qualifier = QUAL_NUMLOCK; + else if( tmp == GLFW_KEY_SCROLOCK ) qualifier = QUAL_SCROLOCK; + else if( tmp == GLFW_KEY_CAPSLOCK ) qualifier = QUAL_CAPSLOCK; + else qualifier = 0; + + if( keypress ) + { + // Key press + if( qualifier & QUAL_MODIFIERS ) + { + _glfwKeyDrv.Qualifiers |= qualifier; + } + if( !(qualifier & QUAL_LEDS) ) + { + _glfwCreateKeyEvent( scancode, _glfwKeyDrv.Qualifiers, + GLFW_PRESS ); + } + else + { + _glfwKeyDrv.Qualifiers ^= qualifier; + _glfwUpdateLeds( _glfwKeyDrv.Qualifiers ); + } + } + else + { + // Key release + if( qualifier & QUAL_MODIFIERS ) + { + _glfwKeyDrv.Qualifiers &= ~qualifier; + } + if( !(qualifier & QUAL_LEDS) ) + { + _glfwCreateKeyEvent( scancode, _glfwKeyDrv.Qualifiers, + GLFW_RELEASE ); + } + } + } +} ENDOFUNC(_glfwHandleCode) + + +//======================================================================== +// _glfwKeyInterrupt() - Keyboard interrupt routine +//======================================================================== + +static int _glfwKeyInterrupt( void ) +{ + unsigned char keycode, scancode; + + _glfwKeyDrv.Interrupt ++; + + keycode = inportb( 0x60 ); + + if( keycode <= 0xE1 ) + { + if( _glfwKeyDrv.KeyPauseLoop ) + { + if( ! --_glfwKeyDrv.KeyPauseLoop ) + _glfwHandleCode( GLFW_KEY_PAUSE, 1 ); + } + else + { + switch( keycode ) + { + case 0xE0: + _glfwKeyDrv.KeyEnhanced = 1; + break; + case 0xE1: + _glfwKeyDrv.KeyPauseLoop = 5; + break; + default: + scancode = keycode & 0x7F; + if( _glfwKeyDrv.KeyEnhanced ) + { + scancode |= 0x80; + _glfwKeyDrv.KeyEnhanced = 0; + } + _glfwHandleCode( scancode, !(keycode & 0x80) ); + } + } + } + + _glfwKeyDrv.Interrupt --; + + if( ((keycode==0x4F) || (keycode==0x53)) && + (_glfwKeyDrv.Qualifiers & QUAL_LCTRL) && + (_glfwKeyDrv.Qualifiers & QUAL_RALT) ) + { + // Hack alert: + // Only SIGINT (but not Ctrl-Break) calls the destructors and will + // safely clean up + asm( + "movb $0x79,%%al\n\t" + "call ___djgpp_hw_exception\n\t" + : + : + : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory" + ); + } + + asm( + "inb $0x61,%%al\n\t" + "movb %%al,%%ah\n\t" + "orb $0x80,%%al\n\t" + "outb %%al,$0x61\n\t" + "xchgb %%al,%%ah\n\t" + "outb %%al,$0x61\n\t" + "movb $0x20,%%al\n\t" + "outb %%al,$0x20\n\t" + : + : + : "%eax" + ); + + return 0; +} ENDOFUNC(_glfwKeyInterrupt) + + + +//************************************************************************ +//**** Keyboard driver interface functions **** +//************************************************************************ + +//======================================================================== +// _glfwInitKeyboard() - Initialize keyboard driver +//======================================================================== + +int _glfwInitKeyboard( void ) +{ + int s1, s2, s3; + + if( _glfwKeyboardInstalled ) + { + return 0; + } + + // Init keyboard state + _glfwKeyDrv.LedsOK = 1; + _glfwKeyDrv.Interrupt = 0; + _glfwKeyDrv.KeyEnhanced = 0; + _glfwKeyDrv.KeyPauseLoop = 0; + + // Lock data buffers + LOCKDATA(_glfwKeyboardInstalled); + LOCKDATA(_glfwKeyDrv); + LOCKDATA(scancode_to_key_us); + + // Lock functions + LOCKFUNC(_glfwMapRawKey); + LOCKFUNC(_glfwCreateKeyEvent); + LOCKFUNC(_glfwWaitForReadReady); + LOCKFUNC(_glfwWaitForWriteReady); + LOCKFUNC(_glfwSendKeyboardByte); + LOCKFUNC(_glfwSendKeyboardCommand); + LOCKFUNC(_glfwUpdateLeds); + LOCKFUNC(_glfwHandleCode); + LOCKFUNC(_glfwKeyInterrupt); + + _farsetsel( __djgpp_dos_sel ); + _farnspokew( 0x41c, _farnspeekw(0x41a) ); + + // Get current state of key qualifiers + s1 = _farnspeekb( 0x417 ); + s2 = _farnspeekb( 0x418 ); + s3 = _farnspeekb( 0x496 ); + _glfwKeyDrv.Qualifiers = 0; + if( s1 & 1 ) _glfwKeyDrv.Qualifiers |= QUAL_RSHIFT; + if( s1 & 2 ) _glfwKeyDrv.Qualifiers |= QUAL_LSHIFT; + if( s2 & 1 ) _glfwKeyDrv.Qualifiers |= QUAL_LCTRL; + if( s2 & 2 ) _glfwKeyDrv.Qualifiers |= QUAL_LALT; + if( s3 & 4 ) _glfwKeyDrv.Qualifiers |= QUAL_RCTRL; + if( s3 & 8 ) _glfwKeyDrv.Qualifiers |= QUAL_RALT; + if( s1 & 16 ) _glfwKeyDrv.Qualifiers |= QUAL_SCROLOCK; + if( s1 & 32 ) _glfwKeyDrv.Qualifiers |= QUAL_NUMLOCK; + if( s1 & 64 ) _glfwKeyDrv.Qualifiers |= QUAL_CAPSLOCK; + _glfwUpdateLeds( _glfwKeyDrv.Qualifiers ); + + // Install keyboard interrupt handler + if( _glfwInstallDOSIrq( KEYB_IRQ, _glfwKeyInterrupt ) ) + { + return 0; + } + + _glfwKeyboardInstalled = 1; + + return 1; +} + + +//======================================================================== +// _glfwTerminateKeyboard() - Terminate keyboard driver +//======================================================================== + +void _glfwTerminateKeyboard( void ) +{ + int s1, s2, s3; + + if( !_glfwKeyboardInstalled ) + { + return; + } + + _glfwKeyboardInstalled = 0; + + // Uninstall keyboard interrupt handler + _glfwRemoveDOSIrq( KEYB_IRQ ); + + _farsetsel( __djgpp_dos_sel ); + _farnspokew( 0x41c, _farnspeekw(0x41a) ); + + // Set current state of key qualifiers + s1 = _farnspeekb( 0x417 ) & 0x80; + s2 = _farnspeekb( 0x418 ) & 0xFC; + s3 = _farnspeekb( 0x496 ) & 0xF3; + if(_glfwKeyDrv.Qualifiers & QUAL_RSHIFT) s1 |= 1; + if(_glfwKeyDrv.Qualifiers & QUAL_LSHIFT) s1 |= 2; + if(_glfwKeyDrv.Qualifiers & QUAL_LCTRL) {s2 |= 1; s1 |= 4;} + if(_glfwKeyDrv.Qualifiers & QUAL_LALT) {s2 |= 2; s1 |= 8;} + if(_glfwKeyDrv.Qualifiers & QUAL_RCTRL) {s3 |= 4; s1 |= 4;} + if(_glfwKeyDrv.Qualifiers & QUAL_RALT) {s3 |= 8; s1 |= 8;} + if(_glfwKeyDrv.Qualifiers & QUAL_SCROLOCK) s1 |= 16; + if(_glfwKeyDrv.Qualifiers & QUAL_NUMLOCK) s1 |= 32; + if(_glfwKeyDrv.Qualifiers & QUAL_CAPSLOCK) s1 |= 64; + _farnspokeb( 0x417, s1 ); + _farnspokeb( 0x418, s2 ); + _farnspokeb( 0x496, s3 ); + _glfwUpdateLeds( _glfwKeyDrv.Qualifiers ); +} diff --git a/libs/glfw/lib/dos/dos_mouse.c b/libs/glfw/lib/dos/dos_mouse.c new file mode 100644 index 0000000..7c23354 --- /dev/null +++ b/libs/glfw/lib/dos/dos_mouse.c @@ -0,0 +1,337 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: dos_mouse.c +// Platform: DOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + +//======================================================================== +// Most of the code in this source file is based on the mouse driver in +// Daniel Borca's GLUT implementation for DOS/MESA. +//======================================================================== + +//======================================================================== +// Definitions +//======================================================================== + +#define _GLFW_MOUSE_STACK_SIZE 16384 + + +// Assembler function prototypes +extern void _glfwMouseWrap( void ); +extern int _glfwMouseWrap_end[]; + + +//======================================================================== +// Global variables +//======================================================================== + +static int _glfwMouseInstalled = 0; + +static struct { + long Callback; + int Emulate3; + int OldX, OldY, OldB; + __dpmi_regs Regs; +} _glfwMouseDrv; + + + +//************************************************************************ +//**** Mouse Interrupt *************************************************** +//************************************************************************ + +//======================================================================== +// _glfwMouseInt() - Mouse interrupt handler +//======================================================================== + +static void _glfwMouseInt( __dpmi_regs *r ) +{ + int newx, newy, dx, dy, dz, buttons; + _GLFWdosevent event; + struct mousemove_event *mousemove = &event.MouseMove; + struct mousewheel_event *mousewheel = &event.MouseWheel; + struct mousebutton_event *mousebutton = &event.MouseButton; + + // Calculate mouse deltas + newx = (signed short)r->x.si; + newy = (signed short)r->x.di; + dx = newx - _glfwMouseDrv.OldX; + dy = newy - _glfwMouseDrv.OldY; + dz = (signed char)r->h.bh; + + // Get mouse buttons status + buttons = r->h.bl; + + // Emulate 3rd mouse button? + if( _glfwMouseDrv.Emulate3 ) + { + if( (buttons & 3) == 3 ) + { + buttons = 4; + } + } + + // Mouse moved? + if( dx || dy ) + { + mousemove->Type = _GLFW_DOS_MOUSE_MOVE_EVENT; + mousemove->DeltaX = dx; + mousemove->DeltaY = dy; + _glfwPostDOSEvent( &event ); + } + + // Mouse wheel moved? + if( dz ) + { + mousewheel->Type = _GLFW_DOS_MOUSE_WHEEL_EVENT; + mousewheel->WheelDelta = dz; + _glfwPostDOSEvent( &event ); + } + + // Button state changed? + if( buttons != _glfwMouseDrv.OldB ) + { + mousebutton->Type = _GLFW_DOS_MOUSE_BUTTON_EVENT; + + // Left mouse button changed? + if( (_glfwMouseDrv.OldB & 1) && !(buttons & 1) ) + { + mousebutton->Button = GLFW_MOUSE_BUTTON_LEFT; + mousebutton->Action = GLFW_RELEASE; + _glfwPostDOSEvent( &event ); + } + else if( !(_glfwMouseDrv.OldB & 1) && (buttons & 1) ) + { + mousebutton->Button = GLFW_MOUSE_BUTTON_LEFT; + mousebutton->Action = GLFW_PRESS; + _glfwPostDOSEvent( &event ); + } + + // Right mouse button changed? + if( (_glfwMouseDrv.OldB & 2) && !(buttons & 2) ) + { + mousebutton->Button = GLFW_MOUSE_BUTTON_RIGHT; + mousebutton->Action = GLFW_RELEASE; + _glfwPostDOSEvent( &event ); + } + else if( !(_glfwMouseDrv.OldB & 2) && (buttons & 2) ) + { + mousebutton->Button = GLFW_MOUSE_BUTTON_RIGHT; + mousebutton->Action = GLFW_PRESS; + _glfwPostDOSEvent( &event ); + } + + // Middle mouse button changed? + if( (_glfwMouseDrv.OldB & 4) && !(buttons & 4) ) + { + mousebutton->Button = GLFW_MOUSE_BUTTON_MIDDLE; + mousebutton->Action = GLFW_RELEASE; + _glfwPostDOSEvent( &event ); + } + else if( !(_glfwMouseDrv.OldB & 4) && (buttons & 4) ) + { + mousebutton->Button = GLFW_MOUSE_BUTTON_MIDDLE; + mousebutton->Action = GLFW_PRESS; + _glfwPostDOSEvent( &event ); + } + + } + + // Remember old mouse state + _glfwMouseDrv.OldX = newx; + _glfwMouseDrv.OldY = newy; + _glfwMouseDrv.OldB = buttons; +} ENDOFUNC(_glfwMouseInt) + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwInitMouse() - Initialize mouse driver +//======================================================================== + +int _glfwInitMouse( void ) +{ + int buttons; + + // Already installed? + if( _glfwMouseInstalled ) + { + return 0; + } + + // Reset mouse and get status + __asm("\n\ + xorl %%eax, %%eax \n\ + int $0x33 \n\ + andl %%ebx, %%eax \n\ + movl %%eax, %0 \n\ + ":"=g" (buttons)::"%eax", "%ebx"); + if( !buttons ) + { + return 0; + } + + // Lock data and functions + LOCKDATA( _glfwMouseDrv ); + LOCKBUFF( _glfwMouseWrap_end, 8 ); + LOCKFUNC( _glfwMouseInt ); + LOCKFUNC( _glfwMouseWrap ); + + _glfwMouseWrap_end[1] = __djgpp_ds_alias; + + // Grab a locked stack + _glfwMouseWrap_end[0] = (int)malloc( _GLFW_MOUSE_STACK_SIZE ); + if( _glfwMouseWrap_end[0] == NULL ) + { + return 0; + } + LOCKBUFF( _glfwMouseWrap_end[0], _GLFW_MOUSE_STACK_SIZE ); + + // Try to hook a call-back + __asm("\n\ + pushl %%ds \n\ + pushl %%es \n\ + movw $0x0303, %%ax \n\ + pushl %%ds \n\ + pushl %%cs \n\ + popl %%ds \n\ + popl %%es \n\ + int $0x31 \n\ + popl %%es \n\ + popl %%ds \n\ + jc 0f \n\ + shll $16, %%ecx \n\ + movw %%dx, %%cx \n\ + movl %%ecx, %0 \n\ + 0: \n\ + ":"=g"(_glfwMouseDrv.Callback) + :"S" (_glfwMouseWrap), "D"(&_glfwMouseDrv.Regs) + :"%eax", "%ecx", "%edx"); + if( !_glfwMouseDrv.Callback ) + { + free( (void *)_glfwMouseWrap_end[0] ); + return 0; + } + + // Adjust stack + _glfwMouseWrap_end[0] += _GLFW_MOUSE_STACK_SIZE; + + // Install the handler + _glfwMouseDrv.Regs.x.ax = 0x000c; + _glfwMouseDrv.Regs.x.cx = 0x7f | 0x80; + _glfwMouseDrv.Regs.x.dx = _glfwMouseDrv.Callback & 0xffff; + _glfwMouseDrv.Regs.x.es = _glfwMouseDrv.Callback >> 16; + __dpmi_int( 0x33, &_glfwMouseDrv.Regs ); + + // Clear mickeys + __asm __volatile ("\n\ + movw $0xb, %%ax; \n\ + int $0x33 \n\ + ":::"%eax", "%ecx", "%edx"); + + _glfwMouseDrv.OldX = 0; + _glfwMouseDrv.OldY = 0; + _glfwMouseDrv.OldB = 0; + + // Emulate third mouse button? + _glfwMouseDrv.Emulate3 = buttons < 3; + + return 1; +} + + +//======================================================================== +// _glfwTerminateMouse() - Terminate mouse driver +//======================================================================== + +void _glfwTerminateMouse( void ) +{ + if( !_glfwMouseInstalled ) + { + return; + } + + __asm("\n\ + movl %%edx, %%ecx \n\ + shrl $16, %%ecx \n\ + movw $0x0304, %%ax \n\ + int $0x31 \n\ + movw $0x000c, %%ax \n\ + xorl %%ecx, %%ecx \n\ + int $0x33 \n\ + "::"d"(_glfwMouseDrv.Callback):"%eax", "%ecx"); + _glfwMouseDrv.Callback = 0; + + free( (void *)(_glfwMouseWrap_end[0] - _GLFW_MOUSE_STACK_SIZE) ); + + _glfwMouseInstalled = 0; +} + + + +//======================================================================== +// _glfwMouseWrap() +//======================================================================== + +// Hack alert: `_glfwMouseWrap_end' actually holds the address of stack in +// a safe data selector. + +__asm("\n\ + .text \n\ + .p2align 5,,31 \n\ + .global __glfwMouseWrap \n\ +__glfwMouseWrap: \n\ + cld \n\ + lodsl \n\ + movl %eax, %es:42(%edi) \n\ + addw $4, %es:46(%edi) \n\ + pushl %es \n\ + movl %ss, %ebx \n\ + movl %esp, %esi \n\ + lss %cs:__glfwMouseWrap_end, %esp\n\ + pushl %ss \n\ + pushl %ss \n\ + popl %es \n\ + popl %ds \n\ + movl ___djgpp_dos_sel, %fs \n\ + pushl %fs \n\ + popl %gs \n\ + pushl %edi \n\ + call __glfwMouseInt \n\ + popl %edi \n\ + movl %ebx, %ss \n\ + movl %esi, %esp \n\ + popl %es \n\ + iret \n\ + .global __glfwMouseWrap_end \n\ +__glfwMouseWrap_end:.long 0, 0"); diff --git a/libs/glfw/lib/dos/dos_thread.c b/libs/glfw/lib/dos/dos_thread.c new file mode 100644 index 0000000..269ad15 --- /dev/null +++ b/libs/glfw/lib/dos/dos_thread.c @@ -0,0 +1,267 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: dos_thread.c +// Platform: DOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwInitThreads() - Initialize GLFW thread package +//======================================================================== + +int _glfwInitThreads( void ) +{ + // TODO + _glfwThrd.First.Previous = NULL; + _glfwThrd.First.Next = NULL; + _glfwThrd.First.ID = 0; + _glfwThrd.NextID = 1; + + return 1; +} + + +//======================================================================== +// _glfwTerminateThreads() - Terminate GLFW thread package +//======================================================================== + +void _glfwTerminateThreads( void ) +{ + _GLFWthread *t, *t_next; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Kill all threads (NOTE: THE USER SHOULD WAIT FOR ALL THREADS TO + // DIE, _BEFORE_ CALLING glfwTerminate()!!!) + t = _glfwThrd.First.Next; + while( t != NULL ) + { + // Get pointer to next thread + t_next = t->Next; + + // Simply murder the process, no mercy! + // TODO + + // Free memory allocated for this thread + free( (void *) t ); + + // Select next thread in list + t = t_next; + } + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformCreateThread() - Create a new thread +//======================================================================== + +GLFWthread _glfwPlatformCreateThread( GLFWthreadfun fun, void *arg ) +{ + // TODO + return -1; +} + + +//======================================================================== +// _glfwPlatformDestroyThread() - Kill a thread. NOTE: THIS IS A VERY +// DANGEROUS OPERATION, AND SHOULD NOT BE USED EXCEPT IN EXTREME +// SITUATIONS! +//======================================================================== + +void _glfwPlatformDestroyThread( GLFWthread ID ) +{ + _GLFWthread *t, *t_wait; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Get thread information pointer + t = _glfwGetThreadPointer( ID ); + if( t == NULL ) + { + LEAVE_THREAD_CRITICAL_SECTION + return; + } + + // Simply murder the process, no mercy! + // TODO + + // Remove thread from thread list + _glfwRemoveThread( t ); + + // Signal any waiting threads that the thread has died + // TODO + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION +} + + +//======================================================================== +// _glfwPlatformWaitThread() - Wait for a thread to die +//======================================================================== + +int _glfwPlatformWaitThread( GLFWthread ID, int waitmode ) +{ + // TODO + return GL_FALSE; +} + + +//======================================================================== +// _glfwPlatformGetThreadID() - Return the thread ID for the current +// thread +//======================================================================== + +GLFWthread _glfwPlatformGetThreadID( void ) +{ + // TODO + return 0; +} + + +//======================================================================== +// _glfwPlatformCreateMutex() - Create a mutual exclusion object +//======================================================================== + +GLFWmutex _glfwPlatformCreateMutex( void ) +{ + // TODO + return NULL; +} + + +//======================================================================== +// _glfwPlatformDestroyMutex() - Destroy a mutual exclusion object +//======================================================================== + +void _glfwPlatformDestroyMutex( GLFWmutex mutex ) +{ + // TODO +} + + +//======================================================================== +// _glfwPlatformLockMutex() - Request access to a mutex +//======================================================================== + +void _glfwPlatformLockMutex( GLFWmutex mutex ) +{ + // TODO +} + + +//======================================================================== +// _glfwPlatformUnlockMutex() - Release a mutex +//======================================================================== + +void _glfwPlatformUnlockMutex( GLFWmutex mutex ) +{ + // TODO +} + + +//======================================================================== +// _glfwPlatformCreateCond() - Create a new condition variable object +//======================================================================== + +GLFWcond _glfwPlatformCreateCond( void ) +{ + // TODO + return NULL; +} + + +//======================================================================== +// _glfwPlatformDestroyCond() - Destroy a condition variable object +//======================================================================== + +void _glfwPlatformDestroyCond( GLFWcond cond ) +{ + // TODO +} + + +//======================================================================== +// _glfwPlatformWaitCond() - Wait for a condition to be raised +//======================================================================== + +void _glfwPlatformWaitCond( GLFWcond cond, GLFWmutex mutex, + double timeout ) +{ + // TODO +} + + +//======================================================================== +// _glfwPlatformSignalCond() - Signal a condition to one waiting thread +//======================================================================== + +void _glfwPlatformSignalCond( GLFWcond cond ) +{ + // TODO +} + + +//======================================================================== +// _glfwPlatformBroadcastCond() - Broadcast a condition to all waiting +// threads +//======================================================================== + +void _glfwPlatformBroadcastCond( GLFWcond cond ) +{ + // TODO +} + + +//======================================================================== +// _glfwPlatformGetNumberOfProcessors() - Return the number of processors +// in the system. +//======================================================================== + +int _glfwPlatformGetNumberOfProcessors( void ) +{ + // Return number of processors online (DOS does not support multiple + // CPUs...) + return 1; +} diff --git a/libs/glfw/lib/dos/dos_time.c b/libs/glfw/lib/dos/dos_time.c new file mode 100644 index 0000000..eed4bcc --- /dev/null +++ b/libs/glfw/lib/dos/dos_time.c @@ -0,0 +1,309 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: dos_time.c +// Platform: DOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +// We use the __i386 define later in the code. Check if there are any +// other defines that hint that we are compiling for 32-bit x86. +#ifndef __i386 + #if defined(__i386__) || defined(i386) || defined(X86) || defined(_M_IX86) + #define __i386 + #endif +#endif // __i386 + +// Should we use inline x86 assembler? +#if defined(__i386) && defined(__GNUC__) + #define _USE_X86_ASM +#endif + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +// Functions for accessing upper and lower parts of 64-bit integers +// (Note: These are endian dependent, but ONLY used on x86 platforms!) +#define _HIGH(x) ((unsigned int*)&x)[1] +#define _LOW(x) *((unsigned int*)&x) + + +//======================================================================== +// _glfwCPUID() - Execute x86 CPUID instruction +//======================================================================== + +#ifdef _USE_X86_ASM + +static int _glfwCPUID( unsigned int ID, unsigned int *a, unsigned int *b, + unsigned int *c, unsigned int *d ) +{ + int has_cpuid; + unsigned int local_a, local_b, local_c, local_d; + + // Inline assembly - GCC version +#if defined(__i386) && defined(__GNUC__) + + // Detect CPUID support + asm( + "pushf\n\t" + "pop %%eax\n\t" + "movl %%eax,%%ebx\n\t" + "xorl $0x00200000,%%eax\n\t" + "push %%eax\n\t" + "popf\n\t" + "pushf\n\t" + "pop %%eax\n\t" + "xorl %%eax,%%ebx\n\t" + "movl %%eax,%0\n\t" + : "=m" (has_cpuid) + : + : "%eax", "%ebx" + ); + if( !has_cpuid ) + { + return GL_FALSE; + } + + // Execute CPUID + asm( + "movl %4,%%eax\n\t" + "cpuid\n\t" + "movl %%eax,%0\n\t" + "movl %%ebx,%1\n\t" + "movl %%ecx,%2\n\t" + "movl %%edx,%3\n\t" + : "=m" (local_a), "=m" (local_b), "=m" (local_c), "=m" (local_d) + : "m" (ID) + : "%eax", "%ebx", "%ecx", "%edx" + ); + +#endif + + // Common code for all compilers + *a = local_a; + *b = local_b; + *c = local_c; + *d = local_d; + return GL_TRUE; +} + +#endif // _USE_X86_ASM + + +//======================================================================== +// _glfwHasRDTSC() - Check for RDTSC availability AND usefulness +//======================================================================== + +static int _glfwHasRDTSC( void ) +{ +#ifdef _USE_X86_ASM + + unsigned int cpu_name1, cpu_name2, cpu_name3; + unsigned int cpu_signature, cpu_brandID; + unsigned int max_base, feature_flags; + unsigned int dummy; + + // Get processor vendor string (will return 0 if CPUID is not + // supported) + if( !_glfwCPUID( 0, &max_base, &cpu_name1, &cpu_name3, &cpu_name2 ) ) + { + return GL_FALSE; + } + + // Does the processor support base CPUID function 1? + if( max_base < 1 ) + { + return GL_FALSE; + } + + // Get CPU capabilities, CPU Brand ID & CPU Signature + _glfwCPUID( 1, &cpu_signature, &cpu_brandID, &dummy, &feature_flags ); + + // Is RDTSC supported? + if( !(feature_flags & 0x00000010) ) + { + return GL_FALSE; + } + + return GL_TRUE; + +#else + + // Not a supported compiler + return GL_FALSE; + +#endif +} + + +//------------------------------------------------------------------------ +// _RDTSC() - Get CPU cycle count using the RDTSC instruction +//------------------------------------------------------------------------ + +#if defined(__i386) && defined(__GNUC__) + +// Read 64-bit processor Time Stamp Counter - GCC version +#define _RDTSC( hi, lo ) \ + asm( \ + "rdtsc\n\t" \ + "movl %%edx,%0\n\t" \ + "movl %%eax,%1" \ + : "=m" (hi), "=m" (lo) \ + : \ + : "%edx", "%eax" \ + ); + +#else + +#define _RDTSC( hi, lo ) {hi=lo=0;} + +#endif + + + + +//======================================================================== +// _glfwInitTimer() - Initialize timer +//======================================================================== + +int _glfwInitTimer( void ) +{ + clock_t t, t1, t2; + long long c1, c2; + + // Do we have RDTSC? + _glfwTimer.HasRDTSC = _glfwHasRDTSC(); + if( _glfwTimer.HasRDTSC ) + { + // Measure the CPU clock with the raw DOS clock (18.2 Hz) + t = clock(); + while( (t1=clock()) == t ); + _RDTSC( _HIGH(c1), _LOW(c1) ); + t = t1+CLOCKS_PER_SEC/3; + while( (t2=clock()) < t ); + _RDTSC( _HIGH(c2), _LOW(c2) ); + + // Calculate CPU clock period + _glfwTimer.Period = (double)(t2-t1) / + (CLOCKS_PER_SEC * (double)(c2-c1)); + _RDTSC( _HIGH(_glfwTimer.t0), _LOW(_glfwTimer.t0) ); + } + else + { + // Use the raw DOS clock (18.2 Hz) + _glfwTimer.Period = 1.0 / CLOCKS_PER_SEC; + _glfwTimer.t0 = clock(); + } + + return 1; +} + + +//======================================================================== +// _glfwTerminateTimer() - Terminate timer +//======================================================================== + +void _glfwTerminateTimer( void ) +{ + // Nothing to do here +} + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformGetTime() - Return timer value in seconds +//======================================================================== + +double _glfwPlatformGetTime( void ) +{ + long long t_now; + + // Get current clock count + if( _glfwTimer.HasRDTSC ) + { + _RDTSC( _HIGH(t_now), _LOW(t_now) ); + } + else + { + t_now = (long long) clock(); + } + + // Convert to seconds + return (t_now-_glfwTimer.t0) * _glfwTimer.Period; +} + + +//======================================================================== +// _glfwPlatformSetTime() - Set timer value in seconds +//======================================================================== + +void _glfwPlatformSetTime( double t ) +{ + long long t_now; + + // Get current clock count + if( _glfwTimer.HasRDTSC ) + { + _RDTSC( _HIGH(t_now), _LOW(t_now) ); + } + else + { + t_now = (long long) clock(); + } + + // Set timer + _glfwTimer.t0 = t_now - (long long)(t/_glfwTimer.Period); +} + + +//======================================================================== +// _glfwPlatformSleep() - Put a thread to sleep for a specified amount of +// time +//======================================================================== + +void _glfwPlatformSleep( double time ) +{ + // TODO: Proper threaded version + if( time > 0 ) + { + if( time < 0.001 ) + { + delay( 1 ); + } + else + { + delay( (unsigned int)(time*1000.0+0.5) ); + } + } +} diff --git a/libs/glfw/lib/dos/dos_window.c b/libs/glfw/lib/dos/dos_window.c new file mode 100644 index 0000000..1801e1b --- /dev/null +++ b/libs/glfw/lib/dos/dos_window.c @@ -0,0 +1,563 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: dos_window.c +// Platform: DOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwRedirectOutput() - Standard output redirection +//======================================================================== + +static void _glfwRedirectOutput( void ) +{ + // Generate temporary names + tmpnam( _glfwWin.OutName ); + tmpnam( _glfwWin.ErrName ); + + // Open temporary output files + _glfwWin.hOut = open( _glfwWin.OutName, O_WRONLY | O_CREAT | O_TEXT | + O_TRUNC, S_IREAD | S_IWRITE ); + _glfwWin.hErr = open( _glfwWin.ErrName, O_WRONLY | O_CREAT | O_TEXT | + O_TRUNC, S_IREAD | S_IWRITE ); + + // Redirect stdout + if( _glfwWin.hOut > 0 ) + { + _glfwWin.hOutOld = dup( STDOUT_FILENO ); + fflush( stdout ); + dup2( _glfwWin.hOut, STDOUT_FILENO ); + } + + // Redirect stderr + if( _glfwWin.hErr > 0 ) + { + _glfwWin.hErrOld = dup( STDERR_FILENO ); + fflush( stderr ); + dup2( _glfwWin.hErr, STDERR_FILENO ); + } +} + + +//======================================================================== +// _glfwRestoreOutput() - Standard output redirection +//======================================================================== + +static void _glfwRestoreOutput( void ) +{ + FILE *f; + char *str = alloca( 512 ); + + // Dump from temporary file to stdout + if( _glfwWin.hOut > 0) + { + // Restore old stdout + dup2( _glfwWin.hOutOld, STDOUT_FILENO ); + close( _glfwWin.hOut ); + close( _glfwWin.hOutOld ); + _glfwWin.hOut = 0; + + // Dump file to stdout + f = fopen( _glfwWin.OutName, "rt" ); + while( fgets( str, 512, f ) ) + { + fputs( str, stdout ); + } + fclose( f ); + + // Remove temporary file + remove( _glfwWin.OutName ); + } + + // Dump from temporary file to stderr + if( _glfwWin.hOut > 0) + { + // Restore old stderr + dup2( _glfwWin.hErrOld, STDERR_FILENO ); + close( _glfwWin.hErr ); + close( _glfwWin.hErrOld ); + _glfwWin.hErr = 0; + + // Dump file to stderr + f = fopen( _glfwWin.ErrName, "rt" ); + while( fgets( str, 512, f ) ) + { + fputs( str, stderr ); + } + fclose( f ); + + // Remove temporary file + remove( _glfwWin.ErrName ); + } +} + + +//======================================================================== +// _glfwTranslateChar() - Translates a DOS key code to Unicode +//======================================================================== + +static int _glfwTranslateChar( int keycode ) +{ + // Unicode? + if( (keycode >= 32 && keycode <= 126) || keycode >= 160 ) + { + return keycode; + } + + return -1; +} + + +//======================================================================== +// _glfwTranslateKey() - Translates a DOS key code to GLFW coding +//======================================================================== + +static int _glfwTranslateKey( int keycode ) +{ + // ISO 8859-1? + if( ((keycode>=32) && (keycode<=126)) || + ((keycode>=160) && (keycode<=254)) ) + { + return keycode; + } + + // Special keys? + if( keycode < 0 ) + { + return -keycode; + } + + return -1; +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformOpenWindow() - Here is where the window is created, and +// the OpenGL rendering context is created +//======================================================================== + +int _glfwPlatformOpenWindow( int width, int height, int redbits, + int greenbits, int bluebits, int alphabits, int depthbits, + int stencilbits, int mode, int accumredbits, int accumgreenbits, + int accumbluebits, int accumalphabits, int auxbuffers, int stereo, + int refreshrate ) +{ + GLint params[2]; + + // Clear window resources + _glfwWin.Visual = NULL; + _glfwWin.Context = NULL; + _glfwWin.Buffer = NULL; + _glfwWin.hOut = 0; + _glfwWin.hErr = 0; + + // For now, we only support 640x480, 800x600 and 1024x768 + if( (width*height) < (700*500) ) + { + width = 640; + height = 480; + } + else if( (width*height) < (900*700) ) + { + width = 800; + height = 600; + } + else + { + width = 1024; + height = 768; + } + + // For now, we only support 5,6,5 and 8,8,8 color formats + if( (redbits+greenbits+bluebits) < 20 ) + { + redbits = 5; + greenbits = 6; + bluebits = 5; + } + else + { + redbits = 8; + greenbits = 8; + bluebits = 8; + } + + // For now, we always set refresh rate = 0 (default) + refreshrate = 0; + + // stdout/stderr redirection + _glfwRedirectOutput(); + + // Create visual + _glfwWin.Visual = DMesaCreateVisual( + width, height, + redbits+greenbits+bluebits, + refreshrate, + GL_TRUE, // Double buffer + GL_TRUE, // RGB mode + alphabits?GL_TRUE:GL_FALSE, // Alpha buffer? + depthbits, + stencilbits, + (accumredbits+accumgreenbits+ + accumbluebits+accumalphabits)>>2 + ); + if( _glfwWin.Visual == NULL ) + { + printf("Unable to create visual\n"); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Create context + _glfwWin.Context = DMesaCreateContext( _glfwWin.Visual, NULL ); + if( _glfwWin.Context == NULL ) + { + printf("Unable to create context\n"); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Create buffer + _glfwWin.Buffer = DMesaCreateBuffer( _glfwWin.Visual, 0, 0, + width, height ); + if( _glfwWin.Buffer == NULL ) + { + printf("Unable to create buffer\n"); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Make current context + if( !DMesaMakeCurrent( _glfwWin.Context, _glfwWin.Buffer ) ) + { + printf("Unable to make current context\n"); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Start DOS event handler + if( !_glfwInitEvents() ) + { + printf("Unable to start event handler\n"); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Start keyboard handler + if( !_glfwInitKeyboard() ) + { + printf("Unable to start keyboard driver\n"); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Start mouse handler + if( !_glfwInitMouse() ) + { + printf("***Warning: Unable to start mouse driver\n"); + } + + // Remember actual screen/window size + _glfwWin.Width = width; + _glfwWin.Height = height; + + return GL_TRUE; +} + + +//======================================================================== +// _glfwPlatformCloseWindow() - Properly kill the window/video display +//======================================================================== + +void _glfwPlatformCloseWindow( void ) +{ + // Terminate mouse handler + _glfwTerminateMouse(); + + // Terminate keyboard handler + _glfwTerminateKeyboard(); + + // Terminate event handler + _glfwTerminateEvents(); + + // Destroy buffer + if( _glfwWin.Buffer != NULL ) + { + DMesaDestroyBuffer( _glfwWin.Buffer ); + _glfwWin.Buffer = NULL; + } + + // Destroy context + if( _glfwWin.Context != NULL ) + { + DMesaDestroyContext( _glfwWin.Context ); + _glfwWin.Context = NULL; + } + + // Destroy visual + if( _glfwWin.Visual != NULL ) + { + DMesaDestroyVisual( _glfwWin.Visual ); + _glfwWin.Visual = NULL; + } + + // stdout/stderr redirection + _glfwRestoreOutput(); +} + + +//======================================================================== +// _glfwPlatformSetWindowTitle() - Set the window title. +//======================================================================== + +void _glfwPlatformSetWindowTitle( const char *title ) +{ + // Nothing to do here... +} + + +//======================================================================== +// _glfwPlatformSetWindowSize() - Set the window size. +//======================================================================== + +void _glfwPlatformSetWindowSize( int width, int height ) +{ + // TODO +} + + +//======================================================================== +// _glfwPlatformSetWindowPos() - Set the window position. +//======================================================================== + +void _glfwPlatformSetWindowPos( int x, int y ) +{ + // Nothing to do here... +} + + +//======================================================================== +// _glfwPlatformIconfyWindow() - Window iconification +//======================================================================== + +void _glfwPlatformIconifyWindow( void ) +{ + // Nothing to do here... +} + + +//======================================================================== +// _glfwPlatformRestoreWindow() - Window un-iconification +//======================================================================== + +void _glfwPlatformRestoreWindow( void ) +{ + // Nothing to do here... +} + + +//======================================================================== +// _glfwPlatformSwapBuffers() - Swap buffers (double-buffering) and poll +// any new events. +//======================================================================== + +void _glfwPlatformSwapBuffers( void ) +{ + DMesaSwapBuffers( _glfwWin.Buffer ); +} + + +//======================================================================== +// _glfwPlatformSwapInterval() - Set double buffering swap interval +//======================================================================== + +void _glfwPlatformSwapInterval( int interval ) +{ + // TODO +} + + +//======================================================================== +// _glfwPlatformRefreshWindowParams() +//======================================================================== + +void _glfwPlatformRefreshWindowParams( void ) +{ + GLint x; + GLboolean b; + + // Fill out information + _glfwWin.Accelerated = GL_TRUE; + glGetIntegerv( GL_RED_BITS, &x ); + _glfwWin.RedBits = x; + glGetIntegerv( GL_GREEN_BITS, &x ); + _glfwWin.GreenBits = x; + glGetIntegerv( GL_BLUE_BITS, &x ); + _glfwWin.BlueBits = x; + glGetIntegerv( GL_ALPHA_BITS, &x ); + _glfwWin.AlphaBits = x; + glGetIntegerv( GL_DEPTH_BITS, &x ); + _glfwWin.DepthBits = x; + glGetIntegerv( GL_STENCIL_BITS, &x ); + _glfwWin.StencilBits = x; + glGetIntegerv( GL_ACCUM_RED_BITS, &x ); + _glfwWin.AccumRedBits = x; + glGetIntegerv( GL_ACCUM_GREEN_BITS, &x ); + _glfwWin.AccumGreenBits = x; + glGetIntegerv( GL_ACCUM_BLUE_BITS, &x ); + _glfwWin.AccumBlueBits = x; + glGetIntegerv( GL_ACCUM_ALPHA_BITS, &x ); + _glfwWin.AccumAlphaBits = x; + glGetIntegerv( GL_AUX_BUFFERS, &x ); + _glfwWin.AuxBuffers = x; + glGetBooleanv( GL_AUX_BUFFERS, &b ); + _glfwWin.Stereo = b ? GL_TRUE : GL_FALSE; + _glfwWin.RefreshRate = 0; +} + + +//======================================================================== +// _glfwPlatformPollEvents() - Poll for new window and input events +//======================================================================== + +void _glfwPlatformPollEvents( void ) +{ + _GLFWdosevent event; + struct key_event *key; + struct mousemove_event *mousemove; + struct mousewheel_event *mousewheel; + struct mousebutton_event *mousebutton; + + // Empty the event queue + while( _glfwGetNextEvent( &event ) ) + { + switch( event.Type ) + { + // Keyboard event? + case _GLFW_DOS_KEY_EVENT: + key = &event.Key; + _glfwInputKey( _glfwTranslateKey( key->KeyNoMod ), + key->Action ); + _glfwInputChar( _glfwTranslateChar( key->Key ), + key->Action ); + break; + + // Mouse move event? + case _GLFW_DOS_MOUSE_MOVE_EVENT: + mousemove = &event.MouseMove; + _glfwInput.MousePosX += mousemove->DeltaX; + _glfwInput.MousePosY += mousemove->DeltaY; + + // Call user callback function + if( _glfwWin.MousePosCallback ) + { + _glfwWin.MousePosCallback( _glfwInput.MousePosX, + _glfwInput.MousePosY ); + } + break; + + // Mouse wheel event? + case _GLFW_DOS_MOUSE_WHEEL_EVENT: + mousewheel = &event.MouseWheel; + _glfwInput.WheelPos += mousewheel->WheelDelta; + + // Call user callback function + if( _glfwWin.MouseWheelCallback ) + { + _glfwWin.MouseWheelCallback( _glfwInput.WheelPos ); + } + break; + + // Mouse button event? + case _GLFW_DOS_MOUSE_BUTTON_EVENT: + mousebutton = &event.MouseButton; + _glfwInputMouseClick( mousebutton->Button, + mousebutton->Action ); + break; + + default: + break; + } + + } +} + + +//======================================================================== +// _glfwPlatformWaitEvents() - Wait for new window and input events +//======================================================================== + +void _glfwPlatformWaitEvents( void ) +{ + // Wait for new events + _glfwWaitNextEvent; + + // Poll new events + _glfwPlatformPollEvents(); +} + + +//======================================================================== +// _glfwPlatformHideMouseCursor() - Hide mouse cursor (lock it) +//======================================================================== + +void _glfwPlatformHideMouseCursor( void ) +{ + // TODO +} + + +//======================================================================== +// _glfwPlatformShowMouseCursor() - Show mouse cursor (unlock it) +//======================================================================== + +void _glfwPlatformShowMouseCursor( void ) +{ + // TODO +} + + +//======================================================================== +// _glfwPlatformSetMouseCursorPos() - Set physical mouse cursor position +//======================================================================== + +void _glfwPlatformSetMouseCursorPos( int x, int y ) +{ + // TODO +} diff --git a/libs/glfw/lib/dos/platform.h b/libs/glfw/lib/dos/platform.h new file mode 100644 index 0000000..10bc34d --- /dev/null +++ b/libs/glfw/lib/dos/platform.h @@ -0,0 +1,341 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: platform.h +// Platform: DOS +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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 _platform_h_ +#define _platform_h_ + + +// This is the DOS version of GLFW +#define _GLFW_DOS + + +// Include files +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// GLFW+GL+GLU defines +#include "../../include/GL/glfw.h" + +// DOS Mesa (include this AFTER gl.h!) +#include + + +// Stack size for each thread (in bytes) +#define _GLFW_TASK_STACK_SIZE 50000 + + + + +//======================================================================== +// Global variables (GLFW internals) +//======================================================================== + + +//------------------------------------------------------------------------ +// Window structure +//------------------------------------------------------------------------ +typedef struct _GLFWwin_struct _GLFWwin; + +struct _GLFWwin_struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // User callback functions + GLFWwindowsizefun WindowSizeCallback; + GLFWwindowclosefun WindowCloseCallback; + GLFWwindowrefreshfun WindowRefreshCallback; + GLFWmousebuttonfun MouseButtonCallback; + GLFWmouseposfun MousePosCallback; + GLFWmousewheelfun MouseWheelCallback; + GLFWkeyfun KeyCallback; + GLFWcharfun CharCallback; + + // User selected window settings + int Fullscreen; // Fullscreen flag + int MouseLock; // Mouse-lock flag + int AutoPollEvents; // Auto polling flag + int SysKeysDisabled; // System keys disabled flag + int WindowNoResize; // Resize- and maximize gadgets disabled flag + + // Window status & parameters + int Opened; // Flag telling if window is opened or not + int Active; // Application active flag + int Iconified; // Window iconified flag + int Width, Height; // Window width and heigth + int Accelerated; // GL_TRUE if window is HW accelerated + int RedBits; + int GreenBits; + int BlueBits; + int AlphaBits; + int DepthBits; + int StencilBits; + int AccumRedBits; + int AccumGreenBits; + int AccumBlueBits; + int AccumAlphaBits; + int AuxBuffers; + int Stereo; + int RefreshRate; // Vertical monitor refresh rate + + // Extensions & OpenGL version + int Has_GL_SGIS_generate_mipmap; + int Has_GL_ARB_texture_non_power_of_two; + int GLVerMajor,GLVerMinor; + + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Platform specific window resources + DMesaVisual Visual; + DMesaContext Context; + DMesaBuffer Buffer; + + // Standard output redirection + char OutName[L_tmpnam]; + char ErrName[L_tmpnam]; + int hOut,hOutOld,hErr,hErrOld; + + // Platform specific extensions + + // Various platform specific internal variables + +}; + +GLFWGLOBAL _GLFWwin _glfwWin; + + +//------------------------------------------------------------------------ +// User input status (most of this should go in _GLFWwin) +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Mouse status + int MousePosX, MousePosY; + int WheelPos; + char MouseButton[ GLFW_MOUSE_BUTTON_LAST+1 ]; + + // Keyboard status + char Key[ GLFW_KEY_LAST+1 ]; + int LastChar; + + // User selected settings + int StickyKeys; + int StickyMouseButtons; + int KeyRepeat; + + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Platform specific internal variables + +} _glfwInput; + + +//------------------------------------------------------------------------ +// Timer status +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + double Period; + long long t0; + int HasRDTSC; +} _glfwTimer; + + +//------------------------------------------------------------------------ +// Thread record (one for each thread) +//------------------------------------------------------------------------ +typedef struct _GLFWthread_struct _GLFWthread; + +struct _GLFWthread_struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Pointer to previous and next threads in linked list + _GLFWthread *Previous, *Next; + + // GLFW user side thread information + GLFWthread ID; + +// ========= PLATFORM SPECIFIC PART ====================================== + + // System side thread information + GLFWthreadfun Function; + void *Arg; +}; + + +//------------------------------------------------------------------------ +// General thread information +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Next thread ID to use (increments for every created thread) + GLFWthread NextID; + + // First thread in linked list (always the main thread) + _GLFWthread First; + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Critical section lock + +} _glfwThrd; + + +//------------------------------------------------------------------------ +// Joystick information & state +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + int dummy; +} _glfwJoy; + + +//======================================================================== +// Macros for encapsulating critical code sections (i.e. making parts +// of GLFW thread safe) +//======================================================================== + +// Thread list management +#define ENTER_THREAD_CRITICAL_SECTION \ + ; +#define LEAVE_THREAD_CRITICAL_SECTION \ + ; + + +//======================================================================== +// DOS events +//======================================================================== + +// Valid event types +#define _GLFW_DOS_KEY_EVENT 1 +#define _GLFW_DOS_MOUSE_MOVE_EVENT 2 +#define _GLFW_DOS_MOUSE_WHEEL_EVENT 3 +#define _GLFW_DOS_MOUSE_BUTTON_EVENT 4 + +// Keyboard event structure +struct key_event { + int Type; + int Key; + int KeyNoMod; + int Action; +}; + +// Mouse move event structure +struct mousemove_event { + int Type; + int DeltaX, DeltaY; +}; + +// Mouse wheel event structure +struct mousewheel_event { + int Type; + int WheelDelta; +}; + +// Mouse button event structure +struct mousebutton_event { + int Type; + int Button; + int Action; +}; + +// DOS event structure +typedef union { + int Type; + struct key_event Key; + struct mousemove_event MouseMove; + struct mousewheel_event MouseWheel; + struct mousebutton_event MouseButton; +} _GLFWdosevent; + + + +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +// Time +int _glfwInitTimer( void ); +void _glfwTerminateTimer( void ); + +// Fullscreen + +// Events +int _glfwInitEvents( void ); +void _glfwTerminateEvents( void ); +void _glfwWaitNextEvent( void ); +int _glfwGetNextEvent( _GLFWdosevent *event ); +void _glfwPostDOSEvent( _GLFWdosevent *event ); + +// Mouse +int _glfwInitMouse( void ); +void _glfwTerminateMouse( void ); + +// Keyboard +int _glfwInitKeyboard( void ); +void _glfwTerminateKeyboard( void ); + +// Joystick +void _glfwInitJoysticks( void ); +void _glfwTerminateJoysticks( void ); + +// Threads +int _glfwInitThreads( void ); +void _glfwTerminateThreads( void ); + +// Interrupt handling +int _glfwInstallDOSIrq( int i, int (*handler) () ); +int _glfwRemoveDOSIrq( int i ); + +// Interrupt macros +#define ENABLE() __asm __volatile("sti") +#define DISABLE() __asm __volatile("cli") + +// Memory macros (for locking memory) +#define ENDOFUNC(x) static void x##_end() { } +#define LOCKFUNC(x) _go32_dpmi_lock_code((void *)x, (long)x##_end - (long)x) +#define LOCKDATA(x) _go32_dpmi_lock_data((void *)&x, sizeof(x)) +#define LOCKBUFF(x, l) _go32_dpmi_lock_data((void *)x, l) + +#endif // _platform_h_ diff --git a/libs/glfw/lib/enable.c b/libs/glfw/lib/enable.c new file mode 100644 index 0000000..3207428 --- /dev/null +++ b/libs/glfw/lib/enable.c @@ -0,0 +1,295 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: enable.c +// Platform: Any +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// Enable (show) mouse cursor +//======================================================================== + +static void _glfwEnableMouseCursor( void ) +{ + int CenterPosX, CenterPosY; + + if( !_glfwWin.Opened || !_glfwWin.MouseLock ) + { + return; + } + + // Show mouse cursor + _glfwPlatformShowMouseCursor(); + + CenterPosX = _glfwWin.Width / 2; + CenterPosY = _glfwWin.Height / 2; + + if( CenterPosX != _glfwInput.MousePosX || CenterPosY != _glfwInput.MousePosY ) + { + _glfwPlatformSetMouseCursorPos( CenterPosX, CenterPosY ); + + _glfwInput.MousePosX = CenterPosX; + _glfwInput.MousePosY = CenterPosY; + + if( _glfwWin.MousePosCallback ) + { + _glfwWin.MousePosCallback( _glfwInput.MousePosX, + _glfwInput.MousePosY ); + } + } + + // From now on the mouse is unlocked + _glfwWin.MouseLock = GL_FALSE; +} + +//======================================================================== +// Disable (hide) mouse cursor +//======================================================================== + +static void _glfwDisableMouseCursor( void ) +{ + if( !_glfwWin.Opened || _glfwWin.MouseLock ) + { + return; + } + + // Hide mouse cursor + _glfwPlatformHideMouseCursor(); + + // Move cursor to the middle of the window + _glfwPlatformSetMouseCursorPos( _glfwWin.Width>>1, + _glfwWin.Height>>1 ); + + // From now on the mouse is locked + _glfwWin.MouseLock = GL_TRUE; +} + + +//======================================================================== +// _glfwEnableStickyKeys() - Enable sticky keys +// _glfwDisableStickyKeys() - Disable sticky keys +//======================================================================== + +static void _glfwEnableStickyKeys( void ) +{ + _glfwInput.StickyKeys = 1; +} + +static void _glfwDisableStickyKeys( void ) +{ + int i; + + _glfwInput.StickyKeys = 0; + + // Release all sticky keys + for( i = 0; i <= GLFW_KEY_LAST; i ++ ) + { + if( _glfwInput.Key[ i ] == 2 ) + { + _glfwInput.Key[ i ] = 0; + } + } +} + + +//======================================================================== +// _glfwEnableStickyMouseButtons() - Enable sticky mouse buttons +// _glfwDisableStickyMouseButtons() - Disable sticky mouse buttons +//======================================================================== + +static void _glfwEnableStickyMouseButtons( void ) +{ + _glfwInput.StickyMouseButtons = 1; +} + +static void _glfwDisableStickyMouseButtons( void ) +{ + int i; + + _glfwInput.StickyMouseButtons = 0; + + // Release all sticky mouse buttons + for( i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i ++ ) + { + if( _glfwInput.MouseButton[ i ] == 2 ) + { + _glfwInput.MouseButton[ i ] = 0; + } + } +} + + +//======================================================================== +// _glfwEnableSystemKeys() - Enable system keys +// _glfwDisableSystemKeys() - Disable system keys +//======================================================================== + +static void _glfwEnableSystemKeys( void ) +{ + if( !_glfwWin.SysKeysDisabled ) + { + return; + } + + _glfwPlatformEnableSystemKeys(); + + // Indicate that system keys are no longer disabled + _glfwWin.SysKeysDisabled = GL_FALSE; +} + +static void _glfwDisableSystemKeys( void ) +{ + if( _glfwWin.SysKeysDisabled ) + { + return; + } + + _glfwPlatformDisableSystemKeys(); + + // Indicate that system keys are now disabled + _glfwWin.SysKeysDisabled = GL_TRUE; +} + + +//======================================================================== +// _glfwEnableKeyRepeat() - Enable key repeat +// _glfwDisableKeyRepeat() - Disable key repeat +//======================================================================== + +static void _glfwEnableKeyRepeat( void ) +{ + _glfwInput.KeyRepeat = 1; +} + +static void _glfwDisableKeyRepeat( void ) +{ + _glfwInput.KeyRepeat = 0; +} + + +//======================================================================== +// _glfwEnableAutoPollEvents() - Enable automatic event polling +// _glfwDisableAutoPollEvents() - Disable automatic event polling +//======================================================================== + +static void _glfwEnableAutoPollEvents( void ) +{ + _glfwWin.AutoPollEvents = 1; +} + +static void _glfwDisableAutoPollEvents( void ) +{ + _glfwWin.AutoPollEvents = 0; +} + + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// glfwEnable() - Enable certain GLFW/window/system functions. +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwEnable( int token ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + switch( token ) + { + case GLFW_MOUSE_CURSOR: + _glfwEnableMouseCursor(); + break; + case GLFW_STICKY_KEYS: + _glfwEnableStickyKeys(); + break; + case GLFW_STICKY_MOUSE_BUTTONS: + _glfwEnableStickyMouseButtons(); + break; + case GLFW_SYSTEM_KEYS: + _glfwEnableSystemKeys(); + break; + case GLFW_KEY_REPEAT: + _glfwEnableKeyRepeat(); + break; + case GLFW_AUTO_POLL_EVENTS: + _glfwEnableAutoPollEvents(); + break; + default: + break; + } +} + + +//======================================================================== +// glfwDisable() - Disable certain GLFW/window/system functions. +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwDisable( int token ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + switch( token ) + { + case GLFW_MOUSE_CURSOR: + _glfwDisableMouseCursor(); + break; + case GLFW_STICKY_KEYS: + _glfwDisableStickyKeys(); + break; + case GLFW_STICKY_MOUSE_BUTTONS: + _glfwDisableStickyMouseButtons(); + break; + case GLFW_SYSTEM_KEYS: + _glfwDisableSystemKeys(); + break; + case GLFW_KEY_REPEAT: + _glfwDisableKeyRepeat(); + break; + case GLFW_AUTO_POLL_EVENTS: + _glfwDisableAutoPollEvents(); + break; + default: + break; + } +} + diff --git a/libs/glfw/lib/fullscreen.c b/libs/glfw/lib/fullscreen.c new file mode 100644 index 0000000..bbef892 --- /dev/null +++ b/libs/glfw/lib/fullscreen.c @@ -0,0 +1,95 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: fullscreen.c +// Platform: Any +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// glfwGetVideoModes() - Get a list of available video modes +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwGetVideoModes( GLFWvidmode *list, + int maxcount ) +{ + int count, i, swap, res1, res2, depth1, depth2; + GLFWvidmode vm; + + if( !_glfwInitialized || maxcount <= 0 || list == (GLFWvidmode*) 0 ) + { + return 0; + } + + // Get list of video modes + count = _glfwPlatformGetVideoModes( list, maxcount ); + + // Sort list (bubble sort) + do + { + swap = 0; + for( i = 0; i < count-1; ++ i ) + { + res1 = list[i].Width*list[i].Height; + depth1 = list[i].RedBits+list[i].GreenBits+list[i].BlueBits; + res2 = list[i+1].Width*list[i+1].Height; + depth2 = list[i+1].RedBits+list[i+1].GreenBits+ + list[i+1].BlueBits; + if( (depth2= '0' && *ptr <= '9'; ptr ++ ) + { + _major = 10*_major + (*ptr - '0'); + } + if( *ptr == '.' ) + { + ptr ++; + for( _minor = 0; *ptr >= '0' && *ptr <= '9'; ptr ++ ) + { + _minor = 10*_minor + (*ptr - '0'); + } + if( *ptr == '.' ) + { + ptr ++; + for( _rev = 0; *ptr >= '0' && *ptr <= '9'; ptr ++ ) + { + _rev = 10*_rev + (*ptr - '0'); + } + } + } + + // Return parsed values + if( major != NULL ) + { + *major = _major; + } + if( minor != NULL ) + { + *minor = _minor; + } + if( rev != NULL ) + { + *rev = _rev; + } +} + diff --git a/libs/glfw/lib/image.c b/libs/glfw/lib/image.c new file mode 100644 index 0000000..7cee4d9 --- /dev/null +++ b/libs/glfw/lib/image.c @@ -0,0 +1,629 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: image.c +// Platform: Any +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +//======================================================================== +// Description: +// +// This module acts as an interface for different image file formats (the +// image file format is detected automatically). +// +// By default the loaded image is rescaled (using bilinear interpolation) +// to the next higher 2^N x 2^M resolution, unless it has a valid +// 2^N x 2^M resolution. The interpolation is quite slow, even if the +// routine has been optimized for speed (a 200x200 RGB image is scaled to +// 256x256 in ~30 ms on a P3-500). +// +// Paletted images are converted to RGB/RGBA images. +// +// A convenience function is also included (glfwLoadTexture2D), which +// loads a texture image from a file directly to OpenGL texture memory, +// with an option to generate all mipmap levels. GL_SGIS_generate_mipmap +// is used whenever available, which should give an optimal mipmap +// generation speed (possibly performed in hardware). A software fallback +// method is included when GL_SGIS_generate_mipmap is not supported (it +// generates all mipmaps of a 256x256 RGB texture in ~3 ms on a P3-500). +// +//======================================================================== + + +#include "internal.h" + + +// We want to support automatic mipmap generation +#ifndef GL_SGIS_generate_mipmap + #define GL_GENERATE_MIPMAP_SGIS 0x8191 + #define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 + #define GL_SGIS_generate_mipmap 1 +#endif // GL_SGIS_generate_mipmap + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwUpsampleImage() - Upsample image, from size w1 x h1 to w2 x h2 +//======================================================================== + +static void _glfwUpsampleImage( unsigned char *src, unsigned char *dst, + int w1, int h1, int w2, int h2, int bpp ) +{ + int m, n, k, x, y, col8; + float dx, dy, xstep, ystep, col, col1, col2; + unsigned char *src1, *src2, *src3, *src4; + + // Calculate scaling factor + xstep = (float)(w1-1) / (float)(w2-1); + ystep = (float)(h1-1) / (float)(h2-1); + + // Copy source data to destination data with bilinear interpolation + // Note: The rather strange look of this routine is a direct result of + // my attempts at optimizing it. Improvements are welcome! + dy = 0.0f; + y = 0; + for( n = 0; n < h2; n ++ ) + { + dx = 0.0f; + src1 = &src[ y*w1*bpp ]; + src3 = y < (h1-1) ? src1 + w1*bpp : src1; + src2 = src1 + bpp; + src4 = src3 + bpp; + x = 0; + for( m = 0; m < w2; m ++ ) + { + for( k = 0; k < bpp; k ++ ) + { + col1 = *src1 ++; + col2 = *src2 ++; + col = col1 + (col2 - col1) * dx; + col1 = *src3 ++; + col2 = *src4 ++; + col2 = col1 + (col2 - col1) * dx; + col += (col2 - col) * dy; + col8 = (int) (col + 0.5); + if( col8 >= 256 ) col8 = 255; + *dst++ = (unsigned char) col8; + } + dx += xstep; + if( dx >= 1.0f ) + { + x ++; + dx -= 1.0f; + if( x >= (w1-1) ) + { + src2 = src1; + src4 = src3; + } + } + else + { + src1 -= bpp; + src2 -= bpp; + src3 -= bpp; + src4 -= bpp; + } + } + dy += ystep; + if( dy >= 1.0f ) + { + y ++; + dy -= 1.0f; + } + } +} + + +//======================================================================== +// _glfwHalveImage() - Build the next mip-map level +//======================================================================== + +static int _glfwHalveImage( GLubyte *src, int *width, int *height, + int components ) +{ + int halfwidth, halfheight, m, n, k, idx1, idx2; + GLubyte *dst; + + // Last level? + if( *width <= 1 && *height <= 1 ) + { + return GL_FALSE; + } + + // Calculate new width and height (handle 1D case) + halfwidth = *width > 1 ? *width / 2 : 1; + halfheight = *height > 1 ? *height / 2 : 1; + + // Downsample image with a simple box-filter + dst = src; + if( *width == 1 || *height == 1 ) + { + // 1D case + for( m = 0; m < halfwidth+halfheight-1; m ++ ) + { + for( k = 0; k < components; k ++ ) + { + *dst ++ = (GLubyte) (((int)*src + + (int)src[components] + 1) >> 1); + src ++; + } + src += components; + } + } + else + { + // 2D case + idx1 = *width*components; + idx2 = (*width+1)*components; + for( m = 0; m < halfheight; m ++ ) + { + for( n = 0; n < halfwidth; n ++ ) + { + for( k = 0; k < components; k ++ ) + { + *dst ++ = (GLubyte) (((int)*src + + (int)src[components] + + (int)src[idx1] + + (int)src[idx2] + 2) >> 2); + src ++; + } + src += components; + } + src += components * (*width); + } + } + + // Return new width and height + *width = halfwidth; + *height = halfheight; + + return GL_TRUE; +} + + +//======================================================================== +// _glfwRescaleImage() - Rescales an image into power-of-two dimensions +//======================================================================== + +static int _glfwRescaleImage( GLFWimage* image ) +{ + int width, height, log2, newsize; + unsigned char *data; + + // Calculate next larger 2^N width + for( log2 = 0, width = image->Width; width > 1; width >>= 1, log2 ++ ) + ; + width = (int) 1 << log2; + if( width < image->Width ) + { + width <<= 1; + } + + // Calculate next larger 2^M height + for( log2 = 0, height = image->Height; height > 1; height >>= 1, log2 ++ ) + ; + height = (int) 1 << log2; + if( height < image->Height ) + { + height <<= 1; + } + + // Do we really need to rescale? + if( width != image->Width || height != image->Height ) + { + // Allocate memory for new (upsampled) image data + newsize = width * height * image->BytesPerPixel; + data = (unsigned char *) malloc( newsize ); + if( data == NULL ) + { + free( image->Data ); + return GL_FALSE; + } + + // Copy old image data to new image data with interpolation + _glfwUpsampleImage( image->Data, data, image->Width, image->Height, + width, height, image->BytesPerPixel ); + + // Free memory for old image data (not needed anymore) + free( image->Data ); + + // Set pointer to new image data, and set new image dimensions + image->Data = data; + image->Width = width; + image->Height = height; + } + + return GL_TRUE; +} + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// glfwReadImage() - Read an image from a named file +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwReadImage( const char *name, GLFWimage *img, + int flags ) +{ + _GLFWstream stream; + + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return GL_FALSE; + } + + // Start with an empty image descriptor + img->Width = 0; + img->Height = 0; + img->BytesPerPixel = 0; + img->Data = NULL; + + // Open file + if( !_glfwOpenFileStream( &stream, name, "rb" ) ) + { + return GL_FALSE; + } + + // We only support TGA files at the moment + if( !_glfwReadTGA( &stream, img, flags ) ) + { + _glfwCloseStream( &stream ); + return GL_FALSE; + } + + // Close stream + _glfwCloseStream( &stream ); + + // Should we rescale the image to closest 2^N x 2^M resolution? + if( !(flags & GLFW_NO_RESCALE_BIT) ) + { + if( !_glfwRescaleImage( img ) ) + { + return GL_FALSE; + } + } + + // Interpret BytesPerPixel as an OpenGL format + switch( img->BytesPerPixel ) + { + default: + case 1: + if( flags & GLFW_ALPHA_MAP_BIT ) + { + img->Format = GL_ALPHA; + } + else + { + img->Format = GL_LUMINANCE; + } + break; + case 3: + img->Format = GL_RGB; + break; + case 4: + img->Format = GL_RGBA; + break; + } + + return GL_TRUE; +} + + +//======================================================================== +// glfwReadMemoryImage() - Read an image file from a memory buffer +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwReadMemoryImage( const void *data, long size, GLFWimage *img, int flags ) +{ + _GLFWstream stream; + + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return GL_FALSE; + } + + // Start with an empty image descriptor + img->Width = 0; + img->Height = 0; + img->BytesPerPixel = 0; + img->Data = NULL; + + // Open buffer + if( !_glfwOpenBufferStream( &stream, (void*) data, size ) ) + { + return GL_FALSE; + } + + // We only support TGA files at the moment + if( !_glfwReadTGA( &stream, img, flags ) ) + { + _glfwCloseStream( &stream ); + return GL_FALSE; + } + + // Close stream + _glfwCloseStream( &stream ); + + // Should we rescale the image to closest 2^N x 2^M resolution? + if( !(flags & GLFW_NO_RESCALE_BIT) ) + { + if( !_glfwRescaleImage( img ) ) + { + return GL_FALSE; + } + } + + // Interpret BytesPerPixel as an OpenGL format + switch( img->BytesPerPixel ) + { + default: + case 1: + if( flags & GLFW_ALPHA_MAP_BIT ) + { + img->Format = GL_ALPHA; + } + else + { + img->Format = GL_LUMINANCE; + } + break; + case 3: + img->Format = GL_RGB; + break; + case 4: + img->Format = GL_RGBA; + break; + } + + return GL_TRUE; +} + + +//======================================================================== +// glfwFreeImage() - Free allocated memory for an image +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwFreeImage( GLFWimage *img ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + // Free memory + if( img->Data != NULL ) + { + free( img->Data ); + img->Data = NULL; + } + + // Clear all fields + img->Width = 0; + img->Height = 0; + img->Format = 0; + img->BytesPerPixel = 0; +} + + +//======================================================================== +// glfwLoadTexture2D() - Read an image from a file, and upload it to +// texture memory +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwLoadTexture2D( const char *name, int flags ) +{ + GLFWimage img; + + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return GL_FALSE; + } + + // Force rescaling if necessary + if( !_glfwWin.Has_GL_ARB_texture_non_power_of_two ) + { + flags &= (~GLFW_NO_RESCALE_BIT); + } + + // Read image from file + if( !glfwReadImage( name, &img, flags ) ) + { + return GL_FALSE; + } + + if( !glfwLoadTextureImage2D( &img, flags ) ) + { + return GL_FALSE; + } + + // Data buffer is not needed anymore + glfwFreeImage( &img ); + + return GL_TRUE; +} + + +//======================================================================== +// glfwLoadMemoryTexture2D() - Read an image from a buffer, and upload it to +// texture memory +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwLoadMemoryTexture2D( const void *data, long size, int flags ) +{ + GLFWimage img; + + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return GL_FALSE; + } + + // Force rescaling if necessary + if( !_glfwWin.Has_GL_ARB_texture_non_power_of_two ) + { + flags &= (~GLFW_NO_RESCALE_BIT); + } + + // Read image from file + if( !glfwReadMemoryImage( data, size, &img, flags ) ) + { + return GL_FALSE; + } + + if( !glfwLoadTextureImage2D( &img, flags ) ) + { + return GL_FALSE; + } + + // Data buffer is not needed anymore + glfwFreeImage( &img ); + + return GL_TRUE; +} + + +//======================================================================== +// glfwLoadTextureImage2D() - Upload an image object to texture memory +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwLoadTextureImage2D( GLFWimage *img, int flags ) +{ + GLint UnpackAlignment, GenMipMap; + int level, format, AutoGen, newsize, n; + unsigned char *data, *dataptr; + + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return GL_FALSE; + } + + // TODO: Use GL_MAX_TEXTURE_SIZE or GL_PROXY_TEXTURE_2D to determine + // whether the image size is valid. + // NOTE: May require box filter downsampling routine. + + // Do we need to convert the alpha map to RGBA format (OpenGL 1.0)? + if( (_glfwWin.GLVerMajor == 1) && (_glfwWin.GLVerMinor == 0) && + (img->Format == GL_ALPHA) ) + { + // We go to RGBA representation instead + img->BytesPerPixel = 4; + + // Allocate memory for new RGBA image data + newsize = img->Width * img->Height * img->BytesPerPixel; + data = (unsigned char *) malloc( newsize ); + if( data == NULL ) + { + free( img->Data ); + return GL_FALSE; + } + + // Convert Alpha map to RGBA + dataptr = data; + for( n = 0; n < (img->Width*img->Height); ++ n ) + { + *dataptr ++ = 255; + *dataptr ++ = 255; + *dataptr ++ = 255; + *dataptr ++ = img->Data[n]; + } + + // Free memory for old image data (not needed anymore) + free( img->Data ); + + // Set pointer to new image data + img->Data = data; + } + + // Set unpack alignment to one byte + glGetIntegerv( GL_UNPACK_ALIGNMENT, &UnpackAlignment ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + // Should we use automatic mipmap generation? + AutoGen = ( flags & GLFW_BUILD_MIPMAPS_BIT ) && + _glfwWin.Has_GL_SGIS_generate_mipmap; + + // Enable automatic mipmap generation + if( AutoGen ) + { + glGetTexParameteriv( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, + &GenMipMap ); + glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, + GL_TRUE ); + } + + // Format specification is different for OpenGL 1.0 + if( _glfwWin.GLVerMajor == 1 && _glfwWin.GLVerMinor == 0 ) + { + format = img->BytesPerPixel; + } + else + { + format = img->Format; + } + + // Upload to texture memeory + level = 0; + do + { + // Upload this mipmap level + glTexImage2D( GL_TEXTURE_2D, level, format, + img->Width, img->Height, 0, format, + GL_UNSIGNED_BYTE, (void*) img->Data ); + + // Build next mipmap level manually, if required + if( ( flags & GLFW_BUILD_MIPMAPS_BIT ) && !AutoGen ) + { + level = _glfwHalveImage( img->Data, &img->Width, + &img->Height, img->BytesPerPixel ) ? + level + 1 : 0; + } + } + while( level != 0 ); + + // Restore old automatic mipmap generation state + if( AutoGen ) + { + glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, + GenMipMap ); + } + + // Restore old unpack alignment + glPixelStorei( GL_UNPACK_ALIGNMENT, UnpackAlignment ); + + return GL_TRUE; +} + diff --git a/libs/glfw/lib/init.c b/libs/glfw/lib/init.c new file mode 100644 index 0000000..bde6470 --- /dev/null +++ b/libs/glfw/lib/init.c @@ -0,0 +1,108 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: init.c +// Platform: Any +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#define _init_c_ +#include "internal.h" + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// glfwInit() - Initialize various GLFW state +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwInit( void ) +{ + // Is GLFW already initialized? + if( _glfwInitialized ) + { + return GL_TRUE; + } + + // Window is not yet opened + _glfwWin.Opened = GL_FALSE; + + // Default enable/disable settings + _glfwWin.SysKeysDisabled = GL_FALSE; + + // Clear window hints + _glfwClearWindowHints(); + + // Platform specific initialization + if( !_glfwPlatformInit() ) + { + return GL_FALSE; + } + + // Form now on, GLFW state is valid + _glfwInitialized = GL_TRUE; + + return GL_TRUE; +} + + + +//======================================================================== +// glfwTerminate() - Close window and kill all threads. +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwTerminate( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + // Platform specific termination + if( !_glfwPlatformTerminate() ) + { + return; + } + + // GLFW is no longer initialized + _glfwInitialized = GL_FALSE; +} + + +//======================================================================== +// glfwGetVersion() - Get GLFW version +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwGetVersion( int *major, int *minor, + int *rev ) +{ + if( major != NULL ) *major = GLFW_VERSION_MAJOR; + if( minor != NULL ) *minor = GLFW_VERSION_MINOR; + if( rev != NULL ) *rev = GLFW_VERSION_REVISION; +} + diff --git a/libs/glfw/lib/input.c b/libs/glfw/lib/input.c new file mode 100644 index 0000000..e32469f --- /dev/null +++ b/libs/glfw/lib/input.c @@ -0,0 +1,280 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: input.c +// Platform: Any +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//======================================================================== +// glfwGetKey() +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwGetKey( int key ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return GLFW_RELEASE; + } + + // Is it a valid key? + if( key < 0 || key > GLFW_KEY_LAST ) + { + return GLFW_RELEASE; + } + + if( _glfwInput.Key[ key ] == GLFW_STICK ) + { + // Sticky mode: release key now + _glfwInput.Key[ key ] = GLFW_RELEASE; + return GLFW_PRESS; + } + + return (int) _glfwInput.Key[ key ]; +} + + +//======================================================================== +// glfwGetMouseButton() +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwGetMouseButton( int button ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return GLFW_RELEASE; + } + + // Is it a valid mouse button? + if( button < 0 || button > GLFW_MOUSE_BUTTON_LAST ) + { + return GLFW_RELEASE; + } + + if( _glfwInput.MouseButton[ button ] == GLFW_STICK ) + { + // Sticky mode: release mouse button now + _glfwInput.MouseButton[ button ] = GLFW_RELEASE; + return GLFW_PRESS; + } + + return (int) _glfwInput.MouseButton[ button ]; +} + + +//======================================================================== +// glfwGetMousePos() +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwGetMousePos( int *xpos, int *ypos ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Return mouse position + if( xpos != NULL ) + { + *xpos = _glfwInput.MousePosX; + } + if( ypos != NULL ) + { + *ypos = _glfwInput.MousePosY; + } +} + + +//======================================================================== +// glfwSetMousePos() +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetMousePos( int xpos, int ypos ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Don't do anything if the mouse position did not change + if( xpos == _glfwInput.MousePosX && ypos == _glfwInput.MousePosY ) + { + return; + } + + // Set GLFW mouse position + _glfwInput.MousePosX = xpos; + _glfwInput.MousePosY = ypos; + + // If we have a locked mouse, do not change cursor position + if( _glfwWin.MouseLock ) + { + return; + } + + // Update physical cursor position + _glfwPlatformSetMouseCursorPos( xpos, ypos ); +} + + +//======================================================================== +// glfwGetMouseWheel() +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwGetMouseWheel( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return 0; + } + + // Return mouse wheel position + return _glfwInput.WheelPos; +} + + +//======================================================================== +// glfwSetMouseWheel() +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetMouseWheel( int pos ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Set mouse wheel position + _glfwInput.WheelPos = pos; +} + + +//======================================================================== +// glfwSetKeyCallback() - Set callback function for keyboard input +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetKeyCallback( GLFWkeyfun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Set callback function + _glfwWin.KeyCallback = cbfun; +} + + +//======================================================================== +// glfwSetCharCallback() - Set callback function for character input +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetCharCallback( GLFWcharfun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Set callback function + _glfwWin.CharCallback = cbfun; +} + + +//======================================================================== +// glfwSetMouseButtonCallback() - Set callback function for mouse clicks +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetMouseButtonCallback( GLFWmousebuttonfun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Set callback function + _glfwWin.MouseButtonCallback = cbfun; +} + + +//======================================================================== +// glfwSetMousePosCallback() - Set callback function for mouse moves +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetMousePosCallback( GLFWmouseposfun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Set callback function + _glfwWin.MousePosCallback = cbfun; + + // Call the callback function to let the application know the current + // mouse position + if( cbfun ) + { + cbfun( _glfwInput.MousePosX, _glfwInput.MousePosY ); + } +} + + +//======================================================================== +// glfwSetMouseWheelCallback() - Set callback function for mouse wheel +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetMouseWheelCallback( GLFWmousewheelfun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Set callback function + _glfwWin.MouseWheelCallback = cbfun; + + // Call the callback function to let the application know the current + // mouse wheel position + if( cbfun ) + { + cbfun( _glfwInput.WheelPos ); + } +} + diff --git a/libs/glfw/lib/internal.h b/libs/glfw/lib/internal.h new file mode 100644 index 0000000..42aa440 --- /dev/null +++ b/libs/glfw/lib/internal.h @@ -0,0 +1,210 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: internal.h +// Platform: Any +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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 _internal_h_ +#define _internal_h_ + +//======================================================================== +// GLFWGLOBAL is a macro that places all global variables in the init.c +// module (all other modules reference global variables as 'extern') +//======================================================================== + +#if defined( _init_c_ ) +#define GLFWGLOBAL +#else +#define GLFWGLOBAL extern +#endif + + +//======================================================================== +// Input handling definitions +//======================================================================== + +// Internal key and button state/action definitions +#define GLFW_STICK 2 + + +//======================================================================== +// System independent include files +//======================================================================== + +#include +#include +#include + + +//------------------------------------------------------------------------ +// Platform specific definitions goes in platform.h (which also includes +// glfw.h) +//------------------------------------------------------------------------ + +#include "platform.h" + + +//======================================================================== +// System independent global variables (GLFW internals) +//======================================================================== + +// Flag indicating if GLFW has been initialized +#if defined( _init_c_ ) +int _glfwInitialized = 0; +#else +GLFWGLOBAL int _glfwInitialized; +#endif + + +//------------------------------------------------------------------------ +// Window hints (set by glfwOpenWindowHint - will go into _GLFWthread) +//------------------------------------------------------------------------ +typedef struct { + int RefreshRate; + int AccumRedBits; + int AccumGreenBits; + int AccumBlueBits; + int AccumAlphaBits; + int AuxBuffers; + int Stereo; + int WindowNoResize; + int Samples; +} _GLFWhints; + +GLFWGLOBAL _GLFWhints _glfwWinHints; + + +//------------------------------------------------------------------------ +// Abstracted data stream (for image I/O) +//------------------------------------------------------------------------ +typedef struct { + FILE* File; + void* Data; + long Position; + long Size; +} _GLFWstream; + + +//======================================================================== +// Prototypes for platform specific implementation functions +//======================================================================== + +// Init/terminate +int _glfwPlatformInit( void ); +int _glfwPlatformTerminate( void ); + +// Enable/Disable +void _glfwPlatformEnableSystemKeys( void ); +void _glfwPlatformDisableSystemKeys( void ); + +// Fullscreen +int _glfwPlatformGetVideoModes( GLFWvidmode *list, int maxcount ); +void _glfwPlatformGetDesktopMode( GLFWvidmode *mode ); + +// OpenGL extensions +int _glfwPlatformExtensionSupported( const char *extension ); +void * _glfwPlatformGetProcAddress( const char *procname ); + +// Joystick +int _glfwPlatformGetJoystickParam( int joy, int param ); +int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes ); +int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, int numbuttons ); + +// Threads +GLFWthread _glfwPlatformCreateThread( GLFWthreadfun fun, void *arg ); +void _glfwPlatformDestroyThread( GLFWthread ID ); +int _glfwPlatformWaitThread( GLFWthread ID, int waitmode ); +GLFWthread _glfwPlatformGetThreadID( void ); +GLFWmutex _glfwPlatformCreateMutex( void ); +void _glfwPlatformDestroyMutex( GLFWmutex mutex ); +void _glfwPlatformLockMutex( GLFWmutex mutex ); +void _glfwPlatformUnlockMutex( GLFWmutex mutex ); +GLFWcond _glfwPlatformCreateCond( void ); +void _glfwPlatformDestroyCond( GLFWcond cond ); +void _glfwPlatformWaitCond( GLFWcond cond, GLFWmutex mutex, double timeout ); +void _glfwPlatformSignalCond( GLFWcond cond ); +void _glfwPlatformBroadcastCond( GLFWcond cond ); +int _glfwPlatformGetNumberOfProcessors( void ); + +// Time +double _glfwPlatformGetTime( void ); +void _glfwPlatformSetTime( double time ); +void _glfwPlatformSleep( double time ); + +// Window management +int _glfwPlatformOpenWindow( int width, int height, int redbits, int greenbits, int bluebits, int alphabits, int depthbits, int stencilbits, int mode, _GLFWhints* hints ); +void _glfwPlatformCloseWindow( void ); +void _glfwPlatformSetWindowTitle( const char *title ); +void _glfwPlatformSetWindowSize( int width, int height ); +void _glfwPlatformSetWindowPos( int x, int y ); +void _glfwPlatformIconifyWindow( void ); +void _glfwPlatformRestoreWindow( void ); +void _glfwPlatformSwapBuffers( void ); +void _glfwPlatformSwapInterval( int interval ); +void _glfwPlatformRefreshWindowParams( void ); +void _glfwPlatformPollEvents( void ); +void _glfwPlatformWaitEvents( void ); +void _glfwPlatformHideMouseCursor( void ); +void _glfwPlatformShowMouseCursor( void ); +void _glfwPlatformSetMouseCursorPos( int x, int y ); + + +//======================================================================== +// Prototypes for platform independent internal functions +//======================================================================== + +// Window management (window.c) +void _glfwClearWindowHints( void ); + +// Input handling (window.c) +void _glfwClearInput( void ); +void _glfwInputDeactivation( void ); +void _glfwInputKey( int key, int action ); +void _glfwInputChar( int character, int action ); +void _glfwInputMouseClick( int button, int action ); + +// Threads (thread.c) +_GLFWthread * _glfwGetThreadPointer( int ID ); +void _glfwAppendThread( _GLFWthread * t ); +void _glfwRemoveThread( _GLFWthread * t ); + +// OpenGL extensions (glext.c) +int _glfwStringInExtensionString( const char *string, const GLubyte *extensions ); + +// Abstracted data streams (stream.c) +int _glfwOpenFileStream( _GLFWstream *stream, const char *name, const char *mode ); +int _glfwOpenBufferStream( _GLFWstream *stream, void *data, long size ); +long _glfwReadStream( _GLFWstream *stream, void *data, long size ); +long _glfwTellStream( _GLFWstream *stream ); +int _glfwSeekStream( _GLFWstream *stream, long offset, int whence ); +void _glfwCloseStream( _GLFWstream *stream ); + +// Targa image I/O (tga.c) +int _glfwReadTGA( _GLFWstream *s, GLFWimage *img, int flags ); + + +#endif // _internal_h_ diff --git a/libs/glfw/lib/joystick.c b/libs/glfw/lib/joystick.c new file mode 100644 index 0000000..947e8f5 --- /dev/null +++ b/libs/glfw/lib/joystick.c @@ -0,0 +1,101 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: joystick.c +// Platform: Any +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// glfwGetJoystickParam() - Determine joystick capabilities +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwGetJoystickParam( int joy, int param ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return 0; + } + + return _glfwPlatformGetJoystickParam( joy, param ); +} + + +//======================================================================== +// glfwGetJoystickPos() - Get joystick axis positions +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwGetJoystickPos( int joy, float *pos, + int numaxes ) +{ + int i; + + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return 0; + } + + // Clear positions + for( i = 0; i < numaxes; i++ ) + { + pos[ i ] = 0.0f; + } + + return _glfwPlatformGetJoystickPos( joy, pos, numaxes ); +} + + +//======================================================================== +// glfwGetJoystickButtons() - Get joystick button states +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwGetJoystickButtons( int joy, + unsigned char *buttons, int numbuttons ) +{ + int i; + + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return 0; + } + + // Clear button states + for( i = 0; i < numbuttons; i++ ) + { + buttons[ i ] = GLFW_RELEASE; + } + + return _glfwPlatformGetJoystickButtons( joy, buttons, numbuttons ); +} diff --git a/libs/glfw/lib/macosx/Makefile.macosx.gcc b/libs/glfw/lib/macosx/Makefile.macosx.gcc new file mode 100644 index 0000000..5141704 --- /dev/null +++ b/libs/glfw/lib/macosx/Makefile.macosx.gcc @@ -0,0 +1,172 @@ +########################################################################## +# Makefile for GLFW on Mac OS X using GCC (Apple SDK). +#------------------------------------------------------------------------- +# To compile GLFW using this makefile, run: +# make -f Makefile.macosx.gcc +########################################################################## + +########################################################################## +# Installation prefix (default to /usr/local) +########################################################################## +PREFIX ?= /usr/local + + +########################################################################## +# Default: Build GLFW static and shared library +########################################################################## +default: libglfw.a libglfw.dylib + + +########################################################################## +# Compiler settings +########################################################################## +CC = gcc +CFLAGS = -c -I. -I.. -Wall -O2 -fno-common -g + +# Some modules should be optimized for speed (e.g. image decoding) +CFLAGS_SPEED = -c -I. -I.. -Wall -O3 -ffast-math -fno-common -g + + +########################################################################## +# Library builder settings +########################################################################## +AR = ar +SED = sed +INSTALL = install +ARFLAGS = -rcs +RANLIB = ranlib +DYLIBFLAGS = -framework AGL -framework Carbon -framework OpenGL \ + -dynamiclib -Wl,-single_module -compatibility_version 1 \ + -current_version 1 -install_name @executable_path/libglfw.dylib + + +########################################################################## +# Install GLFW header and static library +########################################################################## +install: libglfw.a libglfw.pc + $(INSTALL) -d $(PREFIX)/lib + $(INSTALL) -c -m 644 libglfw.a $(PREFIX)/lib/libglfw.a + $(RANLIB) $(PREFIX)/lib/libglfw.a + $(INSTALL) -d $(PREFIX)/include/GL + $(INSTALL) -c -m 644 ../../include/GL/glfw.h $(PREFIX)/include/GL/glfw.h + $(INSTALL) -d $(PREFIX)/lib/pkgconfig + $(INSTALL) -c -m 644 libglfw.pc $(PREFIX)/lib/pkgconfig/libglfw.pc + + +########################################################################## +# Object files for the GLFW library +########################################################################## +OBJS = \ + enable.o \ + fullscreen.o \ + glext.o \ + image.o \ + init.o \ + input.o \ + joystick.o \ + stream.o \ + tga.o \ + thread.o \ + time.o \ + window.o \ + macosx_enable.o \ + macosx_fullscreen.o \ + macosx_glext.o \ + macosx_init.o \ + macosx_joystick.o \ + macosx_thread.o \ + macosx_time.o \ + macosx_window.o + + +########################################################################## +# Rule for building libglfw.pc +########################################################################## +libglfw.pc: libglfw.pc.in + $(SED) -e 's,\@PREFIX\@,$(PREFIX),' libglfw.pc.in > libglfw.pc + + +########################################################################## +# Rule for building static library +########################################################################## +libglfw.a: $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + $(RANLIB) $@ + + +########################################################################## +# Rule for building shared library +########################################################################## +libglfw.dylib: $(OBJS) + $(CC) -o $@ $(DYLIBFLAGS) $(OBJS) + + +########################################################################## +# Rule for cleaning up generated files +########################################################################## +clean: + @rm -f *.o libglfw.a libglfw.dylib libglfw.pc + + +########################################################################## +# Rules for building library object files +########################################################################## +enable.o: ../enable.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../enable.c + +fullscreen.o: ../fullscreen.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../fullscreen.c + +glext.o: ../glext.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../glext.c + +image.o: ../image.c ../internal.h platform.h + $(CC) $(CFLAGS_SPEED) -o $@ ../image.c + +init.o: ../init.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../init.c + +input.o: ../input.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../input.c + +joystick.o: ../joystick.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../joystick.c + +stream.o: ../stream.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../stream.c + +tga.o: ../tga.c ../internal.h platform.h + $(CC) $(CFLAGS_SPEED) -o $@ ../tga.c + +thread.o: ../thread.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../thread.c + +time.o: ../time.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../time.c + +window.o: ../window.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../window.c + +macosx_enable.o: macosx_enable.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_enable.c + +macosx_fullscreen.o: macosx_fullscreen.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_fullscreen.c + +macosx_glext.o: macosx_glext.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_glext.c + +macosx_init.o: macosx_init.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_init.c + +macosx_joystick.o: macosx_joystick.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_joystick.c + +macosx_thread.o: macosx_thread.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_thread.c + +macosx_time.o: macosx_time.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_time.c + +macosx_window.o: macosx_window.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_window.c diff --git a/libs/glfw/lib/macosx/Makefile.macosx.gcc.universal b/libs/glfw/lib/macosx/Makefile.macosx.gcc.universal new file mode 100644 index 0000000..a57d8c8 --- /dev/null +++ b/libs/glfw/lib/macosx/Makefile.macosx.gcc.universal @@ -0,0 +1,166 @@ +########################################################################## +# Makefile for GLFW on Mac OS X using GCC (Apple SDK). +#------------------------------------------------------------------------- +# To compile GLFW using this makefile, run: +# make -f Makefile.macosx.gcc +########################################################################## + +########################################################################## +# Installation prefix (default to /usr/local) +########################################################################## +PREFIX ?= /usr/local + + +########################################################################## +# Default: Build GLFW static library +########################################################################## +default: libglfw.a + + +########################################################################## +# Compiler settings +########################################################################## +CC = gcc +FATFLAGS = -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch ppc -arch i386 +CFLAGS = -c -I. -I.. -Wall -Os -fno-common $(FATFLAGS) + +# Some modules should be optimized for speed (e.g. image decoding) +CFLAGS_SPEED = -c -I. -I.. -Wall -O3 -ffast-math -fno-common $(FATFLAGS) + + +########################################################################## +# Library builder settings +########################################################################## +# Static library +SED = sed +INSTALL = install +MKLIB = ar +LIBFLAGS = -rcs +RANLIB = ranlib + + +########################################################################## +# Install GLFW header and static library +########################################################################## +install: libglfw.a libglfw.pc + $(INSTALL) -d $(PREFIX)/lib + $(INSTALL) -c -m 644 libglfw.a $(PREFIX)/lib/libglfw.a + $(RANLIB) $(PREFIX)/lib/libglfw.a + $(INSTALL) -d $(PREFIX)/include/GL + $(INSTALL) -c -m 644 ../../include/GL/glfw.h $(PREFIX)/include/GL/glfw.h + $(INSTALL) -d $(PREFIX)/lib/pkgconfig + $(INSTALL) -c -m 644 libglfw.pc $(PREFIX)/lib/pkgconfig/libglfw.pc + + +########################################################################## +# Rule for cleaning up generated files +########################################################################## +clean: + @rm -f *.o libglfw.a libglfw.pc + + +########################################################################## +# Object files which are part of the GLFW library +########################################################################## +OBJS = \ + enable.o \ + fullscreen.o \ + glext.o \ + image.o \ + init.o \ + input.o \ + joystick.o \ + stream.o \ + tga.o \ + thread.o \ + time.o \ + window.o \ + macosx_enable.o \ + macosx_fullscreen.o \ + macosx_glext.o \ + macosx_init.o \ + macosx_joystick.o \ + macosx_thread.o \ + macosx_time.o \ + macosx_window.o + + +########################################################################## +# Rule for building libglfw.pc +########################################################################## +libglfw.pc: libglfw.pc.in + $(SED) -e 's,\@PREFIX\@,$(PREFIX),' libglfw.pc.in > libglfw.pc + + +########################################################################## +# Rule for building library +########################################################################## +libglfw.a: $(OBJS) + rm -f $@ + $(MKLIB) $(LIBFLAGS) $@ $(OBJS) + $(RANLIB) $@ + + +########################################################################## +# Rules for building library object files +########################################################################## +enable.o: ../enable.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../enable.c + +fullscreen.o: ../fullscreen.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../fullscreen.c + +glext.o: ../glext.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../glext.c + +image.o: ../image.c ../internal.h platform.h + $(CC) $(CFLAGS_SPEED) -o $@ ../image.c + +init.o: ../init.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../init.c + +input.o: ../input.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../input.c + +joystick.o: ../joystick.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../joystick.c + +stream.o: ../stream.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../stream.c + +tga.o: ../tga.c ../internal.h platform.h + $(CC) $(CFLAGS_SPEED) -o $@ ../tga.c + +thread.o: ../thread.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../thread.c + +time.o: ../time.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../time.c + +window.o: ../window.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ ../window.c + +macosx_enable.o: macosx_enable.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_enable.c + +macosx_fullscreen.o: macosx_fullscreen.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_fullscreen.c + +macosx_glext.o: macosx_glext.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_glext.c + +macosx_init.o: macosx_init.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_init.c + +macosx_joystick.o: macosx_joystick.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_joystick.c + +macosx_thread.o: macosx_thread.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_thread.c + +macosx_time.o: macosx_time.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_time.c + +macosx_window.o: macosx_window.c ../internal.h platform.h + $(CC) $(CFLAGS) -o $@ macosx_window.c + diff --git a/libs/glfw/lib/macosx/libglfw.pc.in b/libs/glfw/lib/macosx/libglfw.pc.in new file mode 100644 index 0000000..be69fee --- /dev/null +++ b/libs/glfw/lib/macosx/libglfw.pc.in @@ -0,0 +1,11 @@ +prefix=@PREFIX@ +exec_prefix=@PREFIX@ +libdir=@PREFIX@/lib +includedir=@PREFIX@/include + +Name: GLFW +Description: A portable framework for OpenGL development +Version: 2.6.0 +URL: http://glfw.sourceforge.net/ +Libs: -L${libdir} -lglfw -framework AGL -framework OpenGL -framework Carbon +Cflags: -I${includedir} diff --git a/libs/glfw/lib/macosx/macosx_enable.c b/libs/glfw/lib/macosx/macosx_enable.c new file mode 100644 index 0000000..957f240 --- /dev/null +++ b/libs/glfw/lib/macosx/macosx_enable.c @@ -0,0 +1,42 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: macosx_enable.c +// Platform: Mac OS X +// API Version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +void _glfwPlatformEnableSystemKeys( void ) +{ + // Nothing to do; event handling code checks the status of + // _glfwWin.SysKeysDisabled to ensure this behavior. +} + +void _glfwPlatformDisableSystemKeys( void ) +{ + // Nothing to do; event handling code checks the status of + // _glfwWin.SysKeysDisabled to ensure this behavior. +} + diff --git a/libs/glfw/lib/macosx/macosx_fullscreen.c b/libs/glfw/lib/macosx/macosx_fullscreen.c new file mode 100644 index 0000000..57fcd5f --- /dev/null +++ b/libs/glfw/lib/macosx/macosx_fullscreen.c @@ -0,0 +1,126 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: macosx_fullscreen.c +// Platform: Mac OS X +// API Version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + +//======================================================================== +// _glfwVideoModesEqual() - Compares two video modes +//======================================================================== + +static int _glfwVideoModesEqual( GLFWvidmode* first, + GLFWvidmode* second ) +{ + if( first->Width != second->Width ) + return 0; + + if( first->Height != second->Height ) + return 0; + + if( first->RedBits + first->GreenBits + first->BlueBits != + second->RedBits + second->GreenBits + second->BlueBits ) + return 0; + + return 1; +} + +//======================================================================== +// _glfwCGToGLFWVideoMode() - Converts a CG mode to a GLFW mode +//======================================================================== + +static void _glfwCGToGLFWVideoMode( CFDictionaryRef cgMode, + GLFWvidmode* glfwMode ) +{ + int bitsPerSample; + + CFNumberGetValue( CFDictionaryGetValue( cgMode, kCGDisplayWidth ), + kCFNumberIntType, + &(glfwMode->Width) ); + CFNumberGetValue( CFDictionaryGetValue( cgMode, kCGDisplayHeight ), + kCFNumberIntType, + &(glfwMode->Height) ); + + CFNumberGetValue( CFDictionaryGetValue( cgMode, kCGDisplayBitsPerSample ), + kCFNumberIntType, + &bitsPerSample ); + + glfwMode->RedBits = bitsPerSample; + glfwMode->GreenBits = bitsPerSample; + glfwMode->BlueBits = bitsPerSample; +} + +//======================================================================== +// _glfwPlatformGetVideoModes() - Get a list of available video modes +//======================================================================== + +int _glfwPlatformGetVideoModes( GLFWvidmode *list, int maxcount ) +{ + int i, j, maxModes, numModes; + GLFWvidmode mode; + CFArrayRef availableModes = CGDisplayAvailableModes( kCGDirectMainDisplay ); + CFIndex numberOfAvailableModes = CFArrayGetCount( availableModes ); + + numModes = 0; + maxModes = ( numberOfAvailableModes < maxcount ? + numberOfAvailableModes : + maxcount ); + + for( i = 0; i < maxModes; ++i ) + { + _glfwCGToGLFWVideoMode( CFArrayGetValueAtIndex( availableModes, i ), + &mode ); + + // Is it a valid mode? (only list depths >= 15 bpp) + if( mode.RedBits + mode.GreenBits + mode.BlueBits < 15 ) + continue; + + // Check for duplicate of current mode in target list + for( j = 0; j < numModes; ++j ) + { + if( _glfwVideoModesEqual( &mode, &(list[j]) ) ) + break; + } + + // If empty list or no match found + if( numModes == 0 || j == numModes ) + list[numModes++] = mode; + } + + return numModes; +} + +//======================================================================== +// glfwGetDesktopMode() - Get the desktop video mode +//======================================================================== + +void _glfwPlatformGetDesktopMode( GLFWvidmode *mode ) +{ + _glfwCGToGLFWVideoMode( _glfwDesktopVideoMode, mode ); +} + diff --git a/libs/glfw/lib/macosx/macosx_glext.c b/libs/glfw/lib/macosx/macosx_glext.c new file mode 100644 index 0000000..d696e8a --- /dev/null +++ b/libs/glfw/lib/macosx/macosx_glext.c @@ -0,0 +1,52 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: macosx_glext.c +// Platform: Mac OS X +// API Version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + +int _glfwPlatformExtensionSupported( const char *extension ) +{ + // There are no AGL, CGL or NSGL extensions. + return GL_FALSE; +} + +void * _glfwPlatformGetProcAddress( const char *procname ) +{ + CFStringRef symbolName = CFStringCreateWithCString( kCFAllocatorDefault, + procname, + kCFStringEncodingASCII ); + + void *symbol = CFBundleGetFunctionPointerForName( _glfwLibrary.Libs.OpenGLFramework, + symbolName ); + + CFRelease( symbolName ); + + return symbol; +} + diff --git a/libs/glfw/lib/macosx/macosx_init.c b/libs/glfw/lib/macosx/macosx_init.c new file mode 100644 index 0000000..e41f20e --- /dev/null +++ b/libs/glfw/lib/macosx/macosx_init.c @@ -0,0 +1,194 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: macosx_init.c +// Platform: Mac OS X +// API Version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + +#include + +//======================================================================== +// Global variables +//======================================================================== + +// KCHR resource pointer for keycode translation +void *KCHRPtr; + + +//======================================================================== +// _glfwInitThreads() - Initialize GLFW thread package +//======================================================================== + +static void _glfwInitThreads( void ) +{ + // Initialize critical section handle + (void) pthread_mutex_init( &_glfwThrd.CriticalSection, NULL ); + + // The first thread (the main thread) has ID 0 + _glfwThrd.NextID = 0; + + // Fill out information about the main thread (this thread) + _glfwThrd.First.ID = _glfwThrd.NextID ++; + _glfwThrd.First.Function = NULL; + _glfwThrd.First.PosixID = pthread_self(); + _glfwThrd.First.Previous = NULL; + _glfwThrd.First.Next = NULL; +} + +#define NO_BUNDLE_MESSAGE \ + "Working in unbundled mode. " \ + "You should build a .app wrapper for your Mac OS X applications.\n" + +#define UNBUNDLED \ + fprintf(stderr, NO_BUNDLE_MESSAGE); \ + _glfwLibrary.Unbundled = 1; \ + return + +void _glfwChangeToResourcesDirectory( void ) +{ + CFBundleRef mainBundle = CFBundleGetMainBundle(); + CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL( mainBundle ); + char resourcesPath[ _GLFW_MAX_PATH_LENGTH ]; + + CFStringRef lastComponent = CFURLCopyLastPathComponent( resourcesURL ); + if ( kCFCompareEqualTo != CFStringCompare( + CFSTR( "Resources" ), + lastComponent, + 0 ) ) + { + UNBUNDLED; + } + + CFRelease( lastComponent ); + + if( !CFURLGetFileSystemRepresentation( resourcesURL, + TRUE, + (UInt8*)resourcesPath, + _GLFW_MAX_PATH_LENGTH ) ) + { + CFRelease( resourcesURL ); + UNBUNDLED; + } + + CFRelease( resourcesURL ); + + if( chdir( resourcesPath ) != 0 ) + { + UNBUNDLED; + } +} + +int _glfwPlatformInit( void ) +{ + struct timeval tv; + UInt32 nullDummy = 0; + + _glfwWin.MacWindow = NULL; + _glfwWin.AGLContext = NULL; + _glfwWin.CGLContext = NULL; + _glfwWin.WindowFunctions = NULL; + _glfwWin.MouseUPP = NULL; + _glfwWin.CommandUPP = NULL; + _glfwWin.KeyboardUPP = NULL; + _glfwWin.WindowUPP = NULL; + + _glfwInput.Modifiers = 0; + + _glfwLibrary.Unbundled = 0; + + _glfwLibrary.Libs.OpenGLFramework + = CFBundleGetBundleWithIdentifier( CFSTR( "com.apple.opengl" ) ); + if( _glfwLibrary.Libs.OpenGLFramework == NULL ) + { + fprintf( + stderr, + "glfwInit failing because you aren't linked to OpenGL\n" ); + return GL_FALSE; + } + + _glfwDesktopVideoMode = CGDisplayCurrentMode( kCGDirectMainDisplay ); + if( _glfwDesktopVideoMode == NULL ) + { + fprintf( + stderr, + "glfwInit failing because it kind find the desktop display mode\n" ); + return GL_FALSE; + } + + _glfwInitThreads(); + + _glfwChangeToResourcesDirectory(); + + if( !_glfwInstallEventHandlers() ) + { + fprintf( + stderr, + "glfwInit failing because it can't install event handlers\n" ); + _glfwPlatformTerminate(); + return GL_FALSE; + } + + // Ugly hack to reduce the nasty jump that occurs at the first non- + // sys keypress, caused by OS X loading certain meta scripts used + // for lexical- and raw keycode translation - instead of letting + // this happen while our application is running, we do some blunt + // function calls in advance just to get the script caching out of + // the way BEFORE our window/screen is opened. These calls might + // generate err return codes, but we don't care in this case. + // NOTE: KCHRPtr is declared globally, because we need it later on. + KCHRPtr = (void *)GetScriptVariable( smCurrentScript, smKCHRCache ); + KeyTranslate( KCHRPtr, 0, &nullDummy ); + UppercaseText( (char *)&nullDummy, 0, smSystemScript ); + + gettimeofday( &tv, NULL ); + _glfwLibrary.Timer.t0 = tv.tv_sec + (double) tv.tv_usec / 1000000.0; + + return GL_TRUE; +} + +int _glfwPlatformTerminate( void ) +{ + if( _glfwWin.MouseUPP != NULL ) + { + DisposeEventHandlerUPP( _glfwWin.MouseUPP ); + _glfwWin.MouseUPP = NULL; + } + if( _glfwWin.CommandUPP != NULL ) + { + DisposeEventHandlerUPP( _glfwWin.CommandUPP ); + _glfwWin.CommandUPP = NULL; + } + if( _glfwWin.KeyboardUPP != NULL ) + { + DisposeEventHandlerUPP( _glfwWin.KeyboardUPP ); + _glfwWin.KeyboardUPP = NULL; + } + + return GL_TRUE; +} + diff --git a/libs/glfw/lib/macosx/macosx_joystick.c b/libs/glfw/lib/macosx/macosx_joystick.c new file mode 100644 index 0000000..90b186a --- /dev/null +++ b/libs/glfw/lib/macosx/macosx_joystick.c @@ -0,0 +1,50 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: macosx_joystick.c +// Platform: Mac OS X +// API Version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + +// TO DO: use HID manager to implement joystick support. + +int _glfwPlatformGetJoystickParam( int joy, int param ) +{ + // GL_FALSE == 0 + return 0; +} + +int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes ) +{ + return 0; +} + +int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, int numbuttons ) +{ + return 0; +} + diff --git a/libs/glfw/lib/macosx/macosx_thread.c b/libs/glfw/lib/macosx/macosx_thread.c new file mode 100644 index 0000000..76008d4 --- /dev/null +++ b/libs/glfw/lib/macosx/macosx_thread.c @@ -0,0 +1,414 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: macosx_thread.c +// Platform: Mac OS X +// API Version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwNewThread() - This is simply a "wrapper" for calling the user +// thread function. +//======================================================================== + +void * _glfwNewThread( void * arg ) +{ + GLFWthreadfun threadfun; + _GLFWthread *t; + + // Get pointer to thread information for current thread + t = _glfwGetThreadPointer( glfwGetThreadID() ); + if( t == NULL ) + { + return 0; + } + + // Get user thread function pointer + threadfun = t->Function; + + // Call the user thread function + threadfun( arg ); + + // Remove thread from thread list + ENTER_THREAD_CRITICAL_SECTION + _glfwRemoveThread( t ); + LEAVE_THREAD_CRITICAL_SECTION + + // When the thread function returns, the thread will die... + return NULL; +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformCreateThread() - Create a new thread +//======================================================================== + +GLFWthread _glfwPlatformCreateThread( GLFWthreadfun fun, void *arg ) +{ + GLFWthread ID; + _GLFWthread *t; + int result; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Create a new thread information memory area + t = (_GLFWthread *) malloc( sizeof(_GLFWthread) ); + if( t == NULL ) + { + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + return -1; + } + + // Get a new unique thread id + ID = _glfwThrd.NextID ++; + + // Store thread information in the thread list + t->Function = fun; + t->ID = ID; + + // Create thread + result = pthread_create( + &t->PosixID, // Thread handle + NULL, // Default thread attributes + _glfwNewThread, // Thread function (a wrapper function) + (void *)arg // Argument to thread is user argument + ); + + // Did the thread creation fail? + if( result != 0 ) + { + free( (void *) t ); + LEAVE_THREAD_CRITICAL_SECTION + return -1; + } + + // Append thread to thread list + _glfwAppendThread( t ); + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Return the GLFW thread ID + return ID; +} + + +//======================================================================== +// _glfwPlatformDestroyThread() - Kill a thread. NOTE: THIS IS A VERY +// DANGEROUS OPERATION, AND SHOULD NOT BE USED EXCEPT IN EXTREME +// SITUATIONS! +//======================================================================== + +void _glfwPlatformDestroyThread( GLFWthread ID ) +{ + _GLFWthread *t; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Get thread information pointer + t = _glfwGetThreadPointer( ID ); + if( t == NULL ) + { + LEAVE_THREAD_CRITICAL_SECTION + return; + } + + // Simply murder the process, no mercy! + pthread_kill( t->PosixID, SIGKILL ); + + // Remove thread from thread list + _glfwRemoveThread( t ); + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION +} + + +//======================================================================== +// _glfwPlatformWaitThread() - Wait for a thread to die +//======================================================================== + +int _glfwPlatformWaitThread( GLFWthread ID, int waitmode ) +{ + pthread_t thread; + _GLFWthread *t; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Get thread information pointer + t = _glfwGetThreadPointer( ID ); + + // Is the thread already dead? + if( t == NULL ) + { + LEAVE_THREAD_CRITICAL_SECTION + return GL_TRUE; + } + + // If got this far, the thread is alive => polling returns FALSE + if( waitmode == GLFW_NOWAIT ) + { + LEAVE_THREAD_CRITICAL_SECTION + return GL_FALSE; + } + + // Get thread handle + thread = t->PosixID; + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Wait for thread to die + (void) pthread_join( thread, NULL ); + + return GL_TRUE; +} + + +//======================================================================== +// _glfwPlatformGetThreadID() - Return the thread ID for the current +// thread +//======================================================================== + +GLFWthread _glfwPlatformGetThreadID( void ) +{ + _GLFWthread *t; + GLFWthread ID = -1; + pthread_t posixID; + + // Get current thread ID + posixID = pthread_self(); + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Loop through entire list of threads to find the matching POSIX + // thread ID + for( t = &_glfwThrd.First; t != NULL; t = t->Next ) + { + if( t->PosixID == posixID ) + { + ID = t->ID; + break; + } + } + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Return the found GLFW thread identifier + return ID; +} + + +//======================================================================== +// _glfwPlatformCreateMutex() - Create a mutual exclusion object +//======================================================================== + +GLFWmutex _glfwPlatformCreateMutex( void ) +{ + pthread_mutex_t *mutex; + + // Allocate memory for mutex + mutex = (pthread_mutex_t *) malloc( sizeof( pthread_mutex_t ) ); + if( !mutex ) + { + return NULL; + } + + // Initialise a mutex object + (void) pthread_mutex_init( mutex, NULL ); + + // Cast to GLFWmutex and return + return (GLFWmutex) mutex; +} + + +//======================================================================== +// _glfwPlatformDestroyMutex() - Destroy a mutual exclusion object +//======================================================================== + +void _glfwPlatformDestroyMutex( GLFWmutex mutex ) +{ + // Destroy the mutex object + pthread_mutex_destroy( (pthread_mutex_t *) mutex ); + + // Free memory for mutex object + free( (void *) mutex ); +} + + +//======================================================================== +// _glfwPlatformLockMutex() - Request access to a mutex +//======================================================================== + +void _glfwPlatformLockMutex( GLFWmutex mutex ) +{ + // Wait for mutex to be released + (void) pthread_mutex_lock( (pthread_mutex_t *) mutex ); +} + + +//======================================================================== +// _glfwPlatformUnlockMutex() - Release a mutex +//======================================================================== + +void _glfwPlatformUnlockMutex( GLFWmutex mutex ) +{ + // Release mutex + pthread_mutex_unlock( (pthread_mutex_t *) mutex ); +} + + +//======================================================================== +// _glfwPlatformCreateCond() - Create a new condition variable object +//======================================================================== + +GLFWcond _glfwPlatformCreateCond( void ) +{ + pthread_cond_t *cond; + + // Allocate memory for condition variable + cond = (pthread_cond_t *) malloc( sizeof(pthread_cond_t) ); + if( !cond ) + { + return NULL; + } + + // Initialise condition variable + (void) pthread_cond_init( cond, NULL ); + + // Cast to GLFWcond and return + return (GLFWcond) cond; +} + + +//======================================================================== +// _glfwPlatformDestroyCond() - Destroy a condition variable object +//======================================================================== + +void _glfwPlatformDestroyCond( GLFWcond cond ) +{ + // Destroy the condition variable object + (void) pthread_cond_destroy( (pthread_cond_t *) cond ); + + // Free memory for condition variable object + free( (void *) cond ); +} + + +//======================================================================== +// _glfwPlatformWaitCond() - Wait for a condition to be raised +//======================================================================== + +void _glfwPlatformWaitCond( GLFWcond cond, GLFWmutex mutex, + double timeout ) +{ + struct timeval currenttime; + struct timespec wait; + long dt_sec, dt_usec; + + // Select infinite or timed wait + if( timeout >= GLFW_INFINITY ) + { + // Wait for condition (infinite wait) + (void) pthread_cond_wait( (pthread_cond_t *) cond, + (pthread_mutex_t *) mutex ); + } + else + { + // Set timeout time, relatvie to current time + gettimeofday( ¤ttime, NULL ); + dt_sec = (long) timeout; + dt_usec = (long) ((timeout - (double)dt_sec) * 1000000.0); + wait.tv_nsec = (currenttime.tv_usec + dt_usec) * 1000L; + if( wait.tv_nsec > 1000000000L ) + { + wait.tv_nsec -= 1000000000L; + dt_sec ++; + } + wait.tv_sec = currenttime.tv_sec + dt_sec; + + // Wait for condition (timed wait) + (void) pthread_cond_timedwait( (pthread_cond_t *) cond, + (pthread_mutex_t *) mutex, &wait ); + } +} + + +//======================================================================== +// _glfwPlatformSignalCond() - Signal a condition to one waiting thread +//======================================================================== + +void _glfwPlatformSignalCond( GLFWcond cond ) +{ + // Signal condition + (void) pthread_cond_signal( (pthread_cond_t *) cond ); +} + + +//======================================================================== +// _glfwPlatformBroadcastCond() - Broadcast a condition to all waiting +// threads +//======================================================================== + +void _glfwPlatformBroadcastCond( GLFWcond cond ) +{ + // Broadcast condition + (void) pthread_cond_broadcast( (pthread_cond_t *) cond ); +} + + +//======================================================================== +// _glfwPlatformGetNumberOfProcessors() - Return the number of processors +// in the system. +//======================================================================== + +int _glfwPlatformGetNumberOfProcessors( void ) +{ + int n; + + // Get number of processors online + _glfw_numprocessors( n ); + return n; +} + diff --git a/libs/glfw/lib/macosx/macosx_time.c b/libs/glfw/lib/macosx/macosx_time.c new file mode 100644 index 0000000..d1a1b93 --- /dev/null +++ b/libs/glfw/lib/macosx/macosx_time.c @@ -0,0 +1,112 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: macosx_time.c +// Platform: Mac OS X +// API Version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Return timer value in seconds +//======================================================================== + +double _glfwPlatformGetTime( void ) +{ + struct timeval tv; + + gettimeofday( &tv, NULL ); + return tv.tv_sec + (double) tv.tv_usec / 1000000.0 - _glfwLibrary.Timer.t0; +} + + +//======================================================================== +// Set timer value in seconds +//======================================================================== + +void _glfwPlatformSetTime( double time ) +{ + struct timeval tv; + + gettimeofday( &tv, NULL ); + _glfwLibrary.Timer.t0 = tv.tv_sec + (double) tv.tv_usec / 1000000.0 - time; +} + + +//======================================================================== +// Put a thread to sleep for a specified amount of time +//======================================================================== + +void _glfwPlatformSleep( double time ) +{ + if( time == 0.0 ) + { + sched_yield(); + return; + } + + struct timeval currenttime; + struct timespec wait; + pthread_mutex_t mutex; + pthread_cond_t cond; + long dt_sec, dt_usec; + + // Not all pthread implementations have a pthread_sleep() function. We + // do it the portable way, using a timed wait for a condition that we + // will never signal. NOTE: The unistd functions sleep/usleep suspends + // the entire PROCESS, not a signle thread, which is why we can not + // use them to implement glfwSleep. + + // Set timeout time, relatvie to current time + gettimeofday( ¤ttime, NULL ); + dt_sec = (long) time; + dt_usec = (long) ((time - (double)dt_sec) * 1000000.0); + wait.tv_nsec = (currenttime.tv_usec + dt_usec) * 1000L; + if( wait.tv_nsec > 1000000000L ) + { + wait.tv_nsec -= 1000000000L; + dt_sec ++; + } + wait.tv_sec = currenttime.tv_sec + dt_sec; + + // Initialize condition and mutex objects + pthread_mutex_init( &mutex, NULL ); + pthread_cond_init( &cond, NULL ); + + // Do a timed wait + pthread_mutex_lock( &mutex ); + pthread_cond_timedwait( &cond, &mutex, &wait ); + pthread_mutex_unlock( &mutex ); + + // Destroy condition and mutex objects + pthread_mutex_destroy( &mutex ); + pthread_cond_destroy( &cond ); +} + diff --git a/libs/glfw/lib/macosx/macosx_window.c b/libs/glfw/lib/macosx/macosx_window.c new file mode 100644 index 0000000..21af88f --- /dev/null +++ b/libs/glfw/lib/macosx/macosx_window.c @@ -0,0 +1,1279 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: macosx_window.c +// Platform: Mac OS X +// API Version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + +static _GLFWmacwindowfunctions _glfwMacFSWindowFunctions = +{ + _glfwMacFSOpenWindow, + _glfwMacFSCloseWindow, + _glfwMacFSSetWindowTitle, + _glfwMacFSSetWindowSize, + _glfwMacFSSetWindowPos, + _glfwMacFSIconifyWindow, + _glfwMacFSRestoreWindow, + _glfwMacFSRefreshWindowParams, + _glfwMacFSSetMouseCursorPos +}; + +static _GLFWmacwindowfunctions _glfwMacDWWindowFunctions = +{ + _glfwMacDWOpenWindow, + _glfwMacDWCloseWindow, + _glfwMacDWSetWindowTitle, + _glfwMacDWSetWindowSize, + _glfwMacDWSetWindowPos, + _glfwMacDWIconifyWindow, + _glfwMacDWRestoreWindow, + _glfwMacDWRefreshWindowParams, + _glfwMacDWSetMouseCursorPos +}; + +#define _glfwTestModifier( modifierMask, glfwKey ) \ +if ( changed & modifierMask ) \ +{ \ + _glfwInputKey( glfwKey, (modifiers & modifierMask ? GLFW_PRESS : GLFW_RELEASE) ); \ +} + +void _glfwHandleMacModifierChange( UInt32 modifiers ) +{ + UInt32 changed = modifiers ^ _glfwInput.Modifiers; + + _glfwTestModifier( shiftKey, GLFW_KEY_LSHIFT ); + _glfwTestModifier( rightShiftKey, GLFW_KEY_RSHIFT ); + _glfwTestModifier( controlKey, GLFW_KEY_LCTRL ); + _glfwTestModifier( rightControlKey, GLFW_KEY_RCTRL ); + _glfwTestModifier( optionKey, GLFW_KEY_LALT ); + _glfwTestModifier( rightOptionKey, GLFW_KEY_RALT ); + + _glfwInput.Modifiers = modifiers; +} + +void _glfwHandleMacKeyChange( UInt32 keyCode, int action ) +{ + switch ( keyCode ) + { + case MAC_KEY_ENTER: _glfwInputKey( GLFW_KEY_ENTER, action); break; + case MAC_KEY_RETURN: _glfwInputKey( GLFW_KEY_KP_ENTER, action); break; + case MAC_KEY_ESC: _glfwInputKey( GLFW_KEY_ESC, action); break; + case MAC_KEY_F1: _glfwInputKey( GLFW_KEY_F1, action); break; + case MAC_KEY_F2: _glfwInputKey( GLFW_KEY_F2, action); break; + case MAC_KEY_F3: _glfwInputKey( GLFW_KEY_F3, action); break; + case MAC_KEY_F4: _glfwInputKey( GLFW_KEY_F4, action); break; + case MAC_KEY_F5: _glfwInputKey( GLFW_KEY_F5, action); break; + case MAC_KEY_F6: _glfwInputKey( GLFW_KEY_F6, action); break; + case MAC_KEY_F7: _glfwInputKey( GLFW_KEY_F7, action); break; + case MAC_KEY_F8: _glfwInputKey( GLFW_KEY_F8, action); break; + case MAC_KEY_F9: _glfwInputKey( GLFW_KEY_F9, action); break; + case MAC_KEY_F10: _glfwInputKey( GLFW_KEY_F10, action); break; + case MAC_KEY_F11: _glfwInputKey( GLFW_KEY_F11, action); break; + case MAC_KEY_F12: _glfwInputKey( GLFW_KEY_F12, action); break; + case MAC_KEY_F13: _glfwInputKey( GLFW_KEY_F13, action); break; + case MAC_KEY_F14: _glfwInputKey( GLFW_KEY_F14, action); break; + case MAC_KEY_F15: _glfwInputKey( GLFW_KEY_F15, action); break; + case MAC_KEY_UP: _glfwInputKey( GLFW_KEY_UP, action); break; + case MAC_KEY_DOWN: _glfwInputKey( GLFW_KEY_DOWN, action); break; + case MAC_KEY_LEFT: _glfwInputKey( GLFW_KEY_LEFT, action); break; + case MAC_KEY_RIGHT: _glfwInputKey( GLFW_KEY_RIGHT, action); break; + case MAC_KEY_TAB: _glfwInputKey( GLFW_KEY_TAB, action); break; + case MAC_KEY_BACKSPACE: _glfwInputKey( GLFW_KEY_BACKSPACE, action); break; + case MAC_KEY_HELP: _glfwInputKey( GLFW_KEY_INSERT, action); break; + case MAC_KEY_DEL: _glfwInputKey( GLFW_KEY_DEL, action); break; + case MAC_KEY_PAGEUP: _glfwInputKey( GLFW_KEY_PAGEUP, action); break; + case MAC_KEY_PAGEDOWN: _glfwInputKey( GLFW_KEY_PAGEDOWN, action); break; + case MAC_KEY_HOME: _glfwInputKey( GLFW_KEY_HOME, action); break; + case MAC_KEY_END: _glfwInputKey( GLFW_KEY_END, action); break; + case MAC_KEY_KP_0: _glfwInputKey( GLFW_KEY_KP_0, action); break; + case MAC_KEY_KP_1: _glfwInputKey( GLFW_KEY_KP_1, action); break; + case MAC_KEY_KP_2: _glfwInputKey( GLFW_KEY_KP_2, action); break; + case MAC_KEY_KP_3: _glfwInputKey( GLFW_KEY_KP_3, action); break; + case MAC_KEY_KP_4: _glfwInputKey( GLFW_KEY_KP_4, action); break; + case MAC_KEY_KP_5: _glfwInputKey( GLFW_KEY_KP_5, action); break; + case MAC_KEY_KP_6: _glfwInputKey( GLFW_KEY_KP_6, action); break; + case MAC_KEY_KP_7: _glfwInputKey( GLFW_KEY_KP_7, action); break; + case MAC_KEY_KP_8: _glfwInputKey( GLFW_KEY_KP_8, action); break; + case MAC_KEY_KP_9: _glfwInputKey( GLFW_KEY_KP_9, action); break; + case MAC_KEY_KP_DIVIDE: _glfwInputKey( GLFW_KEY_KP_DIVIDE, action); break; + case MAC_KEY_KP_MULTIPLY: _glfwInputKey( GLFW_KEY_KP_MULTIPLY, action); break; + case MAC_KEY_KP_SUBTRACT: _glfwInputKey( GLFW_KEY_KP_SUBTRACT, action); break; + case MAC_KEY_KP_ADD: _glfwInputKey( GLFW_KEY_KP_ADD, action); break; + case MAC_KEY_KP_DECIMAL: _glfwInputKey( GLFW_KEY_KP_DECIMAL, action); break; + case MAC_KEY_KP_EQUAL: _glfwInputKey( GLFW_KEY_KP_EQUAL, action); break; + case MAC_KEY_KP_ENTER: _glfwInputKey( GLFW_KEY_KP_ENTER, action); break; + default: + { + extern void *KCHRPtr; + UInt32 state = 0; + char charCode = (char)KeyTranslate( KCHRPtr, keyCode, &state ); + UppercaseText( &charCode, 1, smSystemScript ); + _glfwInputKey( (unsigned char)charCode, action ); + } + break; + } +} + +EventTypeSpec GLFW_KEY_EVENT_TYPES[] = +{ + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassKeyboard, kEventRawKeyUp }, + { kEventClassKeyboard, kEventRawKeyModifiersChanged } +}; + +OSStatus _glfwKeyEventHandler( EventHandlerCallRef handlerCallRef, + EventRef event, + void *userData ) +{ + UInt32 keyCode; + short int keyChar; + UInt32 modifiers; + + switch( GetEventKind( event ) ) + { + case kEventRawKeyDown: + { + if( GetEventParameter( event, + kEventParamKeyCode, + typeUInt32, + NULL, + sizeof( UInt32 ), + NULL, + &keyCode ) == noErr ) + { + _glfwHandleMacKeyChange( keyCode, GLFW_PRESS ); + } + if( GetEventParameter( event, + kEventParamKeyUnicodes, + typeUnicodeText, + NULL, + sizeof(keyChar), + NULL, + &keyChar) == noErr ) + { + _glfwInputChar( keyChar, GLFW_PRESS ); + } + return noErr; + } + + case kEventRawKeyUp: + { + if( GetEventParameter( event, + kEventParamKeyCode, + typeUInt32, + NULL, + sizeof( UInt32 ), + NULL, + &keyCode ) == noErr ) + { + _glfwHandleMacKeyChange( keyCode, GLFW_RELEASE ); + } + if( GetEventParameter( event, + kEventParamKeyUnicodes, + typeUnicodeText, + NULL, + sizeof(keyChar), + NULL, + &keyChar) == noErr ) + { + _glfwInputChar( keyChar, GLFW_RELEASE ); + } + return noErr; + } + + case kEventRawKeyModifiersChanged: + { + if( GetEventParameter( event, + kEventParamKeyModifiers, + typeUInt32, + NULL, + sizeof( UInt32 ), + NULL, + &modifiers ) == noErr ) + { + _glfwHandleMacModifierChange( modifiers ); + return noErr; + } + } + break; + } + + return eventNotHandledErr; +} + +EventTypeSpec GLFW_MOUSE_EVENT_TYPES[] = +{ + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, kEventMouseDragged }, + { kEventClassMouse, kEventMouseWheelMoved }, +}; + +OSStatus _glfwMouseEventHandler( EventHandlerCallRef handlerCallRef, + EventRef event, + void *userData ) +{ + switch( GetEventKind( event ) ) + { + case kEventMouseDown: + { + WindowRef window; + EventRecord oldStyleMacEvent; + ConvertEventRefToEventRecord( event, &oldStyleMacEvent ); + if( FindWindow ( oldStyleMacEvent.where, &window ) == inMenuBar ) + { + MenuSelect( oldStyleMacEvent.where ); + HiliteMenu(0); + return noErr; + } + else + { + EventMouseButton button; + if( GetEventParameter( event, + kEventParamMouseButton, + typeMouseButton, + NULL, + sizeof( EventMouseButton ), + NULL, + &button ) == noErr ) + { + button -= kEventMouseButtonPrimary; + if( button <= GLFW_MOUSE_BUTTON_LAST ) + { + _glfwInputMouseClick( button + + GLFW_MOUSE_BUTTON_LEFT, + GLFW_PRESS ); + } + return noErr; + } + } + break; + } + + case kEventMouseUp: + { + EventMouseButton button; + if( GetEventParameter( event, + kEventParamMouseButton, + typeMouseButton, + NULL, + sizeof( EventMouseButton ), + NULL, + &button ) == noErr ) + { + button -= kEventMouseButtonPrimary; + if( button <= GLFW_MOUSE_BUTTON_LAST ) + { + _glfwInputMouseClick( button + + GLFW_MOUSE_BUTTON_LEFT, + GLFW_RELEASE ); + } + return noErr; + } + break; + } + + case kEventMouseMoved: + case kEventMouseDragged: + { + HIPoint mouseLocation; + if( _glfwWin.MouseLock ) + { + if( GetEventParameter( event, + kEventParamMouseDelta, + typeHIPoint, + NULL, + sizeof( HIPoint ), + NULL, + &mouseLocation ) != noErr ) + { + break; + } + + _glfwInput.MousePosX += mouseLocation.x; + _glfwInput.MousePosY += mouseLocation.y; + } + else + { + if( GetEventParameter( event, + kEventParamMouseLocation, + typeHIPoint, + NULL, + sizeof( HIPoint ), + NULL, + &mouseLocation ) != noErr ) + { + break; + } + + _glfwInput.MousePosX = mouseLocation.x; + _glfwInput.MousePosY = mouseLocation.y; + + if( !_glfwWin.Fullscreen ) + { + Rect content; + GetWindowBounds( _glfwWin.MacWindow, + kWindowContentRgn, + &content ); + + _glfwInput.MousePosX -= content.left; + _glfwInput.MousePosY -= content.top; + } + } + + if( _glfwWin.MousePosCallback ) + { + _glfwWin.MousePosCallback( _glfwInput.MousePosX, + _glfwInput.MousePosY ); + } + + break; + } + + case kEventMouseWheelMoved: + { + EventMouseWheelAxis axis; + if( GetEventParameter( event, + kEventParamMouseWheelAxis, + typeMouseWheelAxis, + NULL, + sizeof( EventMouseWheelAxis ), + NULL, + &axis) == noErr ) + { + long wheelDelta; + if( axis == kEventMouseWheelAxisY && + GetEventParameter( event, + kEventParamMouseWheelDelta, + typeLongInteger, + NULL, + sizeof( long ), + NULL, + &wheelDelta ) == noErr ) + { + _glfwInput.WheelPos += wheelDelta; + if( _glfwWin.MouseWheelCallback ) + { + _glfwWin.MouseWheelCallback( _glfwInput.WheelPos ); + } + return noErr; + } + } + break; + } + } + + return eventNotHandledErr; +} + +EventTypeSpec GLFW_COMMAND_EVENT_TYPES[] = +{ + { kEventClassCommand, kEventCommandProcess } +}; + +OSStatus _glfwCommandHandler( EventHandlerCallRef handlerCallRef, + EventRef event, + void *userData ) +{ + if( _glfwWin.SysKeysDisabled ) + { + // TO DO: give adequate UI feedback that this is the case + return eventNotHandledErr; + } + + HICommand command; + if( GetEventParameter( event, + kEventParamDirectObject, + typeHICommand, + NULL, + sizeof( HICommand ), + NULL, + &command ) == noErr ) + { + switch( command.commandID ) + { + case kHICommandClose: + case kHICommandQuit: + { + // Check if the program wants us to close the window + if( _glfwWin.WindowCloseCallback ) + { + if( _glfwWin.WindowCloseCallback() ) + { + glfwCloseWindow(); + } + } + else + { + glfwCloseWindow(); + } + return noErr; + } + } + } + + return eventNotHandledErr; +} + +EventTypeSpec GLFW_WINDOW_EVENT_TYPES[] = +{ + { kEventClassWindow, kEventWindowBoundsChanged }, + { kEventClassWindow, kEventWindowClose }, + { kEventClassWindow, kEventWindowDrawContent }, + { kEventClassWindow, kEventWindowActivated }, + { kEventClassWindow, kEventWindowDeactivated }, +}; + +OSStatus _glfwWindowEventHandler( EventHandlerCallRef handlerCallRef, + EventRef event, + void *userData ) +{ + switch( GetEventKind(event) ) + { + case kEventWindowBoundsChanged: + { + WindowRef window; + GetEventParameter( event, kEventParamDirectObject, typeWindowRef, NULL, + sizeof(WindowRef), NULL, &window ); + + Rect rect; + GetWindowPortBounds( window, &rect ); + + if( _glfwWin.Width != rect.right || + _glfwWin.Height != rect.bottom ) + { + aglUpdateContext(_glfwWin.AGLContext); + + _glfwWin.Width = rect.right; + _glfwWin.Height = rect.bottom; + if( _glfwWin.WindowSizeCallback ) + { + _glfwWin.WindowSizeCallback( _glfwWin.Width, + _glfwWin.Height ); + } + // Emulate (force) content invalidation + if( _glfwWin.WindowRefreshCallback ) + { + _glfwWin.WindowRefreshCallback(); + } + } + break; + } + + case kEventWindowClose: + { + // Check if the program wants us to close the window + if( _glfwWin.WindowCloseCallback ) + { + if( _glfwWin.WindowCloseCallback() ) + { + glfwCloseWindow(); + } + } + else + { + glfwCloseWindow(); + } + return noErr; + } + + case kEventWindowDrawContent: + { + // Call user callback function + if( _glfwWin.WindowRefreshCallback ) + { + _glfwWin.WindowRefreshCallback(); + } + break; + } + + case kEventWindowActivated: + { + _glfwWin.Active = GL_TRUE; + break; + } + + case kEventWindowDeactivated: + { + _glfwWin.Active = GL_FALSE; + _glfwInputDeactivation(); + break; + } + } + + return eventNotHandledErr; +} + +int _glfwInstallEventHandlers( void ) +{ + OSStatus error; + + _glfwWin.MouseUPP = NewEventHandlerUPP( _glfwMouseEventHandler ); + + error = InstallEventHandler( GetApplicationEventTarget(), + _glfwWin.MouseUPP, + GetEventTypeCount( GLFW_MOUSE_EVENT_TYPES ), + GLFW_MOUSE_EVENT_TYPES, + NULL, + NULL ); + if( error != noErr ) + { + fprintf( stderr, "glfwOpenWindow failing because it can't install mouse event handler\n" ); + return GL_FALSE; + } + + _glfwWin.CommandUPP = NewEventHandlerUPP( _glfwCommandHandler ); + + error = InstallEventHandler( GetApplicationEventTarget(), + _glfwWin.CommandUPP, + GetEventTypeCount( GLFW_COMMAND_EVENT_TYPES ), + GLFW_COMMAND_EVENT_TYPES, + NULL, + NULL ); + if( error != noErr ) + { + fprintf( stderr, "glfwOpenWindow failing because it can't install command event handler\n" ); + return GL_FALSE; + } + + _glfwWin.KeyboardUPP = NewEventHandlerUPP( _glfwKeyEventHandler ); + + error = InstallEventHandler( GetApplicationEventTarget(), + _glfwWin.KeyboardUPP, + GetEventTypeCount( GLFW_KEY_EVENT_TYPES ), + GLFW_KEY_EVENT_TYPES, + NULL, + NULL ); + if( error != noErr ) + { + fprintf( stderr, "glfwOpenWindow failing because it can't install key event handler\n" ); + return GL_FALSE; + } + + return GL_TRUE; +} + +#define _setAGLAttribute( aglAttributeName, AGLparameter ) \ +if ( AGLparameter != 0 ) \ +{ \ + AGLpixelFormatAttributes[numAGLAttrs++] = aglAttributeName; \ + AGLpixelFormatAttributes[numAGLAttrs++] = AGLparameter; \ +} + +#define _getAGLAttribute( aglAttributeName, variableName ) \ +{ \ + GLint aglValue; \ + (void)aglDescribePixelFormat( pixelFormat, aglAttributeName, &aglValue ); \ + variableName = aglValue; \ +} + +#define _setCGLAttribute( cglAttributeName, CGLparameter ) \ +if ( CGLparameter != 0 ) \ +{ \ + CGLpixelFormatAttributes[ numCGLAttrs++ ] = cglAttributeName; \ + CGLpixelFormatAttributes[ numCGLAttrs++ ] = CGLparameter; \ +} + +#define _getCGLAttribute( cglAttributeName, variableName ) \ +{ \ + long cglValue; \ + (void)CGLDescribePixelFormat( CGLpfObj, 0, cglAttributeName, &cglValue ); \ + variableName = cglValue; \ +} + +int _glfwPlatformOpenWindow( int width, + int height, + int redbits, + int greenbits, + int bluebits, + int alphabits, + int depthbits, + int stencilbits, + int mode, + _GLFWhints* hints ) +{ + OSStatus error; + ProcessSerialNumber psn; + + unsigned int windowAttributes; + + // TO DO: Refactor this function! + _glfwWin.WindowFunctions = ( _glfwWin.Fullscreen ? + &_glfwMacFSWindowFunctions : + &_glfwMacDWWindowFunctions ); + + // Windowed or fullscreen; AGL or CGL? Quite the mess... + // AGL appears to be the only choice for attaching OpenGL contexts to + // Carbon windows, but it leaves the user no control over fullscreen + // mode stretching. Solution: AGL for windowed, CGL for fullscreen. + if( !_glfwWin.Fullscreen ) + { + // create AGL pixel format attribute list + GLint AGLpixelFormatAttributes[256]; + int numAGLAttrs = 0; + + AGLpixelFormatAttributes[numAGLAttrs++] = AGL_RGBA; + AGLpixelFormatAttributes[numAGLAttrs++] = AGL_DOUBLEBUFFER; + + if( hints->Stereo ) + { + AGLpixelFormatAttributes[numAGLAttrs++] = AGL_STEREO; + } + + _setAGLAttribute( AGL_AUX_BUFFERS, hints->AuxBuffers); + _setAGLAttribute( AGL_RED_SIZE, redbits ); + _setAGLAttribute( AGL_GREEN_SIZE, greenbits ); + _setAGLAttribute( AGL_BLUE_SIZE, bluebits ); + _setAGLAttribute( AGL_ALPHA_SIZE, alphabits ); + _setAGLAttribute( AGL_DEPTH_SIZE, depthbits ); + _setAGLAttribute( AGL_STENCIL_SIZE, stencilbits ); + _setAGLAttribute( AGL_ACCUM_RED_SIZE, hints->AccumRedBits ); + _setAGLAttribute( AGL_ACCUM_GREEN_SIZE, hints->AccumGreenBits ); + _setAGLAttribute( AGL_ACCUM_BLUE_SIZE, hints->AccumBlueBits ); + _setAGLAttribute( AGL_ACCUM_ALPHA_SIZE, hints->AccumAlphaBits ); + + if( hints->Samples > 1 ) + { + _setAGLAttribute( AGL_SAMPLE_BUFFERS_ARB, 1 ); + _setAGLAttribute( AGL_SAMPLES_ARB, hints->Samples ); + AGLpixelFormatAttributes[numAGLAttrs++] = AGL_NO_RECOVERY; + } + + AGLpixelFormatAttributes[numAGLAttrs++] = AGL_NONE; + + // create pixel format descriptor + AGLDevice mainMonitor = GetMainDevice(); + AGLPixelFormat pixelFormat = aglChoosePixelFormat( &mainMonitor, + 1, + AGLpixelFormatAttributes ); + if( pixelFormat == NULL ) + { + fprintf( stderr, "glfwOpenWindow failing because it can't create a pixel format\n" ); + return GL_FALSE; + } + + // store pixel format's values for _glfwPlatformGetWindowParam's use + _getAGLAttribute( AGL_ACCELERATED, _glfwWin.Accelerated ); + _getAGLAttribute( AGL_RED_SIZE, _glfwWin.RedBits ); + _getAGLAttribute( AGL_GREEN_SIZE, _glfwWin.GreenBits ); + _getAGLAttribute( AGL_BLUE_SIZE, _glfwWin.BlueBits ); + _getAGLAttribute( AGL_ALPHA_SIZE, _glfwWin.AlphaBits ); + _getAGLAttribute( AGL_DEPTH_SIZE, _glfwWin.DepthBits ); + _getAGLAttribute( AGL_STENCIL_SIZE, _glfwWin.StencilBits ); + _getAGLAttribute( AGL_ACCUM_RED_SIZE, _glfwWin.AccumRedBits ); + _getAGLAttribute( AGL_ACCUM_GREEN_SIZE, _glfwWin.AccumGreenBits ); + _getAGLAttribute( AGL_ACCUM_BLUE_SIZE, _glfwWin.AccumBlueBits ); + _getAGLAttribute( AGL_ACCUM_ALPHA_SIZE, _glfwWin.AccumAlphaBits ); + _getAGLAttribute( AGL_AUX_BUFFERS, _glfwWin.AuxBuffers ); + _getAGLAttribute( AGL_STEREO, _glfwWin.Stereo ); + _getAGLAttribute( AGL_SAMPLES_ARB, _glfwWin.Samples ); + _glfwWin.RefreshRate = hints->RefreshRate; + + // create AGL context + _glfwWin.AGLContext = aglCreateContext( pixelFormat, NULL ); + + aglDestroyPixelFormat( pixelFormat ); + + if( _glfwWin.AGLContext == NULL ) + { + fprintf( stderr, "glfwOpenWindow failing because it can't create an OpenGL context\n" ); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + if (_glfwLibrary.Unbundled) + { + if( GetCurrentProcess( &psn ) != noErr ) + { + fprintf( stderr, "glfwOpenWindow failing because it can't get its PSN\n" ); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + if( TransformProcessType( &psn, kProcessTransformToForegroundApplication ) != noErr ) + { + fprintf( stderr, "glfwOpenWindow failing because it can't become a foreground application\n" ); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + /* Keith Bauer 2007-07-12 - I don't believe this is desirable + if( SetFrontProcess( &psn ) != noErr ) + { + fprintf( stderr, "glfwOpenWindow failing because it can't become the front process\n" ); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + */ + } + + // create window + Rect windowContentBounds; + windowContentBounds.left = 0; + windowContentBounds.top = 0; + windowContentBounds.right = width; + windowContentBounds.bottom = height; + + windowAttributes = ( kWindowCloseBoxAttribute \ + | kWindowCollapseBoxAttribute \ + | kWindowStandardHandlerAttribute ); + + if( hints->WindowNoResize ) + { + windowAttributes |= kWindowLiveResizeAttribute; + } + else + { + windowAttributes |= ( kWindowFullZoomAttribute | kWindowResizableAttribute ); + } + + error = CreateNewWindow( kDocumentWindowClass, + windowAttributes, + &windowContentBounds, + &( _glfwWin.MacWindow ) ); + if( ( error != noErr ) || ( _glfwWin.MacWindow == NULL ) ) + { + fprintf( stderr, "glfwOpenWindow failing because it can't create a window\n" ); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + _glfwWin.WindowUPP = NewEventHandlerUPP( _glfwWindowEventHandler ); + + error = InstallWindowEventHandler( _glfwWin.MacWindow, + _glfwWin.WindowUPP, + GetEventTypeCount( GLFW_WINDOW_EVENT_TYPES ), + GLFW_WINDOW_EVENT_TYPES, + NULL, + NULL ); + if( error != noErr ) + { + fprintf( stderr, "glfwOpenWindow failing because it can't install window event handlers\n" ); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Don't care if we fail here + (void)SetWindowTitleWithCFString( _glfwWin.MacWindow, CFSTR( "GLFW Window" ) ); + (void)RepositionWindow( _glfwWin.MacWindow, + NULL, + kWindowCenterOnMainScreen ); + + if( !aglSetDrawable( _glfwWin.AGLContext, + GetWindowPort( _glfwWin.MacWindow ) ) ) + { + fprintf( stderr, "glfwOpenWindow failing because it can't draw to the window\n" ); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Make OpenGL context current + if( !aglSetCurrentContext( _glfwWin.AGLContext ) ) + { + fprintf( stderr, "glfwOpenWindow failing because it can't make the OpenGL context current\n" ); + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // show window + ShowWindow( _glfwWin.MacWindow ); + + return GL_TRUE; + } + else + { + CGDisplayErr cgErr; + CGLError cglErr; + + CFDictionaryRef optimalMode; + + CGLPixelFormatObj CGLpfObj; + long numCGLvs = 0; + + CGLPixelFormatAttribute CGLpixelFormatAttributes[64]; + int numCGLAttrs = 0; + + // variables for enumerating color depths + long rgbColorDepth; + long rgbaAccumDepth = 0; + int rgbChannelDepth = 0; + + // CGL pixel format attributes + _setCGLAttribute( kCGLPFADisplayMask, + CGDisplayIDToOpenGLDisplayMask( kCGDirectMainDisplay ) ); + + if( hints->Stereo ) + { + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFAStereo; + } + + if( hints->Samples > 1 ) + { + _setCGLAttribute( kCGLPFASamples, (CGLPixelFormatAttribute)hints->Samples ); + _setCGLAttribute( kCGLPFASampleBuffers, (CGLPixelFormatAttribute)1 ); + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFANoRecovery; + } + + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFAFullScreen; + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFADoubleBuffer; + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFAAccelerated; + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFANoRecovery; + CGLpixelFormatAttributes[ numCGLAttrs++ ] = kCGLPFAMinimumPolicy; + + _setCGLAttribute( kCGLPFAAccumSize, + (CGLPixelFormatAttribute)( hints->AccumRedBits \ + + hints->AccumGreenBits \ + + hints->AccumBlueBits \ + + hints->AccumAlphaBits ) ); + + _setCGLAttribute( kCGLPFAAlphaSize, (CGLPixelFormatAttribute)alphabits ); + _setCGLAttribute( kCGLPFADepthSize, (CGLPixelFormatAttribute)depthbits ); + _setCGLAttribute( kCGLPFAStencilSize, (CGLPixelFormatAttribute)stencilbits ); + _setCGLAttribute( kCGLPFAAuxBuffers, (CGLPixelFormatAttribute)hints->AuxBuffers ); + + CGLpixelFormatAttributes[ numCGLAttrs++ ] = (CGLPixelFormatAttribute)NULL; + + // create a suitable pixel format with above attributes.. + cglErr = CGLChoosePixelFormat( CGLpixelFormatAttributes, + &CGLpfObj, + &numCGLvs ); + if( cglErr != kCGLNoError ) + { + return GL_FALSE; + } + + // ..and create a rendering context using that pixel format + cglErr = CGLCreateContext( CGLpfObj, NULL, &_glfwWin.CGLContext ); + if( cglErr != kCGLNoError ) + { + return GL_FALSE; + } + + // enumerate depth of RGB channels - unlike AGL, CGL works with + // a single parameter reflecting the full depth of the frame buffer + (void)CGLDescribePixelFormat( CGLpfObj, 0, kCGLPFAColorSize, &rgbColorDepth ); + if( rgbColorDepth == 24 || rgbColorDepth == 32 ) + { + rgbChannelDepth = 8; + } + if( rgbColorDepth == 16 ) + { + rgbChannelDepth = 5; + } + + // get pixel depth of accumulator - I haven't got the slightest idea + // how this number conforms to any other channel depth than 8 bits, + // so this might end up giving completely knackered results... + (void)CGLDescribePixelFormat( CGLpfObj, 0, kCGLPFAAccumSize, &rgbaAccumDepth ); + if( rgbaAccumDepth == 32 ) + { + rgbaAccumDepth = 8; + } + + // store values of pixel format for _glfwPlatformGetWindowParam's use + _getCGLAttribute( kCGLPFAAccelerated, _glfwWin.Accelerated ); + _getCGLAttribute( rgbChannelDepth, _glfwWin.RedBits ); + _getCGLAttribute( rgbChannelDepth, _glfwWin.GreenBits ); + _getCGLAttribute( rgbChannelDepth, _glfwWin.BlueBits ); + _getCGLAttribute( kCGLPFAAlphaSize, _glfwWin.AlphaBits ); + _getCGLAttribute( kCGLPFADepthSize, _glfwWin.DepthBits ); + _getCGLAttribute( kCGLPFAStencilSize, _glfwWin.StencilBits ); + _getCGLAttribute( rgbaAccumDepth, _glfwWin.AccumRedBits ); + _getCGLAttribute( rgbaAccumDepth, _glfwWin.AccumGreenBits ); + _getCGLAttribute( rgbaAccumDepth, _glfwWin.AccumBlueBits ); + _getCGLAttribute( rgbaAccumDepth, _glfwWin.AccumAlphaBits ); + _getCGLAttribute( kCGLPFAAuxBuffers, _glfwWin.AuxBuffers ); + _getCGLAttribute( kCGLPFAStereo, _glfwWin.Stereo ); + _glfwWin.RefreshRate = hints->RefreshRate; + + // destroy our pixel format + (void)CGLDestroyPixelFormat( CGLpfObj ); + + // capture the display for our application + cgErr = CGCaptureAllDisplays(); + if( cgErr != kCGErrorSuccess ) + { + return GL_FALSE; + } + + // find closest matching NON-STRETCHED display mode.. + optimalMode = CGDisplayBestModeForParametersAndRefreshRateWithProperty( kCGDirectMainDisplay, + rgbColorDepth, + width, + /* Check further to the right -> */ height, + hints->RefreshRate, + NULL, + NULL ); + if( optimalMode == NULL ) + { + return GL_FALSE; + } + + // ..and switch to that mode + cgErr = CGDisplaySwitchToMode( kCGDirectMainDisplay, optimalMode ); + if( cgErr != kCGErrorSuccess ) + { + return GL_FALSE; + } + + // switch to our OpenGL context, and bring it up fullscreen + cglErr = CGLSetCurrentContext( _glfwWin.CGLContext ); + if( cglErr != kCGLNoError ) + { + return GL_FALSE; + } + + cglErr = CGLSetFullScreen( _glfwWin.CGLContext ); + if( cglErr != kCGLNoError ) + { + return GL_FALSE; + } + + return GL_TRUE; + } +} + +void _glfwPlatformCloseWindow( void ) +{ + if( _glfwWin.WindowFunctions != NULL ) + { + if( _glfwWin.WindowUPP != NULL ) + { + DisposeEventHandlerUPP( _glfwWin.WindowUPP ); + _glfwWin.WindowUPP = NULL; + } + + _glfwWin.WindowFunctions->CloseWindow(); + + if( !_glfwWin.Fullscreen && _glfwWin.AGLContext != NULL ) + { + aglSetCurrentContext( NULL ); + aglSetDrawable( _glfwWin.AGLContext, NULL ); + aglDestroyContext( _glfwWin.AGLContext ); + _glfwWin.AGLContext = NULL; + } + + if( _glfwWin.Fullscreen && _glfwWin.CGLContext != NULL ) + { + CGLSetCurrentContext( NULL ); + CGLClearDrawable( _glfwWin.CGLContext ); + CGLDestroyContext( _glfwWin.CGLContext ); + CGReleaseAllDisplays(); + _glfwWin.CGLContext = NULL; + } + + if( _glfwWin.MacWindow != NULL ) + { + ReleaseWindow( _glfwWin.MacWindow ); + _glfwWin.MacWindow = NULL; + } + + _glfwWin.WindowFunctions = NULL; + } +} + +void _glfwPlatformSetWindowTitle( const char *title ) +{ + _glfwWin.WindowFunctions->SetWindowTitle( title ); +} + +void _glfwPlatformSetWindowSize( int width, int height ) +{ + _glfwWin.WindowFunctions->SetWindowSize( width, height ); +} + +void _glfwPlatformSetWindowPos( int x, int y ) +{ + _glfwWin.WindowFunctions->SetWindowPos( x, y ); +} + +void _glfwPlatformIconifyWindow( void ) +{ + _glfwWin.WindowFunctions->IconifyWindow(); +} + +void _glfwPlatformRestoreWindow( void ) +{ + _glfwWin.WindowFunctions->RestoreWindow(); +} + +void _glfwPlatformSwapBuffers( void ) +{ + if( !_glfwWin.Fullscreen ) + { + aglSwapBuffers( _glfwWin.AGLContext ); + } + else + { + CGLFlushDrawable( _glfwWin.CGLContext ); + } +} + +void _glfwPlatformSwapInterval( int interval ) +{ + GLint AGLparameter = interval; + + // CGL doesn't seem to like intervals other than 0 (vsync off) or 1 (vsync on) + long CGLparameter = ( interval == 0 ? 0 : 1 ); + + if( !_glfwWin.Fullscreen ) + { + // Don't care if we fail here.. + (void)aglSetInteger( _glfwWin.AGLContext, + AGL_SWAP_INTERVAL, + &AGLparameter ); + } + else + { + // ..or here + (void)CGLSetParameter( _glfwWin.CGLContext, + kCGLCPSwapInterval, + &CGLparameter ); + } +} + +void _glfwPlatformRefreshWindowParams( void ) +{ + _glfwWin.WindowFunctions->RefreshWindowParams(); +} + +int _glfwPlatformGetWindowParam( int param ) +{ + switch ( param ) + { + case GLFW_ACCELERATED: return _glfwWin.Accelerated; break; + case GLFW_RED_BITS: return _glfwWin.RedBits; break; + case GLFW_GREEN_BITS: return _glfwWin.GreenBits; break; + case GLFW_BLUE_BITS: return _glfwWin.BlueBits; break; + case GLFW_ALPHA_BITS: return _glfwWin.AlphaBits; break; + case GLFW_DEPTH_BITS: return _glfwWin.DepthBits; break; + case GLFW_STENCIL_BITS: return _glfwWin.StencilBits; break; + case GLFW_ACCUM_RED_BITS: return _glfwWin.AccumRedBits; break; + case GLFW_ACCUM_GREEN_BITS: return _glfwWin.AccumGreenBits; break; + case GLFW_ACCUM_BLUE_BITS: return _glfwWin.AccumBlueBits; break; + case GLFW_ACCUM_ALPHA_BITS: return _glfwWin.AccumAlphaBits; break; + case GLFW_AUX_BUFFERS: return _glfwWin.AuxBuffers; break; + case GLFW_STEREO: return _glfwWin.Stereo; break; + case GLFW_REFRESH_RATE: return _glfwWin.RefreshRate; break; + default: return GL_FALSE; + } +} + +void _glfwPlatformPollEvents( void ) +{ + EventRef event; + EventTargetRef eventDispatcher = GetEventDispatcherTarget(); + + while ( ReceiveNextEvent( 0, NULL, 0.0, TRUE, &event ) == noErr ) + { + SendEventToEventTarget( event, eventDispatcher ); + ReleaseEvent( event ); + } +} + +void _glfwPlatformWaitEvents( void ) +{ + EventRef event; + + // Wait for new events + ReceiveNextEvent( 0, NULL, kEventDurationForever, FALSE, &event ); + + // Poll new events + _glfwPlatformPollEvents(); +} + +void _glfwPlatformHideMouseCursor( void ) +{ + // TO DO: What if we fail here? + CGDisplayHideCursor( kCGDirectMainDisplay ); + CGAssociateMouseAndMouseCursorPosition( false ); +} + +void _glfwPlatformShowMouseCursor( void ) +{ + // TO DO: What if we fail here? + CGDisplayShowCursor( kCGDirectMainDisplay ); + CGAssociateMouseAndMouseCursorPosition( true ); +} + +void _glfwPlatformSetMouseCursorPos( int x, int y ) +{ + _glfwWin.WindowFunctions->SetMouseCursorPos( x, y ); +} + +int _glfwMacFSOpenWindow( int width, + int height, + int redbits, + int greenbits, + int bluebits, + int alphabits, + int depthbits, + int stencilbits, + int accumredbits, + int accumgreenbits, + int accumbluebits, + int accumalphabits, + int auxbuffers, + int stereo, + int refreshrate ) +{ + return GL_FALSE; +} + +void _glfwMacFSCloseWindow( void ) +{ + // TO DO: un-capture displays, &c. +} + +void _glfwMacFSSetWindowTitle( const char *title ) +{ + // no-op really, change "fake" mini-window title + _glfwMacDWSetWindowTitle( title ); +} + +void _glfwMacFSSetWindowSize( int width, int height ) +{ + // TO DO: something funky for full-screen + _glfwMacDWSetWindowSize( width, height ); +} + +void _glfwMacFSSetWindowPos( int x, int y ) +{ + // no-op really, change "fake" mini-window position + _glfwMacDWSetWindowPos( x, y ); +} + +void _glfwMacFSIconifyWindow( void ) +{ + // TO DO: Something funky for full-screen + _glfwMacDWIconifyWindow(); +} + +void _glfwMacFSRestoreWindow( void ) +{ + _glfwMacDWRestoreWindow(); + // TO DO: Something funky for full-screen +} + +void _glfwMacFSRefreshWindowParams( void ) +{ + // TO DO: implement this! +} + +void _glfwMacFSSetMouseCursorPos( int x, int y ) +{ + // TO DO: what if we fail here? + CGDisplayMoveCursorToPoint( kCGDirectMainDisplay, + CGPointMake( x, y ) ); +} + +int _glfwMacDWOpenWindow( int width, + int height, + int redbits, + int greenbits, + int bluebits, + int alphabits, + int depthbits, + int stencilbits, + int accumredbits, + int accumgreenbits, + int accumbluebits, + int accumalphabits, + int auxbuffers, + int stereo, + int refreshrate ) +{ + return GL_FALSE; +} + +void _glfwMacDWCloseWindow( void ) +{ +} + +void _glfwMacDWSetWindowTitle( const char *title ) +{ + CFStringRef windowTitle = CFStringCreateWithCString( kCFAllocatorDefault, + title, + kCFStringEncodingISOLatin1 ); + + // Don't care if we fail + (void)SetWindowTitleWithCFString( _glfwWin.MacWindow, windowTitle ); + + CFRelease( windowTitle ); +} + +void _glfwMacDWSetWindowSize( int width, int height ) +{ + SizeWindow( _glfwWin.MacWindow, + width, + height, + TRUE ); +} + +void _glfwMacDWSetWindowPos( int x, int y ) +{ + // TO DO: take main monitor bounds into account + MoveWindow( _glfwWin.MacWindow, + x, + y, + FALSE ); +} + +void _glfwMacDWIconifyWindow( void ) +{ + // TO DO: What if we fail here? + (void)CollapseWindow( _glfwWin.MacWindow, + TRUE ); +} + +void _glfwMacDWRestoreWindow( void ) +{ + // TO DO: What if we fail here? + (void)CollapseWindow( _glfwWin.MacWindow, + FALSE ); +} + +void _glfwMacDWRefreshWindowParams( void ) +{ + // TO DO: implement this! +} + +void _glfwMacDWSetMouseCursorPos( int x, int y ) +{ + Rect content; + GetWindowBounds(_glfwWin.MacWindow, kWindowContentRgn, &content); + + _glfwInput.MousePosX = x + content.left; + _glfwInput.MousePosY = y + content.top; + + CGDisplayMoveCursorToPoint( kCGDirectMainDisplay, + CGPointMake( _glfwInput.MousePosX, + _glfwInput.MousePosY ) ); +} + diff --git a/libs/glfw/lib/macosx/platform.h b/libs/glfw/lib/macosx/platform.h new file mode 100644 index 0000000..1b719b3 --- /dev/null +++ b/libs/glfw/lib/macosx/platform.h @@ -0,0 +1,349 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: platform.h +// Platform: Mac OS X +// API Version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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 _platform_h_ +#define _platform_h_ + + +// This is the Mac OS X version of GLFW +#define _GLFW_MAC_OS_X + + +// Include files +#include +#include +#include +#include +#include +#include +#include "../../include/GL/glfw.h" + + +//======================================================================== +// Defines +//======================================================================== + +#define _GLFW_MAX_PATH_LENGTH (8192) + +#define MAC_KEY_ENTER 0x24 +#define MAC_KEY_RETURN 0x34 +#define MAC_KEY_ESC 0x35 +#define MAC_KEY_F1 0x7A +#define MAC_KEY_F2 0x78 +#define MAC_KEY_F3 0x63 +#define MAC_KEY_F4 0x76 +#define MAC_KEY_F5 0x60 +#define MAC_KEY_F6 0x61 +#define MAC_KEY_F7 0x62 +#define MAC_KEY_F8 0x64 +#define MAC_KEY_F9 0x65 +#define MAC_KEY_F10 0x6D +#define MAC_KEY_F11 0x67 +#define MAC_KEY_F12 0x6F +#define MAC_KEY_F13 0x69 +#define MAC_KEY_F14 0x6B +#define MAC_KEY_F15 0x71 +#define MAC_KEY_UP 0x7E +#define MAC_KEY_DOWN 0x7D +#define MAC_KEY_LEFT 0x7B +#define MAC_KEY_RIGHT 0x7C +#define MAC_KEY_TAB 0x30 +#define MAC_KEY_BACKSPACE 0x33 +#define MAC_KEY_HELP 0x72 +#define MAC_KEY_DEL 0x75 +#define MAC_KEY_PAGEUP 0x74 +#define MAC_KEY_PAGEDOWN 0x79 +#define MAC_KEY_HOME 0x73 +#define MAC_KEY_END 0x77 +#define MAC_KEY_KP_0 0x52 +#define MAC_KEY_KP_1 0x53 +#define MAC_KEY_KP_2 0x54 +#define MAC_KEY_KP_3 0x55 +#define MAC_KEY_KP_4 0x56 +#define MAC_KEY_KP_5 0x57 +#define MAC_KEY_KP_6 0x58 +#define MAC_KEY_KP_7 0x59 +#define MAC_KEY_KP_8 0x5B +#define MAC_KEY_KP_9 0x5C +#define MAC_KEY_KP_DIVIDE 0x4B +#define MAC_KEY_KP_MULTIPLY 0x43 +#define MAC_KEY_KP_SUBTRACT 0x4E +#define MAC_KEY_KP_ADD 0x45 +#define MAC_KEY_KP_DECIMAL 0x41 +#define MAC_KEY_KP_EQUAL 0x51 +#define MAC_KEY_KP_ENTER 0x4C + +//======================================================================== +// full-screen/desktop-window "virtual" function table +//======================================================================== + +typedef int ( * GLFWmacopenwindowfun )( int, int, int, int, int, int, int, int, int, int, int, int, int, int, int ); +typedef void ( * GLFWmacclosewindowfun )( void ); +typedef void ( * GLFWmacsetwindowtitlefun )( const char * ); +typedef void ( * GLFWmacsetwindowsizefun )( int, int ); +typedef void ( * GLFWmacsetwindowposfun )( int, int ); +typedef void ( * GLFWmaciconifywindowfun )( void ); +typedef void ( * GLFWmacrestorewindowfun )( void ); +typedef void ( * GLFWmacrefreshwindowparamsfun )( void ); +typedef void ( * GLFWmacsetmousecursorposfun )( int, int ); + +typedef struct +{ + GLFWmacopenwindowfun OpenWindow; + GLFWmacclosewindowfun CloseWindow; + GLFWmacsetwindowtitlefun SetWindowTitle; + GLFWmacsetwindowsizefun SetWindowSize; + GLFWmacsetwindowposfun SetWindowPos; + GLFWmaciconifywindowfun IconifyWindow; + GLFWmacrestorewindowfun RestoreWindow; + GLFWmacrefreshwindowparamsfun RefreshWindowParams; + GLFWmacsetmousecursorposfun SetMouseCursorPos; +} +_GLFWmacwindowfunctions; + + +//======================================================================== +// Global variables (GLFW internals) +//======================================================================== + +GLFWGLOBAL CFDictionaryRef _glfwDesktopVideoMode; + +//------------------------------------------------------------------------ +// Window structure +//------------------------------------------------------------------------ +typedef struct _GLFWwin_struct _GLFWwin; + +struct _GLFWwin_struct { + + // ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Window states + int Opened; // Flag telling if window is opened or not + int Active; // Application active flag + int Iconified; // Window iconified flag + + // User callback functions + GLFWwindowsizefun WindowSizeCallback; + GLFWwindowclosefun WindowCloseCallback; + GLFWwindowrefreshfun WindowRefreshCallback; + GLFWmousebuttonfun MouseButtonCallback; + GLFWmouseposfun MousePosCallback; + GLFWmousewheelfun MouseWheelCallback; + GLFWkeyfun KeyCallback; + GLFWcharfun CharCallback; + + // User selected window settings + int Fullscreen; // Fullscreen flag + int MouseLock; // Mouse-lock flag + int AutoPollEvents; // Auto polling flag + int SysKeysDisabled; // System keys disabled flag + int RefreshRate; // Refresh rate (for fullscreen mode) + int WindowNoResize; // Resize- and maximize gadgets disabled flag + int Samples; + + // Window status + int Width, Height; // Window width and heigth + + // Extensions & OpenGL version + int Has_GL_SGIS_generate_mipmap; + int Has_GL_ARB_texture_non_power_of_two; + int GLVerMajor,GLVerMinor; + + + // ========= PLATFORM SPECIFIC PART ====================================== + + WindowRef MacWindow; + AGLContext AGLContext; + CGLContextObj CGLContext; + + EventHandlerUPP MouseUPP; + EventHandlerUPP CommandUPP; + EventHandlerUPP KeyboardUPP; + EventHandlerUPP WindowUPP; + + _GLFWmacwindowfunctions* WindowFunctions; + + // for easy access by _glfwPlatformGetWindowParam + int Accelerated; + int RedBits, GreenBits, BlueBits, AlphaBits; + int DepthBits; + int StencilBits; + int AccumRedBits, AccumGreenBits, AccumBlueBits, AccumAlphaBits; + int AuxBuffers; + int Stereo; +}; + +GLFWGLOBAL _GLFWwin _glfwWin; + + +//------------------------------------------------------------------------ +// User input status (some of this should go in _GLFWwin) +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + + // ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Mouse status + int MousePosX, MousePosY; + int WheelPos; + char MouseButton[ GLFW_MOUSE_BUTTON_LAST+1 ]; + + // Keyboard status + char Key[ GLFW_KEY_LAST+1 ]; + int LastChar; + + // User selected settings + int StickyKeys; + int StickyMouseButtons; + int KeyRepeat; + + + // ========= PLATFORM SPECIFIC PART ====================================== + + UInt32 Modifiers; + +} _glfwInput; + + + + +//------------------------------------------------------------------------ +// Thread information +//------------------------------------------------------------------------ +typedef struct _GLFWthread_struct _GLFWthread; + +// Thread record (one for each thread) +struct _GLFWthread_struct { + // Pointer to previous and next threads in linked list + _GLFWthread *Previous, *Next; + + // GLFW user side thread information + GLFWthread ID; + GLFWthreadfun Function; + + // System side thread information + pthread_t PosixID; +}; + +// General thread information +GLFWGLOBAL struct { + // Critical section lock + pthread_mutex_t CriticalSection; + + // Next thread ID to use (increments for every created thread) + GLFWthread NextID; + + // First thread in linked list (always the main thread) + _GLFWthread First; +} _glfwThrd; + + +//------------------------------------------------------------------------ +// Library global data +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + + // Timer data + struct { + double t0; + } Timer; + + struct { + // Bundle for dynamically-loading extension function pointers + CFBundleRef OpenGLFramework; + } Libs; + + int Unbundled; + +} _glfwLibrary; + + + +//======================================================================== +// Macros for encapsulating critical code sections (i.e. making parts +// of GLFW thread safe) +//======================================================================== + +// Define so we can use the same thread code as X11 +#define _glfw_numprocessors(n) { \ + int mib[2], ncpu; \ + size_t len = 1; \ + mib[0] = CTL_HW; \ + mib[1] = HW_NCPU; \ + n = 1; \ + if( sysctl( mib, 2, &ncpu, &len, NULL, 0 ) != -1 ) \ + { \ + if( len > 0 ) \ + { \ + n = ncpu; \ + } \ + } \ +} + +// Thread list management +#define ENTER_THREAD_CRITICAL_SECTION \ +pthread_mutex_lock( &_glfwThrd.CriticalSection ); +#define LEAVE_THREAD_CRITICAL_SECTION \ +pthread_mutex_unlock( &_glfwThrd.CriticalSection ); + + +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +void _glfwChangeToResourcesDirectory( void ); + +int _glfwInstallEventHandlers( void ); + +//======================================================================== +// Prototypes for full-screen/desktop-window "virtual" functions +//======================================================================== + +int _glfwMacFSOpenWindow( int width, int height, int redbits, int greenbits, int bluebits, int alphabits, int depthbits, int stencilbits, int accumredbits, int accumgreenbits, int accumbluebits, int accumalphabits, int auxbuffers, int stereo, int refreshrate ); +void _glfwMacFSCloseWindow( void ); +void _glfwMacFSSetWindowTitle( const char *title ); +void _glfwMacFSSetWindowSize( int width, int height ); +void _glfwMacFSSetWindowPos( int x, int y ); +void _glfwMacFSIconifyWindow( void ); +void _glfwMacFSRestoreWindow( void ); +void _glfwMacFSRefreshWindowParams( void ); +void _glfwMacFSSetMouseCursorPos( int x, int y ); + +int _glfwMacDWOpenWindow( int width, int height, int redbits, int greenbits, int bluebits, int alphabits, int depthbits, int stencilbits, int accumredbits, int accumgreenbits, int accumbluebits, int accumalphabits, int auxbuffers, int stereo, int refreshrate ); +void _glfwMacDWCloseWindow( void ); +void _glfwMacDWSetWindowTitle( const char *title ); +void _glfwMacDWSetWindowSize( int width, int height ); +void _glfwMacDWSetWindowPos( int x, int y ); +void _glfwMacDWIconifyWindow( void ); +void _glfwMacDWRestoreWindow( void ); +void _glfwMacDWRefreshWindowParams( void ); +void _glfwMacDWSetMouseCursorPos( int x, int y ); + +#endif // _platform_h_ diff --git a/libs/glfw/lib/stream.c b/libs/glfw/lib/stream.c new file mode 100644 index 0000000..f14d5c3 --- /dev/null +++ b/libs/glfw/lib/stream.c @@ -0,0 +1,194 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: stream.c +// Platform: Any +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + + +#include "internal.h" + + +//======================================================================== +// Opens a GLFW stream with a file +//======================================================================== + +int _glfwOpenFileStream( _GLFWstream *stream, const char* name, const char* mode ) +{ + memset( stream, 0, sizeof(_GLFWstream) ); + + stream->File = fopen( name, mode ); + if( stream->File == NULL ) + { + return GL_FALSE; + } + + return GL_TRUE; +} + + +//======================================================================== +// Opens a GLFW stream with a memory block +//======================================================================== + +int _glfwOpenBufferStream( _GLFWstream *stream, void *data, long size ) +{ + memset( stream, 0, sizeof(_GLFWstream) ); + + stream->Data = data; + stream->Size = size; + return GL_TRUE; +} + + +//======================================================================== +// Reads data from a GLFW stream +//======================================================================== + +long _glfwReadStream( _GLFWstream *stream, void *data, long size ) +{ + if( stream->File != NULL ) + { + return fread( data, 1, size, stream->File ); + } + + if( stream->Data != NULL ) + { + // Check for EOF + if( stream->Position == stream->Size ) + { + return 0; + } + + // Clamp read size to available data + if( stream->Position + size > stream->Size ) + { + size = stream->Size - stream->Position; + } + + // Perform data read + memcpy( data, (unsigned char*) stream->Data + stream->Position, size ); + stream->Position += size; + return size; + } + + return 0; +} + + +//======================================================================== +// Returns the current position of a GLFW stream +//======================================================================== + +long _glfwTellStream( _GLFWstream *stream ) +{ + if( stream->File != NULL ) + { + return ftell( stream->File ); + } + + if( stream->Data != NULL ) + { + return stream->Position; + } + + return 0; +} + + +//======================================================================== +// Sets the current position of a GLFW stream +//======================================================================== + +int _glfwSeekStream( _GLFWstream *stream, long offset, int whence ) +{ + long position; + + if( stream->File != NULL ) + { + if( fseek( stream->File, offset, whence ) != 0 ) + { + return GL_FALSE; + } + + return GL_TRUE; + } + + if( stream->Data != NULL ) + { + position = offset; + + // Handle whence parameter + if( whence == SEEK_CUR ) + { + position += stream->Position; + } + else if( whence == SEEK_END ) + { + position += stream->Size; + } + else if( whence != SEEK_SET ) + { + return GL_FALSE; + } + + // Clamp offset to buffer bounds and apply it + if( position > stream->Size ) + { + stream->Position = stream->Size; + } + else if( position < 0 ) + { + stream->Position = 0; + } + else + { + stream->Position = position; + } + + return GL_TRUE; + } + + return GL_FALSE; +} + + +//======================================================================== +// Closes a GLFW stream +//======================================================================== + +void _glfwCloseStream( _GLFWstream *stream ) +{ + if( stream->File != NULL ) + { + fclose( stream->File ); + } + + // Nothing to be done about (user allocated) memory blocks + + memset( stream, 0, sizeof(_GLFWstream) ); +} + diff --git a/libs/glfw/lib/tga.c b/libs/glfw/lib/tga.c new file mode 100644 index 0000000..4eff314 --- /dev/null +++ b/libs/glfw/lib/tga.c @@ -0,0 +1,405 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: tga.c +// Platform: Any +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +//======================================================================== +// Description: +// +// TGA format image file loader. This module supports version 1 Targa +// images, with these restrictions: +// - Pixel format may only be 8, 24 or 32 bits +// - Colormaps must be no longer than 256 entries +// +//======================================================================== + + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions & declarations **** +//************************************************************************ + +//======================================================================== +// TGA file header information +//======================================================================== + +typedef struct { + int idlen; // 1 byte + int cmaptype; // 1 byte + int imagetype; // 1 byte + int cmapfirstidx; // 2 bytes + int cmaplen; // 2 bytes + int cmapentrysize; // 1 byte + int xorigin; // 2 bytes + int yorigin; // 2 bytes + int width; // 2 bytes + int height; // 2 bytes + int bitsperpixel; // 1 byte + int imageinfo; // 1 byte + int _alphabits; // (derived from imageinfo) + int _origin; // (derived from imageinfo) +} _tga_header_t; + +#define _TGA_CMAPTYPE_NONE 0 +#define _TGA_CMAPTYPE_PRESENT 1 + +#define _TGA_IMAGETYPE_NONE 0 +#define _TGA_IMAGETYPE_CMAP 1 +#define _TGA_IMAGETYPE_TC 2 +#define _TGA_IMAGETYPE_GRAY 3 +#define _TGA_IMAGETYPE_CMAP_RLE 9 +#define _TGA_IMAGETYPE_TC_RLE 10 +#define _TGA_IMAGETYPE_GRAY_RLE 11 + +#define _TGA_IMAGEINFO_ALPHA_MASK 0x0f +#define _TGA_IMAGEINFO_ALPHA_SHIFT 0 +#define _TGA_IMAGEINFO_ORIGIN_MASK 0x30 +#define _TGA_IMAGEINFO_ORIGIN_SHIFT 4 + +#define _TGA_ORIGIN_BL 0 +#define _TGA_ORIGIN_BR 1 +#define _TGA_ORIGIN_UL 2 +#define _TGA_ORIGIN_UR 3 + + +//======================================================================== +// _glfwReadTGAHeader() - Read TGA file header (and check that it is +// valid) +//======================================================================== + +static int _glfwReadTGAHeader( _GLFWstream *s, _tga_header_t *h ) +{ + unsigned char buf[ 18 ]; + int pos; + + // Read TGA file header from file + pos = _glfwTellStream( s ); + _glfwReadStream( s, buf, 18 ); + + // Interpret header (endian independent parsing) + h->idlen = (int) buf[0]; + h->cmaptype = (int) buf[1]; + h->imagetype = (int) buf[2]; + h->cmapfirstidx = (int) buf[3] | (((int) buf[4]) << 8); + h->cmaplen = (int) buf[5] | (((int) buf[6]) << 8); + h->cmapentrysize = (int) buf[7]; + h->xorigin = (int) buf[8] | (((int) buf[9]) << 8); + h->yorigin = (int) buf[10] | (((int) buf[11]) << 8); + h->width = (int) buf[12] | (((int) buf[13]) << 8); + h->height = (int) buf[14] | (((int) buf[15]) << 8); + h->bitsperpixel = (int) buf[16]; + h->imageinfo = (int) buf[17]; + + // Extract alphabits and origin information + h->_alphabits = (int) (h->imageinfo & _TGA_IMAGEINFO_ALPHA_MASK) >> + _TGA_IMAGEINFO_ALPHA_SHIFT; + h->_origin = (int) (h->imageinfo & _TGA_IMAGEINFO_ORIGIN_MASK) >> + _TGA_IMAGEINFO_ORIGIN_SHIFT; + + // Validate TGA header (is this a TGA file?) + if( (h->cmaptype == 0 || h->cmaptype == 1) && + ((h->imagetype >= 1 && h->imagetype <= 3) || + (h->imagetype >= 9 && h->imagetype <= 11)) && + (h->bitsperpixel == 8 || h->bitsperpixel == 24 || + h->bitsperpixel == 32) ) + { + // Skip the ID field + _glfwSeekStream( s, h->idlen, SEEK_CUR ); + + // Indicate that the TGA header was valid + return GL_TRUE; + } + else + { + // Restore file position + _glfwSeekStream( s, pos, SEEK_SET ); + + // Indicate that the TGA header was invalid + return GL_FALSE; + } +} + +//======================================================================== +// _glfwReadTGA_RLE() - Read Run-Length Encoded data +//======================================================================== + +static void _glfwReadTGA_RLE( unsigned char *buf, int size, int bpp, + _GLFWstream *s ) +{ + int repcount, bytes, k, n; + unsigned char pixel[ 4 ]; + char c; + + // Dummy check + if( bpp > 4 ) + { + return; + } + + while( size > 0 ) + { + // Get repetition count + _glfwReadStream( s, &c, 1 ); + repcount = (unsigned int) c; + bytes = ((repcount & 127) + 1) * bpp; + if( size < bytes ) + { + bytes = size; + } + + // Run-Length packet? + if( repcount & 128 ) + { + _glfwReadStream( s, pixel, bpp ); + for( n = 0; n < (repcount & 127) + 1; n ++ ) + { + for( k = 0; k < bpp; k ++ ) + { + *buf ++ = pixel[ k ]; + } + } + } + else + { + // It's a Raw packet + _glfwReadStream( s, buf, bytes ); + buf += bytes; + } + + size -= bytes; + } +} + + +//======================================================================== +// _glfwReadTGA() - Read a TGA image from a file +//======================================================================== + +int _glfwReadTGA( _GLFWstream *s, GLFWimage *img, int flags ) +{ + _tga_header_t h; + unsigned char *cmap, *pix, tmp, *src, *dst; + int cmapsize, pixsize, pixsize2; + int bpp, bpp2, k, m, n, swapx, swapy; + + // Read TGA header + if( !_glfwReadTGAHeader( s, &h ) ) + { + return 0; + } + + // Is there a colormap? + cmapsize = (h.cmaptype == _TGA_CMAPTYPE_PRESENT ? 1 : 0) * h.cmaplen * + ((h.cmapentrysize+7) / 8); + if( cmapsize > 0 ) + { + // Is it a colormap that we can handle? + if( (h.cmapentrysize != 24 && h.cmapentrysize != 32) || + h.cmaplen == 0 || h.cmaplen > 256 ) + { + return 0; + } + + // Allocate memory for colormap + cmap = (unsigned char *) malloc( cmapsize ); + if( cmap == NULL ) + { + return 0; + } + + // Read colormap from file + _glfwReadStream( s, cmap, cmapsize ); + } + else + { + cmap = NULL; + } + + // Size of pixel data + pixsize = h.width * h.height * ((h.bitsperpixel + 7) / 8); + + // Bytes per pixel (pixel data - unexpanded) + bpp = (h.bitsperpixel + 7) / 8; + + // Bytes per pixel (expanded pixels - not colormap indeces) + if( cmap ) + { + bpp2 = (h.cmapentrysize + 7) / 8; + } + else + { + bpp2 = bpp; + } + + // For colormaped images, the RGB/RGBA image data may use more memory + // than the stored pixel data + pixsize2 = h.width * h.height * bpp2; + + // Allocate memory for pixel data + pix = (unsigned char *) malloc( pixsize2 ); + if( pix == NULL ) + { + if( cmap ) + { + free( cmap ); + } + return 0; + } + + // Read pixel data from file + if( h.imagetype >= _TGA_IMAGETYPE_CMAP_RLE ) + { + _glfwReadTGA_RLE( pix, pixsize, bpp, s ); + } + else + { + _glfwReadStream( s, pix, pixsize ); + } + + // If the image origin is not what we want, re-arrange the pixels + switch( h._origin ) + { + default: + case _TGA_ORIGIN_UL: + swapx = 0; + swapy = 1; + break; + + case _TGA_ORIGIN_BL: + swapx = 0; + swapy = 0; + break; + + case _TGA_ORIGIN_UR: + swapx = 1; + swapy = 1; + break; + + case _TGA_ORIGIN_BR: + swapx = 1; + swapy = 0; + break; + } + if( (swapy && !(flags & GLFW_ORIGIN_UL_BIT)) || + (!swapy && (flags & GLFW_ORIGIN_UL_BIT)) ) + { + src = pix; + dst = &pix[ (h.height-1)*h.width*bpp ]; + for( n = 0; n < h.height/2; n ++ ) + { + for( m = 0; m < h.width ; m ++ ) + { + for( k = 0; k < bpp; k ++ ) + { + tmp = *src; + *src ++ = *dst; + *dst ++ = tmp; + } + } + dst -= 2*h.width*bpp; + } + } + if( swapx ) + { + src = pix; + dst = &pix[ (h.width-1)*bpp ]; + for( n = 0; n < h.height; n ++ ) + { + for( m = 0; m < h.width/2 ; m ++ ) + { + for( k = 0; k < bpp; k ++ ) + { + tmp = *src; + *src ++ = *dst; + *dst ++ = tmp; + } + dst -= 2*bpp; + } + src += ((h.width+1)/2)*bpp; + dst += ((3*h.width+1)/2)*bpp; + } + } + + // Convert BGR/BGRA to RGB/RGBA, and optionally colormap indeces to + // RGB/RGBA values + if( cmap ) + { + // Convert colormap pixel format (BGR -> RGB or BGRA -> RGBA) + if( bpp2 == 3 || bpp2 == 4 ) + { + for( n = 0; n < h.cmaplen; n ++ ) + { + tmp = cmap[ n*bpp2 ]; + cmap[ n*bpp2 ] = cmap[ n*bpp2 + 2 ]; + cmap[ n*bpp2 + 2 ] = tmp; + } + } + + // Convert pixel data to RGB/RGBA data + for( m = h.width * h.height - 1; m >= 0; m -- ) + { + n = pix[ m ]; + for( k = 0; k < bpp2; k ++ ) + { + pix[ m*bpp2 + k ] = cmap[ n*bpp2 + k ]; + } + } + + // Free memory for colormap (it's not needed anymore) + free( cmap ); + } + else + { + // Convert image pixel format (BGR -> RGB or BGRA -> RGBA) + if( bpp2 == 3 || bpp2 == 4 ) + { + src = pix; + dst = &pix[ 2 ]; + for( n = 0; n < h.height * h.width; n ++ ) + { + tmp = *src; + *src = *dst; + *dst = tmp; + src += bpp2; + dst += bpp2; + } + } + } + + // Fill out GLFWimage struct (the Format field will be set by + // glfwReadImage) + img->Width = h.width; + img->Height = h.height; + img->BytesPerPixel = bpp2; + img->Data = pix; + + return 1; +} + diff --git a/libs/glfw/lib/thread.c b/libs/glfw/lib/thread.c new file mode 100644 index 0000000..76f5db9 --- /dev/null +++ b/libs/glfw/lib/thread.c @@ -0,0 +1,340 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: thread.c +// Platform: Any +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwGetThreadPointer() - Find pointer to thread with a matching ID +//======================================================================== + +_GLFWthread * _glfwGetThreadPointer( int ID ) +{ + _GLFWthread *t; + + for( t = &_glfwThrd.First; t != NULL; t = t->Next ) + { + if( t->ID == ID ) + { + break; + } + } + + return t; +} + + +//======================================================================== +// _glfwAppendThread() - Append thread to thread list +//======================================================================== + +void _glfwAppendThread( _GLFWthread * t ) +{ + _GLFWthread *t_tmp; + + t_tmp = &_glfwThrd.First; + while( t_tmp->Next != NULL ) + { + t_tmp = t_tmp->Next; + } + t_tmp->Next = t; + t->Previous = t_tmp; + t->Next = NULL; +} + + +//======================================================================== +// _glfwRemoveThread() - Remove thread from thread list +//======================================================================== + +void _glfwRemoveThread( _GLFWthread * t ) +{ + if( t->Previous != NULL ) + { + t->Previous->Next = t->Next; + } + if( t->Next != NULL ) + { + t->Next->Previous = t->Previous; + } + free( (void *) t ); +} + + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// glfwCreateThread() - Create a new thread +//======================================================================== + +GLFWAPI GLFWthread GLFWAPIENTRY glfwCreateThread( GLFWthreadfun fun, + void *arg ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return -1; + } + + // Return the GLFW thread ID + return _glfwPlatformCreateThread( fun, arg ); +} + + +//======================================================================== +// glfwDestroyThread() - Kill a thread. NOTE: THIS IS A VERY DANGEROUS +// OPERATION, AND SHOULD NOT BE USED EXCEPT IN EXTREME SITUATIONS! +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwDestroyThread( GLFWthread ID ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + // Is it a valid thread? (killing the main thread is not allowed) + if( ID < 1 ) + { + return; + } + + _glfwPlatformDestroyThread( ID ); +} + + +//======================================================================== +// glfwWaitThread() - Wait for a thread to die +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwWaitThread( GLFWthread ID, int waitmode ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return GL_TRUE; + } + + // Is it a valid thread? (waiting for the main thread is not allowed) + if( ID < 1 ) + { + return GL_TRUE; + } + + return _glfwPlatformWaitThread( ID, waitmode ); +} + + +//======================================================================== +// glfwGetThreadID() - Return the thread ID for the current thread +//======================================================================== + +GLFWAPI GLFWthread GLFWAPIENTRY glfwGetThreadID( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return 0; + } + + return _glfwPlatformGetThreadID(); +} + + +//======================================================================== +// glfwCreateMutex() - Create a mutual exclusion object +//======================================================================== + +GLFWAPI GLFWmutex GLFWAPIENTRY glfwCreateMutex( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return (GLFWmutex) 0; + } + + return _glfwPlatformCreateMutex(); +} + + +//======================================================================== +// glfwDestroyMutex() - Destroy a mutual exclusion object +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwDestroyMutex( GLFWmutex mutex ) +{ + // Initialized & valid mutex (no real way of assuring this)? + if( !_glfwInitialized || !mutex ) + { + return; + } + + _glfwPlatformDestroyMutex( mutex ); +} + + +//======================================================================== +// glfwLockMutex() - Request access to a mutex +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwLockMutex( GLFWmutex mutex ) +{ + // Initialized & valid mutex (no real way of assuring this)? + if( !_glfwInitialized && !mutex ) + { + return; + } + + _glfwPlatformLockMutex( mutex ); +} + + +//======================================================================== +// glfwUnlockMutex() - Release a mutex +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwUnlockMutex( GLFWmutex mutex ) +{ + // Initialized & valid mutex (no real way of assuring this)? + if( !_glfwInitialized && !mutex ) + { + return; + } + + _glfwPlatformUnlockMutex( mutex ); +} + + +//======================================================================== +// glfwCreateCond() - Create a new condition variable object +//======================================================================== + +GLFWAPI GLFWcond GLFWAPIENTRY glfwCreateCond( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return (GLFWcond) 0; + } + + return _glfwPlatformCreateCond(); +} + + +//======================================================================== +// glfwDestroyCond() - Destroy a condition variable object +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwDestroyCond( GLFWcond cond ) +{ + // Initialized & valid condition variable? + if( !_glfwInitialized || !cond ) + { + return; + } + + _glfwPlatformDestroyCond( cond ); +} + + +//======================================================================== +// glfwWaitCond() - Wait for a condition to be raised +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwWaitCond( GLFWcond cond, GLFWmutex mutex, + double timeout ) +{ + // Initialized & valid condition variable and mutex? + if( !_glfwInitialized || !cond || !mutex ) + { + return; + } + + _glfwPlatformWaitCond( cond, mutex, timeout ); +} + + +//======================================================================== +// glfwSignalCond() - Signal a condition to one waiting thread +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSignalCond( GLFWcond cond ) +{ + // Initialized & valid condition variable? + if( !_glfwInitialized || !cond ) + { + return; + } + + _glfwPlatformSignalCond( cond ); +} + + +//======================================================================== +// glfwBroadcastCond() - Broadcast a condition to all waiting threads +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwBroadcastCond( GLFWcond cond ) +{ + // Initialized & valid condition variable? + if( !_glfwInitialized || !cond ) + { + return; + } + + _glfwPlatformBroadcastCond( cond ); +} + + +//======================================================================== +// glfwGetNumberOfProcessors() - Return the number of processors in the +// system. This information can be useful for determining the optimal +// number of threads to use for performing a certain task. +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwGetNumberOfProcessors( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return 0; + } + + return _glfwPlatformGetNumberOfProcessors(); +} diff --git a/libs/glfw/lib/time.c b/libs/glfw/lib/time.c new file mode 100644 index 0000000..5bd07b2 --- /dev/null +++ b/libs/glfw/lib/time.c @@ -0,0 +1,83 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: time.c +// Platform: Any +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// glfwGetTime() - Return timer value in seconds +//======================================================================== + +GLFWAPI double GLFWAPIENTRY glfwGetTime( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return 0.0; + } + + return _glfwPlatformGetTime(); +} + + +//======================================================================== +// glfwSetTime() - Set timer value in seconds +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetTime( double time ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + _glfwPlatformSetTime( time ); +} + + +//======================================================================== +// glfwSleep() - Put a thread to sleep for a specified amount of time +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSleep( double time ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + _glfwPlatformSleep( time ); +} diff --git a/libs/glfw/lib/win32/platform.h b/libs/glfw/lib/win32/platform.h new file mode 100644 index 0000000..0e36fb3 --- /dev/null +++ b/libs/glfw/lib/win32/platform.h @@ -0,0 +1,474 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: platform.h +// Platform: Windows +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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 _platform_h_ +#define _platform_h_ + + +// This is the Windows version of GLFW +#define _GLFW_WIN32 + + +// Include files +#include +#include +#include "../../include/GL/glfw.h" + + +//======================================================================== +// Hack: Define things that some 's do not define +//======================================================================== + +// Some old versions of w32api (used by MinGW and Cygwin) define +// WH_KEYBOARD_LL without typedef:ing KBDLLHOOKSTRUCT (!) +#if defined(__MINGW32__) || defined(__CYGWIN__) +#include +#if defined(WH_KEYBOARD_LL) && (__W32API_MAJOR_VERSION == 1) && (__W32API_MINOR_VERSION <= 2) +#undef WH_KEYBOARD_LL +#endif +#endif + +//------------------------------------------------------------------------ +// ** NOTE ** If this gives you compiler errors and you are using MinGW +// (or Dev-C++), update to w32api version 1.3 or later: +// http://sourceforge.net/project/showfiles.php?group_id=2435 +//------------------------------------------------------------------------ +#ifndef WH_KEYBOARD_LL +#define WH_KEYBOARD_LL 13 +typedef struct tagKBDLLHOOKSTRUCT { + DWORD vkCode; + DWORD scanCode; + DWORD flags; + DWORD time; + DWORD dwExtraInfo; +} KBDLLHOOKSTRUCT, FAR *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT; +#endif // WH_KEYBOARD_LL + +#ifndef LLKHF_ALTDOWN +#define LLKHF_ALTDOWN 0x00000020 +#endif + +#ifndef SPI_SETSCREENSAVERRUNNING +#define SPI_SETSCREENSAVERRUNNING 97 +#endif +#ifndef SPI_GETANIMATION +#define SPI_GETANIMATION 72 +#endif +#ifndef SPI_SETANIMATION +#define SPI_SETANIMATION 73 +#endif +#ifndef SPI_GETFOREGROUNDLOCKTIMEOUT +#define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000 +#endif +#ifndef SPI_SETFOREGROUNDLOCKTIMEOUT +#define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001 +#endif + +#ifndef CDS_FULLSCREEN +#define CDS_FULLSCREEN 4 +#endif + +#ifndef PFD_GENERIC_ACCELERATED +#define PFD_GENERIC_ACCELERATED 0x00001000 +#endif +#ifndef PFD_DEPTH_DONTCARE +#define PFD_DEPTH_DONTCARE 0x20000000 +#endif + +#ifndef ENUM_CURRENT_SETTINGS +#define ENUM_CURRENT_SETTINGS -1 +#endif +#ifndef ENUM_REGISTRY_SETTINGS +#define ENUM_REGISTRY_SETTINGS -2 +#endif + +#ifndef WM_MOUSEWHEEL +#define WM_MOUSEWHEEL 0x020A +#endif +#ifndef WHEEL_DELTA +#define WHEEL_DELTA 120 +#endif + +#ifndef WM_XBUTTONDOWN +#define WM_XBUTTONDOWN 0x020B +#endif +#ifndef WM_XBUTTONUP +#define WM_XBUTTONUP 0x020C +#endif +#ifndef XBUTTON1 +#define XBUTTON1 1 +#endif +#ifndef XBUTTON2 +#define XBUTTON2 2 +#endif + +// wglSwapIntervalEXT typedef (Win32 buffer-swap interval control) +typedef int (APIENTRY * WGLSWAPINTERVALEXT_T) (int); +// wglChoosePixelFormatARB typedef +typedef BOOL (WINAPI * WGLCHOOSEPIXELFORMATARB_T) (HDC, const int *, const FLOAT *, UINT, int *, UINT *); +// wglGetPixelFormatAttribivARB typedef +typedef BOOL (WINAPI * WGLGETPIXELFORMATATTRIBIVARB_T) (HDC, int, int, UINT, const int *, int *); +// wglGetExtensionStringEXT typedef +typedef const char *(APIENTRY * WGLGETEXTENSIONSSTRINGEXT_T)( void ); +// wglGetExtensionStringARB typedef +typedef const char *(APIENTRY * WGLGETEXTENSIONSSTRINGARB_T)( HDC ); + +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_STEREO_ARB 0x2012 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_ACCUM_BITS_ARB 0x201D +#define WGL_ACCUM_RED_BITS_ARB 0x201E +#define WGL_ACCUM_GREEN_BITS_ARB 0x201F +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 + + +//======================================================================== +// DLLs that are loaded at glfwInit() +//======================================================================== + +// gdi32.dll function pointer typedefs +#ifndef _GLFW_NO_DLOAD_GDI32 +typedef int (WINAPI * CHOOSEPIXELFORMAT_T) (HDC,CONST PIXELFORMATDESCRIPTOR*); +typedef int (WINAPI * DESCRIBEPIXELFORMAT_T) (HDC,int,UINT,LPPIXELFORMATDESCRIPTOR); +typedef int (WINAPI * GETPIXELFORMAT_T) (HDC); +typedef BOOL (WINAPI * SETPIXELFORMAT_T) (HDC,int,const PIXELFORMATDESCRIPTOR*); +typedef BOOL (WINAPI * SWAPBUFFERS_T) (HDC); +#endif // _GLFW_NO_DLOAD_GDI32 + +// winmm.dll function pointer typedefs +#ifndef _GLFW_NO_DLOAD_WINMM +typedef MMRESULT (WINAPI * JOYGETDEVCAPSA_T) (UINT,LPJOYCAPSA,UINT); +typedef MMRESULT (WINAPI * JOYGETPOS_T) (UINT,LPJOYINFO); +typedef MMRESULT (WINAPI * JOYGETPOSEX_T) (UINT,LPJOYINFOEX); +typedef DWORD (WINAPI * TIMEGETTIME_T) (void); +#endif // _GLFW_NO_DLOAD_WINMM + + +// gdi32.dll shortcuts +#ifndef _GLFW_NO_DLOAD_GDI32 +#define _glfw_ChoosePixelFormat _glfwLibrary.Libs.ChoosePixelFormat +#define _glfw_DescribePixelFormat _glfwLibrary.Libs.DescribePixelFormat +#define _glfw_GetPixelFormat _glfwLibrary.Libs.GetPixelFormat +#define _glfw_SetPixelFormat _glfwLibrary.Libs.SetPixelFormat +#define _glfw_SwapBuffers _glfwLibrary.Libs.SwapBuffers +#else +#define _glfw_ChoosePixelFormat ChoosePixelFormat +#define _glfw_DescribePixelFormat DescribePixelFormat +#define _glfw_GetPixelFormat GetPixelFormat +#define _glfw_SetPixelFormat SetPixelFormat +#define _glfw_SwapBuffers SwapBuffers +#endif // _GLFW_NO_DLOAD_GDI32 + +// winmm.dll shortcuts +#ifndef _GLFW_NO_DLOAD_WINMM +#define _glfw_joyGetDevCaps _glfwLibrary.Libs.joyGetDevCapsA +#define _glfw_joyGetPos _glfwLibrary.Libs.joyGetPos +#define _glfw_joyGetPosEx _glfwLibrary.Libs.joyGetPosEx +#define _glfw_timeGetTime _glfwLibrary.Libs.timeGetTime +#else +#define _glfw_joyGetDevCaps joyGetDevCapsA +#define _glfw_joyGetPos joyGetPos +#define _glfw_joyGetPosEx joyGetPosEx +#define _glfw_timeGetTime timeGetTime +#endif // _GLFW_NO_DLOAD_WINMM + + +//======================================================================== +// Global variables (GLFW internals) +//======================================================================== + +//------------------------------------------------------------------------ +// Window structure +//------------------------------------------------------------------------ +typedef struct _GLFWwin_struct _GLFWwin; + +struct _GLFWwin_struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // User callback functions + GLFWwindowsizefun WindowSizeCallback; + GLFWwindowclosefun WindowCloseCallback; + GLFWwindowrefreshfun WindowRefreshCallback; + GLFWmousebuttonfun MouseButtonCallback; + GLFWmouseposfun MousePosCallback; + GLFWmousewheelfun MouseWheelCallback; + GLFWkeyfun KeyCallback; + GLFWcharfun CharCallback; + + // User selected window settings + int Fullscreen; // Fullscreen flag + int MouseLock; // Mouse-lock flag + int AutoPollEvents; // Auto polling flag + int SysKeysDisabled; // System keys disabled flag + int WindowNoResize; // Resize- and maximize gadgets disabled flag + + // Window status & parameters + int Opened; // Flag telling if window is opened or not + int Active; // Application active flag + int Iconified; // Window iconified flag + int Width, Height; // Window width and heigth + int Accelerated; // GL_TRUE if window is HW accelerated + int RedBits; + int GreenBits; + int BlueBits; + int AlphaBits; + int DepthBits; + int StencilBits; + int AccumRedBits; + int AccumGreenBits; + int AccumBlueBits; + int AccumAlphaBits; + int AuxBuffers; + int Stereo; + int RefreshRate; // Vertical monitor refresh rate + int Samples; + + // Extensions & OpenGL version + int Has_GL_SGIS_generate_mipmap; + int Has_GL_ARB_texture_non_power_of_two; + int GLVerMajor,GLVerMinor; + + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Platform specific window resources + HDC DC; // Private GDI device context + HGLRC RC; // Permanent rendering context + HWND Wnd; // Window handle + ATOM ClassAtom; // Window class atom + int ModeID; // Mode ID for fullscreen mode + HHOOK KeyboardHook; // Keyboard hook handle + DWORD dwStyle; // Window styles used for window creation + DWORD dwExStyle; // --"-- + + // Platform specific extensions (context specific) + WGLSWAPINTERVALEXT_T SwapInterval; + WGLCHOOSEPIXELFORMATARB_T ChoosePixelFormat; + WGLGETPIXELFORMATATTRIBIVARB_T GetPixelFormatAttribiv; + WGLGETEXTENSIONSSTRINGEXT_T GetExtensionsStringEXT; + WGLGETEXTENSIONSSTRINGARB_T GetExtensionsStringARB; + + // Various platform specific internal variables + int OldMouseLock; // Old mouse-lock flag (used for remembering + // mouse-lock state when iconifying) + int OldMouseLockValid; + int DesiredRefreshRate; // Desired vertical monitor refresh rate + +}; + +GLFWGLOBAL _GLFWwin _glfwWin; + + +//------------------------------------------------------------------------ +// User input status (most of this should go in _GLFWwin) +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Mouse status + int MousePosX, MousePosY; + int WheelPos; + char MouseButton[ GLFW_MOUSE_BUTTON_LAST+1 ]; + + // Keyboard status + char Key[ GLFW_KEY_LAST+1 ]; + int LastChar; + + // User selected settings + int StickyKeys; + int StickyMouseButtons; + int KeyRepeat; + + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Platform specific internal variables + int MouseMoved, OldMouseX, OldMouseY; + +} _glfwInput; + + +//------------------------------------------------------------------------ +// Library global data +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM SPECIFIC PART ====================================== + + HINSTANCE Instance; // Instance of the application + + // Timer data + struct { + int HasPerformanceCounter; + double Resolution; + unsigned int t0_32; + __int64 t0_64; + } Timer; + + // System information + struct { + int WinVer; + int HasUnicode; + DWORD ForegroundLockTimeout; + } Sys; + +#if !defined(_GLFW_NO_DLOAD_WINMM) || !defined(_GLFW_NO_DLOAD_GDI32) + // Library handles and function pointers + struct { +#ifndef _GLFW_NO_DLOAD_GDI32 + // gdi32.dll + HINSTANCE gdi32; + CHOOSEPIXELFORMAT_T ChoosePixelFormat; + DESCRIBEPIXELFORMAT_T DescribePixelFormat; + GETPIXELFORMAT_T GetPixelFormat; + SETPIXELFORMAT_T SetPixelFormat; + SWAPBUFFERS_T SwapBuffers; +#endif // _GLFW_NO_DLOAD_GDI32 + + // winmm.dll +#ifndef _GLFW_NO_DLOAD_WINMM + HINSTANCE winmm; + JOYGETDEVCAPSA_T joyGetDevCapsA; + JOYGETPOS_T joyGetPos; + JOYGETPOSEX_T joyGetPosEx; + TIMEGETTIME_T timeGetTime; +#endif // _GLFW_NO_DLOAD_WINMM + } Libs; +#endif + +} _glfwLibrary; + + +//------------------------------------------------------------------------ +// Thread record (one for each thread) +//------------------------------------------------------------------------ +typedef struct _GLFWthread_struct _GLFWthread; + +struct _GLFWthread_struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Pointer to previous and next threads in linked list + _GLFWthread *Previous, *Next; + + // GLFW user side thread information + GLFWthread ID; + GLFWthreadfun Function; + +// ========= PLATFORM SPECIFIC PART ====================================== + + // System side thread information + HANDLE Handle; + DWORD WinID; + +}; + + +//------------------------------------------------------------------------ +// General thread information +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Next thread ID to use (increments for every created thread) + GLFWthread NextID; + + // First thread in linked list (always the main thread) + _GLFWthread First; + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Critical section lock + CRITICAL_SECTION CriticalSection; + +} _glfwThrd; + + + +//======================================================================== +// Macros for encapsulating critical code sections (i.e. making parts +// of GLFW thread safe) +//======================================================================== + +// Thread list management +#define ENTER_THREAD_CRITICAL_SECTION \ + EnterCriticalSection( &_glfwThrd.CriticalSection ); +#define LEAVE_THREAD_CRITICAL_SECTION \ + LeaveCriticalSection( &_glfwThrd.CriticalSection ); + + +//======================================================================== +// Various Windows version constants +//======================================================================== + +#define _GLFW_WIN_UNKNOWN 0x0000 // Earlier than 95 or NT4 +#define _GLFW_WIN_95 0x0001 +#define _GLFW_WIN_98 0x0002 +#define _GLFW_WIN_ME 0x0003 +#define _GLFW_WIN_UNKNOWN_9x 0x0004 // Later than ME +#define _GLFW_WIN_NT4 0x0101 +#define _GLFW_WIN_2K 0x0102 +#define _GLFW_WIN_XP 0x0103 +#define _GLFW_WIN_NET_SERVER 0x0104 +#define _GLFW_WIN_UNKNOWN_NT 0x0105 // Later than .NET Server + + +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +// Time +void _glfwInitTimer( void ); + +// Fullscreen support +int _glfwGetClosestVideoModeBPP( int *w, int *h, int *bpp, int *refresh ); +int _glfwGetClosestVideoMode( int *w, int *h, int *r, int *g, int *b, int *refresh ); +void _glfwSetVideoModeMODE( int mode ); +void _glfwSetVideoMode( int *w, int *h, int r, int g, int b, int refresh ); + + +#endif // _platform_h_ diff --git a/libs/glfw/lib/win32/win32_dllmain.c b/libs/glfw/lib/win32/win32_dllmain.c new file mode 100644 index 0000000..c1749a4 --- /dev/null +++ b/libs/glfw/lib/win32/win32_dllmain.c @@ -0,0 +1,60 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: win32_dllmain.c +// Platform: Windows +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +#if defined(GLFW_BUILD_DLL) + +//======================================================================== +// DllMain() +//======================================================================== + +int WINAPI DllMain( HINSTANCE hinst, unsigned long reason, void *x ) +{ + // NOTE: Some compilers complains about hinst and x never being used - + // never mind that (we don't want to use them)! + + switch( reason ) + { + case DLL_PROCESS_ATTACH: + // Initializations + //glfwInit(); // We don't want to do that now! + break; + case DLL_PROCESS_DETACH: + // Do some cleanup + glfwTerminate(); + break; + }; + + return 1; +} + +#endif // GLFW_BUILD_DLL diff --git a/libs/glfw/lib/win32/win32_enable.c b/libs/glfw/lib/win32/win32_enable.c new file mode 100644 index 0000000..0a5e27d --- /dev/null +++ b/libs/glfw/lib/win32/win32_enable.c @@ -0,0 +1,155 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: win32_enable.c +// Platform: Windows +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwLLKeyboardProc() - Low level keyboard callback function (used to +// disable system keys under Windows NT). +//======================================================================== + +LRESULT CALLBACK _glfwLLKeyboardProc( int nCode, WPARAM wParam, + LPARAM lParam ) +{ + BOOL syskeys = 0; + PKBDLLHOOKSTRUCT p; + + // We are only looking for keyboard events - interpret lParam as a + // pointer to a KBDLLHOOKSTRUCT + p = (PKBDLLHOOKSTRUCT) lParam; + + // If nCode == HC_ACTION, then we have a keyboard event + if( nCode == HC_ACTION ) + { + switch( wParam ) + { + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + // Detect: ALT+TAB, ALT+ESC, ALT+F4, CTRL+ESC, + // LWIN, RWIN, APPS (mysterious menu key) + syskeys = ( p->vkCode == VK_TAB && + p->flags & LLKHF_ALTDOWN ) || + ( p->vkCode == VK_ESCAPE && + p->flags & LLKHF_ALTDOWN ) || + ( p->vkCode == VK_F4 && + p->flags & LLKHF_ALTDOWN ) || + ( p->vkCode == VK_ESCAPE && + (GetKeyState(VK_CONTROL) & 0x8000)) || + p->vkCode == VK_LWIN || + p->vkCode == VK_RWIN || + p->vkCode == VK_APPS; + break; + + default: + break; + } + } + + // Was it a system key combination (e.g. ALT+TAB)? + if( syskeys ) + { + // Pass the key event to our window message loop + if( _glfwWin.Opened ) + { + PostMessage( _glfwWin.Wnd, (UINT) wParam, p->vkCode, 0 ); + } + + // We've taken care of it - don't let the system know about this + // key event + return 1; + } + else + { + // It's a harmless key press, let the system deal with it + return CallNextHookEx( _glfwWin.KeyboardHook, nCode, wParam, + lParam ); + } +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformEnableSystemKeys() - Enable system keys +// _glfwPlatformDisableSystemKeys() - Disable system keys +//======================================================================== + +void _glfwPlatformEnableSystemKeys( void ) +{ + BOOL bOld; + + // Use different methods depending on operating system version + if( _glfwLibrary.Sys.WinVer >= _GLFW_WIN_NT4 ) + { + if( _glfwWin.KeyboardHook != NULL ) + { + UnhookWindowsHookEx( _glfwWin.KeyboardHook ); + _glfwWin.KeyboardHook = NULL; + } + } + else + { + (void) SystemParametersInfo( SPI_SETSCREENSAVERRUNNING, FALSE, + &bOld, 0 ); + } +} + +void _glfwPlatformDisableSystemKeys( void ) +{ + BOOL bOld; + + // Use different methods depending on operating system version + if( _glfwLibrary.Sys.WinVer >= _GLFW_WIN_NT4 ) + { + // Under Windows NT, install a low level keyboard hook + _glfwWin.KeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, + _glfwLLKeyboardProc, + _glfwLibrary.Instance, + 0 ); + } + else + { + // Under Windows 95/98/ME, fool Windows that a screensaver + // is running => prevents ALT+TAB, CTRL+ESC and CTRL+ALT+DEL + (void) SystemParametersInfo( SPI_SETSCREENSAVERRUNNING, TRUE, + &bOld, 0 ); + } +} + diff --git a/libs/glfw/lib/win32/win32_fullscreen.c b/libs/glfw/lib/win32/win32_fullscreen.c new file mode 100644 index 0000000..24078fe --- /dev/null +++ b/libs/glfw/lib/win32/win32_fullscreen.c @@ -0,0 +1,317 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: win32_fullscreen.c +// Platform: Windows +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwBPP2RGB() - Convert BPP to RGB bits (based on "best guess") +//======================================================================== + +static void _glfwBPP2RGB( int bpp, int *r, int *g, int *b ) +{ + int delta; + + // Special case: BPP = 32 + if( bpp == 32 ) bpp = 24; + + // Convert "bits per pixel" to red, green & blue sizes + *r = *g = *b = bpp / 3; + delta = bpp - (*r * 3); + if( delta >= 1 ) + { + *g = *g + 1; + } + if( delta == 2 ) + { + *r = *r + 1; + } +} + + +//======================================================================== +// _glfwGetClosestVideoModeBPP() +//======================================================================== + +int _glfwGetClosestVideoModeBPP( int *w, int *h, int *bpp, int *refresh ) +{ + int mode, bestmode, match, bestmatch, rr, bestrr, success; + DEVMODE dm; + + // Find best match + bestmatch = 0x7fffffff; + bestrr = 0x7fffffff; + mode = bestmode = 0; + do + { + dm.dmSize = sizeof( DEVMODE ); + success = EnumDisplaySettings( NULL, mode, &dm ); + if( success ) + { + match = dm.dmBitsPerPel - *bpp; + if( match < 0 ) match = -match; + match = ( match << 25 ) | + ( (dm.dmPelsWidth - *w) * + (dm.dmPelsWidth - *w) + + (dm.dmPelsHeight - *h) * + (dm.dmPelsHeight - *h) ); + if( match < bestmatch ) + { + bestmatch = match; + bestmode = mode; + bestrr = (dm.dmDisplayFrequency - *refresh) * + (dm.dmDisplayFrequency - *refresh); + } + else if( match == bestmatch && *refresh > 0 ) + { + rr = (dm.dmDisplayFrequency - *refresh) * + (dm.dmDisplayFrequency - *refresh); + if( rr < bestrr ) + { + bestmatch = match; + bestmode = mode; + bestrr = rr; + } + } + } + mode ++; + } + while( success ); + + // Get the parameters for the best matching display mode + dm.dmSize = sizeof( DEVMODE ); + (void) EnumDisplaySettings( NULL, bestmode, &dm ); + + // Fill out actual width and height + *w = dm.dmPelsWidth; + *h = dm.dmPelsHeight; + + // Return bits per pixel + *bpp = dm.dmBitsPerPel; + + // Return vertical refresh rate + *refresh = dm.dmDisplayFrequency; + + return bestmode; +} + + +//======================================================================== +// _glfwGetClosestVideoMode() +//======================================================================== + +int _glfwGetClosestVideoMode( int *w, int *h, int *r, int *g, int *b, + int *refresh ) +{ + int bpp, bestmode; + + // Colorbits = sum of red/green/blue bits + bpp = *r + *g + *b; + + // If colorbits < 15 (e.g. 0) or >= 24, default to 32 bpp + if( bpp < 15 || bpp >= 24 ) + { + bpp = 32; + } + + // Find best match + bestmode = _glfwGetClosestVideoModeBPP( w, h, &bpp, refresh ); + + // Convert "bits per pixel" to red, green & blue sizes + _glfwBPP2RGB( bpp, r, g, b ); + + return bestmode; +} + + +//======================================================================== +// Change the current video mode +//======================================================================== + +void _glfwSetVideoModeMODE( int mode ) +{ + DEVMODE dm; + int success; + + // Get the parameters for the best matching display mode + dm.dmSize = sizeof( DEVMODE ); + (void) EnumDisplaySettings( NULL, mode, &dm ); + + // Set which fields we want to specify + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; + + // Do we have a prefered refresh rate? + if( _glfwWin.DesiredRefreshRate > 0 ) + { + dm.dmFields = dm.dmFields | DM_DISPLAYFREQUENCY; + dm.dmDisplayFrequency = _glfwWin.DesiredRefreshRate; + } + + // Change display setting + dm.dmSize = sizeof( DEVMODE ); + success = ChangeDisplaySettings( &dm, CDS_FULLSCREEN ); + + // If the mode change was not possible, query the current display + // settings (we'll use the desktop resolution for fullscreen mode) + if( success == DISP_CHANGE_SUCCESSFUL ) + { + _glfwWin.ModeID = mode; + } + else + { + _glfwWin.ModeID = ENUM_REGISTRY_SETTINGS; + EnumDisplaySettings( NULL, ENUM_REGISTRY_SETTINGS, &dm ); + } + + // Set the window size to that of the display mode + _glfwWin.Width = dm.dmPelsWidth; + _glfwWin.Height = dm.dmPelsHeight; +} + + +//======================================================================== +// _glfwSetVideoMode() - Change the current video mode +//======================================================================== + +void _glfwSetVideoMode( int *w, int *h, int r, int g, int b, int refresh ) +{ + int bestmode; + + // Find a best match mode + bestmode = _glfwGetClosestVideoMode( w, h, &r, &g, &b, &refresh ); + + // Change mode + _glfwSetVideoModeMODE( bestmode ); +} + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformGetVideoModes() - Get a list of available video modes +//======================================================================== + +int _glfwPlatformGetVideoModes( GLFWvidmode *list, int maxcount ) +{ + int count, success, mode, i, j; + int m1, m2, bpp, r, g, b; + DEVMODE dm; + + // Loop through all video modes and extract all the UNIQUE modes + count = 0; + mode = 0; + do + { + // Get video mode properties + dm.dmSize = sizeof( DEVMODE ); + success = EnumDisplaySettings( NULL, mode, &dm ); + + // Is it a valid mode? (only list depths >= 15 bpp) + if( success && dm.dmBitsPerPel >= 15 ) + { + // Convert to RGB, and back to bpp ("mask out" alpha bits etc) + _glfwBPP2RGB( dm.dmBitsPerPel, &r, &g, &b ); + bpp = r + g + b; + + // Mode "code" for this mode + m1 = (bpp << 25) | (dm.dmPelsWidth * dm.dmPelsHeight); + + // Insert mode in list (sorted), and avoid duplicates + for( i = 0; i < count; i ++ ) + { + // Mode "code" for already listed mode + bpp = list[i].RedBits + list[i].GreenBits + + list[i].BlueBits; + m2 = (bpp << 25) | (list[i].Width * list[i].Height); + if( m1 <= m2 ) + { + break; + } + } + + // New entry at the end of the list? + if( i >= count ) + { + list[count].Width = dm.dmPelsWidth; + list[count].Height = dm.dmPelsHeight; + list[count].RedBits = r; + list[count].GreenBits = g; + list[count].BlueBits = b; + count ++; + } + // Insert new entry in the list? + else if( m1 < m2 ) + { + for( j = count; j > i; j -- ) + { + list[j] = list[j-1]; + } + list[i].Width = dm.dmPelsWidth; + list[i].Height = dm.dmPelsHeight; + list[i].RedBits = r; + list[i].GreenBits = g; + list[i].BlueBits = b; + count ++; + } + } + mode ++; + } + while( success && (count < maxcount) ); + + return count; +} + + +//======================================================================== +// _glfwPlatformGetDesktopMode() - Get the desktop video mode +//======================================================================== + +void _glfwPlatformGetDesktopMode( GLFWvidmode *mode ) +{ + DEVMODE dm; + + // Get desktop display mode + dm.dmSize = sizeof( DEVMODE ); + (void) EnumDisplaySettings( NULL, ENUM_REGISTRY_SETTINGS, &dm ); + + // Return desktop mode parameters + mode->Width = dm.dmPelsWidth; + mode->Height = dm.dmPelsHeight; + _glfwBPP2RGB( dm.dmBitsPerPel, &mode->RedBits, &mode->GreenBits, + &mode->BlueBits ); +} + + diff --git a/libs/glfw/lib/win32/win32_glext.c b/libs/glfw/lib/win32/win32_glext.c new file mode 100644 index 0000000..379fa56 --- /dev/null +++ b/libs/glfw/lib/win32/win32_glext.c @@ -0,0 +1,85 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: win32_glext.c +// Platform: Windows +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Check if an OpenGL extension is available at runtime (Windows version checks +// for WGL extensions) +//======================================================================== + +int _glfwPlatformExtensionSupported( const char *extension ) +{ + const GLubyte *extensions; + + // Try wglGetExtensionsStringEXT + if( _glfwWin.GetExtensionsStringEXT != NULL ) + { + extensions = (GLubyte *) _glfwWin.GetExtensionsStringEXT(); + if( extensions != NULL ) + { + if( _glfwStringInExtensionString( extension, extensions ) ) + { + return GL_TRUE; + } + } + } + + // Try wglGetExtensionsStringARB + if( _glfwWin.GetExtensionsStringARB != NULL ) + { + extensions = (GLubyte *) _glfwWin.GetExtensionsStringARB( _glfwWin.DC ); + if( extensions != NULL ) + { + if( _glfwStringInExtensionString( extension, extensions ) ) + { + return GL_TRUE; + } + } + } + + return GL_FALSE; +} + + +//======================================================================== +// Get the function pointer to an OpenGL function +//======================================================================== + +void * _glfwPlatformGetProcAddress( const char *procname ) +{ + return (void *) wglGetProcAddress( procname ); +} + diff --git a/libs/glfw/lib/win32/win32_init.c b/libs/glfw/lib/win32/win32_init.c new file mode 100644 index 0000000..feaff1a --- /dev/null +++ b/libs/glfw/lib/win32/win32_init.c @@ -0,0 +1,356 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: win32_init.c +// Platform: Windows +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + +// With the Borland C++ compiler, we want to disable FPU exceptions +#ifdef __BORLANDC__ +#include +#endif // __BORLANDC__ + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwInitLibraries() - Load necessary libraries (DLLs) +//======================================================================== + +static int _glfwInitLibraries( void ) +{ + // gdi32.dll (OpenGL pixel format functions & SwapBuffers) +#ifndef _GLFW_NO_DLOAD_GDI32 + _glfwLibrary.Libs.gdi32 = LoadLibrary( "gdi32.dll" ); + if( _glfwLibrary.Libs.gdi32 != NULL ) + { + _glfwLibrary.Libs.ChoosePixelFormat = (CHOOSEPIXELFORMAT_T) + GetProcAddress( _glfwLibrary.Libs.gdi32, "ChoosePixelFormat" ); + _glfwLibrary.Libs.DescribePixelFormat = (DESCRIBEPIXELFORMAT_T) + GetProcAddress( _glfwLibrary.Libs.gdi32, "DescribePixelFormat" ); + _glfwLibrary.Libs.GetPixelFormat = (GETPIXELFORMAT_T) + GetProcAddress( _glfwLibrary.Libs.gdi32, "GetPixelFormat" ); + _glfwLibrary.Libs.SetPixelFormat = (SETPIXELFORMAT_T) + GetProcAddress( _glfwLibrary.Libs.gdi32, "SetPixelFormat" ); + _glfwLibrary.Libs.SwapBuffers = (SWAPBUFFERS_T) + GetProcAddress( _glfwLibrary.Libs.gdi32, "SwapBuffers" ); + if( _glfwLibrary.Libs.ChoosePixelFormat == NULL || + _glfwLibrary.Libs.DescribePixelFormat == NULL || + _glfwLibrary.Libs.GetPixelFormat == NULL || + _glfwLibrary.Libs.SetPixelFormat == NULL || + _glfwLibrary.Libs.SwapBuffers == NULL ) + { + FreeLibrary( _glfwLibrary.Libs.gdi32 ); + _glfwLibrary.Libs.gdi32 = NULL; + return GL_FALSE; + } + } + else + { + return GL_FALSE; + } +#endif // _GLFW_NO_DLOAD_GDI32 + + // winmm.dll (for joystick and timer support) +#ifndef _GLFW_NO_DLOAD_WINMM + _glfwLibrary.Libs.winmm = LoadLibrary( "winmm.dll" ); + if( _glfwLibrary.Libs.winmm != NULL ) + { + _glfwLibrary.Libs.joyGetDevCapsA = (JOYGETDEVCAPSA_T) + GetProcAddress( _glfwLibrary.Libs.winmm, "joyGetDevCapsA" ); + _glfwLibrary.Libs.joyGetPos = (JOYGETPOS_T) + GetProcAddress( _glfwLibrary.Libs.winmm, "joyGetPos" ); + _glfwLibrary.Libs.joyGetPosEx = (JOYGETPOSEX_T) + GetProcAddress( _glfwLibrary.Libs.winmm, "joyGetPosEx" ); + _glfwLibrary.Libs.timeGetTime = (TIMEGETTIME_T) + GetProcAddress( _glfwLibrary.Libs.winmm, "timeGetTime" ); + if( _glfwLibrary.Libs.joyGetDevCapsA == NULL || + _glfwLibrary.Libs.joyGetPos == NULL || + _glfwLibrary.Libs.joyGetPosEx == NULL || + _glfwLibrary.Libs.timeGetTime == NULL ) + { + FreeLibrary( _glfwLibrary.Libs.winmm ); + _glfwLibrary.Libs.winmm = NULL; + return GL_FALSE; + } + } + else + { + return GL_FALSE; + } +#endif // _GLFW_NO_DLOAD_WINMM + + return GL_TRUE; +} + + +//======================================================================== +// _glfwFreeLibraries() - Unload used libraries (DLLs) +//======================================================================== + +static void _glfwFreeLibraries( void ) +{ + // gdi32.dll +#ifndef _GLFW_NO_DLOAD_GDI32 + if( _glfwLibrary.Libs.gdi32 != NULL ) + { + FreeLibrary( _glfwLibrary.Libs.gdi32 ); + _glfwLibrary.Libs.gdi32 = NULL; + } +#endif // _GLFW_NO_DLOAD_GDI32 + + // winmm.dll +#ifndef _GLFW_NO_DLOAD_WINMM + if( _glfwLibrary.Libs.winmm != NULL ) + { + FreeLibrary( _glfwLibrary.Libs.winmm ); + _glfwLibrary.Libs.winmm = NULL; + } +#endif // _GLFW_NO_DLOAD_WINMM +} + + +//======================================================================== +// _glfwInitThreads() - Initialize GLFW thread package +//======================================================================== + +static void _glfwInitThreads( void ) +{ + // Initialize critical section handle + InitializeCriticalSection( &_glfwThrd.CriticalSection ); + + // The first thread (the main thread) has ID 0 + _glfwThrd.NextID = 0; + + // Fill out information about the main thread (this thread) + _glfwThrd.First.ID = _glfwThrd.NextID ++; + _glfwThrd.First.Function = NULL; + _glfwThrd.First.Handle = GetCurrentThread(); + _glfwThrd.First.WinID = GetCurrentThreadId(); + _glfwThrd.First.Previous = NULL; + _glfwThrd.First.Next = NULL; +} + + +//======================================================================== +// _glfwTerminateThreads() - Terminate GLFW thread package +//======================================================================== + +static void _glfwTerminateThreads( void ) +{ + _GLFWthread *t, *t_next; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Kill all threads (NOTE: THE USER SHOULD WAIT FOR ALL THREADS TO + // DIE, _BEFORE_ CALLING glfwTerminate()!!!) + t = _glfwThrd.First.Next; + while( t != NULL ) + { + // Get pointer to next thread + t_next = t->Next; + + // Simply murder the process, no mercy! + if( TerminateThread( t->Handle, 0 ) ) + { + // Close thread handle + CloseHandle( t->Handle ); + + // Free memory allocated for this thread + free( (void *) t ); + } + + // Select next thread in list + t = t_next; + } + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Delete critical section handle + DeleteCriticalSection( &_glfwThrd.CriticalSection ); +} + + +//======================================================================== +// _glfwTerminate_atexit() - Terminate GLFW when exiting application +//======================================================================== + +void _glfwTerminate_atexit( void ) +{ + glfwTerminate(); +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformInit() - Initialize various GLFW state +//======================================================================== + +int _glfwPlatformInit( void ) +{ + OSVERSIONINFO osi; + + // To make SetForegroundWindow() work as we want, we need to fiddle + // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early + // as possible in the hope of still being the foreground process) + SystemParametersInfo( SPI_GETFOREGROUNDLOCKTIMEOUT, 0, + &_glfwLibrary.Sys.ForegroundLockTimeout, 0 ); + SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, + SPIF_SENDCHANGE ); + + // Check which OS version we are running + osi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); + GetVersionEx( &osi ); + _glfwLibrary.Sys.WinVer = _GLFW_WIN_UNKNOWN; + if( osi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) + { + if( osi.dwMajorVersion == 4 && osi.dwMinorVersion < 10 ) + { + _glfwLibrary.Sys.WinVer = _GLFW_WIN_95; + } + else if( osi.dwMajorVersion == 4 && osi.dwMinorVersion < 90 ) + { + _glfwLibrary.Sys.WinVer = _GLFW_WIN_98; + } + else if( osi.dwMajorVersion == 4 && osi.dwMinorVersion == 90 ) + { + _glfwLibrary.Sys.WinVer = _GLFW_WIN_ME; + } + else if( osi.dwMajorVersion >= 4 ) + { + _glfwLibrary.Sys.WinVer = _GLFW_WIN_UNKNOWN_9x; + } + } + else if( osi.dwPlatformId == VER_PLATFORM_WIN32_NT ) + { + if( osi.dwMajorVersion == 4 && osi.dwMinorVersion == 0 ) + { + _glfwLibrary.Sys.WinVer = _GLFW_WIN_NT4; + } + else if( osi.dwMajorVersion == 5 && osi.dwMinorVersion == 0 ) + { + _glfwLibrary.Sys.WinVer = _GLFW_WIN_2K; + } + else if( osi.dwMajorVersion == 5 && osi.dwMinorVersion == 1 ) + { + _glfwLibrary.Sys.WinVer = _GLFW_WIN_XP; + } + else if( osi.dwMajorVersion == 5 && osi.dwMinorVersion == 2 ) + { + _glfwLibrary.Sys.WinVer = _GLFW_WIN_NET_SERVER; + } + else if( osi.dwMajorVersion >= 5 ) + { + _glfwLibrary.Sys.WinVer = _GLFW_WIN_UNKNOWN_NT; + } + } + + // Do we have Unicode support? + if( _glfwLibrary.Sys.WinVer >= _GLFW_WIN_NT4 ) + { + // Windows NT/2000/XP/.NET has Unicode support + _glfwLibrary.Sys.HasUnicode = GL_TRUE; + } + else + { + // Windows 9x/ME does not have Unicode support + _glfwLibrary.Sys.HasUnicode = GL_FALSE; + } + + // Load libraries (DLLs) + if( !_glfwInitLibraries() ) + { + return GL_FALSE; + } + + // With the Borland C++ compiler, we want to disable FPU exceptions + // (this is recommended for OpenGL applications under Windows) +#ifdef __BORLANDC__ + _control87( MCW_EM, MCW_EM ); +#endif + + // Retrieve GLFW instance handle + _glfwLibrary.Instance = GetModuleHandle( NULL ); + + // System keys are not disabled + _glfwWin.KeyboardHook = NULL; + + // Initialise thread package + _glfwInitThreads(); + + // Install atexit() routine + atexit( _glfwTerminate_atexit ); + + // Start the timer + _glfwInitTimer(); + + return GL_TRUE; +} + + +//======================================================================== +// _glfwPlatformTerminate() - Close window and kill all threads +//======================================================================== + +int _glfwPlatformTerminate( void ) +{ + // Only the main thread is allowed to do this... + if( GetCurrentThreadId() != _glfwThrd.First.WinID ) + { + return GL_FALSE; + } + + // Close OpenGL window + glfwCloseWindow(); + + // Kill thread package + _glfwTerminateThreads(); + + // Enable system keys again (if they were disabled) + glfwEnable( GLFW_SYSTEM_KEYS ); + + // Unload libraries (DLLs) + _glfwFreeLibraries(); + + // Restore FOREGROUNDLOCKTIMEOUT system setting + SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0, + (LPVOID)_glfwLibrary.Sys.ForegroundLockTimeout, + SPIF_SENDCHANGE ); + + return GL_TRUE; +} + diff --git a/libs/glfw/lib/win32/win32_joystick.c b/libs/glfw/lib/win32/win32_joystick.c new file mode 100644 index 0000000..5559b4a --- /dev/null +++ b/libs/glfw/lib/win32/win32_joystick.c @@ -0,0 +1,234 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: win32_joystick.c +// Platform: Windows +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwJoystickPresent() - Return GL_TRUE if joystick is present, +// else return GL_FALSE. +//======================================================================== + +static int _glfwJoystickPresent( int joy ) +{ + JOYINFO ji; + + // Windows NT 4.0 MMSYSTEM only supports 2 sticks (other Windows + // versions support 16 sticks) + if( _glfwLibrary.Sys.WinVer == _GLFW_WIN_NT4 && joy > GLFW_JOYSTICK_2 ) + { + return GL_FALSE; + } + + // Is it a valid stick ID (Windows don't support more than 16 sticks)? + if( joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_16 ) + { + return GL_FALSE; + } + + // Is the joystick present? + if( _glfw_joyGetPos( joy - GLFW_JOYSTICK_1, &ji ) != JOYERR_NOERROR ) + { + return GL_FALSE; + } + + return GL_TRUE; +} + + +//======================================================================== +// _glfwCalcJoystickPos() - Calculate joystick position +//======================================================================== + +static float _glfwCalcJoystickPos( DWORD pos, DWORD min, DWORD max ) +{ + float fpos = (float) pos; + float fmin = (float) min; + float fmax = (float) max; + return (2.0f*(fpos - fmin) / (fmax - fmin)) - 1.0f; +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformGetJoystickParam() - Determine joystick capabilities +//======================================================================== + +int _glfwPlatformGetJoystickParam( int joy, int param ) +{ + JOYCAPS jc; + +// return 0; + + // Is joystick present? + if( !_glfwJoystickPresent( joy ) ) + { + return 0; + } + + // We got this far, the joystick is present + if( param == GLFW_PRESENT ) + { + return GL_TRUE; + } + + // Get joystick capabilities + _glfw_joyGetDevCaps( joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS) ); + + switch( param ) + { + case GLFW_AXES: + // Return number of joystick axes + return jc.wNumAxes; + + case GLFW_BUTTONS: + // Return number of joystick axes + return jc.wNumButtons; + + default: + break; + } + + return 0; +} + + +//======================================================================== +// _glfwPlatformGetJoystickPos() - Get joystick axis positions +//======================================================================== + +int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes ) +{ + JOYCAPS jc; + JOYINFOEX ji; + int axis; + +// return 0; + + // Is joystick present? + if( !_glfwJoystickPresent( joy ) ) + { + return 0; + } + + // Get joystick capabilities + _glfw_joyGetDevCaps( joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS) ); + + // Get joystick state + ji.dwSize = sizeof( JOYINFOEX ); + ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | + JOY_RETURNR | JOY_RETURNU | JOY_RETURNV; + _glfw_joyGetPosEx( joy - GLFW_JOYSTICK_1, &ji ); + + // Get position values for all axes + axis = 0; + if( axis < numaxes ) + { + pos[ axis++ ] = _glfwCalcJoystickPos( ji.dwXpos, jc.wXmin, + jc.wXmax ); + } + if( axis < numaxes ) + { + pos[ axis++ ] = -_glfwCalcJoystickPos( ji.dwYpos, jc.wYmin, + jc.wYmax ); + } + if( axis < numaxes && jc.wCaps & JOYCAPS_HASZ ) + { + pos[ axis++ ] = _glfwCalcJoystickPos( ji.dwZpos, jc.wZmin, + jc.wZmax ); + } + if( axis < numaxes && jc.wCaps & JOYCAPS_HASR ) + { + pos[ axis++ ] = _glfwCalcJoystickPos( ji.dwRpos, jc.wRmin, + jc.wRmax ); + } + if( axis < numaxes && jc.wCaps & JOYCAPS_HASU ) + { + pos[ axis++ ] = _glfwCalcJoystickPos( ji.dwUpos, jc.wUmin, + jc.wUmax ); + } + if( axis < numaxes && jc.wCaps & JOYCAPS_HASV ) + { + pos[ axis++ ] = -_glfwCalcJoystickPos( ji.dwVpos, jc.wVmin, + jc.wVmax ); + } + + // Return number of returned axes + return axis; +} + + +//======================================================================== +// _glfwPlatformGetJoystickButtons() - Get joystick button states +//======================================================================== + +int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, + int numbuttons ) +{ + JOYCAPS jc; + JOYINFOEX ji; + int button; + +// return 0; + + // Is joystick present? + if( !_glfwJoystickPresent( joy ) ) + { + return 0; + } + + // Get joystick capabilities + _glfw_joyGetDevCaps( joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS) ); + + // Get joystick state + ji.dwSize = sizeof( JOYINFOEX ); + ji.dwFlags = JOY_RETURNBUTTONS; + _glfw_joyGetPosEx( joy - GLFW_JOYSTICK_1, &ji ); + + // Get states of all requested buttons + button = 0; + while( button < numbuttons && button < (int) jc.wNumButtons ) + { + buttons[ button ] = (unsigned char) + (ji.dwButtons & (1UL << button) ? GLFW_PRESS : GLFW_RELEASE); + button ++; + } + + return button; +} + diff --git a/libs/glfw/lib/win32/win32_thread.c b/libs/glfw/lib/win32/win32_thread.c new file mode 100644 index 0000000..3b383f5 --- /dev/null +++ b/libs/glfw/lib/win32/win32_thread.c @@ -0,0 +1,511 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: win32_thread.c +// Platform: Windows +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +// This is an implementation of POSIX "compatible" condition variables for +// Win32, as described by Douglas C. Schmidt and Irfan Pyarali: +// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html +//************************************************************************ + +enum { + _GLFW_COND_SIGNAL = 0, + _GLFW_COND_BROADCAST = 1 +}; + +typedef struct { + // Signal and broadcast event HANDLEs + HANDLE events[ 2 ]; + + // Count of the number of waiters + unsigned int waiters_count; + + // Serialize access to + CRITICAL_SECTION waiters_count_lock; +} _GLFWcond; + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwNewThread() - This is simply a "wrapper" for calling the user +// thread function. +//======================================================================== + +DWORD WINAPI _glfwNewThread( LPVOID lpParam ) +{ + GLFWthreadfun threadfun; + _GLFWthread *t; + + // Get pointer to thread information for current thread + t = _glfwGetThreadPointer( _glfwPlatformGetThreadID() ); + if( t == NULL ) + { + return 0; + } + + // Get user thread function pointer + threadfun = t->Function; + + // Call the user thread function + threadfun( (void *) lpParam ); + + // Remove thread from thread list + ENTER_THREAD_CRITICAL_SECTION + _glfwRemoveThread( t ); + LEAVE_THREAD_CRITICAL_SECTION + + // When the thread function returns, the thread will die... + return 0; +} + + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformCreateThread() - Create a new thread +//======================================================================== + +GLFWthread _glfwPlatformCreateThread( GLFWthreadfun fun, void *arg ) +{ + GLFWthread ID; + _GLFWthread *t, *t_tmp; + HANDLE hThread; + DWORD dwThreadId; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Create a new thread information memory area + t = (_GLFWthread *) malloc( sizeof(_GLFWthread) ); + if( t == NULL ) + { + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + return -1; + } + + // Get a new unique thread id + ID = _glfwThrd.NextID ++; + + // Store thread information in the thread list + t->Function = fun; + t->ID = ID; + + // Create thread + hThread = CreateThread( + NULL, // Default security attributes + 0, // Default stack size (1 MB) + _glfwNewThread, // Thread function (a wrapper function) + (LPVOID)arg, // Argument to thread is the user argument + 0, // Default creation flags + &dwThreadId // Returned thread identifier + ); + + // Did the thread creation fail? + if( hThread == NULL ) + { + free( (void *) t ); + LEAVE_THREAD_CRITICAL_SECTION + return -1; + } + + // Store more thread information in the thread list + t->Handle = hThread; + t->WinID = dwThreadId; + + // Append thread to thread list + t_tmp = &_glfwThrd.First; + while( t_tmp->Next != NULL ) + { + t_tmp = t_tmp->Next; + } + t_tmp->Next = t; + t->Previous = t_tmp; + t->Next = NULL; + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Return the GLFW thread ID + return ID; +} + + +//======================================================================== +// _glfwPlatformDestroyThread() - Kill a thread. NOTE: THIS IS A VERY +// DANGEROUS OPERATION, AND SHOULD NOT BE USED EXCEPT IN EXTREME +// SITUATIONS! +//======================================================================== + +void _glfwPlatformDestroyThread( GLFWthread ID ) +{ + _GLFWthread *t; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Get thread information pointer + t = _glfwGetThreadPointer( ID ); + if( t == NULL ) + { + LEAVE_THREAD_CRITICAL_SECTION + return; + } + + // Simply murder the process, no mercy! + if( TerminateThread( t->Handle, 0 ) ) + { + // Close thread handle + CloseHandle( t->Handle ); + + // Remove thread from thread list + _glfwRemoveThread( t ); + } + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION +} + + +//======================================================================== +// _glfwPlatformWaitThread() - Wait for a thread to die +//======================================================================== + +int _glfwPlatformWaitThread( GLFWthread ID, int waitmode ) +{ + DWORD result; + HANDLE hThread; + _GLFWthread *t; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Get thread information pointer + t = _glfwGetThreadPointer( ID ); + + // Is the thread already dead? + if( t == NULL ) + { + LEAVE_THREAD_CRITICAL_SECTION + return GL_TRUE; + } + + // Get thread handle + hThread = t->Handle; + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Wait for thread to die + if( waitmode == GLFW_WAIT ) + { + result = WaitForSingleObject( hThread, INFINITE ); + } + else if( waitmode == GLFW_NOWAIT ) + { + result = WaitForSingleObject( hThread, 0 ); + } + else + { + return GL_FALSE; + } + + // Did we have a time-out? + if( result == WAIT_TIMEOUT ) + { + return GL_FALSE; + } + return GL_TRUE; +} + + +//======================================================================== +// _glfwPlatformGetThreadID() - Return the thread ID for the current +// thread +//======================================================================== + +GLFWthread _glfwPlatformGetThreadID( void ) +{ + _GLFWthread *t; + GLFWthread ID = -1; + DWORD WinID; + + // Get Windows thread ID + WinID = GetCurrentThreadId(); + + // Enter critical section (to avoid an inconsistent thread list) + ENTER_THREAD_CRITICAL_SECTION + + // Loop through entire list of threads to find the matching Windows + // thread ID + for( t = &_glfwThrd.First; t != NULL; t = t->Next ) + { + if( t->WinID == WinID ) + { + ID = t->ID; + break; + } + } + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Return the found GLFW thread identifier + return ID; +} + + +//======================================================================== +// _glfwPlatformCreateMutex() - Create a mutual exclusion object +//======================================================================== + +GLFWmutex _glfwPlatformCreateMutex( void ) +{ + CRITICAL_SECTION *mutex; + + // Allocate memory for mutex + mutex = (CRITICAL_SECTION *) malloc( sizeof(CRITICAL_SECTION) ); + if( !mutex ) + { + return NULL; + } + + // Initialize mutex + InitializeCriticalSection( mutex ); + + // Cast to GLFWmutex and return + return (GLFWmutex) mutex; +} + + +//======================================================================== +// glfwDestroyMutex() - Destroy a mutual exclusion object +//======================================================================== + +void _glfwPlatformDestroyMutex( GLFWmutex mutex ) +{ + // Destroy mutex + DeleteCriticalSection( (CRITICAL_SECTION *) mutex ); + free( mutex ); +} + + +//======================================================================== +// _glfwPlatformLockMutex() - Request access to a mutex +//======================================================================== + +void _glfwPlatformLockMutex( GLFWmutex mutex ) +{ + // Wait for mutex to be released + EnterCriticalSection( (CRITICAL_SECTION *) mutex ); +} + + +//======================================================================== +// _glfwPlatformUnlockMutex() - Release a mutex +//======================================================================== + +void _glfwPlatformUnlockMutex( GLFWmutex mutex ) +{ + // Release mutex + LeaveCriticalSection( (CRITICAL_SECTION *) mutex ); +} + + +//======================================================================== +// _glfwPlatformCreateCond() - Create a new condition variable object +//======================================================================== + +GLFWcond _glfwPlatformCreateCond( void ) +{ + _GLFWcond *cond; + + // Allocate memory for condition variable + cond = (_GLFWcond *) malloc( sizeof(_GLFWcond) ); + if( !cond ) + { + return NULL; + } + + // Initialize condition variable + cond->waiters_count = 0; + cond->events[ _GLFW_COND_SIGNAL ] = CreateEvent( NULL, FALSE, + FALSE, NULL ); + cond->events[ _GLFW_COND_BROADCAST ] = CreateEvent( NULL, TRUE, + FALSE, NULL ); + InitializeCriticalSection( &cond->waiters_count_lock ); + + // Cast to GLFWcond and return + return (GLFWcond) cond; +} + + +//======================================================================== +// _glfwPlatformDestroyCond() - Destroy a condition variable object +//======================================================================== + +void _glfwPlatformDestroyCond( GLFWcond cond ) +{ + // Close the condition variable handles + CloseHandle( ((_GLFWcond *)cond)->events[ _GLFW_COND_SIGNAL ] ); + CloseHandle( ((_GLFWcond *)cond)->events[ _GLFW_COND_BROADCAST ] ); + + // Delete critical section + DeleteCriticalSection( &((_GLFWcond *)cond)->waiters_count_lock ); + + // Free memory for condition variable + free( (void *) cond ); +} + + +//======================================================================== +// _glfwPlatformWaitCond() - Wait for a condition to be raised +//======================================================================== + +void _glfwPlatformWaitCond( GLFWcond cond, GLFWmutex mutex, + double timeout ) +{ + _GLFWcond *cv = (_GLFWcond *) cond; + int result, last_waiter; + DWORD timeout_ms; + + // Avoid race conditions + EnterCriticalSection( &cv->waiters_count_lock ); + cv->waiters_count ++; + LeaveCriticalSection( &cv->waiters_count_lock ); + + // It's ok to release the mutex here since Win32 manual-reset events + // maintain state when used with SetEvent() + LeaveCriticalSection( (CRITICAL_SECTION *) mutex ); + + // Translate timeout into milliseconds + if( timeout >= GLFW_INFINITY ) + { + timeout_ms = INFINITE; + } + else + { + timeout_ms = (DWORD) (1000.0 * timeout + 0.5); + if( timeout_ms <= 0 ) + { + timeout_ms = 1; + } + } + + // Wait for either event to become signaled due to glfwSignalCond or + // glfwBroadcastCond being called + result = WaitForMultipleObjects( 2, cv->events, FALSE, timeout_ms ); + + // Check if we are the last waiter + EnterCriticalSection( &cv->waiters_count_lock ); + cv->waiters_count --; + last_waiter = (result == WAIT_OBJECT_0 + _GLFW_COND_BROADCAST) && + (cv->waiters_count == 0); + LeaveCriticalSection( &cv->waiters_count_lock ); + + // Some thread called glfwBroadcastCond + if( last_waiter ) + { + // We're the last waiter to be notified or to stop waiting, so + // reset the manual event + ResetEvent( cv->events[ _GLFW_COND_BROADCAST ] ); + } + + // Reacquire the mutex + EnterCriticalSection( (CRITICAL_SECTION *) mutex ); +} + + +//======================================================================== +// _glfwPlatformSignalCond() - Signal a condition to one waiting thread +//======================================================================== + +void _glfwPlatformSignalCond( GLFWcond cond ) +{ + _GLFWcond *cv = (_GLFWcond *) cond; + int have_waiters; + + // Avoid race conditions + EnterCriticalSection( &cv->waiters_count_lock ); + have_waiters = cv->waiters_count > 0; + LeaveCriticalSection( &cv->waiters_count_lock ); + + if( have_waiters ) + { + SetEvent( cv->events[ _GLFW_COND_SIGNAL ] ); + } +} + + +//======================================================================== +// _glfwPlatformBroadcastCond() - Broadcast a condition to all waiting +// threads +//======================================================================== + +void _glfwPlatformBroadcastCond( GLFWcond cond ) +{ + _GLFWcond *cv = (_GLFWcond *) cond; + int have_waiters; + + // Avoid race conditions + EnterCriticalSection( &cv->waiters_count_lock ); + have_waiters = cv->waiters_count > 0; + LeaveCriticalSection( &cv->waiters_count_lock ); + + if( have_waiters ) + { + SetEvent( cv->events[ _GLFW_COND_BROADCAST ] ); + } +} + + +//======================================================================== +// _glfwPlatformGetNumberOfProcessors() - Return the number of processors +// in the system. +//======================================================================== + +int _glfwPlatformGetNumberOfProcessors( void ) +{ + SYSTEM_INFO si; + + // Get hardware system information + GetSystemInfo( &si ); + + return (int) si.dwNumberOfProcessors; +} diff --git a/libs/glfw/lib/win32/win32_time.c b/libs/glfw/lib/win32/win32_time.c new file mode 100644 index 0000000..382a6ba --- /dev/null +++ b/libs/glfw/lib/win32/win32_time.c @@ -0,0 +1,146 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: win32_time.c +// Platform: Windows +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwInitTimer() - Initialise timer +//======================================================================== + +void _glfwInitTimer( void ) +{ + __int64 freq; + + // Check if we have a performance counter + if( QueryPerformanceFrequency( (LARGE_INTEGER *)&freq ) ) + { + // Performance counter is available => use it! + _glfwLibrary.Timer.HasPerformanceCounter = GL_TRUE; + + // Counter resolution is 1 / counter frequency + _glfwLibrary.Timer.Resolution = 1.0 / (double)freq; + + // Set start time for timer + QueryPerformanceCounter( (LARGE_INTEGER *)&_glfwLibrary.Timer.t0_64 ); + } + else + { + // No performace counter available => use the tick counter + _glfwLibrary.Timer.HasPerformanceCounter = GL_FALSE; + + // Counter resolution is 1 ms + _glfwLibrary.Timer.Resolution = 0.001; + + // Set start time for timer + _glfwLibrary.Timer.t0_32 = _glfw_timeGetTime(); + } +} + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Return timer value in seconds +//======================================================================== + +double _glfwPlatformGetTime( void ) +{ + double t; + __int64 t_64; + + if( _glfwLibrary.Timer.HasPerformanceCounter ) + { + QueryPerformanceCounter( (LARGE_INTEGER *)&t_64 ); + t = (double)(t_64 - _glfwLibrary.Timer.t0_64); + } + else + { + t = (double)(_glfw_timeGetTime() - _glfwLibrary.Timer.t0_32); + } + + // Calculate the current time in seconds + return t * _glfwLibrary.Timer.Resolution; +} + + +//======================================================================== +// Set timer value in seconds +//======================================================================== + +void _glfwPlatformSetTime( double t ) +{ + __int64 t_64; + + if( _glfwLibrary.Timer.HasPerformanceCounter ) + { + QueryPerformanceCounter( (LARGE_INTEGER *)&t_64 ); + _glfwLibrary.Timer.t0_64 = t_64 - (__int64)(t/_glfwLibrary.Timer.Resolution); + } + else + { + _glfwLibrary.Timer.t0_32 = _glfw_timeGetTime() - (int)(t*1000.0); + } +} + + +//======================================================================== +// Put a thread to sleep for a specified amount of time +//======================================================================== + +void _glfwPlatformSleep( double time ) +{ + DWORD t; + + if( time == 0.0 ) + { + t = 0; + } + else if( time < 0.001 ) + { + t = 1; + } + else if( time > 2147483647.0 ) + { + t = 2147483647; + } + else + { + t = (DWORD)(time*1000.0 + 0.5); + } + Sleep( t ); +} + diff --git a/libs/glfw/lib/win32/win32_window.c b/libs/glfw/lib/win32/win32_window.c new file mode 100644 index 0000000..8562dac --- /dev/null +++ b/libs/glfw/lib/win32/win32_window.c @@ -0,0 +1,1714 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: win32_window.c +// Platform: Windows +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +#define _GLFW_WNDCLASSNAME "GLFW26" + + +//======================================================================== +// Enable/disable minimize/restore animations +//======================================================================== + +static int _glfwMinMaxAnimations( int enable ) +{ + ANIMATIONINFO AI; + int old_enable; + + // Get old animation setting + AI.cbSize = sizeof( ANIMATIONINFO ); + SystemParametersInfo( SPI_GETANIMATION, AI.cbSize, &AI, 0 ); + old_enable = AI.iMinAnimate; + + // If requested, change setting + if( old_enable != enable ) + { + AI.iMinAnimate = enable; + SystemParametersInfo( SPI_SETANIMATION, AI.cbSize, &AI, + SPIF_SENDCHANGE ); + } + + return old_enable; +} + + +//======================================================================== +// Function for bringing a window into focus and placing it on top of the +// window z stack. Due to some nastiness with how Win98/ME/2k/XP handles +// SetForegroundWindow, we have to go through some really bizarre measures to +// achieve this (thanks again, MS, for making life so much easier)! +//======================================================================== + +static void _glfwSetForegroundWindow( HWND hWnd ) +{ + int try_count = 0; + int old_animate; + + // Try the standard approach first... + BringWindowToTop( hWnd ); + SetForegroundWindow( hWnd ); + + // If it worked, return now + if( hWnd == GetForegroundWindow() ) + { + // Try to modify the system settings (since this is the foreground + // process, we are allowed to do this) + SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, + SPIF_SENDCHANGE ); + return; + } + + // For other Windows versions than 95 & NT4.0, the standard approach + // may not work, so if we failed we have to "trick" Windows into + // making our window the foureground window: Iconify and restore + // again. It is ugly, but it seems to work (we turn off those annoying + // zoom animations to make it look a bit better at least). + + // Turn off minimize/restore animations + old_animate = _glfwMinMaxAnimations( 0 ); + + // We try this a few times, just to be on the safe side of things... + do + { + // Iconify & restore + ShowWindow( hWnd, SW_HIDE ); + ShowWindow( hWnd, SW_SHOWMINIMIZED ); + ShowWindow( hWnd, SW_SHOWNORMAL ); + + // Try to get focus + BringWindowToTop( hWnd ); + SetForegroundWindow( hWnd ); + + // We do not want to keep going on forever, so we keep track of + // how many times we tried + try_count ++; + } + while( hWnd != GetForegroundWindow() && try_count <= 3 ); + + // Restore the system minimize/restore animation setting + (void) _glfwMinMaxAnimations( old_animate ); + + // Try to modify the system settings (since this is now hopefully the + // foreground process, we are probably allowed to do this) + SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, + SPIF_SENDCHANGE ); +} + + +//======================================================================== +// Sets the device context pixel format using a PFD +//======================================================================== + +static int _glfwSetPixelFormatPFD( int redbits, int greenbits, int bluebits, + int alphabits, int depthbits, int stencilbits, + int mode, _GLFWhints* hints ) +{ + int PixelFormat; + PIXELFORMATDESCRIPTOR pfd; + + // Set required pixel format + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | // Draw to window + PFD_SUPPORT_OPENGL | // Support OpenGL + PFD_DOUBLEBUFFER; // Double buffered window + pfd.iPixelType = PFD_TYPE_RGBA; // Request an RGBA format + pfd.cColorBits = (BYTE) (redbits + + greenbits + + bluebits); // Color bits (ex. alpha) + pfd.cRedBits = (BYTE) redbits; // Red bits + pfd.cRedShift = 0; // Red shift ignored + pfd.cGreenBits = (BYTE) greenbits; // Green bits + pfd.cGreenShift = 0; // Green shift ignored + pfd.cBlueBits = (BYTE) bluebits; // Blue bits + pfd.cBlueShift = 0; // Blue shift ignored + pfd.cAlphaBits = (BYTE) alphabits; // Alpha bits + pfd.cAlphaShift = 0; // Alpha shift ignored + pfd.cAccumBits = (BYTE) (hints->AccumRedBits + + hints->AccumGreenBits + + hints->AccumBlueBits + + hints->AccumAlphaBits); // Accum. bits + pfd.cAccumRedBits = (BYTE) hints->AccumRedBits; // Accum. red bits + pfd.cAccumGreenBits = (BYTE) hints->AccumGreenBits; // Accum. green bits + pfd.cAccumBlueBits = (BYTE) hints->AccumBlueBits; // Accum. blue bits + pfd.cAccumAlphaBits = (BYTE) hints->AccumAlphaBits; // Accum. alpha bits + pfd.cDepthBits = (BYTE) depthbits; // Depth buffer bits + pfd.cStencilBits = (BYTE) stencilbits; // Stencil buffer bits + pfd.cAuxBuffers = (BYTE) hints->AuxBuffers; // No. of aux buffers + pfd.iLayerType = PFD_MAIN_PLANE; // Drawing layer: main + pfd.bReserved = 0; // (reserved) + pfd.dwLayerMask = 0; // Ignored + pfd.dwVisibleMask = 0; // " + pfd.dwDamageMask = 0; // " + + if( depthbits <= 0 ) + { + // We do not need a depth buffer + pfd.dwFlags |= PFD_DEPTH_DONTCARE; + } + + if( hints->Stereo ) + { + // Request a stereo mode + pfd.dwFlags |= PFD_STEREO; + } + + // Find a matching pixel format + PixelFormat = _glfw_ChoosePixelFormat( _glfwWin.DC, &pfd ); + if( !PixelFormat ) + { + return GL_FALSE; + } + + // Get actual pixel format description + if( !_glfw_DescribePixelFormat( _glfwWin.DC, PixelFormat, sizeof(pfd), &pfd ) ) + { + return GL_FALSE; + } + + // "stereo" is a strict requirement + if( hints->Stereo && !(pfd.dwFlags & PFD_STEREO) ) + { + return GL_FALSE; + } + + // Set the pixel-format + if( !_glfw_SetPixelFormat( _glfwWin.DC, PixelFormat, &pfd ) ) + { + return GL_FALSE; + } + + return GL_TRUE; +} + + +//======================================================================== +// Sets the device context pixel format using attributes +//======================================================================== + +#define _glfwSetWGLAttribute( _glfwName, _glfwValue ) \ + attribs[ count++ ] = _glfwName; \ + attribs[ count++ ] = _glfwValue; + +static int _glfwSetPixelFormatAttrib( int redbits, int greenbits, int bluebits, + int alphabits, int depthbits, int stencilbits, + int mode, _GLFWhints* hints ) +{ + int PixelFormat, dummy, count = 0; + int attribs[128]; + PIXELFORMATDESCRIPTOR pfd; + + int accumredbits = hints->AccumRedBits; + int accumgreenbits = hints->AccumGreenBits; + int accumbluebits = hints->AccumBlueBits; + int accumalphabits = hints->AccumAlphaBits; + + _glfwSetWGLAttribute( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE ); + _glfwSetWGLAttribute( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB ); + _glfwSetWGLAttribute( WGL_SUPPORT_OPENGL_ARB, GL_TRUE ); + _glfwSetWGLAttribute( WGL_DOUBLE_BUFFER_ARB, GL_TRUE ); + _glfwSetWGLAttribute( WGL_COLOR_BITS_ARB, redbits + greenbits + bluebits ); + _glfwSetWGLAttribute( WGL_RED_BITS_ARB, redbits ); + _glfwSetWGLAttribute( WGL_GREEN_BITS_ARB, greenbits ); + _glfwSetWGLAttribute( WGL_BLUE_BITS_ARB, bluebits ); + _glfwSetWGLAttribute( WGL_ALPHA_BITS_ARB, alphabits ); + _glfwSetWGLAttribute( WGL_DEPTH_BITS_ARB, depthbits ); + _glfwSetWGLAttribute( WGL_STENCIL_BITS_ARB, stencilbits ); + _glfwSetWGLAttribute( WGL_AUX_BUFFERS_ARB, hints->AuxBuffers ); + + if( accumredbits || accumgreenbits || accumbluebits || accumalphabits ) + { + _glfwSetWGLAttribute( WGL_ACCUM_BITS_ARB, accumredbits + + accumgreenbits + + accumbluebits + + accumalphabits ); + + _glfwSetWGLAttribute( WGL_ACCUM_RED_BITS_ARB, accumredbits ); + _glfwSetWGLAttribute( WGL_ACCUM_GREEN_BITS_ARB, accumgreenbits ); + _glfwSetWGLAttribute( WGL_ACCUM_BLUE_BITS_ARB, accumbluebits ); + _glfwSetWGLAttribute( WGL_ACCUM_ALPHA_BITS_ARB, accumalphabits ); + } + + if( hints->Stereo ) + { + _glfwSetWGLAttribute( WGL_STEREO_ARB, GL_TRUE ); + } + + if( hints->Samples > 0 ) + { + _glfwSetWGLAttribute( WGL_SAMPLE_BUFFERS_ARB, 1 ); + _glfwSetWGLAttribute( WGL_SAMPLES_ARB, hints->Samples ); + } + + _glfwSetWGLAttribute( 0, 0 ); + + if( !_glfwWin.ChoosePixelFormat( _glfwWin.DC, attribs, NULL, 1, &PixelFormat, &dummy ) ) + { + return GL_FALSE; + } + + if( !_glfw_DescribePixelFormat( _glfwWin.DC, PixelFormat, sizeof(pfd), &pfd ) ) + { + return GL_FALSE; + } + + // Set the pixel-format + if( !_glfw_SetPixelFormat( _glfwWin.DC, PixelFormat, &pfd ) ) + { + return GL_FALSE; + } + + return GL_TRUE; +} + +#undef _glfwSetWGLAttribute + + +//======================================================================== +// Translates a Windows key to the corresponding GLFW key +//======================================================================== + +static int _glfwTranslateKey( WPARAM wParam, LPARAM lParam ) +{ + MSG next_msg; + DWORD msg_time; + DWORD scan_code; + + // Check which key was pressed or released + switch( wParam ) + { + // The SHIFT keys require special handling + case VK_SHIFT: + // Compare scan code for this key with that of VK_RSHIFT in + // order to determine which shift key was pressed (left or + // right) + scan_code = MapVirtualKey( VK_RSHIFT, 0 ); + if( ((lParam & 0x01ff0000) >> 16) == scan_code ) + { + return GLFW_KEY_RSHIFT; + } + return GLFW_KEY_LSHIFT; + + // The CTRL keys require special handling + case VK_CONTROL: + // Is this an extended key (i.e. right key)? + if( lParam & 0x01000000 ) + { + return GLFW_KEY_RCTRL; + } + // Here is a trick: "Alt Gr" sends LCTRL, then RALT. We only + // want the RALT message, so we try to see if the next message + // is a RALT message. In that case, this is a false LCTRL! + msg_time = GetMessageTime(); + if( PeekMessage( &next_msg, NULL, 0, 0, PM_NOREMOVE ) ) + { + if( next_msg.message == WM_KEYDOWN || + next_msg.message == WM_SYSKEYDOWN ) + { + if( next_msg.wParam == VK_MENU && + (next_msg.lParam & 0x01000000) && + next_msg.time == msg_time ) + { + // Next message is a RALT down message, which + // means that this is NOT a proper LCTRL message! + return GLFW_KEY_UNKNOWN; + } + } + } + return GLFW_KEY_LCTRL; + + // The ALT keys require special handling + case VK_MENU: + // Is this an extended key (i.e. right key)? + if( lParam & 0x01000000 ) + { + return GLFW_KEY_RALT; + } + return GLFW_KEY_LALT; + + // The ENTER keys require special handling + case VK_RETURN: + // Is this an extended key (i.e. right key)? + if( lParam & 0x01000000 ) + { + return GLFW_KEY_KP_ENTER; + } + return GLFW_KEY_ENTER; + + // Special keys (non character keys) + case VK_ESCAPE: return GLFW_KEY_ESC; + case VK_TAB: return GLFW_KEY_TAB; + case VK_BACK: return GLFW_KEY_BACKSPACE; + case VK_HOME: return GLFW_KEY_HOME; + case VK_END: return GLFW_KEY_END; + case VK_PRIOR: return GLFW_KEY_PAGEUP; + case VK_NEXT: return GLFW_KEY_PAGEDOWN; + case VK_INSERT: return GLFW_KEY_INSERT; + case VK_DELETE: return GLFW_KEY_DEL; + case VK_LEFT: return GLFW_KEY_LEFT; + case VK_UP: return GLFW_KEY_UP; + case VK_RIGHT: return GLFW_KEY_RIGHT; + case VK_DOWN: return GLFW_KEY_DOWN; + case VK_F1: return GLFW_KEY_F1; + case VK_F2: return GLFW_KEY_F2; + case VK_F3: return GLFW_KEY_F3; + case VK_F4: return GLFW_KEY_F4; + case VK_F5: return GLFW_KEY_F5; + case VK_F6: return GLFW_KEY_F6; + case VK_F7: return GLFW_KEY_F7; + case VK_F8: return GLFW_KEY_F8; + case VK_F9: return GLFW_KEY_F9; + case VK_F10: return GLFW_KEY_F10; + case VK_F11: return GLFW_KEY_F11; + case VK_F12: return GLFW_KEY_F12; + case VK_F13: return GLFW_KEY_F13; + case VK_F14: return GLFW_KEY_F14; + case VK_F15: return GLFW_KEY_F15; + case VK_F16: return GLFW_KEY_F16; + case VK_F17: return GLFW_KEY_F17; + case VK_F18: return GLFW_KEY_F18; + case VK_F19: return GLFW_KEY_F19; + case VK_F20: return GLFW_KEY_F20; + case VK_F21: return GLFW_KEY_F21; + case VK_F22: return GLFW_KEY_F22; + case VK_F23: return GLFW_KEY_F23; + case VK_F24: return GLFW_KEY_F24; + case VK_SPACE: return GLFW_KEY_SPACE; + + // Numeric keypad + case VK_NUMPAD0: return GLFW_KEY_KP_0; + case VK_NUMPAD1: return GLFW_KEY_KP_1; + case VK_NUMPAD2: return GLFW_KEY_KP_2; + case VK_NUMPAD3: return GLFW_KEY_KP_3; + case VK_NUMPAD4: return GLFW_KEY_KP_4; + case VK_NUMPAD5: return GLFW_KEY_KP_5; + case VK_NUMPAD6: return GLFW_KEY_KP_6; + case VK_NUMPAD7: return GLFW_KEY_KP_7; + case VK_NUMPAD8: return GLFW_KEY_KP_8; + case VK_NUMPAD9: return GLFW_KEY_KP_9; + case VK_DIVIDE: return GLFW_KEY_KP_DIVIDE; + case VK_MULTIPLY: return GLFW_KEY_KP_MULTIPLY; + case VK_SUBTRACT: return GLFW_KEY_KP_SUBTRACT; + case VK_ADD: return GLFW_KEY_KP_ADD; + case VK_DECIMAL: return GLFW_KEY_KP_DECIMAL; + + // The rest (should be printable keys) + default: + // Convert to printable character (ISO-8859-1 or Unicode) + wParam = MapVirtualKey( (UINT) wParam, 2 ) & 0x0000FFFF; + + // Make sure that the character is uppercase + if( _glfwLibrary.Sys.HasUnicode ) + { + wParam = (WPARAM) CharUpperW( (LPWSTR) wParam ); + } + else + { + wParam = (WPARAM) CharUpperA( (LPSTR) wParam ); + } + + // Valid ISO-8859-1 character? + if( (wParam >= 32 && wParam <= 126) || + (wParam >= 160 && wParam <= 255) ) + { + return (int) wParam; + } + return GLFW_KEY_UNKNOWN; + } +} + + +//======================================================================== +// Translates a windows key to Unicode +//======================================================================== + +static void _glfwTranslateChar( DWORD wParam, DWORD lParam, int action ) +{ + BYTE keyboard_state[ 256 ]; + UCHAR char_buf[ 10 ]; + WCHAR unicode_buf[ 10 ]; + UINT scan_code; + int i, num_chars, unicode; + + // Get keyboard state + GetKeyboardState( keyboard_state ); + + // Derive scan code from lParam and action + scan_code = (lParam & 0x01ff0000) >> 16; + if( action == GLFW_RELEASE ) + { + scan_code |= 0x8000000; + } + + // Do we have Unicode support? + if( _glfwLibrary.Sys.HasUnicode ) + { + // Convert to Unicode + num_chars = ToUnicode( + wParam, // virtual-key code + scan_code, // scan code + keyboard_state, // key-state array + unicode_buf, // buffer for translated key + 10, // size of translated key buffer + 0 // active-menu flag + ); + unicode = 1; + } + else + { + // Convert to ISO-8859-1 + num_chars = ToAscii( + wParam, // virtual-key code + scan_code, // scan code + keyboard_state, // key-state array + (LPWORD) char_buf, // buffer for translated key + 0 // active-menu flag + ); + unicode = 0; + } + + // Report characters + for( i = 0; i < num_chars; i++ ) + { + // Get next character from buffer + if( unicode ) + { + _glfwInputChar( (int) unicode_buf[ i ], action ); + } + else + { + _glfwInputChar( (int) char_buf[ i ], action ); + } + } +} + + +//======================================================================== +// Window callback function (handles window events) +//======================================================================== + +static LRESULT CALLBACK _glfwWindowCallback( HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam ) +{ + int WheelDelta, Iconified; + + // Handle certain window messages + switch( uMsg ) + { + // Window activate message? (iconification?) + case WM_ACTIVATE: + { + _glfwWin.Active = LOWORD(wParam) != WA_INACTIVE ? GL_TRUE : GL_FALSE; + + Iconified = HIWORD(wParam) ? GL_TRUE : GL_FALSE; + + // Were we deactivated/iconified? + if( (!_glfwWin.Active || Iconified) && !_glfwWin.Iconified ) + { + _glfwInputDeactivation(); + + // If we are in fullscreen mode we need to iconify + if( _glfwWin.Opened && _glfwWin.Fullscreen ) + { + // Do we need to manually iconify? + if( !Iconified ) + { + // Minimize window + CloseWindow( _glfwWin.Wnd ); + + // The window is now iconified + Iconified = GL_TRUE; + } + + // Change display settings to the desktop resolution + ChangeDisplaySettings( NULL, CDS_FULLSCREEN ); + } + + // Unlock mouse + if( !_glfwWin.OldMouseLockValid ) + { + _glfwWin.OldMouseLock = _glfwWin.MouseLock; + _glfwWin.OldMouseLockValid = GL_TRUE; + glfwEnable( GLFW_MOUSE_CURSOR ); + } + } + else if( _glfwWin.Active || !Iconified ) + { + // If we are in fullscreen mode we need to maximize + if( _glfwWin.Opened && _glfwWin.Fullscreen && _glfwWin.Iconified ) + { + // Change display settings to the user selected mode + _glfwSetVideoModeMODE( _glfwWin.ModeID ); + + // Do we need to manually restore window? + if( Iconified ) + { + // Restore window + OpenIcon( _glfwWin.Wnd ); + + // The window is no longer iconified + Iconified = GL_FALSE; + + // Activate window + ShowWindow( hWnd, SW_SHOW ); + _glfwSetForegroundWindow( _glfwWin.Wnd ); + SetFocus( _glfwWin.Wnd ); + } + } + + // Lock mouse, if necessary + if( _glfwWin.OldMouseLockValid && _glfwWin.OldMouseLock ) + { + glfwDisable( GLFW_MOUSE_CURSOR ); + } + _glfwWin.OldMouseLockValid = GL_FALSE; + } + + _glfwWin.Iconified = Iconified; + return 0; + } + + // Intercept system commands (forbid certain actions/events) + case WM_SYSCOMMAND: + { + switch( wParam ) + { + // Screensaver trying to start or monitor trying to enter + // powersave? + case SC_SCREENSAVE: + case SC_MONITORPOWER: + if( _glfwWin.Fullscreen ) + { + return 0; + } + else + { + break; + } + + // User trying to access application menu using ALT? + case SC_KEYMENU: + return 0; + } + break; + } + + // Did we receive a close message? + case WM_CLOSE: + PostQuitMessage( 0 ); + return 0; + + // Is a key being pressed? + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + { + // Translate and report key press + _glfwInputKey( _glfwTranslateKey( wParam, lParam ), + GLFW_PRESS ); + + // Translate and report character input + if( _glfwWin.CharCallback ) + { + _glfwTranslateChar( (DWORD) wParam, (DWORD) lParam, GLFW_PRESS ); + } + return 0; + } + + // Is a key being released? + case WM_KEYUP: + case WM_SYSKEYUP: + { + // Special trick: release both shift keys on SHIFT up event + if( wParam == VK_SHIFT ) + { + _glfwInputKey( GLFW_KEY_LSHIFT, GLFW_RELEASE ); + _glfwInputKey( GLFW_KEY_RSHIFT, GLFW_RELEASE ); + } + else + { + // Translate and report key release + _glfwInputKey( _glfwTranslateKey( wParam, lParam ), + GLFW_RELEASE ); + } + + // Translate and report character input + if( _glfwWin.CharCallback ) + { + _glfwTranslateChar( (DWORD) wParam, (DWORD) lParam, GLFW_RELEASE ); + } + + return 0; + } + + // Were any of the mouse-buttons pressed? + case WM_LBUTTONDOWN: + SetCapture(hWnd); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS ); + return 0; + case WM_RBUTTONDOWN: + SetCapture(hWnd); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS ); + return 0; + case WM_MBUTTONDOWN: + SetCapture(hWnd); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS ); + return 0; + case WM_XBUTTONDOWN: + { + if( HIWORD(wParam) == XBUTTON1 ) + { + SetCapture(hWnd); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_4, GLFW_PRESS ); + } + else if( HIWORD(wParam) == XBUTTON2 ) + { + SetCapture(hWnd); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_5, GLFW_PRESS ); + } + return 1; + } + + // Were any of the mouse-buttons released? + case WM_LBUTTONUP: + ReleaseCapture(); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE ); + return 0; + case WM_RBUTTONUP: + ReleaseCapture(); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE ); + return 0; + case WM_MBUTTONUP: + ReleaseCapture(); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_MIDDLE, GLFW_RELEASE ); + return 0; + case WM_XBUTTONUP: + { + if( HIWORD(wParam) == XBUTTON1 ) + { + ReleaseCapture(); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_4, GLFW_RELEASE ); + } + else if( HIWORD(wParam) == XBUTTON2 ) + { + ReleaseCapture(); + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_5, GLFW_RELEASE ); + } + return 1; + } + + // Did the mouse move? + case WM_MOUSEMOVE: + { + { + int NewMouseX, NewMouseY; + + // Get signed (!) mouse position + NewMouseX = (int)((short)LOWORD(lParam)); + NewMouseY = (int)((short)HIWORD(lParam)); + + if( NewMouseX != _glfwInput.OldMouseX || + NewMouseY != _glfwInput.OldMouseY ) + { + if( _glfwWin.MouseLock ) + { + _glfwInput.MousePosX += NewMouseX - + _glfwInput.OldMouseX; + _glfwInput.MousePosY += NewMouseY - + _glfwInput.OldMouseY; + } + else + { + _glfwInput.MousePosX = NewMouseX; + _glfwInput.MousePosY = NewMouseY; + } + _glfwInput.OldMouseX = NewMouseX; + _glfwInput.OldMouseY = NewMouseY; + _glfwInput.MouseMoved = GL_TRUE; + + // Call user callback function + if( _glfwWin.MousePosCallback ) + { + _glfwWin.MousePosCallback( _glfwInput.MousePosX, + _glfwInput.MousePosY ); + } + } + } + return 0; + } + + // Mouse wheel action? + case WM_MOUSEWHEEL: + { + // WM_MOUSEWHEEL is not supported under Windows 95 + if( _glfwLibrary.Sys.WinVer != _GLFW_WIN_95 ) + { + WheelDelta = (((int)wParam) >> 16) / WHEEL_DELTA; + _glfwInput.WheelPos += WheelDelta; + if( _glfwWin.MouseWheelCallback ) + { + _glfwWin.MouseWheelCallback( _glfwInput.WheelPos ); + } + return 0; + } + break; + } + + // Resize the window? + case WM_SIZE: + { + // get the new size + _glfwWin.Width = LOWORD(lParam); + _glfwWin.Height = HIWORD(lParam); + + // If the mouse is locked, update the clipping rect + if( _glfwWin.MouseLock ) + { + RECT ClipWindowRect; + if( GetWindowRect( _glfwWin.Wnd, &ClipWindowRect ) ) + { + ClipCursor( &ClipWindowRect ); + } + } + + // Call the user-supplied callback, if it exists + if( _glfwWin.WindowSizeCallback ) + { + _glfwWin.WindowSizeCallback( LOWORD(lParam), + HIWORD(lParam) ); + } + return 0; + } + + // Move the window? + case WM_MOVE: + { + // If the mouse is locked, update the clipping rect + if( _glfwWin.MouseLock ) + { + RECT ClipWindowRect; + if( GetWindowRect( _glfwWin.Wnd, &ClipWindowRect ) ) + { + ClipCursor( &ClipWindowRect ); + } + } + return 0; + } + + // Was the window contents damaged? + case WM_PAINT: + { + // Call user callback function + if( _glfwWin.WindowRefreshCallback ) + { + _glfwWin.WindowRefreshCallback(); + } + break; + } + + case WM_DISPLAYCHANGE: + { + // TODO: Do stuff here. + + break; + } + } + + // Pass all unhandled messages to DefWindowProc + return DefWindowProc( hWnd, uMsg, wParam, lParam ); +} + + +//======================================================================== +// Translate client window size to full window size (including window borders) +//======================================================================== + +static void _glfwGetFullWindowSize( int w, int h, int *w2, int *h2 ) +{ + RECT rect; + + // Create a window rectangle + rect.left = (long)0; + rect.right = (long)w-1; + rect.top = (long)0; + rect.bottom = (long)h-1; + + // Adjust according to window styles + AdjustWindowRectEx( &rect, _glfwWin.dwStyle, FALSE, + _glfwWin.dwExStyle ); + + // Calculate width and height of full window + *w2 = rect.right-rect.left+1; + *h2 = rect.bottom-rect.top+1; +} + + +//======================================================================== +// Initialize WGL-specific extensions +//======================================================================== + +static void _glfwInitWGLExtensions( void ) +{ + GLubyte *extensions; + int has_swap_control, has_pixel_format; + + _glfwWin.GetExtensionsStringEXT = (WGLGETEXTENSIONSSTRINGEXT_T) + wglGetProcAddress( "wglGetExtensionsStringEXT" ); + if( !_glfwWin.GetExtensionsStringEXT ) + { + // Try wglGetExtensionsStringARB + _glfwWin.GetExtensionsStringARB = (WGLGETEXTENSIONSSTRINGARB_T) + wglGetProcAddress( "wglGetExtensionsStringARB" ); + if( !_glfwWin.GetExtensionsStringARB ) + { + return; + } + } + + // Initialize OpenGL extension: WGL_EXT_swap_control + has_swap_control = GL_FALSE; + has_pixel_format = GL_FALSE; + extensions = (GLubyte *) glGetString( GL_EXTENSIONS ); + + if( extensions != NULL ) + { + has_swap_control = _glfwStringInExtensionString( + "WGL_EXT_swap_control", + extensions + ); + has_pixel_format = _glfwStringInExtensionString( + "WGL_ARB_pixel_format", + extensions + ); + } + + if( !has_swap_control ) + { + has_swap_control = _glfwPlatformExtensionSupported( + "WGL_EXT_swap_control" + ); + } + + if( !has_pixel_format ) + { + has_pixel_format = _glfwPlatformExtensionSupported( + "WGL_ARB_pixel_format" + ); + } + + if( has_swap_control ) + { + _glfwWin.SwapInterval = (WGLSWAPINTERVALEXT_T) + wglGetProcAddress( "wglSwapIntervalEXT" ); + } + else + { + _glfwWin.SwapInterval = NULL; + } + + if( has_pixel_format ) + { + _glfwWin.ChoosePixelFormat = (WGLCHOOSEPIXELFORMATARB_T) + wglGetProcAddress( "wglChoosePixelFormatARB" ); + _glfwWin.GetPixelFormatAttribiv = (WGLGETPIXELFORMATATTRIBIVARB_T) + wglGetProcAddress( "wglGetPixelFormatAttribivARB" ); + } + else + { + _glfwWin.ChoosePixelFormat = NULL; + _glfwWin.GetPixelFormatAttribiv = NULL; + } +} + + +//======================================================================== +// Creates the GLFW window and rendering context +//======================================================================== + +static int _glfwCreateWindow( int redbits, int greenbits, int bluebits, + int alphabits, int depthbits, int stencilbits, + int mode, _GLFWhints* hints ) +{ + int full_width, full_height; + RECT wa; + POINT pos; + + _glfwWin.DC = NULL; + _glfwWin.RC = NULL; + _glfwWin.Wnd = NULL; + + // Set window size to true requested size (adjust for window borders) + _glfwGetFullWindowSize( _glfwWin.Width, _glfwWin.Height, &full_width, + &full_height ); + + // Adjust window position to working area (e.g. if the task bar is at + // the top of the display). Fullscreen windows are always opened in + // the upper left corner regardless of the desktop working area. + if( _glfwWin.Fullscreen ) + { + wa.left = wa.top = 0; + } + else + { + SystemParametersInfo( SPI_GETWORKAREA, 0, &wa, 0 ); + } + + // Create window + _glfwWin.Wnd = CreateWindowEx( + _glfwWin.dwExStyle, // Extended style + _GLFW_WNDCLASSNAME, // Class name + "GLFW Window", // Window title + _glfwWin.dwStyle, // Defined window style + wa.left, wa.top, // Window position + full_width, // Decorated window width + full_height, // Decorated window height + NULL, // No parent window + NULL, // No menu + _glfwLibrary.Instance, // Instance + NULL ); // Nothing to WM_CREATE + + if( !_glfwWin.Wnd ) + { + return GL_FALSE; + } + + // Get a device context + _glfwWin.DC = GetDC( _glfwWin.Wnd ); + if( !_glfwWin.DC ) + { + return GL_FALSE; + } + + if( _glfwWin.ChoosePixelFormat ) + { + if( !_glfwSetPixelFormatAttrib( redbits, greenbits, bluebits, alphabits, + depthbits, stencilbits, mode, hints ) ) + { + return GL_FALSE; + } + } + else + { + if( !_glfwSetPixelFormatPFD( redbits, greenbits, bluebits, alphabits, + depthbits, stencilbits, mode, hints ) ) + { + return GL_FALSE; + } + } + + // Get a rendering context + _glfwWin.RC = wglCreateContext( _glfwWin.DC ); + if( !_glfwWin.RC ) + { + return GL_FALSE; + } + + // Activate the OpenGL rendering context + if( !wglMakeCurrent( _glfwWin.DC, _glfwWin.RC ) ) + { + return GL_FALSE; + } + + // Initialize WGL-specific OpenGL extensions + _glfwInitWGLExtensions(); + + // Initialize mouse position + GetCursorPos( &pos ); + ScreenToClient( _glfwWin.Wnd, &pos ); + _glfwInput.OldMouseX = _glfwInput.MousePosX = pos.x; + _glfwInput.OldMouseY = _glfwInput.MousePosY = pos.y; + + return GL_TRUE; +} + + +//======================================================================== +// Destroys the GLFW window and rendering context +//======================================================================== + +static void _glfwDestroyWindow( void ) +{ + // Do we have a rendering context? + if( _glfwWin.RC ) + { + // Release the DC and RC contexts + wglMakeCurrent( NULL, NULL ); + + // Delete the rendering context + wglDeleteContext( _glfwWin.RC ); + _glfwWin.RC = NULL; + } + + // Do we have a device context? + if( _glfwWin.DC ) + { + // Release the device context + ReleaseDC( _glfwWin.Wnd, _glfwWin.DC ); + _glfwWin.DC = NULL; + } + + // Do we have a window? + if( _glfwWin.Wnd ) + { + // Destroy the window + if( _glfwLibrary.Sys.WinVer <= _GLFW_WIN_NT4 ) + { + // Note: Hiding the window first fixes an annoying W98/NT4 + // remaining icon bug for fullscreen displays + ShowWindow( _glfwWin.Wnd, SW_HIDE ); + } + + DestroyWindow( _glfwWin.Wnd ); + _glfwWin.Wnd = NULL; + } +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Here is where the window is created, and the OpenGL rendering context is +// created +//======================================================================== + +int _glfwPlatformOpenWindow( int width, int height, + int redbits, int greenbits, int bluebits, + int alphabits, int depthbits, int stencilbits, + int mode, _GLFWhints* hints ) +{ + WNDCLASS wc; + DWORD dwStyle, dwExStyle; + + // Clear platform specific GLFW window state + _glfwWin.ClassAtom = 0; + _glfwWin.OldMouseLockValid = GL_FALSE; + _glfwWin.ChoosePixelFormat = NULL; + _glfwWin.GetPixelFormatAttribiv = NULL; + + // Remember desired refresh rate for this window (used only in + // fullscreen mode) + _glfwWin.DesiredRefreshRate = hints->RefreshRate; + + // Set window class parameters + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw on... + wc.lpfnWndProc = (WNDPROC)_glfwWindowCallback; // Message handler + wc.cbClsExtra = 0; // No extra class data + wc.cbWndExtra = 0; // No extra window data + wc.hInstance = _glfwLibrary.Instance; // Set instance + wc.hCursor = LoadCursor( NULL, IDC_ARROW ); // Load arrow pointer + wc.hbrBackground = NULL; // No background + wc.lpszMenuName = NULL; // No menu + wc.lpszClassName = _GLFW_WNDCLASSNAME; // Set class name + + // Load user-provided icon if available + wc.hIcon = LoadIcon( _glfwLibrary.Instance, "GLFW_ICON" ); + if( !wc.hIcon ) + { + // Load default icon + wc.hIcon = LoadIcon( NULL, IDI_WINLOGO ); + } + + // Register the window class + _glfwWin.ClassAtom = RegisterClass( &wc ); + if( !_glfwWin.ClassAtom ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Do we want full-screen mode? + if( _glfwWin.Fullscreen ) + { + _glfwSetVideoMode( &_glfwWin.Width, &_glfwWin.Height, + redbits, greenbits, bluebits, + hints->RefreshRate ); + } + + // Set common window styles + dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; + dwExStyle = WS_EX_APPWINDOW; + + // Set window style, depending on fullscreen mode + if( _glfwWin.Fullscreen ) + { + dwStyle |= WS_POPUP; + + // Here's a trick for helping us getting window focus + // (SetForegroundWindow doesn't work properly under + // Win98/ME/2K/.NET/+) + /* + if( _glfwLibrary.Sys.WinVer != _GLFW_WIN_95 && + _glfwLibrary.Sys.WinVer != _GLFW_WIN_NT4 && + _glfwLibrary.Sys.WinVer != _GLFW_WIN_XP ) + { + dwStyle |= WS_MINIMIZE; + } + */ + } + else + { + dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + + if( !hints->WindowNoResize ) + { + dwStyle |= ( WS_MAXIMIZEBOX | WS_SIZEBOX ); + dwExStyle |= WS_EX_WINDOWEDGE; + } + } + + // Remember window styles (used by _glfwGetFullWindowSize) + _glfwWin.dwStyle = dwStyle; + _glfwWin.dwExStyle = dwExStyle; + + if( !_glfwCreateWindow( redbits, greenbits, bluebits, alphabits, + depthbits, stencilbits, mode, hints ) ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + if( _glfwWin.ChoosePixelFormat && hints->Samples > 0 ) + { + // Iteratively try to create a context with a decreasing number of + // FSAA samples (requires window recreation). + + for (;;) + { + _glfwDestroyWindow(); + + if( _glfwCreateWindow( redbits, greenbits, bluebits, alphabits, + depthbits, stencilbits, mode, hints ) ) + { + break; + } + + if( hints->Samples > 0 ) + { + hints->Samples--; + } + else + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + } + } + + // Make sure that our window ends up on top of things + if( _glfwWin.Fullscreen ) + { + // Place the window above all topmost windows + SetWindowPos( _glfwWin.Wnd, HWND_TOPMOST, 0,0,0,0, + SWP_NOMOVE | SWP_NOSIZE ); + } + _glfwSetForegroundWindow( _glfwWin.Wnd ); + SetFocus( _glfwWin.Wnd ); + + // Start by clearing the front buffer to black (avoid ugly desktop + // remains in our OpenGL window) + glClear( GL_COLOR_BUFFER_BIT ); + _glfw_SwapBuffers( _glfwWin.DC ); + + return GL_TRUE; +} + + +//======================================================================== +// Properly kill the window / video display +//======================================================================== + +void _glfwPlatformCloseWindow( void ) +{ + _glfwDestroyWindow(); + + // Do we have an instance? + if( _glfwWin.ClassAtom ) + { + // Unregister class + UnregisterClass( _GLFW_WNDCLASSNAME, _glfwLibrary.Instance ); + _glfwWin.ClassAtom = 0; + } + + // Are we in fullscreen mode? + if( _glfwWin.Fullscreen ) + { + // Switch back to desktop resolution + ChangeDisplaySettings( NULL, CDS_FULLSCREEN ); + } +} + + +//======================================================================== +// Set the window title +//======================================================================== + +void _glfwPlatformSetWindowTitle( const char *title ) +{ + // Set window title + (void) SetWindowText( _glfwWin.Wnd, title ); +} + + +//======================================================================== +// Set the window size. +//======================================================================== + +void _glfwPlatformSetWindowSize( int width, int height ) +{ + int bpp, mode = 0, refresh; + int sizechanged = GL_FALSE; + GLint drawbuffer; + GLfloat clearcolor[4]; + + // If we are in fullscreen mode, get some info about the current mode + if( _glfwWin.Fullscreen ) + { + DEVMODE dm; + + // Get current BPP settings + dm.dmSize = sizeof( DEVMODE ); + if( EnumDisplaySettings( NULL, _glfwWin.ModeID, &dm ) ) + { + // Get bpp + bpp = dm.dmBitsPerPel; + + // Get closest match for target video mode + refresh = _glfwWin.DesiredRefreshRate; + mode = _glfwGetClosestVideoModeBPP( &width, &height, &bpp, + &refresh ); + } + else + { + mode = _glfwWin.ModeID; + } + } + else + { + // If we are in windowed mode, adjust the window size to + // compensate for window decorations + _glfwGetFullWindowSize( width, height, &width, &height ); + } + + // Change window size before changing fullscreen mode? + if( _glfwWin.Fullscreen && (width > _glfwWin.Width) ) + { + SetWindowPos( _glfwWin.Wnd, HWND_TOP, 0, 0, width, height, + SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER ); + sizechanged = GL_TRUE; + } + + // Change fullscreen video mode? + if( _glfwWin.Fullscreen && mode != _glfwWin.ModeID ) + { + // Change video mode + _glfwSetVideoModeMODE( mode ); + + // Clear the front buffer to black (avoid ugly desktop remains in + // our OpenGL window) + glGetIntegerv( GL_DRAW_BUFFER, &drawbuffer ); + glGetFloatv( GL_COLOR_CLEAR_VALUE, clearcolor ); + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + glClear( GL_COLOR_BUFFER_BIT ); + if( drawbuffer == GL_BACK ) + { + _glfw_SwapBuffers( _glfwWin.DC ); + } + glClearColor( clearcolor[0], clearcolor[1], clearcolor[2], + clearcolor[3] ); + } + + // Set window size (if not already changed) + if( !sizechanged ) + { + SetWindowPos( _glfwWin.Wnd, HWND_TOP, 0, 0, width, height, + SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER ); + } +} + + +//======================================================================== +// Set the window position +//======================================================================== + +void _glfwPlatformSetWindowPos( int x, int y ) +{ + // Set window position + (void) SetWindowPos( _glfwWin.Wnd, HWND_TOP, x, y, 0, 0, + SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER ); +} + + +//======================================================================== +// Window iconification +//======================================================================== + +void _glfwPlatformIconifyWindow( void ) +{ + // Iconify window + CloseWindow( _glfwWin.Wnd ); + + // Window is now iconified + _glfwWin.Iconified = GL_TRUE; + + // If we are in fullscreen mode we need to change video modes + if( _glfwWin.Fullscreen ) + { + // Change display settings to the desktop resolution + ChangeDisplaySettings( NULL, CDS_FULLSCREEN ); + } + + // Unlock mouse + if( !_glfwWin.OldMouseLockValid ) + { + _glfwWin.OldMouseLock = _glfwWin.MouseLock; + _glfwWin.OldMouseLockValid = GL_TRUE; + glfwEnable( GLFW_MOUSE_CURSOR ); + } +} + + +//======================================================================== +// Window un-iconification +//======================================================================== + +void _glfwPlatformRestoreWindow( void ) +{ + // If we are in fullscreen mode we need to change video modes + if( _glfwWin.Fullscreen ) + { + // Change display settings to the user selected mode + _glfwSetVideoModeMODE( _glfwWin.ModeID ); + } + + // Un-iconify window + OpenIcon( _glfwWin.Wnd ); + + // Make sure that our window ends up on top of things + ShowWindow( _glfwWin.Wnd, SW_SHOW ); + _glfwSetForegroundWindow( _glfwWin.Wnd ); + SetFocus( _glfwWin.Wnd ); + + // Window is no longer iconified + _glfwWin.Iconified = GL_FALSE; + + // Lock mouse, if necessary + if( _glfwWin.OldMouseLockValid && _glfwWin.OldMouseLock ) + { + glfwDisable( GLFW_MOUSE_CURSOR ); + } + _glfwWin.OldMouseLockValid = GL_FALSE; +} + + +//======================================================================== +// Swap buffers (double-buffering) +//======================================================================== + +void _glfwPlatformSwapBuffers( void ) +{ + _glfw_SwapBuffers( _glfwWin.DC ); +} + + +//======================================================================== +// Set double buffering swap interval +//======================================================================== + +void _glfwPlatformSwapInterval( int interval ) +{ + if( _glfwWin.SwapInterval ) + { + _glfwWin.SwapInterval( interval ); + } +} + + +//======================================================================== +// Write back window parameters into GLFW window structure +//======================================================================== + +void _glfwPlatformRefreshWindowParams( void ) +{ + PIXELFORMATDESCRIPTOR pfd; + DEVMODE dm; + int PixelFormat, mode; + + // Obtain a detailed description of current pixel format + PixelFormat = _glfw_GetPixelFormat( _glfwWin.DC ); + + if( !_glfwWin.GetPixelFormatAttribiv ) + { + _glfw_DescribePixelFormat( _glfwWin.DC, PixelFormat, + sizeof(PIXELFORMATDESCRIPTOR), &pfd ); + + // Is current OpenGL context accelerated? + _glfwWin.Accelerated = (pfd.dwFlags & PFD_GENERIC_ACCELERATED) || + !(pfd.dwFlags & PFD_GENERIC_FORMAT) ? 1 : 0; + + // "Standard" window parameters + _glfwWin.RedBits = pfd.cRedBits; + _glfwWin.GreenBits = pfd.cGreenBits; + _glfwWin.BlueBits = pfd.cBlueBits; + _glfwWin.AlphaBits = pfd.cAlphaBits; + _glfwWin.DepthBits = pfd.cDepthBits; + _glfwWin.StencilBits = pfd.cStencilBits; + _glfwWin.AccumRedBits = pfd.cAccumRedBits; + _glfwWin.AccumGreenBits = pfd.cAccumGreenBits; + _glfwWin.AccumBlueBits = pfd.cAccumBlueBits; + _glfwWin.AccumAlphaBits = pfd.cAccumAlphaBits; + _glfwWin.AuxBuffers = pfd.cAuxBuffers; + _glfwWin.Stereo = pfd.dwFlags & PFD_STEREO ? 1 : 0; + _glfwWin.Samples = 0; + } + else + { + const int attribs[] = { + WGL_ACCELERATION_ARB, + WGL_RED_BITS_ARB, + WGL_GREEN_BITS_ARB, + WGL_BLUE_BITS_ARB, + WGL_ALPHA_BITS_ARB, + WGL_DEPTH_BITS_ARB, + WGL_STENCIL_BITS_ARB, + WGL_ACCUM_RED_BITS_ARB, + WGL_ACCUM_GREEN_BITS_ARB, + WGL_ACCUM_BLUE_BITS_ARB, + WGL_ACCUM_ALPHA_BITS_ARB, + WGL_AUX_BUFFERS_ARB, + WGL_STEREO_ARB, + WGL_SAMPLES_ARB + }; + + int values[sizeof(attribs) / sizeof(attribs[0])]; + + _glfwWin.GetPixelFormatAttribiv( _glfwWin.DC, PixelFormat, 0, + sizeof(attribs) / sizeof(attribs[0]), + attribs, values); + + // Is current OpenGL context accelerated? + _glfwWin.Accelerated = (values[0] == WGL_FULL_ACCELERATION_ARB); + + // "Standard" window parameters + _glfwWin.RedBits = values[1]; + _glfwWin.GreenBits = values[2]; + _glfwWin.BlueBits = values[3]; + _glfwWin.AlphaBits = values[4]; + _glfwWin.DepthBits = values[5]; + _glfwWin.StencilBits = values[6]; + _glfwWin.AccumRedBits = values[7]; + _glfwWin.AccumGreenBits = values[8]; + _glfwWin.AccumBlueBits = values[9]; + _glfwWin.AccumAlphaBits = values[10]; + _glfwWin.AuxBuffers = values[11]; + _glfwWin.Stereo = values[12]; + _glfwWin.Samples = values[13]; + } + + // Get refresh rate + mode = _glfwWin.Fullscreen ? _glfwWin.ModeID : ENUM_CURRENT_SETTINGS; + dm.dmSize = sizeof( DEVMODE ); + + if( EnumDisplaySettings( NULL, mode, &dm ) ) + { + _glfwWin.RefreshRate = dm.dmDisplayFrequency; + if( _glfwWin.RefreshRate <= 1 ) + { + _glfwWin.RefreshRate = 0; + } + } + else + { + _glfwWin.RefreshRate = 0; + } +} + + +//======================================================================== +// Poll for new window and input events +//======================================================================== + +void _glfwPlatformPollEvents( void ) +{ + MSG msg; + int winclosed = GL_FALSE; + + // Flag: mouse was not moved (will be changed by _glfwGetNextEvent if + // there was a mouse move event) + _glfwInput.MouseMoved = GL_FALSE; + if( _glfwWin.MouseLock ) + { + _glfwInput.OldMouseX = _glfwWin.Width/2; + _glfwInput.OldMouseY = _glfwWin.Height/2; + } + else + { + _glfwInput.OldMouseX = _glfwInput.MousePosX; + _glfwInput.OldMouseY = _glfwInput.MousePosY; + } + + // Check for new window messages + while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) + { + switch( msg.message ) + { + // QUIT-message (from close window)? + case WM_QUIT: + winclosed = GL_TRUE; + break; + + // Ok, send it to the window message handler + default: + DispatchMessage( &msg ); + break; + } + } + + // LSHIFT/RSHIFT fixup (keys tend to "stick" without this fix) + // This is the only async event handling in GLFW, but it solves some + // nasty problems. + // Caveat: Does not work under Win 9x/ME. + if( _glfwLibrary.Sys.WinVer >= _GLFW_WIN_NT4 ) + { + int lshift_down, rshift_down; + + // Get current state of left and right shift keys + lshift_down = (GetAsyncKeyState( VK_LSHIFT ) >> 15) & 1; + rshift_down = (GetAsyncKeyState( VK_RSHIFT ) >> 15) & 1; + + // See if this differs from our belief of what has happened + // (we only have to check for lost key up events) + if( !lshift_down && _glfwInput.Key[ GLFW_KEY_LSHIFT ] == 1 ) + { + _glfwInputKey( GLFW_KEY_LSHIFT, GLFW_RELEASE ); + } + if( !rshift_down && _glfwInput.Key[ GLFW_KEY_RSHIFT ] == 1 ) + { + _glfwInputKey( GLFW_KEY_RSHIFT, GLFW_RELEASE ); + } + } + + // Did we have mouse movement in locked cursor mode? + if( _glfwInput.MouseMoved && _glfwWin.MouseLock ) + { + _glfwPlatformSetMouseCursorPos( _glfwWin.Width / 2, + _glfwWin.Height / 2 ); + } + + // Was there a window close request? + if( winclosed && _glfwWin.WindowCloseCallback ) + { + // Check if the program wants us to close the window + winclosed = _glfwWin.WindowCloseCallback(); + } + if( winclosed ) + { + glfwCloseWindow(); + } +} + + +//======================================================================== +// _glfwPlatformWaitEvents() - Wait for new window and input events +//======================================================================== + +void _glfwPlatformWaitEvents( void ) +{ + // Wait for new events + WaitMessage(); + + // Poll new events + _glfwPlatformPollEvents(); +} + + +//======================================================================== +// Hide mouse cursor (lock it) +//======================================================================== + +void _glfwPlatformHideMouseCursor( void ) +{ + RECT ClipWindowRect; + + // Hide cursor + ShowCursor( FALSE ); + + // Clip cursor to the window + if( GetWindowRect( _glfwWin.Wnd, &ClipWindowRect ) ) + { + ClipCursor( &ClipWindowRect ); + } + + // Capture cursor to user window + SetCapture( _glfwWin.Wnd ); +} + + +//======================================================================== +// Show mouse cursor (unlock it) +//======================================================================== + +void _glfwPlatformShowMouseCursor( void ) +{ + // Un-capture cursor + ReleaseCapture(); + + // Disable cursor clipping + ClipCursor( NULL ); + + // Show cursor + ShowCursor( TRUE ); +} + + +//======================================================================== +// Set physical mouse cursor position +//======================================================================== + +void _glfwPlatformSetMouseCursorPos( int x, int y ) +{ + POINT pos; + + // Convert client coordinates to screen coordinates + pos.x = x; + pos.y = y; + ClientToScreen( _glfwWin.Wnd, &pos ); + + // Change cursor position + SetCursorPos( pos.x, pos.y ); +} + diff --git a/libs/glfw/lib/window.c b/libs/glfw/lib/window.c new file mode 100644 index 0000000..90b13cf --- /dev/null +++ b/libs/glfw/lib/window.c @@ -0,0 +1,727 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: window.c +// Platform: Any +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// Clear all open window hints +//======================================================================== + +void _glfwClearWindowHints( void ) +{ + _glfwWinHints.RefreshRate = 0; + _glfwWinHints.AccumRedBits = 0; + _glfwWinHints.AccumGreenBits = 0; + _glfwWinHints.AccumBlueBits = 0; + _glfwWinHints.AccumAlphaBits = 0; + _glfwWinHints.AuxBuffers = 0; + _glfwWinHints.Stereo = 0; + _glfwWinHints.WindowNoResize = 0; + _glfwWinHints.Samples = 0; +} + + +//======================================================================== +// Handle the input tracking part of window deactivation +//======================================================================== + +void _glfwInputDeactivation( void ) +{ + int i; + + // Release all keyboard keys + for( i = 0; i <= GLFW_KEY_LAST; i ++ ) + { + if( _glfwInput.Key[ i ] == GLFW_PRESS ) + { + _glfwInputKey( i, GLFW_RELEASE ); + } + } + + // Release all mouse buttons + for( i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i ++ ) + { + if( _glfwInput.MouseButton[ i ] == GLFW_PRESS ) + { + _glfwInputMouseClick( i, GLFW_RELEASE ); + } + } +} + + +//======================================================================== +// _glfwClearInput() - Clear all input state +//======================================================================== + +void _glfwClearInput( void ) +{ + int i; + + // Release all keyboard keys + for( i = 0; i <= GLFW_KEY_LAST; i ++ ) + { + _glfwInput.Key[ i ] = GLFW_RELEASE; + } + + // Clear last character + _glfwInput.LastChar = 0; + + // Release all mouse buttons + for( i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i ++ ) + { + _glfwInput.MouseButton[ i ] = GLFW_RELEASE; + } + + // Set mouse position to (0,0) + _glfwInput.MousePosX = 0; + _glfwInput.MousePosY = 0; + + // Set mouse wheel position to 0 + _glfwInput.WheelPos = 0; + + // The default is to use non sticky keys and mouse buttons + _glfwInput.StickyKeys = GL_FALSE; + _glfwInput.StickyMouseButtons = GL_FALSE; + + // The default is to disable key repeat + _glfwInput.KeyRepeat = GL_FALSE; +} + + +//======================================================================== +// _glfwInputKey() - Register keyboard activity +//======================================================================== + +void _glfwInputKey( int key, int action ) +{ + int keyrepeat = 0; + + if( key < 0 || key > GLFW_KEY_LAST ) + { + return; + } + + // Are we trying to release an already released key? + if( action == GLFW_RELEASE && _glfwInput.Key[ key ] != GLFW_PRESS ) + { + return; + } + + // Register key action + if( action == GLFW_RELEASE && _glfwInput.StickyKeys ) + { + _glfwInput.Key[ key ] = GLFW_STICK; + } + else + { + keyrepeat = (_glfwInput.Key[ key ] == GLFW_PRESS) && + (action == GLFW_PRESS); + _glfwInput.Key[ key ] = (char) action; + } + + // Call user callback function + if( _glfwWin.KeyCallback && (_glfwInput.KeyRepeat || !keyrepeat) ) + { + _glfwWin.KeyCallback( key, action ); + } +} + + +//======================================================================== +// _glfwInputChar() - Register (keyboard) character activity +//======================================================================== + +void _glfwInputChar( int character, int action ) +{ + int keyrepeat = 0; + + // Valid Unicode (ISO 10646) character? + if( !( (character >= 32 && character <= 126) || character >= 160 ) ) + { + return; + } + + // Is this a key repeat? + if( action == GLFW_PRESS && _glfwInput.LastChar == character ) + { + keyrepeat = 1; + } + + // Store this character as last character (or clear it, if released) + if( action == GLFW_PRESS ) + { + _glfwInput.LastChar = character; + } + else + { + _glfwInput.LastChar = 0; + } + + // Call user callback function + if( _glfwWin.CharCallback && (_glfwInput.KeyRepeat || !keyrepeat) ) + { + _glfwWin.CharCallback( character, action ); + } +} + + +//======================================================================== +// _glfwInputMouseClick() - Register mouse button clicks +//======================================================================== + +void _glfwInputMouseClick( int button, int action ) +{ + if( button >= 0 && button <= GLFW_MOUSE_BUTTON_LAST ) + { + // Register mouse button action + if( action == GLFW_RELEASE && _glfwInput.StickyMouseButtons ) + { + _glfwInput.MouseButton[ button ] = GLFW_STICK; + } + else + { + _glfwInput.MouseButton[ button ] = (char) action; + } + + // Call user callback function + if( _glfwWin.MouseButtonCallback ) + { + _glfwWin.MouseButtonCallback( button, action ); + } + } +} + + + +//************************************************************************ +//**** GLFW user functions **** +//************************************************************************ + +//======================================================================== +// glfwOpenWindow() - Here is where the window is created, and the OpenGL +// rendering context is created +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwOpenWindow( int width, int height, + int redbits, int greenbits, int bluebits, int alphabits, + int depthbits, int stencilbits, int mode ) +{ + int x; + _GLFWhints hints; + + // Is GLFW initialized? + if( !_glfwInitialized || _glfwWin.Opened ) + { + return GL_FALSE; + } + + // Copy and clear window hints + hints = _glfwWinHints; + _glfwClearWindowHints(); + + // Check input arguments + if( mode != GLFW_WINDOW && mode != GLFW_FULLSCREEN ) + { + return GL_FALSE; + } + + // Clear GLFW window state + _glfwWin.Active = GL_TRUE; + _glfwWin.Iconified = GL_FALSE; + _glfwWin.MouseLock = GL_FALSE; + _glfwWin.AutoPollEvents = GL_TRUE; + _glfwClearInput(); + + // Unregister all callback functions + _glfwWin.WindowSizeCallback = NULL; + _glfwWin.WindowCloseCallback = NULL; + _glfwWin.WindowRefreshCallback = NULL; + _glfwWin.KeyCallback = NULL; + _glfwWin.CharCallback = NULL; + _glfwWin.MousePosCallback = NULL; + _glfwWin.MouseButtonCallback = NULL; + _glfwWin.MouseWheelCallback = NULL; + + // Check width & height + if( width > 0 && height <= 0 ) + { + // Set the window aspect ratio to 4:3 + height = (width * 3) / 4; + } + else if( width <= 0 && height > 0 ) + { + // Set the window aspect ratio to 4:3 + width = (height * 4) / 3; + } + else if( width <= 0 && height <= 0 ) + { + // Default window size + width = 640; + height = 480; + } + + // Remember window settings + _glfwWin.Width = width; + _glfwWin.Height = height; + _glfwWin.Fullscreen = (mode == GLFW_FULLSCREEN ? 1 : 0); + + // Platform specific window opening routine + if( !_glfwPlatformOpenWindow( width, height, redbits, greenbits, + bluebits, alphabits, depthbits, stencilbits, mode, &hints ) ) + { + return GL_FALSE; + } + + // Flag that window is now opened + _glfwWin.Opened = GL_TRUE; + + // Get window parameters (such as color buffer bits etc) + _glfwPlatformRefreshWindowParams(); + + // Get OpenGL version + glfwGetGLVersion( &_glfwWin.GLVerMajor, &_glfwWin.GLVerMinor, &x ); + + // Do we have non-power-of-two textures? + _glfwWin.Has_GL_ARB_texture_non_power_of_two = + glfwExtensionSupported( "GL_ARB_texture_non_power_of_two" ); + + // Do we have automatic mipmap generation? + _glfwWin.Has_GL_SGIS_generate_mipmap = + (_glfwWin.GLVerMajor >= 2) || (_glfwWin.GLVerMinor >= 4) || + glfwExtensionSupported( "GL_SGIS_generate_mipmap" ); + + // If full-screen mode was requested, disable mouse cursor + if( mode == GLFW_FULLSCREEN ) + { + glfwDisable( GLFW_MOUSE_CURSOR ); + } + + return GL_TRUE; +} + + +//======================================================================== +// glfwOpenWindowHint() - Set hints for opening the window +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwOpenWindowHint( int target, int hint ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + switch( target ) + { + case GLFW_REFRESH_RATE: + _glfwWinHints.RefreshRate = hint; + break; + case GLFW_ACCUM_RED_BITS: + _glfwWinHints.AccumRedBits = hint; + break; + case GLFW_ACCUM_GREEN_BITS: + _glfwWinHints.AccumGreenBits = hint; + break; + case GLFW_ACCUM_BLUE_BITS: + _glfwWinHints.AccumBlueBits = hint; + break; + case GLFW_ACCUM_ALPHA_BITS: + _glfwWinHints.AccumAlphaBits = hint; + break; + case GLFW_AUX_BUFFERS: + _glfwWinHints.AuxBuffers = hint; + break; + case GLFW_STEREO: + _glfwWinHints.Stereo = hint; + break; + case GLFW_WINDOW_NO_RESIZE: + _glfwWinHints.WindowNoResize = hint; + break; + case GLFW_FSAA_SAMPLES: + _glfwWinHints.Samples = hint; + break; + default: + break; + } +} + + +//======================================================================== +// glfwCloseWindow() - Properly kill the window / video display +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwCloseWindow( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return; + } + + // Show mouse pointer again (if hidden) + glfwEnable( GLFW_MOUSE_CURSOR ); + + // Close window + _glfwPlatformCloseWindow(); + + // Window is no longer opened + _glfwWin.Opened = GL_FALSE; +} + + +//======================================================================== +// glfwSetWindowTitle() - Set the window title +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetWindowTitle( const char *title ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Set window title + _glfwPlatformSetWindowTitle( title ); +} + + +//======================================================================== +// glfwGetWindowSize() - Get the window size +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwGetWindowSize( int *width, int *height ) +{ + if( width != NULL ) + { + *width = _glfwWin.Width; + } + if( height != NULL ) + { + *height = _glfwWin.Height; + } +} + + +//======================================================================== +// glfwSetWindowSize() - Set the window size +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetWindowSize( int width, int height ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened || _glfwWin.Iconified ) + { + return; + } + + // Don't do anything if the window size did not change + if( width == _glfwWin.Width && height == _glfwWin.Height ) + { + return; + } + + // Change window size + _glfwPlatformSetWindowSize( width, height ); + + // Refresh window parameters (may have changed due to changed video + // modes) + _glfwPlatformRefreshWindowParams(); +} + + +//======================================================================== +// glfwSetWindowPos() - Set the window position +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetWindowPos( int x, int y ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened || _glfwWin.Fullscreen || + _glfwWin.Iconified ) + { + return; + } + + // Set window position + _glfwPlatformSetWindowPos( x, y ); +} + + +//======================================================================== +// glfwIconfyWindow() - Window iconification +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwIconifyWindow( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened || _glfwWin.Iconified ) + { + return; + } + + // Iconify window + _glfwPlatformIconifyWindow(); +} + + +//======================================================================== +// glfwRestoreWindow() - Window un-iconification +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwRestoreWindow( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened || !_glfwWin.Iconified ) + { + return; + } + + // Restore iconified window + _glfwPlatformRestoreWindow(); + + // Refresh window parameters + _glfwPlatformRefreshWindowParams(); +} + + +//======================================================================== +// glfwSwapBuffers() - Swap buffers (double-buffering) and poll any new +// events +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSwapBuffers( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Check for window messages + if( _glfwWin.AutoPollEvents ) + { + glfwPollEvents(); + } + + // Update display-buffer + if( _glfwWin.Opened ) + { + _glfwPlatformSwapBuffers(); + } +} + + +//======================================================================== +// glfwSwapInterval() - Set double buffering swap interval (0 = vsync off) +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSwapInterval( int interval ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Set double buffering swap interval + _glfwPlatformSwapInterval( interval ); +} + + +//======================================================================== +// glfwGetWindowParam() - Get window parameter +//======================================================================== + +GLFWAPI int GLFWAPIENTRY glfwGetWindowParam( int param ) +{ + // Is GLFW initialized? + if( !_glfwInitialized ) + { + return 0; + } + + // Is the window opened? + if( !_glfwWin.Opened ) + { + if( param == GLFW_OPENED ) + { + return GL_FALSE; + } + return 0; + } + + // Window parameters + switch( param ) + { + case GLFW_OPENED: + return GL_TRUE; + case GLFW_ACTIVE: + return _glfwWin.Active; + case GLFW_ICONIFIED: + return _glfwWin.Iconified; + case GLFW_ACCELERATED: + return _glfwWin.Accelerated; + case GLFW_RED_BITS: + return _glfwWin.RedBits; + case GLFW_GREEN_BITS: + return _glfwWin.GreenBits; + case GLFW_BLUE_BITS: + return _glfwWin.BlueBits; + case GLFW_ALPHA_BITS: + return _glfwWin.AlphaBits; + case GLFW_DEPTH_BITS: + return _glfwWin.DepthBits; + case GLFW_STENCIL_BITS: + return _glfwWin.StencilBits; + case GLFW_ACCUM_RED_BITS: + return _glfwWin.AccumRedBits; + case GLFW_ACCUM_GREEN_BITS: + return _glfwWin.AccumGreenBits; + case GLFW_ACCUM_BLUE_BITS: + return _glfwWin.AccumBlueBits; + case GLFW_ACCUM_ALPHA_BITS: + return _glfwWin.AccumAlphaBits; + case GLFW_AUX_BUFFERS: + return _glfwWin.AuxBuffers; + case GLFW_STEREO: + return _glfwWin.Stereo; + case GLFW_REFRESH_RATE: + return _glfwWin.RefreshRate; + case GLFW_WINDOW_NO_RESIZE: + return _glfwWin.WindowNoResize; + case GLFW_FSAA_SAMPLES: + return _glfwWin.Samples; + default: + return 0; + } +} + + +//======================================================================== +// glfwSetWindowSizeCallback() - Set callback function for window size +// changes +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetWindowSizeCallback( GLFWwindowsizefun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Set callback function + _glfwWin.WindowSizeCallback = cbfun; + + // Call the callback function to let the application know the current + // window size + if( cbfun ) + { + cbfun( _glfwWin.Width, _glfwWin.Height ); + } +} + +//======================================================================== +// glfwSetWindowCloseCallback() - Set callback function for window close +// events +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetWindowCloseCallback( GLFWwindowclosefun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Set callback function + _glfwWin.WindowCloseCallback = cbfun; +} + + +//======================================================================== +// glfwSetWindowRefreshCallback() - Set callback function for window +// refresh events +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwSetWindowRefreshCallback( GLFWwindowrefreshfun cbfun ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Set callback function + _glfwWin.WindowRefreshCallback = cbfun; +} + + +//======================================================================== +// glfwPollEvents() - Poll for new window and input events +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwPollEvents( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Poll for new events + _glfwPlatformPollEvents(); +} + + +//======================================================================== +// glfwWaitEvents() - Wait for new window and input events +//======================================================================== + +GLFWAPI void GLFWAPIENTRY glfwWaitEvents( void ) +{ + // Is GLFW initialized? + if( !_glfwInitialized || !_glfwWin.Opened ) + { + return; + } + + // Poll for new events + _glfwPlatformWaitEvents(); +} + diff --git a/libs/glfw/lib/x11/libglfw.pc.in b/libs/glfw/lib/x11/libglfw.pc.in new file mode 100644 index 0000000..a902ba7 --- /dev/null +++ b/libs/glfw/lib/x11/libglfw.pc.in @@ -0,0 +1,11 @@ +prefix=@PREFIX@ +exec_prefix=@PREFIX@ +libdir=@PREFIX@/lib +includedir=@PREFIX@/include + +Name: GLFW +Description: A portable framework for OpenGL development +Version: 2.6.0 +URL: http://glfw.sourceforge.net/ +Libs: -L${libdir} -lglfw -lGL -lX11 -lXrandr -pthread -lm +Cflags: -I${includedir} -pthread diff --git a/libs/glfw/lib/x11/platform.h b/libs/glfw/lib/x11/platform.h new file mode 100644 index 0000000..4ece822 --- /dev/null +++ b/libs/glfw/lib/x11/platform.h @@ -0,0 +1,415 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: platform.h +// Platform: X11 (Unix) +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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 _platform_h_ +#define _platform_h_ + + +// This is the X11 version of GLFW +#define _GLFW_X11 + + +// Include files +#include +#include +#include +#include +#include +#include +#include +#include "../../include/GL/glfw.h" + +// Do we have pthread support? +#ifdef _GLFW_HAS_PTHREAD + #include + #include +#endif + +// With XFree86, we can use the XF86VidMode extension +#if defined( _GLFW_HAS_XF86VIDMODE ) + #include +#endif + +#if defined( _GLFW_HAS_XRANDR ) + #include +#endif + +// Do we have support for dlopen/dlsym? +#if defined( _GLFW_HAS_DLOPEN ) + #include +#endif + +// We support two different ways for getting the number of processors in +// the system: sysconf (POSIX) and sysctl (BSD?) +#if defined( _GLFW_HAS_SYSCONF ) + + // Use a single constant for querying number of online processors using + // the sysconf function (e.g. SGI defines _SC_NPROC_ONLN instead of + // _SC_NPROCESSORS_ONLN) + #ifndef _SC_NPROCESSORS_ONLN + #ifdef _SC_NPROC_ONLN + #define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN + #else + #error POSIX constant _SC_NPROCESSORS_ONLN not defined! + #endif + #endif + + // Macro for querying the number of processors + #define _glfw_numprocessors(n) n=(int)sysconf(_SC_NPROCESSORS_ONLN) + +#elif defined( _GLFW_HAS_SYSCTL ) + + #include + #include + + // Macro for querying the number of processors + #define _glfw_numprocessors(n) { \ + int mib[2], ncpu; \ + size_t len = 1; \ + mib[0] = CTL_HW; \ + mib[1] = HW_NCPU; \ + n = 1; \ + if( sysctl( mib, 2, &ncpu, &len, NULL, 0 ) != -1 ) \ + { \ + if( len > 0 ) \ + { \ + n = ncpu; \ + } \ + } \ + } + +#else + + // If neither sysconf nor sysctl is supported, assume single processor + // system + #define _glfw_numprocessors(n) n=1 + +#endif + +void (*glXGetProcAddress(const GLubyte *procName))(); +void (*glXGetProcAddressARB(const GLubyte *procName))(); +void (*glXGetProcAddressEXT(const GLubyte *procName))(); + +// We support four different ways for getting addresses for GL/GLX +// extension functions: glXGetProcAddress, glXGetProcAddressARB, +// glXGetProcAddressEXT, and dlsym +#if defined( _GLFW_HAS_GLXGETPROCADDRESSARB ) + #define _glfw_glXGetProcAddress(x) glXGetProcAddressARB(x) +#elif defined( _GLFW_HAS_GLXGETPROCADDRESS ) + #define _glfw_glXGetProcAddress(x) glXGetProcAddress(x) +#elif defined( _GLFW_HAS_GLXGETPROCADDRESSEXT ) + #define _glfw_glXGetProcAddress(x) glXGetProcAddressEXT(x) +#elif defined( _GLFW_HAS_DLOPEN ) + #define _glfw_glXGetProcAddress(x) dlsym(_glfwLibs.libGL,x) + #define _GLFW_DLOPEN_LIBGL +#else +#define _glfw_glXGetProcAddress(x) NULL +#endif + +// glXSwapIntervalSGI typedef (X11 buffer-swap interval control) +typedef int ( * GLXSWAPINTERVALSGI_T) (int interval); + + +//======================================================================== +// Global variables (GLFW internals) +//======================================================================== + +//------------------------------------------------------------------------ +// Window structure +//------------------------------------------------------------------------ +typedef struct _GLFWwin_struct _GLFWwin; + +struct _GLFWwin_struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // User callback functions + GLFWwindowsizefun WindowSizeCallback; + GLFWwindowclosefun WindowCloseCallback; + GLFWwindowrefreshfun WindowRefreshCallback; + GLFWmousebuttonfun MouseButtonCallback; + GLFWmouseposfun MousePosCallback; + GLFWmousewheelfun MouseWheelCallback; + GLFWkeyfun KeyCallback; + GLFWcharfun CharCallback; + + // User selected window settings + int Fullscreen; // Fullscreen flag + int MouseLock; // Mouse-lock flag + int AutoPollEvents; // Auto polling flag + int SysKeysDisabled; // System keys disabled flag + int WindowNoResize; // Resize- and maximize gadgets disabled flag + + // Window status & parameters + int Opened; // Flag telling if window is opened or not + int Active; // Application active flag + int Iconified; // Window iconified flag + int Width, Height; // Window width and heigth + int Accelerated; // GL_TRUE if window is HW accelerated + int RedBits; + int GreenBits; + int BlueBits; + int AlphaBits; + int DepthBits; + int StencilBits; + int AccumRedBits; + int AccumGreenBits; + int AccumBlueBits; + int AccumAlphaBits; + int AuxBuffers; + int Stereo; + int RefreshRate; // Vertical monitor refresh rate + int Samples; + + // Extensions & OpenGL version + int Has_GL_SGIS_generate_mipmap; + int Has_GL_ARB_texture_non_power_of_two; + int GLVerMajor,GLVerMinor; + + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Platform specific window resources + Window Win; // Window + int Scrn; // Screen ID + XVisualInfo *VI; // Visual + GLXContext CX; // OpenGL rendering context + Atom WMDeleteWindow; // For WM close detection + Atom WMPing; // For WM ping response + XSizeHints *Hints; // WM size hints + + // Platform specific extensions + GLXSWAPINTERVALSGI_T SwapInterval; + + // Various platform specific internal variables + int OverrideRedirect; // True if window is OverrideRedirect + int KeyboardGrabbed; // True if keyboard is currently grabbed + int PointerGrabbed; // True if pointer is currently grabbed + int PointerHidden; // True if pointer is currently hidden + int MapNotifyCount; // Used for during processing + int FocusInCount; // Used for during processing + + // Screensaver data + struct { + int Changed; + int Timeout; + int Interval; + int Blanking; + int Exposure; + } Saver; + + // Fullscreen data + struct { + int ModeChanged; +#if defined( _GLFW_HAS_XF86VIDMODE ) + XF86VidModeModeInfo OldMode; +#endif +#if defined( _GLFW_HAS_XRANDR ) + SizeID OldSizeID; + int OldWidth; + int OldHeight; + Rotation OldRotation; +#endif + } FS; +}; + +GLFWGLOBAL _GLFWwin _glfwWin; + + +//------------------------------------------------------------------------ +// User input status (most of this should go in _GLFWwin) +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Mouse status + int MousePosX, MousePosY; + int WheelPos; + char MouseButton[ GLFW_MOUSE_BUTTON_LAST+1 ]; + + // Keyboard status + char Key[ GLFW_KEY_LAST+1 ]; + int LastChar; + + // User selected settings + int StickyKeys; + int StickyMouseButtons; + int KeyRepeat; + + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Platform specific internal variables + int MouseMoved, CursorPosX, CursorPosY; + +} _glfwInput; + + +//------------------------------------------------------------------------ +// Library global data +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM SPECIFIC PART ====================================== + + Display *Dpy; + int NumScreens; + int DefaultScreen; + + struct { + int Available; + int EventBase; + int ErrorBase; + } XF86VidMode; + + struct { + int Available; + int EventBase; + int ErrorBase; + } XRandR; + + // Timer data + struct { + double Resolution; + long long t0; + } Timer; + +#if defined(_GLFW_DLOPEN_LIBGL) + struct { + void *libGL; // dlopen handle for libGL.so + } Libs; +#endif +} _glfwLibrary; + + +//------------------------------------------------------------------------ +// Thread record (one for each thread) +//------------------------------------------------------------------------ +typedef struct _GLFWthread_struct _GLFWthread; + +struct _GLFWthread_struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Pointer to previous and next threads in linked list + _GLFWthread *Previous, *Next; + + // GLFW user side thread information + GLFWthread ID; + GLFWthreadfun Function; + +// ========= PLATFORM SPECIFIC PART ====================================== + + // System side thread information +#ifdef _GLFW_HAS_PTHREAD + pthread_t PosixID; +#endif + +}; + + +//------------------------------------------------------------------------ +// General thread information +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + +// ========= PLATFORM INDEPENDENT MANDATORY PART ========================= + + // Next thread ID to use (increments for every created thread) + GLFWthread NextID; + + // First thread in linked list (always the main thread) + _GLFWthread First; + +// ========= PLATFORM SPECIFIC PART ====================================== + + // Critical section lock +#ifdef _GLFW_HAS_PTHREAD + pthread_mutex_t CriticalSection; +#endif + +} _glfwThrd; + + +//------------------------------------------------------------------------ +// Joystick information & state +//------------------------------------------------------------------------ +GLFWGLOBAL struct { + int Present; + int fd; + int NumAxes; + int NumButtons; + float *Axis; + unsigned char *Button; +} _glfwJoy[ GLFW_JOYSTICK_LAST + 1 ]; + + +//======================================================================== +// Macros for encapsulating critical code sections (i.e. making parts +// of GLFW thread safe) +//======================================================================== + +// Thread list management +#ifdef _GLFW_HAS_PTHREAD + #define ENTER_THREAD_CRITICAL_SECTION \ + pthread_mutex_lock( &_glfwThrd.CriticalSection ); + #define LEAVE_THREAD_CRITICAL_SECTION \ + pthread_mutex_unlock( &_glfwThrd.CriticalSection ); +#else + #define ENTER_THREAD_CRITICAL_SECTION + #define LEAVE_THREAD_CRITICAL_SECTION +#endif + + +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +// Time +void _glfwInitTimer( void ); + +// Fullscreen support +int _glfwGetClosestVideoMode( int screen, int *width, int *height, int *rate ); +void _glfwSetVideoModeMODE( int screen, int mode, int rate ); +void _glfwSetVideoMode( int screen, int *width, int *height, int *rate ); + +// Cursor handling +Cursor _glfwCreateNULLCursor( Display *display, Window root ); + +// Joystick input +void _glfwInitJoysticks( void ); +void _glfwTerminateJoysticks( void ); + +// Unicode support +long _glfwKeySym2Unicode( KeySym keysym ); + + +#endif // _platform_h_ diff --git a/libs/glfw/lib/x11/x11_enable.c b/libs/glfw/lib/x11/x11_enable.c new file mode 100644 index 0000000..35bd7c1 --- /dev/null +++ b/libs/glfw/lib/x11/x11_enable.c @@ -0,0 +1,51 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: x11_enable.c +// Platform: X11 (Unix) +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformEnableSystemKeys() - Enable system keys +// _glfwPlatformDisableSystemKeys() - Disable system keys +//======================================================================== + +void _glfwPlatformEnableSystemKeys( void ) +{ + // Not supported under X11 (yet) +} + +void _glfwPlatformDisableSystemKeys( void ) +{ + // Not supported under X11 (yet) +} diff --git a/libs/glfw/lib/x11/x11_fullscreen.c b/libs/glfw/lib/x11/x11_fullscreen.c new file mode 100644 index 0000000..fb72c13 --- /dev/null +++ b/libs/glfw/lib/x11/x11_fullscreen.c @@ -0,0 +1,524 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: x11_fullscreen.c +// Platform: X11 (Unix) +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwBPP2RGB() - Convert BPP to RGB bits (based on "best guess") +//======================================================================== + +static void _glfwBPP2RGB( int bpp, int *r, int *g, int *b ) +{ + int delta; + + // Special case: BPP = 32 (I don't think this is necessary for X11??) + if( bpp == 32 ) + bpp = 24; + + // Convert "bits per pixel" to red, green & blue sizes + *r = *g = *b = bpp / 3; + delta = bpp - (*r * 3); + if( delta >= 1 ) + { + *g = *g + 1; + } + if( delta == 2 ) + { + *r = *r + 1; + } +} + + +//======================================================================== +// Finds the video mode closest in size to the specified desired size +//======================================================================== + +int _glfwGetClosestVideoMode( int screen, int *width, int *height, int *rate ) +{ +#if defined( _GLFW_HAS_XRANDR ) + int i, match, bestmatch; + int sizecount, bestsize; + int ratecount, bestrate; + short *ratelist; + XRRScreenConfiguration *sc; + XRRScreenSize *sizelist; + + if( _glfwLibrary.XRandR.Available ) + { + sc = XRRGetScreenInfo( _glfwLibrary.Dpy, + RootWindow( _glfwLibrary.Dpy, screen ) ); + + sizelist = XRRConfigSizes( sc, &sizecount ); + + // Find the best matching mode + bestsize = -1; + bestmatch = 999999; + for( i = 0; i < sizecount; i++ ) + { + match = (*width - sizelist[i].width) * + (*width - sizelist[i].width) + + (*height - sizelist[i].height) * + (*height - sizelist[i].height); + if( match < bestmatch ) + { + bestmatch = match; + bestsize = i; + } + } + + if( bestsize != -1 ) + { + // Report width & height of best matching mode + *width = sizelist[bestsize].width; + *height = sizelist[bestsize].height; + + if( *rate > 0 ) + { + ratelist = XRRConfigRates( sc, bestsize, &ratecount ); + + bestrate = -1; + bestmatch = 999999; + for( i = 0; i < ratecount; i++ ) + { + match = abs( ratelist[i] - *rate ); + if( match < bestmatch ) + { + bestmatch = match; + bestrate = ratelist[i]; + } + } + + if( bestrate != -1 ) + { + *rate = bestrate; + } + } + } + + // Free modelist + XRRFreeScreenConfigInfo( sc ); + + if( bestsize != -1 ) + { + return bestsize; + } + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + XF86VidModeModeInfo **modelist; + int modecount, i, bestmode, bestmatch, match; + + // Use the XF86VidMode extension to control video resolution + if( _glfwLibrary.XF86VidMode.Available ) + { + // Get a list of all available display modes + XF86VidModeGetAllModeLines( _glfwLibrary.Dpy, screen, + &modecount, &modelist ); + + // Find the best matching mode + bestmode = -1; + bestmatch = 999999; + for( i = 0; i < modecount; i++ ) + { + match = (*width - modelist[i]->hdisplay) * + (*width - modelist[i]->hdisplay) + + (*height - modelist[i]->vdisplay) * + (*height - modelist[i]->vdisplay); + if( match < bestmatch ) + { + bestmatch = match; + bestmode = i; + } + } + + if( bestmode != -1 ) + { + // Report width & height of best matching mode + *width = modelist[ bestmode ]->hdisplay; + *h = modelist[ bestmode ]->vdisplay; + } + + // Free modelist + XFree( modelist ); + + if( bestmode != -1 ) + { + return bestmode; + } + } +#endif + + // Default: Simply use the screen resolution + *width = DisplayWidth( _glfwLibrary.Dpy, screen ); + *height = DisplayHeight( _glfwLibrary.Dpy, screen ); + + return 0; +} + + +//======================================================================== +// Change the current video mode +//======================================================================== + +void _glfwSetVideoModeMODE( int screen, int mode, int rate ) +{ +#if defined( _GLFW_HAS_XRANDR ) + XRRScreenConfiguration *sc; + Window root; + + if( _glfwLibrary.XRandR.Available ) + { + root = RootWindow( _glfwLibrary.Dpy, screen ); + sc = XRRGetScreenInfo( _glfwLibrary.Dpy, root ); + + // Remember old size and flag that we have changed the mode + if( !_glfwWin.FS.ModeChanged ) + { + _glfwWin.FS.OldSizeID = XRRConfigCurrentConfiguration( sc, &_glfwWin.FS.OldRotation ); + _glfwWin.FS.OldWidth = DisplayWidth( _glfwLibrary.Dpy, screen ); + _glfwWin.FS.OldHeight = DisplayHeight( _glfwLibrary.Dpy, screen ); + + _glfwWin.FS.ModeChanged = GL_TRUE; + } + + if( rate > 0 ) + { + // Set desired configuration + XRRSetScreenConfigAndRate( _glfwLibrary.Dpy, + sc, + root, + mode, + RR_Rotate_0, + (short) rate, + CurrentTime ); + } + else + { + // Set desired configuration + XRRSetScreenConfig( _glfwLibrary.Dpy, + sc, + root, + mode, + RR_Rotate_0, + CurrentTime ); + } + + XRRFreeScreenConfigInfo( sc ); + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + XF86VidModeModeInfo **modelist; + int modecount; + + // Use the XF86VidMode extension to control video resolution + if( _glfwLibrary.XF86VidMode.Available ) + { + // Get a list of all available display modes + XF86VidModeGetAllModeLines( _glfwLibrary.Dpy, screen, + &modecount, &modelist ); + + // Unlock mode switch if necessary + if( _glfwWin.FS.ModeChanged ) + { + XF86VidModeLockModeSwitch( _glfwLibrary.Dpy, screen, 0 ); + } + + // Change the video mode to the desired mode + XF86VidModeSwitchToMode( _glfwLibrary.Dpy, screen, + modelist[ mode ] ); + + // Set viewport to upper left corner (where our window will be) + XF86VidModeSetViewPort( _glfwLibrary.Dpy, screen, 0, 0 ); + + // Lock mode switch + XF86VidModeLockModeSwitch( _glfwLibrary.Dpy, screen, 1 ); + + // Remember old mode and flag that we have changed the mode + if( !_glfwWin.FS.ModeChanged ) + { + _glfwWin.FS.OldMode = *modelist[ 0 ]; + _glfwWin.FS.ModeChanged = GL_TRUE; + } + + // Free mode list + XFree( modelist ); + } +#endif +} + + +//======================================================================== +// Change the current video mode +//======================================================================== + +void _glfwSetVideoMode( int screen, int *width, int *height, int *rate ) +{ + int bestmode; + + // Find a best match mode + bestmode = _glfwGetClosestVideoMode( screen, width, height, rate ); + + // Change mode + _glfwSetVideoModeMODE( screen, bestmode, *rate ); +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +struct _glfwResolution { + int width; + int height; +}; + +//======================================================================== +// List available video modes +//======================================================================== + +int _glfwPlatformGetVideoModes( GLFWvidmode *list, int maxcount ) +{ + int count, k, l, r, g, b, rgba, gl; + int depth, screen; + Display *dpy; + XVisualInfo *vislist, dummy; + int viscount, rgbcount, rescount; + int *rgbarray; + struct _glfwResolution *resarray; +#if defined( _GLFW_HAS_XRANDR ) + XRRScreenConfiguration *sc; + XRRScreenSize *sizelist; + int sizecount; +#elif defined( _GLFW_HAS_XF86VIDMODE ) + XF86VidModeModeInfo **modelist; + int modecount, width, height; +#endif + + // Get display and screen + dpy = _glfwLibrary.Dpy; + screen = DefaultScreen( dpy ); + + // Get list of visuals + vislist = XGetVisualInfo( dpy, 0, &dummy, &viscount ); + if( vislist == NULL ) + { + return 0; + } + + rgbarray = (int*) malloc( sizeof(int) * viscount ); + rgbcount = 0; + + // Build RGB array + for( k = 0; k < viscount; k++ ) + { + // Does the visual support OpenGL & true color? + glXGetConfig( dpy, &vislist[k], GLX_USE_GL, &gl ); + glXGetConfig( dpy, &vislist[k], GLX_RGBA, &rgba ); + if( gl && rgba ) + { + // Get color depth for this visual + depth = vislist[k].depth; + + // Convert to RGB + _glfwBPP2RGB( depth, &r, &g, &b ); + depth = (r<<16) | (g<<8) | b; + + // Is this mode unique? + for( l = 0; l < rgbcount; l++ ) + { + if( depth == rgbarray[ l ] ) + { + break; + } + } + if( l >= rgbcount ) + { + rgbarray[ rgbcount ] = depth; + rgbcount++; + } + } + } + + rescount = 0; + resarray = NULL; + + // Build resolution array +#if defined( _GLFW_HAS_XRANDR ) + if( _glfwLibrary.XRandR.Available ) + { + sc = XRRGetScreenInfo( dpy, RootWindow( dpy, screen ) ); + sizelist = XRRConfigSizes( sc, &sizecount ); + + resarray = (struct _glfwResolution*) malloc( sizeof(struct _glfwResolution) * sizecount ); + + for( k = 0; k < sizecount; k++ ) + { + resarray[ rescount ].width = sizelist[ k ].width; + resarray[ rescount ].height = sizelist[ k ].height; + rescount++; + } + + XRRFreeScreenConfigInfo( sc ); + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + if( _glfwLibrary.XF86VidMode.Available ) + { + XF86VidModeGetAllModeLines( dpy, screen, &modecount, &modelist ); + + resarray = (struct _glfwResolution*) malloc( sizeof(struct _glfwResolution) * modecount ); + + for( k = 0; k < modecount; k++ ) + { + width = modelist[ k ]->hdisplay; + height = modelist[ k ]->vdisplay; + + // Is this mode unique? + for( l = 0; l < rescount; l++ ) + { + if( width == resarray[ l ].width && height == resarray[ l ].height ) + { + break; + } + } + if( l >= rescount ) + { + resarray[ rescount ].width = width; + resarray[ rescount ].height = height; + rescount++; + } + } + + XFree( modelist ); + } +#endif + + if( !resarray ) + { + rescount = 1; + resarray = (struct _glfwResolution*) malloc( sizeof(struct _glfwResolution) * rescount ); + + resarray[ 0 ].width = DisplayWidth( dpy, screen ); + resarray[ 0 ].height = DisplayHeight( dpy, screen ); + } + + // Build permutations of colors and resolutions + count = 0; + for( k = 0; k < rgbcount && count < maxcount; k++ ) + { + for( l = 0; l < rescount && count < maxcount; l++ ) + { + list[count].Width = resarray[ l ].width; + list[count].Height = resarray[ l ].height; + list[count].RedBits = (rgbarray[ k ] >> 16) & 255; + list[count].GreenBits = (rgbarray[ k ] >> 8) & 255; + list[count].BlueBits = rgbarray[ k ] & 255; + count++; + } + } + + // Free visuals list + XFree( vislist ); + + free( resarray ); + free( rgbarray ); + + return count; +} + + +//======================================================================== +// Get the desktop video mode +//======================================================================== + +void _glfwPlatformGetDesktopMode( GLFWvidmode *mode ) +{ + Display *dpy; + int bpp, screen; +#if defined( _GLFW_HAS_XF86VIDMODE ) + XF86VidModeModeInfo **modelist; + int modecount; +#endif + + // Get display and screen + dpy = _glfwLibrary.Dpy; + screen = DefaultScreen( dpy ); + + // Get display depth + bpp = DefaultDepth( dpy, screen ); + + // Convert BPP to RGB bits + _glfwBPP2RGB( bpp, &mode->RedBits, &mode->GreenBits, &mode->BlueBits ); + +#if defined( _GLFW_HAS_XRANDR ) + if( _glfwLibrary.XRandR.Available ) + { + if( _glfwWin.FS.ModeChanged ) + { + mode->Width = _glfwWin.FS.OldWidth; + mode->Height = _glfwWin.FS.OldHeight; + return; + } + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + if( _glfwLibrary.XF86VidMode.Available ) + { + if( _glfwWin.FS.ModeChanged ) + { + // The old (desktop) mode is stored in _glfwWin.FS.OldMode + mode->Width = _glfwWin.FS.OldMode.hdisplay; + mode->Height = _glfwWin.FS.OldMode.vdisplay; + } + else + { + // Use the XF86VidMode extension to get list of video modes + XF86VidModeGetAllModeLines( dpy, screen, &modecount, + &modelist ); + + // The first mode in the list is the current (desktio) mode + mode->Width = modelist[ 0 ]->hdisplay; + mode->Height = modelist[ 0 ]->vdisplay; + + // Free list + XFree( modelist ); + } + + return; + } +#endif + + // Get current display width and height + mode->Width = DisplayWidth( dpy, screen ); + mode->Height = DisplayHeight( dpy, screen ); +} + diff --git a/libs/glfw/lib/x11/x11_glext.c b/libs/glfw/lib/x11/x11_glext.c new file mode 100644 index 0000000..740c110 --- /dev/null +++ b/libs/glfw/lib/x11/x11_glext.c @@ -0,0 +1,69 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: x11_glext.c +// Platform: X11 (Unix) +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Check if an OpenGL extension is available at runtime +//======================================================================== + +int _glfwPlatformExtensionSupported( const char *extension ) +{ + const GLubyte *extensions; + + // Get list of GLX extensions + extensions = (const GLubyte*) glXQueryExtensionsString( _glfwLibrary.Dpy, + _glfwWin.Scrn ); + if( extensions != NULL ) + { + if( _glfwStringInExtensionString( extension, extensions ) ) + { + return GL_TRUE; + } + } + + return GL_FALSE; +} + + +//======================================================================== +// Get the function pointer to an OpenGL function +//======================================================================== + +void * _glfwPlatformGetProcAddress( const char *procname ) +{ + return (void *) _glfw_glXGetProcAddress( (const GLubyte *) procname ); +} + diff --git a/libs/glfw/lib/x11/x11_init.c b/libs/glfw/lib/x11/x11_init.c new file mode 100644 index 0000000..8da2112 --- /dev/null +++ b/libs/glfw/lib/x11/x11_init.c @@ -0,0 +1,275 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: x11_init.c +// Platform: X11 (Unix) +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// Initialize GLFW thread package +//======================================================================== + +static void _glfwInitThreads( void ) +{ + // Initialize critical section handle +#ifdef _GLFW_HAS_PTHREAD + (void) pthread_mutex_init( &_glfwThrd.CriticalSection, NULL ); +#endif + + // The first thread (the main thread) has ID 0 + _glfwThrd.NextID = 0; + + // Fill out information about the main thread (this thread) + _glfwThrd.First.ID = _glfwThrd.NextID++; + _glfwThrd.First.Function = NULL; + _glfwThrd.First.Previous = NULL; + _glfwThrd.First.Next = NULL; +#ifdef _GLFW_HAS_PTHREAD + _glfwThrd.First.PosixID = pthread_self(); +#endif +} + + +//======================================================================== +// Terminate GLFW thread package +//======================================================================== + +static void _glfwTerminateThreads( void ) +{ +#ifdef _GLFW_HAS_PTHREAD + + _GLFWthread *t, *t_next; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Kill all threads (NOTE: THE USER SHOULD WAIT FOR ALL THREADS TO + // DIE, _BEFORE_ CALLING glfwTerminate()!!!) + t = _glfwThrd.First.Next; + while( t != NULL ) + { + // Get pointer to next thread + t_next = t->Next; + + // Simply murder the process, no mercy! + pthread_kill( t->PosixID, SIGKILL ); + + // Free memory allocated for this thread + free( (void *) t ); + + // Select next thread in list + t = t_next; + } + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Delete critical section handle + pthread_mutex_destroy( &_glfwThrd.CriticalSection ); + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// Dynamically load libraries +//======================================================================== + +#ifdef _GLFW_DLOPEN_LIBGL +static char * _glfw_libGL_name[ ] = +{ + "libGL.so", + "libGL.so.1", + "/usr/lib/libGL.so", + "/usr/lib/libGL.so.1", + NULL +}; +#endif + +static void _glfwInitLibraries( void ) +{ +#ifdef _GLFW_DLOPEN_LIBGL + int i; + + _glfwLibrary.Libs.libGL = NULL; + for( i = 0; !_glfw_libGL_name[ i ] != NULL; i ++ ) + { + _glfwLibrary.Libs.libGL = dlopen( _glfw_libGL_name[ i ], + RTLD_LAZY | RTLD_GLOBAL ); + if( _glfwLibrary.Libs.libGL ) + break; + } +#endif +} + + +//======================================================================== +// Terminate GLFW when exiting application +//======================================================================== + +void _glfwTerminate_atexit( void ) +{ + glfwTerminate(); +} + + +//======================================================================== +// Initialize X11 display +//======================================================================== + +static int _glfwInitDisplay( void ) +{ + // Open display + _glfwLibrary.Dpy = XOpenDisplay( 0 ); + if( !_glfwLibrary.Dpy ) + { + return GL_FALSE; + } + + // Check screens + _glfwLibrary.NumScreens = ScreenCount( _glfwLibrary.Dpy ); + _glfwLibrary.DefaultScreen = DefaultScreen( _glfwLibrary.Dpy ); + + // Check for XF86VidMode extension +#ifdef _GLFW_HAS_XF86VIDMODE + _glfwLibrary.XF86VidMode.Available = + XF86VidModeQueryExtension( _glfwLibrary.Dpy, + &_glfwLibrary.XF86VidMode.EventBase, + &_glfwLibrary.XF86VidMode.ErrorBase); +#else + _glfwLibrary.XF86VidMode.Available = 0; +#endif + + // Check for XRandR extension +#ifdef _GLFW_HAS_XRANDR + _glfwLibrary.XRandR.Available = + XRRQueryExtension( _glfwLibrary.Dpy, + &_glfwLibrary.XRandR.EventBase, + &_glfwLibrary.XRandR.ErrorBase ); +#else + _glfwLibrary.XRandR.Available = 0; +#endif + + return GL_TRUE; +} + + +//======================================================================== +// Terminate X11 display +//======================================================================== + +static void _glfwTerminateDisplay( void ) +{ + // Open display + if( _glfwLibrary.Dpy ) + { + XCloseDisplay( _glfwLibrary.Dpy ); + _glfwLibrary.Dpy = NULL; + } +} + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Initialize various GLFW state +//======================================================================== + +int _glfwPlatformInit( void ) +{ + // Initialize display + if( !_glfwInitDisplay() ) + { + return GL_FALSE; + } + + // Initialize thread package + _glfwInitThreads(); + + // Try to load libGL.so if necessary + _glfwInitLibraries(); + + // Install atexit() routine + atexit( _glfwTerminate_atexit ); + + // Initialize joysticks + _glfwInitJoysticks(); + + // Start the timer + _glfwInitTimer(); + + return GL_TRUE; +} + + +//======================================================================== +// Close window and kill all threads +//======================================================================== + +int _glfwPlatformTerminate( void ) +{ +#ifdef _GLFW_HAS_PTHREAD + // Only the main thread is allowed to do this... + if( pthread_self() != _glfwThrd.First.PosixID ) + { + return GL_FALSE; + } +#endif // _GLFW_HAS_PTHREAD + + // Close OpenGL window + glfwCloseWindow(); + + // Kill thread package + _glfwTerminateThreads(); + + // Terminate display + _glfwTerminateDisplay(); + + // Terminate joysticks + _glfwTerminateJoysticks(); + + // Unload libGL.so if necessary +#ifdef _GLFW_DLOPEN_LIBGL + if( _glfwLibrary.Libs.libGL != NULL ) + { + dlclose( _glfwLibrary.Libs.libGL ); + _glfwLibrary.Libs.libGL = NULL; + } +#endif + + return GL_TRUE; +} + diff --git a/libs/glfw/lib/x11/x11_joystick.c b/libs/glfw/lib/x11/x11_joystick.c new file mode 100644 index 0000000..3fcb315 --- /dev/null +++ b/libs/glfw/lib/x11/x11_joystick.c @@ -0,0 +1,371 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: x11_joystick.c +// Platform: X11 (Unix) +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//======================================================================== +// Note: Only Linux joystick input is supported at the moment. Other +// systems will behave as if there are no joysticks connected. +//======================================================================== + +#ifdef linux +#define _GLFW_USE_LINUX_JOYSTICKS +#endif // linux + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +#ifdef _GLFW_USE_LINUX_JOYSTICKS + +//------------------------------------------------------------------------ +// Here are the Linux joystick driver v1.x interface definitions that we +// use (we do not want to rely on ): +//------------------------------------------------------------------------ + +#include +#include +#include + +// Joystick event types +#define JS_EVENT_BUTTON 0x01 /* button pressed/released */ +#define JS_EVENT_AXIS 0x02 /* joystick moved */ +#define JS_EVENT_INIT 0x80 /* initial state of device */ + +// Joystick event structure +struct js_event { + unsigned int time; /* (u32) event timestamp in milliseconds */ + signed short value; /* (s16) value */ + unsigned char type; /* (u8) event type */ + unsigned char number; /* (u8) axis/button number */ +}; + +// Joystick IOCTL commands +#define JSIOCGVERSION _IOR('j', 0x01, int) /* get driver version (u32) */ +#define JSIOCGAXES _IOR('j', 0x11, char) /* get number of axes (u8) */ +#define JSIOCGBUTTONS _IOR('j', 0x12, char) /* get number of buttons (u8) */ + +#endif // _GLFW_USE_LINUX_JOYSTICKS + + +//======================================================================== +// _glfwInitJoysticks() - Initialize joystick interface +//======================================================================== + +void _glfwInitJoysticks( void ) +{ +#ifdef _GLFW_USE_LINUX_JOYSTICKS + int k, n, fd, joy_count; + char *joy_base_name, joy_dev_name[ 20 ]; + int driver_version = 0x000800; + char ret_data; +#endif // _GLFW_USE_LINUX_JOYSTICKS + int i; + + // Start by saying that there are no sticks + for( i = 0; i <= GLFW_JOYSTICK_LAST; ++ i ) + { + _glfwJoy[ i ].Present = GL_FALSE; + } + +#ifdef _GLFW_USE_LINUX_JOYSTICKS + + // Try to open joysticks (nonblocking) + joy_count = 0; + for( k = 0; k <= 1 && joy_count <= GLFW_JOYSTICK_LAST; ++ k ) + { + // Pick joystick base name + switch( k ) + { + case 0: + joy_base_name = "/dev/input/js"; // USB sticks + break; + case 1: + joy_base_name = "/dev/js"; // "Legacy" sticks + break; + default: + continue; // (should never happen) + } + + // Try to open a few of these sticks + for( i = 0; i <= 50 && joy_count <= GLFW_JOYSTICK_LAST; ++ i ) + { + sprintf( joy_dev_name, "%s%d", joy_base_name, i ); + fd = open( joy_dev_name, O_NONBLOCK ); + if( fd != -1 ) + { + // Remember fd + _glfwJoy[ joy_count ].fd = fd; + + // Check that the joystick driver version is 1.0+ + ioctl( fd, JSIOCGVERSION, &driver_version ); + if( driver_version < 0x010000 ) + { + // It's an old 0.x interface (we don't support it) + close( fd ); + continue; + } + + // Get number of joystick axes + ioctl( fd, JSIOCGAXES, &ret_data ); + _glfwJoy[ joy_count ].NumAxes = (int) ret_data; + + // Get number of joystick buttons + ioctl( fd, JSIOCGBUTTONS, &ret_data ); + _glfwJoy[ joy_count ].NumButtons = (int) ret_data; + + // Allocate memory for joystick state + _glfwJoy[ joy_count ].Axis = + (float *) malloc( sizeof(float) * + _glfwJoy[ joy_count ].NumAxes ); + if( _glfwJoy[ joy_count ].Axis == NULL ) + { + close( fd ); + continue; + } + _glfwJoy[ joy_count ].Button = + (char *) malloc( sizeof(char) * + _glfwJoy[ joy_count ].NumButtons ); + if( _glfwJoy[ joy_count ].Button == NULL ) + { + free( _glfwJoy[ joy_count ].Axis ); + close( fd ); + continue; + } + + // Clear joystick state + for( n = 0; n < _glfwJoy[ joy_count ].NumAxes; ++ n ) + { + _glfwJoy[ joy_count ].Axis[ n ] = 0.0f; + } + for( n = 0; n < _glfwJoy[ joy_count ].NumButtons; ++ n ) + { + _glfwJoy[ joy_count ].Button[ n ] = GLFW_RELEASE; + } + + // The joystick is supported and connected + _glfwJoy[ joy_count ].Present = GL_TRUE; + joy_count ++; + } + } + } + +#endif // _GLFW_USE_LINUX_JOYSTICKS + +} + + +//======================================================================== +// _glfwTerminateJoysticks() - Close all opened joystick handles +//======================================================================== + +void _glfwTerminateJoysticks( void ) +{ + +#ifdef _GLFW_USE_LINUX_JOYSTICKS + + int i; + + // Close any opened joysticks + for( i = 0; i <= GLFW_JOYSTICK_LAST; ++ i ) + { + if( _glfwJoy[ i ].Present ) + { + close( _glfwJoy[ i ].fd ); + free( _glfwJoy[ i ].Axis ); + free( _glfwJoy[ i ].Button ); + _glfwJoy[ i ].Present = GL_FALSE; + } + } + +#endif // _GLFW_USE_LINUX_JOYSTICKS + +} + + +//======================================================================== +// _glfwPollJoystickEvents() - Empty joystick event queue +//======================================================================== + +static void _glfwPollJoystickEvents( void ) +{ + +#ifdef _GLFW_USE_LINUX_JOYSTICKS + + struct js_event e; + int i; + + // Get joystick events for all GLFW joysticks + for( i = 0; i <= GLFW_JOYSTICK_LAST; ++ i ) + { + // Is the stick present? + if( _glfwJoy[ i ].Present ) + { + // Read all queued events (non-blocking) + while( read(_glfwJoy[i].fd, &e, sizeof(struct js_event)) > 0 ) + { + // We don't care if it's an init event or not + e.type &= ~JS_EVENT_INIT; + + // Check event type + switch( e.type ) + { + case JS_EVENT_AXIS: + _glfwJoy[ i ].Axis[ e.number ] = (float) e.value / + 32767.0f; + // We need to change the sign for the Y axes, so that + // positive = up/forward, according to the GLFW spec. + if( e.number & 1 ) + { + _glfwJoy[ i ].Axis[ e.number ] = + -_glfwJoy[ i ].Axis[ e.number ]; + } + break; + + case JS_EVENT_BUTTON: + _glfwJoy[ i ].Button[ e.number ] = + e.value ? GLFW_PRESS : GLFW_RELEASE; + break; + + default: + break; + } + } + } + } + +#endif // _GLFW_USE_LINUX_JOYSTICKS + +} + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformGetJoystickParam() - Determine joystick capabilities +//======================================================================== + +int _glfwPlatformGetJoystickParam( int joy, int param ) +{ + // Is joystick present? + if( !_glfwJoy[ joy ].Present ) + { + return 0; + } + + switch( param ) + { + case GLFW_PRESENT: + return GL_TRUE; + + case GLFW_AXES: + return _glfwJoy[ joy ].NumAxes; + + case GLFW_BUTTONS: + return _glfwJoy[ joy ].NumButtons; + + default: + break; + } + + return 0; +} + + +//======================================================================== +// _glfwPlatformGetJoystickPos() - Get joystick axis positions +//======================================================================== + +int _glfwPlatformGetJoystickPos( int joy, float *pos, int numaxes ) +{ + int i; + + // Is joystick present? + if( !_glfwJoy[ joy ].Present ) + { + return 0; + } + + // Update joystick state + _glfwPollJoystickEvents(); + + // Does the joystick support less axes than requested? + if( _glfwJoy[ joy ].NumAxes < numaxes ) + { + numaxes = _glfwJoy[ joy ].NumAxes; + } + + // Copy axis positions from internal state + for( i = 0; i < numaxes; ++ i ) + { + pos[ i ] = _glfwJoy[ joy ].Axis[ i ]; + } + + return numaxes; +} + + +//======================================================================== +// _glfwPlatformGetJoystickButtons() - Get joystick button states +//======================================================================== + +int _glfwPlatformGetJoystickButtons( int joy, unsigned char *buttons, + int numbuttons ) +{ + int i; + + // Is joystick present? + if( !_glfwJoy[ joy ].Present ) + { + return 0; + } + + // Update joystick state + _glfwPollJoystickEvents(); + + // Does the joystick support less buttons than requested? + if( _glfwJoy[ joy ].NumButtons < numbuttons ) + { + numbuttons = _glfwJoy[ joy ].NumButtons; + } + + // Copy button states from internal state + for( i = 0; i < numbuttons; ++ i ) + { + buttons[ i ] = _glfwJoy[ joy ].Button[ i ]; + } + + return numbuttons; +} diff --git a/libs/glfw/lib/x11/x11_keysym2unicode.c b/libs/glfw/lib/x11/x11_keysym2unicode.c new file mode 100644 index 0000000..ebbc6d7 --- /dev/null +++ b/libs/glfw/lib/x11/x11_keysym2unicode.c @@ -0,0 +1,902 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: x11_keysym2unicode.c +// Platform: X11 (Unix) +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +/* + * Marcus: This code was originally written by Markus G. Kuhn. + * I have made some slight changes (trimmed it down a bit from >60 KB to + * 20 KB), but the functionality is the same. + */ + +/* + * This module converts keysym values into the corresponding ISO 10646 + * (UCS, Unicode) values. + * + * The array keysymtab[] contains pairs of X11 keysym values for graphical + * characters and the corresponding Unicode value. The function + * _glfwKeySym2Unicode() maps a keysym onto a Unicode value using a binary + * search, therefore keysymtab[] must remain SORTED by keysym value. + * + * We allow to represent any UCS character in the range U-00000000 to + * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. + * This admittedly does not cover the entire 31-bit space of UCS, but + * it does cover all of the characters up to U-10FFFF, which can be + * represented by UTF-16, and more, and it is very unlikely that higher + * UCS codes will ever be assigned by ISO. So to get Unicode character + * U+ABCD you can directly use keysym 0x0100abcd. + * + * Original author: Markus G. Kuhn , University of + * Cambridge, April 2001 + * + * Special thanks to Richard Verhoeven for preparing + * an initial draft of the mapping table. + * + */ + + +//************************************************************************ +//**** KeySym to Unicode mapping table **** +//************************************************************************ + +static struct codepair { + unsigned short keysym; + unsigned short ucs; +} keysymtab[] = { + { 0x01a1, 0x0104 }, + { 0x01a2, 0x02d8 }, + { 0x01a3, 0x0141 }, + { 0x01a5, 0x013d }, + { 0x01a6, 0x015a }, + { 0x01a9, 0x0160 }, + { 0x01aa, 0x015e }, + { 0x01ab, 0x0164 }, + { 0x01ac, 0x0179 }, + { 0x01ae, 0x017d }, + { 0x01af, 0x017b }, + { 0x01b1, 0x0105 }, + { 0x01b2, 0x02db }, + { 0x01b3, 0x0142 }, + { 0x01b5, 0x013e }, + { 0x01b6, 0x015b }, + { 0x01b7, 0x02c7 }, + { 0x01b9, 0x0161 }, + { 0x01ba, 0x015f }, + { 0x01bb, 0x0165 }, + { 0x01bc, 0x017a }, + { 0x01bd, 0x02dd }, + { 0x01be, 0x017e }, + { 0x01bf, 0x017c }, + { 0x01c0, 0x0154 }, + { 0x01c3, 0x0102 }, + { 0x01c5, 0x0139 }, + { 0x01c6, 0x0106 }, + { 0x01c8, 0x010c }, + { 0x01ca, 0x0118 }, + { 0x01cc, 0x011a }, + { 0x01cf, 0x010e }, + { 0x01d0, 0x0110 }, + { 0x01d1, 0x0143 }, + { 0x01d2, 0x0147 }, + { 0x01d5, 0x0150 }, + { 0x01d8, 0x0158 }, + { 0x01d9, 0x016e }, + { 0x01db, 0x0170 }, + { 0x01de, 0x0162 }, + { 0x01e0, 0x0155 }, + { 0x01e3, 0x0103 }, + { 0x01e5, 0x013a }, + { 0x01e6, 0x0107 }, + { 0x01e8, 0x010d }, + { 0x01ea, 0x0119 }, + { 0x01ec, 0x011b }, + { 0x01ef, 0x010f }, + { 0x01f0, 0x0111 }, + { 0x01f1, 0x0144 }, + { 0x01f2, 0x0148 }, + { 0x01f5, 0x0151 }, + { 0x01f8, 0x0159 }, + { 0x01f9, 0x016f }, + { 0x01fb, 0x0171 }, + { 0x01fe, 0x0163 }, + { 0x01ff, 0x02d9 }, + { 0x02a1, 0x0126 }, + { 0x02a6, 0x0124 }, + { 0x02a9, 0x0130 }, + { 0x02ab, 0x011e }, + { 0x02ac, 0x0134 }, + { 0x02b1, 0x0127 }, + { 0x02b6, 0x0125 }, + { 0x02b9, 0x0131 }, + { 0x02bb, 0x011f }, + { 0x02bc, 0x0135 }, + { 0x02c5, 0x010a }, + { 0x02c6, 0x0108 }, + { 0x02d5, 0x0120 }, + { 0x02d8, 0x011c }, + { 0x02dd, 0x016c }, + { 0x02de, 0x015c }, + { 0x02e5, 0x010b }, + { 0x02e6, 0x0109 }, + { 0x02f5, 0x0121 }, + { 0x02f8, 0x011d }, + { 0x02fd, 0x016d }, + { 0x02fe, 0x015d }, + { 0x03a2, 0x0138 }, + { 0x03a3, 0x0156 }, + { 0x03a5, 0x0128 }, + { 0x03a6, 0x013b }, + { 0x03aa, 0x0112 }, + { 0x03ab, 0x0122 }, + { 0x03ac, 0x0166 }, + { 0x03b3, 0x0157 }, + { 0x03b5, 0x0129 }, + { 0x03b6, 0x013c }, + { 0x03ba, 0x0113 }, + { 0x03bb, 0x0123 }, + { 0x03bc, 0x0167 }, + { 0x03bd, 0x014a }, + { 0x03bf, 0x014b }, + { 0x03c0, 0x0100 }, + { 0x03c7, 0x012e }, + { 0x03cc, 0x0116 }, + { 0x03cf, 0x012a }, + { 0x03d1, 0x0145 }, + { 0x03d2, 0x014c }, + { 0x03d3, 0x0136 }, + { 0x03d9, 0x0172 }, + { 0x03dd, 0x0168 }, + { 0x03de, 0x016a }, + { 0x03e0, 0x0101 }, + { 0x03e7, 0x012f }, + { 0x03ec, 0x0117 }, + { 0x03ef, 0x012b }, + { 0x03f1, 0x0146 }, + { 0x03f2, 0x014d }, + { 0x03f3, 0x0137 }, + { 0x03f9, 0x0173 }, + { 0x03fd, 0x0169 }, + { 0x03fe, 0x016b }, + { 0x047e, 0x203e }, + { 0x04a1, 0x3002 }, + { 0x04a2, 0x300c }, + { 0x04a3, 0x300d }, + { 0x04a4, 0x3001 }, + { 0x04a5, 0x30fb }, + { 0x04a6, 0x30f2 }, + { 0x04a7, 0x30a1 }, + { 0x04a8, 0x30a3 }, + { 0x04a9, 0x30a5 }, + { 0x04aa, 0x30a7 }, + { 0x04ab, 0x30a9 }, + { 0x04ac, 0x30e3 }, + { 0x04ad, 0x30e5 }, + { 0x04ae, 0x30e7 }, + { 0x04af, 0x30c3 }, + { 0x04b0, 0x30fc }, + { 0x04b1, 0x30a2 }, + { 0x04b2, 0x30a4 }, + { 0x04b3, 0x30a6 }, + { 0x04b4, 0x30a8 }, + { 0x04b5, 0x30aa }, + { 0x04b6, 0x30ab }, + { 0x04b7, 0x30ad }, + { 0x04b8, 0x30af }, + { 0x04b9, 0x30b1 }, + { 0x04ba, 0x30b3 }, + { 0x04bb, 0x30b5 }, + { 0x04bc, 0x30b7 }, + { 0x04bd, 0x30b9 }, + { 0x04be, 0x30bb }, + { 0x04bf, 0x30bd }, + { 0x04c0, 0x30bf }, + { 0x04c1, 0x30c1 }, + { 0x04c2, 0x30c4 }, + { 0x04c3, 0x30c6 }, + { 0x04c4, 0x30c8 }, + { 0x04c5, 0x30ca }, + { 0x04c6, 0x30cb }, + { 0x04c7, 0x30cc }, + { 0x04c8, 0x30cd }, + { 0x04c9, 0x30ce }, + { 0x04ca, 0x30cf }, + { 0x04cb, 0x30d2 }, + { 0x04cc, 0x30d5 }, + { 0x04cd, 0x30d8 }, + { 0x04ce, 0x30db }, + { 0x04cf, 0x30de }, + { 0x04d0, 0x30df }, + { 0x04d1, 0x30e0 }, + { 0x04d2, 0x30e1 }, + { 0x04d3, 0x30e2 }, + { 0x04d4, 0x30e4 }, + { 0x04d5, 0x30e6 }, + { 0x04d6, 0x30e8 }, + { 0x04d7, 0x30e9 }, + { 0x04d8, 0x30ea }, + { 0x04d9, 0x30eb }, + { 0x04da, 0x30ec }, + { 0x04db, 0x30ed }, + { 0x04dc, 0x30ef }, + { 0x04dd, 0x30f3 }, + { 0x04de, 0x309b }, + { 0x04df, 0x309c }, + { 0x05ac, 0x060c }, + { 0x05bb, 0x061b }, + { 0x05bf, 0x061f }, + { 0x05c1, 0x0621 }, + { 0x05c2, 0x0622 }, + { 0x05c3, 0x0623 }, + { 0x05c4, 0x0624 }, + { 0x05c5, 0x0625 }, + { 0x05c6, 0x0626 }, + { 0x05c7, 0x0627 }, + { 0x05c8, 0x0628 }, + { 0x05c9, 0x0629 }, + { 0x05ca, 0x062a }, + { 0x05cb, 0x062b }, + { 0x05cc, 0x062c }, + { 0x05cd, 0x062d }, + { 0x05ce, 0x062e }, + { 0x05cf, 0x062f }, + { 0x05d0, 0x0630 }, + { 0x05d1, 0x0631 }, + { 0x05d2, 0x0632 }, + { 0x05d3, 0x0633 }, + { 0x05d4, 0x0634 }, + { 0x05d5, 0x0635 }, + { 0x05d6, 0x0636 }, + { 0x05d7, 0x0637 }, + { 0x05d8, 0x0638 }, + { 0x05d9, 0x0639 }, + { 0x05da, 0x063a }, + { 0x05e0, 0x0640 }, + { 0x05e1, 0x0641 }, + { 0x05e2, 0x0642 }, + { 0x05e3, 0x0643 }, + { 0x05e4, 0x0644 }, + { 0x05e5, 0x0645 }, + { 0x05e6, 0x0646 }, + { 0x05e7, 0x0647 }, + { 0x05e8, 0x0648 }, + { 0x05e9, 0x0649 }, + { 0x05ea, 0x064a }, + { 0x05eb, 0x064b }, + { 0x05ec, 0x064c }, + { 0x05ed, 0x064d }, + { 0x05ee, 0x064e }, + { 0x05ef, 0x064f }, + { 0x05f0, 0x0650 }, + { 0x05f1, 0x0651 }, + { 0x05f2, 0x0652 }, + { 0x06a1, 0x0452 }, + { 0x06a2, 0x0453 }, + { 0x06a3, 0x0451 }, + { 0x06a4, 0x0454 }, + { 0x06a5, 0x0455 }, + { 0x06a6, 0x0456 }, + { 0x06a7, 0x0457 }, + { 0x06a8, 0x0458 }, + { 0x06a9, 0x0459 }, + { 0x06aa, 0x045a }, + { 0x06ab, 0x045b }, + { 0x06ac, 0x045c }, + { 0x06ae, 0x045e }, + { 0x06af, 0x045f }, + { 0x06b0, 0x2116 }, + { 0x06b1, 0x0402 }, + { 0x06b2, 0x0403 }, + { 0x06b3, 0x0401 }, + { 0x06b4, 0x0404 }, + { 0x06b5, 0x0405 }, + { 0x06b6, 0x0406 }, + { 0x06b7, 0x0407 }, + { 0x06b8, 0x0408 }, + { 0x06b9, 0x0409 }, + { 0x06ba, 0x040a }, + { 0x06bb, 0x040b }, + { 0x06bc, 0x040c }, + { 0x06be, 0x040e }, + { 0x06bf, 0x040f }, + { 0x06c0, 0x044e }, + { 0x06c1, 0x0430 }, + { 0x06c2, 0x0431 }, + { 0x06c3, 0x0446 }, + { 0x06c4, 0x0434 }, + { 0x06c5, 0x0435 }, + { 0x06c6, 0x0444 }, + { 0x06c7, 0x0433 }, + { 0x06c8, 0x0445 }, + { 0x06c9, 0x0438 }, + { 0x06ca, 0x0439 }, + { 0x06cb, 0x043a }, + { 0x06cc, 0x043b }, + { 0x06cd, 0x043c }, + { 0x06ce, 0x043d }, + { 0x06cf, 0x043e }, + { 0x06d0, 0x043f }, + { 0x06d1, 0x044f }, + { 0x06d2, 0x0440 }, + { 0x06d3, 0x0441 }, + { 0x06d4, 0x0442 }, + { 0x06d5, 0x0443 }, + { 0x06d6, 0x0436 }, + { 0x06d7, 0x0432 }, + { 0x06d8, 0x044c }, + { 0x06d9, 0x044b }, + { 0x06da, 0x0437 }, + { 0x06db, 0x0448 }, + { 0x06dc, 0x044d }, + { 0x06dd, 0x0449 }, + { 0x06de, 0x0447 }, + { 0x06df, 0x044a }, + { 0x06e0, 0x042e }, + { 0x06e1, 0x0410 }, + { 0x06e2, 0x0411 }, + { 0x06e3, 0x0426 }, + { 0x06e4, 0x0414 }, + { 0x06e5, 0x0415 }, + { 0x06e6, 0x0424 }, + { 0x06e7, 0x0413 }, + { 0x06e8, 0x0425 }, + { 0x06e9, 0x0418 }, + { 0x06ea, 0x0419 }, + { 0x06eb, 0x041a }, + { 0x06ec, 0x041b }, + { 0x06ed, 0x041c }, + { 0x06ee, 0x041d }, + { 0x06ef, 0x041e }, + { 0x06f0, 0x041f }, + { 0x06f1, 0x042f }, + { 0x06f2, 0x0420 }, + { 0x06f3, 0x0421 }, + { 0x06f4, 0x0422 }, + { 0x06f5, 0x0423 }, + { 0x06f6, 0x0416 }, + { 0x06f7, 0x0412 }, + { 0x06f8, 0x042c }, + { 0x06f9, 0x042b }, + { 0x06fa, 0x0417 }, + { 0x06fb, 0x0428 }, + { 0x06fc, 0x042d }, + { 0x06fd, 0x0429 }, + { 0x06fe, 0x0427 }, + { 0x06ff, 0x042a }, + { 0x07a1, 0x0386 }, + { 0x07a2, 0x0388 }, + { 0x07a3, 0x0389 }, + { 0x07a4, 0x038a }, + { 0x07a5, 0x03aa }, + { 0x07a7, 0x038c }, + { 0x07a8, 0x038e }, + { 0x07a9, 0x03ab }, + { 0x07ab, 0x038f }, + { 0x07ae, 0x0385 }, + { 0x07af, 0x2015 }, + { 0x07b1, 0x03ac }, + { 0x07b2, 0x03ad }, + { 0x07b3, 0x03ae }, + { 0x07b4, 0x03af }, + { 0x07b5, 0x03ca }, + { 0x07b6, 0x0390 }, + { 0x07b7, 0x03cc }, + { 0x07b8, 0x03cd }, + { 0x07b9, 0x03cb }, + { 0x07ba, 0x03b0 }, + { 0x07bb, 0x03ce }, + { 0x07c1, 0x0391 }, + { 0x07c2, 0x0392 }, + { 0x07c3, 0x0393 }, + { 0x07c4, 0x0394 }, + { 0x07c5, 0x0395 }, + { 0x07c6, 0x0396 }, + { 0x07c7, 0x0397 }, + { 0x07c8, 0x0398 }, + { 0x07c9, 0x0399 }, + { 0x07ca, 0x039a }, + { 0x07cb, 0x039b }, + { 0x07cc, 0x039c }, + { 0x07cd, 0x039d }, + { 0x07ce, 0x039e }, + { 0x07cf, 0x039f }, + { 0x07d0, 0x03a0 }, + { 0x07d1, 0x03a1 }, + { 0x07d2, 0x03a3 }, + { 0x07d4, 0x03a4 }, + { 0x07d5, 0x03a5 }, + { 0x07d6, 0x03a6 }, + { 0x07d7, 0x03a7 }, + { 0x07d8, 0x03a8 }, + { 0x07d9, 0x03a9 }, + { 0x07e1, 0x03b1 }, + { 0x07e2, 0x03b2 }, + { 0x07e3, 0x03b3 }, + { 0x07e4, 0x03b4 }, + { 0x07e5, 0x03b5 }, + { 0x07e6, 0x03b6 }, + { 0x07e7, 0x03b7 }, + { 0x07e8, 0x03b8 }, + { 0x07e9, 0x03b9 }, + { 0x07ea, 0x03ba }, + { 0x07eb, 0x03bb }, + { 0x07ec, 0x03bc }, + { 0x07ed, 0x03bd }, + { 0x07ee, 0x03be }, + { 0x07ef, 0x03bf }, + { 0x07f0, 0x03c0 }, + { 0x07f1, 0x03c1 }, + { 0x07f2, 0x03c3 }, + { 0x07f3, 0x03c2 }, + { 0x07f4, 0x03c4 }, + { 0x07f5, 0x03c5 }, + { 0x07f6, 0x03c6 }, + { 0x07f7, 0x03c7 }, + { 0x07f8, 0x03c8 }, + { 0x07f9, 0x03c9 }, + { 0x08a1, 0x23b7 }, + { 0x08a2, 0x250c }, + { 0x08a3, 0x2500 }, + { 0x08a4, 0x2320 }, + { 0x08a5, 0x2321 }, + { 0x08a6, 0x2502 }, + { 0x08a7, 0x23a1 }, + { 0x08a8, 0x23a3 }, + { 0x08a9, 0x23a4 }, + { 0x08aa, 0x23a6 }, + { 0x08ab, 0x239b }, + { 0x08ac, 0x239d }, + { 0x08ad, 0x239e }, + { 0x08ae, 0x23a0 }, + { 0x08af, 0x23a8 }, + { 0x08b0, 0x23ac }, + { 0x08bc, 0x2264 }, + { 0x08bd, 0x2260 }, + { 0x08be, 0x2265 }, + { 0x08bf, 0x222b }, + { 0x08c0, 0x2234 }, + { 0x08c1, 0x221d }, + { 0x08c2, 0x221e }, + { 0x08c5, 0x2207 }, + { 0x08c8, 0x223c }, + { 0x08c9, 0x2243 }, + { 0x08cd, 0x21d4 }, + { 0x08ce, 0x21d2 }, + { 0x08cf, 0x2261 }, + { 0x08d6, 0x221a }, + { 0x08da, 0x2282 }, + { 0x08db, 0x2283 }, + { 0x08dc, 0x2229 }, + { 0x08dd, 0x222a }, + { 0x08de, 0x2227 }, + { 0x08df, 0x2228 }, + { 0x08ef, 0x2202 }, + { 0x08f6, 0x0192 }, + { 0x08fb, 0x2190 }, + { 0x08fc, 0x2191 }, + { 0x08fd, 0x2192 }, + { 0x08fe, 0x2193 }, + { 0x09e0, 0x25c6 }, + { 0x09e1, 0x2592 }, + { 0x09e2, 0x2409 }, + { 0x09e3, 0x240c }, + { 0x09e4, 0x240d }, + { 0x09e5, 0x240a }, + { 0x09e8, 0x2424 }, + { 0x09e9, 0x240b }, + { 0x09ea, 0x2518 }, + { 0x09eb, 0x2510 }, + { 0x09ec, 0x250c }, + { 0x09ed, 0x2514 }, + { 0x09ee, 0x253c }, + { 0x09ef, 0x23ba }, + { 0x09f0, 0x23bb }, + { 0x09f1, 0x2500 }, + { 0x09f2, 0x23bc }, + { 0x09f3, 0x23bd }, + { 0x09f4, 0x251c }, + { 0x09f5, 0x2524 }, + { 0x09f6, 0x2534 }, + { 0x09f7, 0x252c }, + { 0x09f8, 0x2502 }, + { 0x0aa1, 0x2003 }, + { 0x0aa2, 0x2002 }, + { 0x0aa3, 0x2004 }, + { 0x0aa4, 0x2005 }, + { 0x0aa5, 0x2007 }, + { 0x0aa6, 0x2008 }, + { 0x0aa7, 0x2009 }, + { 0x0aa8, 0x200a }, + { 0x0aa9, 0x2014 }, + { 0x0aaa, 0x2013 }, + { 0x0aae, 0x2026 }, + { 0x0aaf, 0x2025 }, + { 0x0ab0, 0x2153 }, + { 0x0ab1, 0x2154 }, + { 0x0ab2, 0x2155 }, + { 0x0ab3, 0x2156 }, + { 0x0ab4, 0x2157 }, + { 0x0ab5, 0x2158 }, + { 0x0ab6, 0x2159 }, + { 0x0ab7, 0x215a }, + { 0x0ab8, 0x2105 }, + { 0x0abb, 0x2012 }, + { 0x0abc, 0x2329 }, + { 0x0abe, 0x232a }, + { 0x0ac3, 0x215b }, + { 0x0ac4, 0x215c }, + { 0x0ac5, 0x215d }, + { 0x0ac6, 0x215e }, + { 0x0ac9, 0x2122 }, + { 0x0aca, 0x2613 }, + { 0x0acc, 0x25c1 }, + { 0x0acd, 0x25b7 }, + { 0x0ace, 0x25cb }, + { 0x0acf, 0x25af }, + { 0x0ad0, 0x2018 }, + { 0x0ad1, 0x2019 }, + { 0x0ad2, 0x201c }, + { 0x0ad3, 0x201d }, + { 0x0ad4, 0x211e }, + { 0x0ad6, 0x2032 }, + { 0x0ad7, 0x2033 }, + { 0x0ad9, 0x271d }, + { 0x0adb, 0x25ac }, + { 0x0adc, 0x25c0 }, + { 0x0add, 0x25b6 }, + { 0x0ade, 0x25cf }, + { 0x0adf, 0x25ae }, + { 0x0ae0, 0x25e6 }, + { 0x0ae1, 0x25ab }, + { 0x0ae2, 0x25ad }, + { 0x0ae3, 0x25b3 }, + { 0x0ae4, 0x25bd }, + { 0x0ae5, 0x2606 }, + { 0x0ae6, 0x2022 }, + { 0x0ae7, 0x25aa }, + { 0x0ae8, 0x25b2 }, + { 0x0ae9, 0x25bc }, + { 0x0aea, 0x261c }, + { 0x0aeb, 0x261e }, + { 0x0aec, 0x2663 }, + { 0x0aed, 0x2666 }, + { 0x0aee, 0x2665 }, + { 0x0af0, 0x2720 }, + { 0x0af1, 0x2020 }, + { 0x0af2, 0x2021 }, + { 0x0af3, 0x2713 }, + { 0x0af4, 0x2717 }, + { 0x0af5, 0x266f }, + { 0x0af6, 0x266d }, + { 0x0af7, 0x2642 }, + { 0x0af8, 0x2640 }, + { 0x0af9, 0x260e }, + { 0x0afa, 0x2315 }, + { 0x0afb, 0x2117 }, + { 0x0afc, 0x2038 }, + { 0x0afd, 0x201a }, + { 0x0afe, 0x201e }, + { 0x0ba3, 0x003c }, + { 0x0ba6, 0x003e }, + { 0x0ba8, 0x2228 }, + { 0x0ba9, 0x2227 }, + { 0x0bc0, 0x00af }, + { 0x0bc2, 0x22a5 }, + { 0x0bc3, 0x2229 }, + { 0x0bc4, 0x230a }, + { 0x0bc6, 0x005f }, + { 0x0bca, 0x2218 }, + { 0x0bcc, 0x2395 }, + { 0x0bce, 0x22a4 }, + { 0x0bcf, 0x25cb }, + { 0x0bd3, 0x2308 }, + { 0x0bd6, 0x222a }, + { 0x0bd8, 0x2283 }, + { 0x0bda, 0x2282 }, + { 0x0bdc, 0x22a2 }, + { 0x0bfc, 0x22a3 }, + { 0x0cdf, 0x2017 }, + { 0x0ce0, 0x05d0 }, + { 0x0ce1, 0x05d1 }, + { 0x0ce2, 0x05d2 }, + { 0x0ce3, 0x05d3 }, + { 0x0ce4, 0x05d4 }, + { 0x0ce5, 0x05d5 }, + { 0x0ce6, 0x05d6 }, + { 0x0ce7, 0x05d7 }, + { 0x0ce8, 0x05d8 }, + { 0x0ce9, 0x05d9 }, + { 0x0cea, 0x05da }, + { 0x0ceb, 0x05db }, + { 0x0cec, 0x05dc }, + { 0x0ced, 0x05dd }, + { 0x0cee, 0x05de }, + { 0x0cef, 0x05df }, + { 0x0cf0, 0x05e0 }, + { 0x0cf1, 0x05e1 }, + { 0x0cf2, 0x05e2 }, + { 0x0cf3, 0x05e3 }, + { 0x0cf4, 0x05e4 }, + { 0x0cf5, 0x05e5 }, + { 0x0cf6, 0x05e6 }, + { 0x0cf7, 0x05e7 }, + { 0x0cf8, 0x05e8 }, + { 0x0cf9, 0x05e9 }, + { 0x0cfa, 0x05ea }, + { 0x0da1, 0x0e01 }, + { 0x0da2, 0x0e02 }, + { 0x0da3, 0x0e03 }, + { 0x0da4, 0x0e04 }, + { 0x0da5, 0x0e05 }, + { 0x0da6, 0x0e06 }, + { 0x0da7, 0x0e07 }, + { 0x0da8, 0x0e08 }, + { 0x0da9, 0x0e09 }, + { 0x0daa, 0x0e0a }, + { 0x0dab, 0x0e0b }, + { 0x0dac, 0x0e0c }, + { 0x0dad, 0x0e0d }, + { 0x0dae, 0x0e0e }, + { 0x0daf, 0x0e0f }, + { 0x0db0, 0x0e10 }, + { 0x0db1, 0x0e11 }, + { 0x0db2, 0x0e12 }, + { 0x0db3, 0x0e13 }, + { 0x0db4, 0x0e14 }, + { 0x0db5, 0x0e15 }, + { 0x0db6, 0x0e16 }, + { 0x0db7, 0x0e17 }, + { 0x0db8, 0x0e18 }, + { 0x0db9, 0x0e19 }, + { 0x0dba, 0x0e1a }, + { 0x0dbb, 0x0e1b }, + { 0x0dbc, 0x0e1c }, + { 0x0dbd, 0x0e1d }, + { 0x0dbe, 0x0e1e }, + { 0x0dbf, 0x0e1f }, + { 0x0dc0, 0x0e20 }, + { 0x0dc1, 0x0e21 }, + { 0x0dc2, 0x0e22 }, + { 0x0dc3, 0x0e23 }, + { 0x0dc4, 0x0e24 }, + { 0x0dc5, 0x0e25 }, + { 0x0dc6, 0x0e26 }, + { 0x0dc7, 0x0e27 }, + { 0x0dc8, 0x0e28 }, + { 0x0dc9, 0x0e29 }, + { 0x0dca, 0x0e2a }, + { 0x0dcb, 0x0e2b }, + { 0x0dcc, 0x0e2c }, + { 0x0dcd, 0x0e2d }, + { 0x0dce, 0x0e2e }, + { 0x0dcf, 0x0e2f }, + { 0x0dd0, 0x0e30 }, + { 0x0dd1, 0x0e31 }, + { 0x0dd2, 0x0e32 }, + { 0x0dd3, 0x0e33 }, + { 0x0dd4, 0x0e34 }, + { 0x0dd5, 0x0e35 }, + { 0x0dd6, 0x0e36 }, + { 0x0dd7, 0x0e37 }, + { 0x0dd8, 0x0e38 }, + { 0x0dd9, 0x0e39 }, + { 0x0dda, 0x0e3a }, + { 0x0ddf, 0x0e3f }, + { 0x0de0, 0x0e40 }, + { 0x0de1, 0x0e41 }, + { 0x0de2, 0x0e42 }, + { 0x0de3, 0x0e43 }, + { 0x0de4, 0x0e44 }, + { 0x0de5, 0x0e45 }, + { 0x0de6, 0x0e46 }, + { 0x0de7, 0x0e47 }, + { 0x0de8, 0x0e48 }, + { 0x0de9, 0x0e49 }, + { 0x0dea, 0x0e4a }, + { 0x0deb, 0x0e4b }, + { 0x0dec, 0x0e4c }, + { 0x0ded, 0x0e4d }, + { 0x0df0, 0x0e50 }, + { 0x0df1, 0x0e51 }, + { 0x0df2, 0x0e52 }, + { 0x0df3, 0x0e53 }, + { 0x0df4, 0x0e54 }, + { 0x0df5, 0x0e55 }, + { 0x0df6, 0x0e56 }, + { 0x0df7, 0x0e57 }, + { 0x0df8, 0x0e58 }, + { 0x0df9, 0x0e59 }, + { 0x0ea1, 0x3131 }, + { 0x0ea2, 0x3132 }, + { 0x0ea3, 0x3133 }, + { 0x0ea4, 0x3134 }, + { 0x0ea5, 0x3135 }, + { 0x0ea6, 0x3136 }, + { 0x0ea7, 0x3137 }, + { 0x0ea8, 0x3138 }, + { 0x0ea9, 0x3139 }, + { 0x0eaa, 0x313a }, + { 0x0eab, 0x313b }, + { 0x0eac, 0x313c }, + { 0x0ead, 0x313d }, + { 0x0eae, 0x313e }, + { 0x0eaf, 0x313f }, + { 0x0eb0, 0x3140 }, + { 0x0eb1, 0x3141 }, + { 0x0eb2, 0x3142 }, + { 0x0eb3, 0x3143 }, + { 0x0eb4, 0x3144 }, + { 0x0eb5, 0x3145 }, + { 0x0eb6, 0x3146 }, + { 0x0eb7, 0x3147 }, + { 0x0eb8, 0x3148 }, + { 0x0eb9, 0x3149 }, + { 0x0eba, 0x314a }, + { 0x0ebb, 0x314b }, + { 0x0ebc, 0x314c }, + { 0x0ebd, 0x314d }, + { 0x0ebe, 0x314e }, + { 0x0ebf, 0x314f }, + { 0x0ec0, 0x3150 }, + { 0x0ec1, 0x3151 }, + { 0x0ec2, 0x3152 }, + { 0x0ec3, 0x3153 }, + { 0x0ec4, 0x3154 }, + { 0x0ec5, 0x3155 }, + { 0x0ec6, 0x3156 }, + { 0x0ec7, 0x3157 }, + { 0x0ec8, 0x3158 }, + { 0x0ec9, 0x3159 }, + { 0x0eca, 0x315a }, + { 0x0ecb, 0x315b }, + { 0x0ecc, 0x315c }, + { 0x0ecd, 0x315d }, + { 0x0ece, 0x315e }, + { 0x0ecf, 0x315f }, + { 0x0ed0, 0x3160 }, + { 0x0ed1, 0x3161 }, + { 0x0ed2, 0x3162 }, + { 0x0ed3, 0x3163 }, + { 0x0ed4, 0x11a8 }, + { 0x0ed5, 0x11a9 }, + { 0x0ed6, 0x11aa }, + { 0x0ed7, 0x11ab }, + { 0x0ed8, 0x11ac }, + { 0x0ed9, 0x11ad }, + { 0x0eda, 0x11ae }, + { 0x0edb, 0x11af }, + { 0x0edc, 0x11b0 }, + { 0x0edd, 0x11b1 }, + { 0x0ede, 0x11b2 }, + { 0x0edf, 0x11b3 }, + { 0x0ee0, 0x11b4 }, + { 0x0ee1, 0x11b5 }, + { 0x0ee2, 0x11b6 }, + { 0x0ee3, 0x11b7 }, + { 0x0ee4, 0x11b8 }, + { 0x0ee5, 0x11b9 }, + { 0x0ee6, 0x11ba }, + { 0x0ee7, 0x11bb }, + { 0x0ee8, 0x11bc }, + { 0x0ee9, 0x11bd }, + { 0x0eea, 0x11be }, + { 0x0eeb, 0x11bf }, + { 0x0eec, 0x11c0 }, + { 0x0eed, 0x11c1 }, + { 0x0eee, 0x11c2 }, + { 0x0eef, 0x316d }, + { 0x0ef0, 0x3171 }, + { 0x0ef1, 0x3178 }, + { 0x0ef2, 0x317f }, + { 0x0ef3, 0x3181 }, + { 0x0ef4, 0x3184 }, + { 0x0ef5, 0x3186 }, + { 0x0ef6, 0x318d }, + { 0x0ef7, 0x318e }, + { 0x0ef8, 0x11eb }, + { 0x0ef9, 0x11f0 }, + { 0x0efa, 0x11f9 }, + { 0x0eff, 0x20a9 }, + { 0x13a4, 0x20ac }, + { 0x13bc, 0x0152 }, + { 0x13bd, 0x0153 }, + { 0x13be, 0x0178 }, + { 0x20ac, 0x20ac }, + // Numeric keypad with numlock on + { XK_KP_Space, ' ' }, + { XK_KP_Equal, '=' }, + { XK_KP_Multiply, '*' }, + { XK_KP_Add, '+' }, + { XK_KP_Separator, ',' }, + { XK_KP_Subtract, '-' }, + { XK_KP_Decimal, '.' }, + { XK_KP_Divide, '/' }, + { XK_KP_0, 0x0030 }, + { XK_KP_1, 0x0031 }, + { XK_KP_2, 0x0032 }, + { XK_KP_3, 0x0033 }, + { XK_KP_4, 0x0034 }, + { XK_KP_5, 0x0035 }, + { XK_KP_6, 0x0036 }, + { XK_KP_7, 0x0037 }, + { XK_KP_8, 0x0038 }, + { XK_KP_9, 0x0039 } +}; + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwKeySym2Unicode() - Convert X11 KeySym to Unicode +//======================================================================== + +long _glfwKeySym2Unicode( KeySym keysym ) +{ + int min = 0; + int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; + int mid; + + /* First check for Latin-1 characters (1:1 mapping) */ + if( (keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff) ) + { + return keysym; + } + + /* Also check for directly encoded 24-bit UCS characters */ + if( (keysym & 0xff000000) == 0x01000000 ) + { + return keysym & 0x00ffffff; + } + + /* Binary search in table */ + while( max >= min ) + { + mid = (min + max) / 2; + if( keysymtab[mid].keysym < keysym ) + { + min = mid + 1; + } + else if( keysymtab[mid].keysym > keysym ) + { + max = mid - 1; + } + else + { + /* Found it! */ + return keysymtab[mid].ucs; + } + } + + /* No matching Unicode value found */ + return -1; +} diff --git a/libs/glfw/lib/x11/x11_thread.c b/libs/glfw/lib/x11/x11_thread.c new file mode 100644 index 0000000..34c0fde --- /dev/null +++ b/libs/glfw/lib/x11/x11_thread.c @@ -0,0 +1,507 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: x11_thread.c +// Platform: X11 (Unix) +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +#ifdef _GLFW_HAS_PTHREAD + +//======================================================================== +// _glfwNewThread() - This is simply a "wrapper" for calling the user +// thread function. +//======================================================================== + +void * _glfwNewThread( void * arg ) +{ + GLFWthreadfun threadfun; + _GLFWthread *t; + pthread_t posixID; + + // Get current thread ID + posixID = pthread_self(); + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Loop through entire list of threads to find the matching POSIX + // thread ID + for( t = &_glfwThrd.First; t != NULL; t = t->Next ) + { + if( t->PosixID == posixID ) + { + break; + } + } + if( t == NULL ) + { + LEAVE_THREAD_CRITICAL_SECTION + return NULL; + } + + // Get user thread function pointer + threadfun = t->Function; + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Call the user thread function + threadfun( arg ); + + // Remove thread from thread list + ENTER_THREAD_CRITICAL_SECTION + _glfwRemoveThread( t ); + LEAVE_THREAD_CRITICAL_SECTION + + // When the thread function returns, the thread will die... + return NULL; +} + +#endif // _GLFW_HAS_PTHREAD + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformCreateThread() - Create a new thread +//======================================================================== + +GLFWthread _glfwPlatformCreateThread( GLFWthreadfun fun, void *arg ) +{ +#ifdef _GLFW_HAS_PTHREAD + + GLFWthread ID; + _GLFWthread *t; + int result; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Create a new thread information memory area + t = (_GLFWthread *) malloc( sizeof(_GLFWthread) ); + if( t == NULL ) + { + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + return -1; + } + + // Get a new unique thread id + ID = _glfwThrd.NextID ++; + + // Store thread information in the thread list + t->Function = fun; + t->ID = ID; + + // Create thread + result = pthread_create( + &t->PosixID, // Thread handle + NULL, // Default thread attributes + _glfwNewThread, // Thread function (a wrapper function) + (void *)arg // Argument to thread is user argument + ); + + // Did the thread creation fail? + if( result != 0 ) + { + free( (void *) t ); + LEAVE_THREAD_CRITICAL_SECTION + return -1; + } + + // Append thread to thread list + _glfwAppendThread( t ); + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Return the GLFW thread ID + return ID; + +#else + + return -1; + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// _glfwPlatformDestroyThread() - Kill a thread. NOTE: THIS IS A VERY +// DANGEROUS OPERATION, AND SHOULD NOT BE USED EXCEPT IN EXTREME +// SITUATIONS! +//======================================================================== + +void _glfwPlatformDestroyThread( GLFWthread ID ) +{ +#ifdef _GLFW_HAS_PTHREAD + + _GLFWthread *t; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Get thread information pointer + t = _glfwGetThreadPointer( ID ); + if( t == NULL ) + { + LEAVE_THREAD_CRITICAL_SECTION + return; + } + + // Simply murder the process, no mercy! + pthread_kill( t->PosixID, SIGKILL ); + + // Remove thread from thread list + _glfwRemoveThread( t ); + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// _glfwPlatformWaitThread() - Wait for a thread to die +//======================================================================== + +int _glfwPlatformWaitThread( GLFWthread ID, int waitmode ) +{ +#ifdef _GLFW_HAS_PTHREAD + + pthread_t thread; + _GLFWthread *t; + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Get thread information pointer + t = _glfwGetThreadPointer( ID ); + + // Is the thread already dead? + if( t == NULL ) + { + LEAVE_THREAD_CRITICAL_SECTION + return GL_TRUE; + } + + // If got this far, the thread is alive => polling returns FALSE + if( waitmode == GLFW_NOWAIT ) + { + LEAVE_THREAD_CRITICAL_SECTION + return GL_FALSE; + } + + // Get thread handle + thread = t->PosixID; + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Wait for thread to die + (void) pthread_join( thread, NULL ); + + return GL_TRUE; + +#else + + return GL_TRUE; + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// _glfwPlatformGetThreadID() - Return the thread ID for the current +// thread +//======================================================================== + +GLFWthread _glfwPlatformGetThreadID( void ) +{ +#ifdef _GLFW_HAS_PTHREAD + + _GLFWthread *t; + GLFWthread ID = -1; + pthread_t posixID; + + // Get current thread ID + posixID = pthread_self(); + + // Enter critical section + ENTER_THREAD_CRITICAL_SECTION + + // Loop through entire list of threads to find the matching POSIX + // thread ID + for( t = &_glfwThrd.First; t != NULL; t = t->Next ) + { + if( t->PosixID == posixID ) + { + ID = t->ID; + break; + } + } + + // Leave critical section + LEAVE_THREAD_CRITICAL_SECTION + + // Return the found GLFW thread identifier + return ID; + +#else + + return 0; + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// _glfwPlatformCreateMutex() - Create a mutual exclusion object +//======================================================================== + +GLFWmutex _glfwPlatformCreateMutex( void ) +{ +#ifdef _GLFW_HAS_PTHREAD + + pthread_mutex_t *mutex; + + // Allocate memory for mutex + mutex = (pthread_mutex_t *) malloc( sizeof( pthread_mutex_t ) ); + if( !mutex ) + { + return NULL; + } + + // Initialise a mutex object + (void) pthread_mutex_init( mutex, NULL ); + + // Cast to GLFWmutex and return + return (GLFWmutex) mutex; + +#else + + return (GLFWmutex) 0; + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// _glfwPlatformDestroyMutex() - Destroy a mutual exclusion object +//======================================================================== + +void _glfwPlatformDestroyMutex( GLFWmutex mutex ) +{ +#ifdef _GLFW_HAS_PTHREAD + + // Destroy the mutex object + pthread_mutex_destroy( (pthread_mutex_t *) mutex ); + + // Free memory for mutex object + free( (void *) mutex ); + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// _glfwPlatformLockMutex() - Request access to a mutex +//======================================================================== + +void _glfwPlatformLockMutex( GLFWmutex mutex ) +{ +#ifdef _GLFW_HAS_PTHREAD + + // Wait for mutex to be released + (void) pthread_mutex_lock( (pthread_mutex_t *) mutex ); + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// _glfwPlatformUnlockMutex() - Release a mutex +//======================================================================== + +void _glfwPlatformUnlockMutex( GLFWmutex mutex ) +{ +#ifdef _GLFW_HAS_PTHREAD + + // Release mutex + pthread_mutex_unlock( (pthread_mutex_t *) mutex ); + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// _glfwPlatformCreateCond() - Create a new condition variable object +//======================================================================== + +GLFWcond _glfwPlatformCreateCond( void ) +{ +#ifdef _GLFW_HAS_PTHREAD + + pthread_cond_t *cond; + + // Allocate memory for condition variable + cond = (pthread_cond_t *) malloc( sizeof(pthread_cond_t) ); + if( !cond ) + { + return NULL; + } + + // Initialise condition variable + (void) pthread_cond_init( cond, NULL ); + + // Cast to GLFWcond and return + return (GLFWcond) cond; + +#else + + return (GLFWcond) 0; + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// _glfwPlatformDestroyCond() - Destroy a condition variable object +//======================================================================== + +void _glfwPlatformDestroyCond( GLFWcond cond ) +{ +#ifdef _GLFW_HAS_PTHREAD + + // Destroy the condition variable object + (void) pthread_cond_destroy( (pthread_cond_t *) cond ); + + // Free memory for condition variable object + free( (void *) cond ); + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// _glfwPlatformWaitCond() - Wait for a condition to be raised +//======================================================================== + +void _glfwPlatformWaitCond( GLFWcond cond, GLFWmutex mutex, + double timeout ) +{ +#ifdef _GLFW_HAS_PTHREAD + + struct timeval currenttime; + struct timespec wait; + long dt_sec, dt_usec; + + // Select infinite or timed wait + if( timeout >= GLFW_INFINITY ) + { + // Wait for condition (infinite wait) + (void) pthread_cond_wait( (pthread_cond_t *) cond, + (pthread_mutex_t *) mutex ); + } + else + { + // Set timeout time, relatvie to current time + gettimeofday( ¤ttime, NULL ); + dt_sec = (long) timeout; + dt_usec = (long) ((timeout - (double)dt_sec) * 1000000.0); + wait.tv_nsec = (currenttime.tv_usec + dt_usec) * 1000L; + if( wait.tv_nsec > 1000000000L ) + { + wait.tv_nsec -= 1000000000L; + dt_sec ++; + } + wait.tv_sec = currenttime.tv_sec + dt_sec; + + // Wait for condition (timed wait) + (void) pthread_cond_timedwait( (pthread_cond_t *) cond, + (pthread_mutex_t *) mutex, &wait ); + } + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// _glfwPlatformSignalCond() - Signal a condition to one waiting thread +//======================================================================== + +void _glfwPlatformSignalCond( GLFWcond cond ) +{ +#ifdef _GLFW_HAS_PTHREAD + + // Signal condition + (void) pthread_cond_signal( (pthread_cond_t *) cond ); + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// _glfwPlatformBroadcastCond() - Broadcast a condition to all waiting +// threads +//======================================================================== + +void _glfwPlatformBroadcastCond( GLFWcond cond ) +{ +#ifdef _GLFW_HAS_PTHREAD + + // Broadcast condition + (void) pthread_cond_broadcast( (pthread_cond_t *) cond ); + +#endif // _GLFW_HAS_PTHREAD +} + + +//======================================================================== +// _glfwPlatformGetNumberOfProcessors() - Return the number of processors +// in the system. +//======================================================================== + +int _glfwPlatformGetNumberOfProcessors( void ) +{ + int n; + + // Get number of processors online + _glfw_numprocessors( n ); + return n; +} diff --git a/libs/glfw/lib/x11/x11_time.c b/libs/glfw/lib/x11/x11_time.c new file mode 100644 index 0000000..d790762 --- /dev/null +++ b/libs/glfw/lib/x11/x11_time.c @@ -0,0 +1,154 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: x11_time.c +// Platform: X11 (Unix) +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +//======================================================================== +// Initialise timer +//======================================================================== + +void _glfwInitTimer( void ) +{ + struct timeval tv; + + // "Resolution" is 1 us + _glfwLibrary.Timer.Resolution = 1e-6; + + // Set start-time for timer + gettimeofday( &tv, NULL ); + _glfwLibrary.Timer.t0 = (long long) tv.tv_sec * (long long) 1000000 + + (long long) tv.tv_usec; +} + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// Return timer value in seconds +//======================================================================== + +double _glfwPlatformGetTime( void ) +{ + long long t; + struct timeval tv; + + gettimeofday( &tv, NULL ); + t = (long long) tv.tv_sec * (long long) 1000000 + + (long long) tv.tv_usec; + + return (double)(t - _glfwLibrary.Timer.t0) * _glfwLibrary.Timer.Resolution; +} + + +//======================================================================== +// Set timer value in seconds +//======================================================================== + +void _glfwPlatformSetTime( double t ) +{ + long long t0; + struct timeval tv; + + gettimeofday( &tv, NULL ); + t0 = (long long) tv.tv_sec * (long long) 1000000 + + (long long) tv.tv_usec; + + // Calulate new starting time + _glfwLibrary.Timer.t0 = t0 - (long long)(t/_glfwLibrary.Timer.Resolution); +} + + +//======================================================================== +// Put a thread to sleep for a specified amount of time +//======================================================================== + +void _glfwPlatformSleep( double time ) +{ +#ifdef _GLFW_HAS_PTHREAD + + if( time == 0.0 ) + { +#ifdef _GLFW_HAS_SCHED_YIELD + sched_yield(); +#endif + return; + } + + struct timeval currenttime; + struct timespec wait; + pthread_mutex_t mutex; + pthread_cond_t cond; + long dt_sec, dt_usec; + + // Not all pthread implementations have a pthread_sleep() function. We + // do it the portable way, using a timed wait for a condition that we + // will never signal. NOTE: The unistd functions sleep/usleep suspends + // the entire PROCESS, not a signle thread, which is why we can not + // use them to implement glfwSleep. + + // Set timeout time, relatvie to current time + gettimeofday( ¤ttime, NULL ); + dt_sec = (long) time; + dt_usec = (long) ((time - (double)dt_sec) * 1000000.0); + wait.tv_nsec = (currenttime.tv_usec + dt_usec) * 1000L; + if( wait.tv_nsec > 1000000000L ) + { + wait.tv_nsec -= 1000000000L; + dt_sec++; + } + wait.tv_sec = currenttime.tv_sec + dt_sec; + + // Initialize condition and mutex objects + pthread_mutex_init( &mutex, NULL ); + pthread_cond_init( &cond, NULL ); + + // Do a timed wait + pthread_mutex_lock( &mutex ); + pthread_cond_timedwait( &cond, &mutex, &wait ); + pthread_mutex_unlock( &mutex ); + + // Destroy condition and mutex objects + pthread_mutex_destroy( &mutex ); + pthread_cond_destroy( &cond ); + +#else + + // For systems without PTHREAD, use unistd usleep + if( time > 0 ) + { + usleep( (unsigned int) (time*1000000) ); + } + +#endif // _GLFW_HAS_PTHREAD +} + diff --git a/libs/glfw/lib/x11/x11_window.c b/libs/glfw/lib/x11/x11_window.c new file mode 100644 index 0000000..1e87b0b --- /dev/null +++ b/libs/glfw/lib/x11/x11_window.c @@ -0,0 +1,1746 @@ +//======================================================================== +// GLFW - An OpenGL framework +// File: x11_window.c +// Platform: X11 (Unix) +// API version: 2.6 +// WWW: http://glfw.sourceforge.net +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Camilla Berglund +// +// 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. +// +//======================================================================== + +#include "internal.h" + + +/* Defines some GLX FSAA tokens if not yet defined */ +#ifndef GLX_SAMPLE_BUFFERS +# define GLX_SAMPLE_BUFFERS 100000 +#endif +#ifndef GLX_SAMPLES +# define GLX_SAMPLES 100001 +#endif + + +/* KDE decoration values */ +enum { + KDE_noDecoration = 0, + KDE_normalDecoration = 1, + KDE_tinyDecoration = 2, + KDE_noFocus = 256, + KDE_standaloneMenuBar = 512, + KDE_desktopIcon = 1024 , + KDE_staysOnTop = 2048 +}; + + +//************************************************************************ +//**** GLFW internal functions **** +//************************************************************************ + +//======================================================================== +// _glfwWaitForMapNotify() +//======================================================================== + +Bool _glfwWaitForMapNotify( Display *d, XEvent *e, char *arg ) +{ + return (e->type == MapNotify) && (e->xmap.window == (Window)arg); +} + + +//======================================================================== +// _glfwWaitForUnmapNotify() +//======================================================================== + +Bool _glfwWaitForUnmapNotify( Display *d, XEvent *e, char *arg ) +{ + return (e->type == UnmapNotify) && (e->xmap.window == (Window)arg); +} + + +//======================================================================== +// _glfwDisableDecorations() - Turn off window decorations +// Based on xawdecode: src/wmhooks.c +//======================================================================== + +#define MWM_HINTS_DECORATIONS (1L << 1) + +static void _glfwDisableDecorations( void ) +{ + int RemovedDecorations; + Atom HintAtom; + XSetWindowAttributes attributes; + + RemovedDecorations = 0; + + // First try to set MWM hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "_MOTIF_WM_HINTS", True ); + if ( HintAtom != None ) + { + struct { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; + } MWMHints = { MWM_HINTS_DECORATIONS, 0, 0, 0, 0 }; + + XChangeProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom, HintAtom, + 32, PropModeReplace, (unsigned char *)&MWMHints, + sizeof(MWMHints)/4 ); + RemovedDecorations = 1; + } + + // Now try to set KWM hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "KWM_WIN_DECORATION", True ); + if ( HintAtom != None ) + { + long KWMHints = KDE_tinyDecoration; + + XChangeProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom, HintAtom, + 32, PropModeReplace, (unsigned char *)&KWMHints, + sizeof(KWMHints)/4 ); + RemovedDecorations = 1; + } + + // Now try to set GNOME hints + HintAtom = XInternAtom(_glfwLibrary.Dpy, "_WIN_HINTS", True ); + if ( HintAtom != None ) + { + long GNOMEHints = 0; + + XChangeProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom, HintAtom, + 32, PropModeReplace, (unsigned char *)&GNOMEHints, + sizeof(GNOMEHints)/4 ); + RemovedDecorations = 1; + } + + // Now try to set KDE NET_WM hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_WINDOW_TYPE", True ); + if ( HintAtom != None ) + { + Atom NET_WMHints[2]; + + NET_WMHints[0] = XInternAtom( _glfwLibrary.Dpy, "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", True ); + /* define a fallback... */ + NET_WMHints[1] = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_WINDOW_TYPE_NORMAL", True ); + + XChangeProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom, XA_ATOM, + 32, PropModeReplace, (unsigned char *)&NET_WMHints, + 2 ); + RemovedDecorations = 1; + } + + // Set ICCCM fullscreen WM hint + HintAtom = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_STATE", True ); + if ( HintAtom != None ) + { + Atom NET_WMHints[1]; + + NET_WMHints[0] = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_STATE_FULLSCREEN", True ); + + XChangeProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom, XA_ATOM, + 32, PropModeReplace, (unsigned char *)&NET_WMHints, 1 ); + } + + + // Did we sucessfully remove the window decorations? + if( RemovedDecorations ) + { + // Finally set the transient hints + XSetTransientForHint( _glfwLibrary.Dpy, _glfwWin.Win, RootWindow(_glfwLibrary.Dpy, _glfwWin.Scrn) ); + XUnmapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + XMapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + } + else + { + // The Butcher way of removing window decorations + attributes.override_redirect = True; + XChangeWindowAttributes( _glfwLibrary.Dpy, _glfwWin.Win, + CWOverrideRedirect, &attributes ); + _glfwWin.OverrideRedirect = GL_TRUE; + } +} + + +//======================================================================== +// _glfwEnableDecorations() - Turn on window decorations +//======================================================================== + +static void _glfwEnableDecorations( void ) +{ + int ActivatedDecorations; + Atom HintAtom; + + // If this is an override redirect window, skip it... + if( _glfwWin.OverrideRedirect ) + { + return; + } + + ActivatedDecorations = 0; + + // First try to unset MWM hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "_MOTIF_WM_HINTS", True ); + if ( HintAtom != None ) + { + XDeleteProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom ); + ActivatedDecorations = 1; + } + + // Now try to unset KWM hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "KWM_WIN_DECORATION", True ); + if ( HintAtom != None ) + { + XDeleteProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom ); + ActivatedDecorations = 1; + } + + // Now try to unset GNOME hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "_WIN_HINTS", True ); + if ( HintAtom != None ) + { + XDeleteProperty( _glfwLibrary.Dpy, _glfwWin.Win, HintAtom ); + ActivatedDecorations = 1; + } + + // Now try to unset NET_WM hints + HintAtom = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_WINDOW_TYPE", True ); + if ( HintAtom != None ) + { + Atom NET_WMHints = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_WINDOW_TYPE_NORMAL", True); + if( NET_WMHints != None ) + { + XChangeProperty( _glfwLibrary.Dpy, _glfwWin.Win, + HintAtom, XA_ATOM, 32, PropModeReplace, + (unsigned char *)&NET_WMHints, 1 ); + ActivatedDecorations = 1; + } + } + + // Finally unset the transient hints if necessary + if( ActivatedDecorations ) + { + // NOTE: Does this work? + XSetTransientForHint( _glfwLibrary.Dpy, _glfwWin.Win, None); + XUnmapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + XMapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + } +} + + +//======================================================================== +// _glfwChooseVisual() - We do our own function here, since +// glXChooseVisual does not behave as we want it to (not according to the +// GLFW specs) +//======================================================================== + +XVisualInfo * _glfwChooseVisual( Display *Dpy, int Screen, int r, int g, + int b, int a, int d, int s, int ar, int ag, int ab, int aa, int aux, + int fsaa, int stereo) +{ + XVisualInfo *VI, *VI_list, VI_tmp; + int nitems_return, i; + int vi_gl, vi_rgba, vi_double, vi_stereo; + int vi_r, vi_g, vi_b, vi_a, vi_d, vi_s, vi_ar, vi_ag, vi_ab, vi_aa; + int vi_aux; + int color, accum, vi_accum; + int missing, color_diff, extra_diff; + int best_vis, best_missing, best_color_diff, best_extra_diff; + int samples, samplebuffers, vi_samples, vi_samplebuffers; + + // Get list of visuals for this screen & display + VI_tmp.screen = Screen; + VI_list = XGetVisualInfo( Dpy, VisualScreenMask, &VI_tmp, + &nitems_return ); + if( VI_list == NULL ) + { + return NULL; + } + + // Pick some prefered color depth if the user did not request a + // specific depth (note: if the user did not request a specific color + // depth, this will not be a driving demand, it's only here to avoid + // selection randomness) + color = (r > 0 || g > 0 || b > 0); + if( !color ) + { + r = g = b = 8; + } + + // Make sure that stereo is 1 or 0 + stereo = stereo ? 1 : 0; + + // Convenience pre-calculation + accum = (ar > 0 || ag > 0 || ab > 0 || aa > 0); + + samples = fsaa; + samplebuffers = (fsaa > 0) ? 1 : 0; + + + + // Loop through list of visuals to find best match + best_vis = -1; + best_missing = 0x7fffffff; + best_color_diff = 0x7fffffff; + best_extra_diff = 0x7fffffff; + for( i = 0; i < nitems_return; i ++ ) + { + // We want GL, RGBA & DOUBLEBUFFER, and NOT STEREO / STEREO + glXGetConfig( Dpy, &VI_list[i], GLX_USE_GL, &vi_gl ); + glXGetConfig( Dpy, &VI_list[i], GLX_RGBA, &vi_rgba ); + glXGetConfig( Dpy, &VI_list[i], GLX_DOUBLEBUFFER, &vi_double ); + glXGetConfig( Dpy, &VI_list[i], GLX_STEREO, &vi_stereo ); + vi_stereo = vi_stereo ? 0 : 0; + if( vi_gl && vi_rgba && vi_double && (vi_stereo == stereo) ) + { + // Get visual color parameters + glXGetConfig( Dpy, &VI_list[i], GLX_RED_SIZE, &vi_r ); + glXGetConfig( Dpy, &VI_list[i], GLX_GREEN_SIZE, &vi_g ); + glXGetConfig( Dpy, &VI_list[i], GLX_BLUE_SIZE, &vi_b ); + + // Get visual "extra" parameters + glXGetConfig( Dpy, &VI_list[i], GLX_ALPHA_SIZE, &vi_a ); + glXGetConfig( Dpy, &VI_list[i], GLX_DEPTH_SIZE, &vi_d ); + glXGetConfig( Dpy, &VI_list[i], GLX_STENCIL_SIZE, &vi_s ); + glXGetConfig( Dpy, &VI_list[i], GLX_ACCUM_RED_SIZE, &vi_ar ); + glXGetConfig( Dpy, &VI_list[i], GLX_ACCUM_GREEN_SIZE, &vi_ag ); + glXGetConfig( Dpy, &VI_list[i], GLX_ACCUM_BLUE_SIZE, &vi_ab ); + glXGetConfig( Dpy, &VI_list[i], GLX_ACCUM_ALPHA_SIZE, &vi_aa ); + glXGetConfig( Dpy, &VI_list[i], GLX_AUX_BUFFERS, &vi_aux ); + glXGetConfig( Dpy, &VI_list[i], GLX_SAMPLE_BUFFERS, &vi_samplebuffers ); + glXGetConfig( Dpy, &VI_list[i], GLX_SAMPLES, &vi_samples ); + + vi_accum = (vi_ar > 0 || vi_ag > 0 || vi_ab > 0 || vi_aa > 0); + + // Check how many buffers are missing + missing = 0; + if( a > 0 && vi_a == 0 ) missing ++; + if( d > 0 && vi_d == 0 ) missing ++; + if( s > 0 && vi_s == 0 ) missing ++; + if( accum && !vi_accum ) missing ++; + if( aux > 0 && vi_aux == 0 ) missing ++; + if( samplebuffers > 0 && vi_samplebuffers == 0 ) missing ++; + + + // Calculate color diff + color_diff = (r - vi_r) * (r - vi_r) + + (g - vi_g) * (g - vi_g) + + (b - vi_b) * (b - vi_b); + + // Calculate "extra" diff + extra_diff = 0; + if( a > 0 ) + { + extra_diff += (a - vi_a) * (a - vi_a); + } + if( d > 0 ) + { + extra_diff += (d - vi_d) * (d - vi_d); + } + if( s > 0 ) + { + extra_diff += (s - vi_s) * (s - vi_s); + } + if( accum ) + { + extra_diff += (ar - vi_ar) * (ar - vi_ar) + + (ag - vi_ag) * (ag - vi_ag) + + (ab - vi_ab) * (ab - vi_ab) + + (aa - vi_aa) * (aa - vi_aa); + } + if( aux > 0 ) + { + extra_diff += (aux - vi_aux) * (aux - vi_aux); + } + if( samples > 0 ) + { + extra_diff += (samples - vi_samples) * (samples - vi_samples); + + } + // Check if this is a better match. We implement some + // complicated rules, by prioritizing in this order: + // 1) Visuals with the least number of missing buffers always + // have priority + // 2a) If (r,g,b)!=(0,0,0), color depth has priority over + // other buffers + // 2b) If (r,g,b)==(0,0,0), other buffers have priority over + // color depth + if( missing < best_missing ) + { + best_vis = i; + } + else if( missing == best_missing ) + { + if( color ) + { + if( (color_diff < best_color_diff) || + (color_diff == best_color_diff && + extra_diff < best_extra_diff) ) + { + best_vis = i; + } + } + else + { + if( (extra_diff < best_extra_diff) || + (extra_diff == best_extra_diff && + color_diff < best_color_diff) ) + { + best_vis = i; + } + } + } + if( best_vis == i ) + { + best_missing = missing; + best_color_diff = color_diff; + best_extra_diff = extra_diff; + } + } + } + + // Copy best visual to a visual to return + if( best_vis >= 0 ) + { + VI = XGetVisualInfo( Dpy, VisualIDMask, &VI_list[ best_vis ], + &nitems_return ); + } + else + { + VI = NULL; + } + + // Free visuals list + XFree( VI_list ); + + return VI; +} + + +//======================================================================== +// _glfwTranslateKey() - Translates an X Window key to internal coding +//======================================================================== + +static int _glfwTranslateKey( int keycode ) +{ + KeySym key, key_lc, key_uc; + + // Try secondary keysym, for numeric keypad keys + // Note: This way we always force "NumLock = ON", which at least + // enables GLFW users to detect numeric keypad keys + key = XKeycodeToKeysym( _glfwLibrary.Dpy, keycode, 1 ); + switch( key ) + { + // Numeric keypad + case XK_KP_0: return GLFW_KEY_KP_0; + case XK_KP_1: return GLFW_KEY_KP_1; + case XK_KP_2: return GLFW_KEY_KP_2; + case XK_KP_3: return GLFW_KEY_KP_3; + case XK_KP_4: return GLFW_KEY_KP_4; + case XK_KP_5: return GLFW_KEY_KP_5; + case XK_KP_6: return GLFW_KEY_KP_6; + case XK_KP_7: return GLFW_KEY_KP_7; + case XK_KP_8: return GLFW_KEY_KP_8; + case XK_KP_9: return GLFW_KEY_KP_9; + case XK_KP_Separator: + case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + default: break; + } + + // Now try pimary keysym + key = XKeycodeToKeysym( _glfwLibrary.Dpy, keycode, 0 ); + switch( key ) + { + // Special keys (non character keys) + case XK_Escape: return GLFW_KEY_ESC; + case XK_Tab: return GLFW_KEY_TAB; + case XK_Shift_L: return GLFW_KEY_LSHIFT; + case XK_Shift_R: return GLFW_KEY_RSHIFT; + case XK_Control_L: return GLFW_KEY_LCTRL; + case XK_Control_R: return GLFW_KEY_RCTRL; + case XK_Meta_L: + case XK_Alt_L: return GLFW_KEY_LALT; + case XK_Mode_switch: // Mapped to Alt_R on many keyboards + case XK_Meta_R: + case XK_Alt_R: return GLFW_KEY_RALT; + case XK_KP_Delete: + case XK_Delete: return GLFW_KEY_DEL; + case XK_BackSpace: return GLFW_KEY_BACKSPACE; + case XK_Return: return GLFW_KEY_ENTER; + case XK_KP_Home: + case XK_Home: return GLFW_KEY_HOME; + case XK_KP_End: + case XK_End: return GLFW_KEY_END; + case XK_KP_Page_Up: + case XK_Page_Up: return GLFW_KEY_PAGEUP; + case XK_KP_Page_Down: + case XK_Page_Down: return GLFW_KEY_PAGEDOWN; + case XK_KP_Insert: + case XK_Insert: return GLFW_KEY_INSERT; + case XK_KP_Left: + case XK_Left: return GLFW_KEY_LEFT; + case XK_KP_Right: + case XK_Right: return GLFW_KEY_RIGHT; + case XK_KP_Down: + case XK_Down: return GLFW_KEY_DOWN; + case XK_KP_Up: + case XK_Up: return GLFW_KEY_UP; + case XK_F1: return GLFW_KEY_F1; + case XK_F2: return GLFW_KEY_F2; + case XK_F3: return GLFW_KEY_F3; + case XK_F4: return GLFW_KEY_F4; + case XK_F5: return GLFW_KEY_F5; + case XK_F6: return GLFW_KEY_F6; + case XK_F7: return GLFW_KEY_F7; + case XK_F8: return GLFW_KEY_F8; + case XK_F9: return GLFW_KEY_F9; + case XK_F10: return GLFW_KEY_F10; + case XK_F11: return GLFW_KEY_F11; + case XK_F12: return GLFW_KEY_F12; + case XK_F13: return GLFW_KEY_F13; + case XK_F14: return GLFW_KEY_F14; + case XK_F15: return GLFW_KEY_F15; + case XK_F16: return GLFW_KEY_F16; + case XK_F17: return GLFW_KEY_F17; + case XK_F18: return GLFW_KEY_F18; + case XK_F19: return GLFW_KEY_F19; + case XK_F20: return GLFW_KEY_F20; + case XK_F21: return GLFW_KEY_F21; + case XK_F22: return GLFW_KEY_F22; + case XK_F23: return GLFW_KEY_F23; + case XK_F24: return GLFW_KEY_F24; + case XK_F25: return GLFW_KEY_F25; + + // Numeric keypad (should have been detected in secondary keysym!) + case XK_KP_Divide: return GLFW_KEY_KP_DIVIDE; + case XK_KP_Multiply: return GLFW_KEY_KP_MULTIPLY; + case XK_KP_Subtract: return GLFW_KEY_KP_SUBTRACT; + case XK_KP_Add: return GLFW_KEY_KP_ADD; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + + // The rest (should be printable keys) + default: + // Make uppercase + XConvertCase( key, &key_lc, &key_uc ); + key = key_uc; + + // Valid ISO 8859-1 character? + if( (key >= 32 && key <= 126) || + (key >= 160 && key <= 255) ) + { + return (int) key; + } + return GLFW_KEY_UNKNOWN; + } +} + + +//======================================================================== +// _glfwTranslateChar() - Translates an X Window event to Unicode +//======================================================================== + +static int _glfwTranslateChar( XKeyEvent *event ) +{ + KeySym keysym; + + // Get X11 keysym + XLookupString( event, NULL, 0, &keysym, NULL ); + + // Convert to Unicode (see x11_keysym2unicode.c) + return (int) _glfwKeySym2Unicode( keysym ); +} + + + +//======================================================================== +// Get next X event (called by glfwPollEvents) +//======================================================================== + +static int _glfwGetNextEvent( void ) +{ + XEvent event, next_event; + + // Pull next event from event queue + XNextEvent( _glfwLibrary.Dpy, &event ); + + // Handle certain window messages + switch( event.type ) + { + // Is a key being pressed? + case KeyPress: + { + // Translate and report key press + _glfwInputKey( _glfwTranslateKey( event.xkey.keycode ), GLFW_PRESS ); + + // Translate and report character input + if( _glfwWin.CharCallback ) + { + _glfwInputChar( _glfwTranslateChar( &event.xkey ), GLFW_PRESS ); + } + break; + } + + // Is a key being released? + case KeyRelease: + { + // Do not report key releases for key repeats. For key repeats + // we will get KeyRelease/KeyPress pairs with identical time + // stamps. User selected key repeat filtering is handled in + // _glfwInputKey()/_glfwInputChar(). + if( XEventsQueued( _glfwLibrary.Dpy, QueuedAfterReading ) ) + { + XPeekEvent( _glfwLibrary.Dpy, &next_event ); + if( next_event.type == KeyPress && + next_event.xkey.window == event.xkey.window && + next_event.xkey.keycode == event.xkey.keycode && + next_event.xkey.time == event.xkey.time ) + { + // Do not report anything for this event + break; + } + } + + // Translate and report key release + _glfwInputKey( _glfwTranslateKey( event.xkey.keycode ), GLFW_RELEASE ); + + // Translate and report character input + if( _glfwWin.CharCallback ) + { + _glfwInputChar( _glfwTranslateChar( &event.xkey ), GLFW_RELEASE ); + } + break; + } + + // Were any of the mouse-buttons pressed? + case ButtonPress: + { + if( event.xbutton.button == Button1 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS ); + } + else if( event.xbutton.button == Button2 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS ); + } + else if( event.xbutton.button == Button3 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS ); + } + + // XFree86 3.3.2 and later translates mouse wheel up/down into + // mouse button 4 & 5 presses + else if( event.xbutton.button == Button4 ) + { + _glfwInput.WheelPos++; // To verify: is this up or down? + if( _glfwWin.MouseWheelCallback ) + { + _glfwWin.MouseWheelCallback( _glfwInput.WheelPos ); + } + } + else if( event.xbutton.button == Button5 ) + { + _glfwInput.WheelPos--; + if( _glfwWin.MouseWheelCallback ) + { + _glfwWin.MouseWheelCallback( _glfwInput.WheelPos ); + } + } + break; + } + + // Were any of the mouse-buttons released? + case ButtonRelease: + { + if( event.xbutton.button == Button1 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_LEFT, + GLFW_RELEASE ); + } + else if( event.xbutton.button == Button2 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_MIDDLE, + GLFW_RELEASE ); + } + else if( event.xbutton.button == Button3 ) + { + _glfwInputMouseClick( GLFW_MOUSE_BUTTON_RIGHT, + GLFW_RELEASE ); + } + break; + } + + // Was the mouse moved? + case MotionNotify: + { + if( event.xmotion.x != _glfwInput.CursorPosX || + event.xmotion.y != _glfwInput.CursorPosY ) + { + if( _glfwWin.MouseLock ) + { + _glfwInput.MousePosX += event.xmotion.x - + _glfwInput.CursorPosX; + _glfwInput.MousePosY += event.xmotion.y - + _glfwInput.CursorPosY; + } + else + { + _glfwInput.MousePosX = event.xmotion.x; + _glfwInput.MousePosY = event.xmotion.y; + } + _glfwInput.CursorPosX = event.xmotion.x; + _glfwInput.CursorPosY = event.xmotion.y; + _glfwInput.MouseMoved = GL_TRUE; + + // Call user callback function + if( _glfwWin.MousePosCallback ) + { + _glfwWin.MousePosCallback( _glfwInput.MousePosX, + _glfwInput.MousePosY ); + } + } + break; + } + + // Was the window resized? + case ConfigureNotify: + { + if( event.xconfigure.width != _glfwWin.Width || + event.xconfigure.height != _glfwWin.Height ) + { + _glfwWin.Width = event.xconfigure.width; + _glfwWin.Height = event.xconfigure.height; + if( _glfwWin.WindowSizeCallback ) + { + _glfwWin.WindowSizeCallback( _glfwWin.Width, + _glfwWin.Height ); + } + } + break; + } + + // Was the window closed by the window manager? + case ClientMessage: + { + if( (Atom) event.xclient.data.l[ 0 ] == _glfwWin.WMDeleteWindow ) + { + return GL_TRUE; + } + + if( (Atom) event.xclient.data.l[ 0 ] == _glfwWin.WMPing ) + { + XSendEvent( _glfwLibrary.Dpy, + RootWindow( _glfwLibrary.Dpy, _glfwWin.VI->screen ), + False, SubstructureNotifyMask | SubstructureRedirectMask, &event ); + } + break; + } + + // Was the window mapped (un-iconified)? + case MapNotify: + _glfwWin.MapNotifyCount++; + break; + + // Was the window unmapped (iconified)? + case UnmapNotify: + _glfwWin.MapNotifyCount--; + break; + + // Was the window activated? + case FocusIn: + _glfwWin.FocusInCount++; + break; + + // Was the window de-activated? + case FocusOut: + _glfwWin.FocusInCount--; + break; + + // Was the window contents damaged? + case Expose: + { + // Call user callback function + if( _glfwWin.WindowRefreshCallback ) + { + _glfwWin.WindowRefreshCallback(); + } + break; + } + + // Was the window destroyed? + case DestroyNotify: + return GL_TRUE; + + default: + { +#if defined( _GLFW_HAS_XRANDR ) + switch( event.type - _glfwLibrary.XRandR.EventBase ) + { + case RRScreenChangeNotify: + { + // Show XRandR that we really care + XRRUpdateConfiguration( &event ); + break; + } + } +#endif + break; + } + } + + // The window was not destroyed + return GL_FALSE; +} + + +//======================================================================== +// _glfwCreateNULLCursor() - Create a blank cursor (for locked mouse mode) +//======================================================================== + +Cursor _glfwCreateNULLCursor( Display *display, Window root ) +{ + Pixmap cursormask; + XGCValues xgc; + GC gc; + XColor col; + Cursor cursor; + + cursormask = XCreatePixmap( display, root, 1, 1, 1 ); + xgc.function = GXclear; + gc = XCreateGC( display, cursormask, GCFunction, &xgc ); + XFillRectangle( display, cursormask, gc, 0, 0, 1, 1 ); + col.pixel = 0; + col.red = 0; + col.flags = 4; + cursor = XCreatePixmapCursor( display, cursormask, cursormask, + &col,&col, 0,0 ); + XFreePixmap( display, cursormask ); + XFreeGC( display, gc ); + + return cursor; +} + + +//======================================================================== +// _glfwInitGLXExtensions() - Initialize GLX-specific extensions +//======================================================================== + +static void _glfwInitGLXExtensions( void ) +{ + int has_swap_control; + + // Initialize OpenGL extension: GLX_SGI_swap_control + has_swap_control = _glfwPlatformExtensionSupported( + "GLX_SGI_swap_control" + ); + + if( has_swap_control ) + { + _glfwWin.SwapInterval = (GLXSWAPINTERVALSGI_T) + _glfw_glXGetProcAddress( (GLubyte*) "glXSwapIntervalSGI" ); + } + else + { + _glfwWin.SwapInterval = NULL; + } +} + + + +//************************************************************************ +//**** Platform implementation functions **** +//************************************************************************ + +//======================================================================== +// _glfwPlatformOpenWindow() - Here is where the window is created, and +// the OpenGL rendering context is created +//======================================================================== + +int _glfwPlatformOpenWindow( int width, int height, int redbits, + int greenbits, int bluebits, int alphabits, int depthbits, + int stencilbits, int mode, _GLFWhints* hints ) +{ + Colormap cmap; + XSetWindowAttributes wa; + XEvent event; + Atom protocols[2]; + + // Clear platform specific GLFW window state + _glfwWin.VI = NULL; + _glfwWin.CX = (GLXContext)0; + _glfwWin.Win = (Window)0; + _glfwWin.Hints = NULL; + _glfwWin.PointerGrabbed = GL_FALSE; + _glfwWin.KeyboardGrabbed = GL_FALSE; + _glfwWin.OverrideRedirect = GL_FALSE; + _glfwWin.FS.ModeChanged = GL_FALSE; + _glfwWin.Saver.Changed = GL_FALSE; + _glfwWin.RefreshRate = hints->RefreshRate; + + // Fullscreen & screen saver settings + // Check if GLX is supported on this display + if( !glXQueryExtension( _glfwLibrary.Dpy, NULL, NULL ) ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Get screen ID for this window + _glfwWin.Scrn = _glfwLibrary.DefaultScreen; + + // Get an appropriate visual + _glfwWin.VI = _glfwChooseVisual( _glfwLibrary.Dpy, + _glfwWin.Scrn, + redbits, greenbits, bluebits, + alphabits, depthbits, stencilbits, + hints->AccumRedBits, hints->AccumGreenBits, + hints->AccumBlueBits, hints->AccumAlphaBits, + hints->AuxBuffers, hints->Samples, hints->Stereo ); + if( _glfwWin.VI == NULL ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Create a GLX context + _glfwWin.CX = glXCreateContext( _glfwLibrary.Dpy, _glfwWin.VI, 0, GL_TRUE ); + if( _glfwWin.CX == NULL ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Create a colormap + cmap = XCreateColormap( _glfwLibrary.Dpy, RootWindow( _glfwLibrary.Dpy, + _glfwWin.VI->screen), _glfwWin.VI->visual, AllocNone ); + + // Do we want fullscreen? + if( mode == GLFW_FULLSCREEN ) + { + // Change video mode + _glfwSetVideoMode( _glfwWin.Scrn, &_glfwWin.Width, + &_glfwWin.Height, &_glfwWin.RefreshRate ); + + // Remember old screen saver settings + XGetScreenSaver( _glfwLibrary.Dpy, &_glfwWin.Saver.Timeout, + &_glfwWin.Saver.Interval, &_glfwWin.Saver.Blanking, + &_glfwWin.Saver.Exposure ); + + // Disable screen saver + XSetScreenSaver( _glfwLibrary.Dpy, 0, 0, DontPreferBlanking, + DefaultExposures ); + } + + // Attributes for window + wa.colormap = cmap; + wa.border_pixel = 0; + wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask | + ExposureMask | FocusChangeMask | VisibilityChangeMask; + + // Create a window + _glfwWin.Win = XCreateWindow( + _glfwLibrary.Dpy, + RootWindow( _glfwLibrary.Dpy, _glfwWin.VI->screen ), + 0, 0, // Upper left corner + _glfwWin.Width, _glfwWin.Height, // Width, height + 0, // Borderwidth + _glfwWin.VI->depth, // Depth + InputOutput, + _glfwWin.VI->visual, + CWBorderPixel | CWColormap | CWEventMask, + &wa + ); + if( !_glfwWin.Win ) + { + _glfwPlatformCloseWindow(); + return GL_FALSE; + } + + // Get the delete window WM protocol atom + _glfwWin.WMDeleteWindow = XInternAtom( _glfwLibrary.Dpy, + "WM_DELETE_WINDOW", + False ); + + // Get the ping WM protocol atom + _glfwWin.WMPing = XInternAtom( _glfwLibrary.Dpy, "_NET_WM_PING", False ); + + protocols[0] = _glfwWin.WMDeleteWindow; + protocols[1] = _glfwWin.WMPing; + + // Allow us to trap the Window Close protocol + XSetWMProtocols( _glfwLibrary.Dpy, _glfwWin.Win, protocols, + sizeof(protocols) / sizeof(Atom) ); + + // Remove window decorations for fullscreen windows + if( mode == GLFW_FULLSCREEN ) + { + _glfwDisableDecorations(); + } + + _glfwWin.Hints = XAllocSizeHints(); + + if( hints->WindowNoResize ) + { + _glfwWin.Hints->flags |= (PMinSize | PMaxSize); + _glfwWin.Hints->min_width = _glfwWin.Hints->max_width = _glfwWin.Width; + _glfwWin.Hints->min_height = _glfwWin.Hints->max_height = _glfwWin.Height; + } + + if( mode == GLFW_FULLSCREEN ) + { + _glfwWin.Hints->flags |= PPosition; + _glfwWin.Hints->x = 0; + _glfwWin.Hints->y = 0; + } + + XSetWMNormalHints( _glfwLibrary.Dpy, _glfwWin.Win, _glfwWin.Hints ); + + // Map window + XMapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + + // Wait for map notification + XIfEvent( _glfwLibrary.Dpy, &event, _glfwWaitForMapNotify, + (char*)_glfwWin.Win ); + + // Make sure that our window ends up on top of things + XRaiseWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + + // Fullscreen mode "post processing" + if( mode == GLFW_FULLSCREEN ) + { +#if defined( _GLFW_HAS_XRANDR ) + // Request screen change notifications + if( _glfwLibrary.XRandR.Available ) + { + XRRSelectInput( _glfwLibrary.Dpy, + _glfwWin.Win, + RRScreenChangeNotifyMask ); + } +#endif + + // Force window position/size (some WMs do their own window + // geometry, which we want to override) + XMoveWindow( _glfwLibrary.Dpy, _glfwWin.Win, 0, 0 ); + XResizeWindow( _glfwLibrary.Dpy, _glfwWin.Win, _glfwWin.Width, + _glfwWin.Height ); + + // Grab keyboard + if( XGrabKeyboard( _glfwLibrary.Dpy, _glfwWin.Win, True, + GrabModeAsync, GrabModeAsync, CurrentTime ) == + GrabSuccess ) + { + _glfwWin.KeyboardGrabbed = GL_TRUE; + } + + // Grab mouse cursor + if( XGrabPointer( _glfwLibrary.Dpy, _glfwWin.Win, True, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask, GrabModeAsync, GrabModeAsync, + _glfwWin.Win, None, CurrentTime ) == + GrabSuccess ) + { + _glfwWin.PointerGrabbed = GL_TRUE; + } + + // Try to get window inside viewport (for virtual displays) by + // moving the mouse cursor to the upper left corner (and then to + // the center) - this works for XFree86 + XWarpPointer( _glfwLibrary.Dpy, None, _glfwWin.Win, 0,0,0,0, 0,0 ); + XWarpPointer( _glfwLibrary.Dpy, None, _glfwWin.Win, 0,0,0,0, + _glfwWin.Width/2, _glfwWin.Height/2 ); + } + + // Set window & icon name + _glfwPlatformSetWindowTitle( "GLFW Window" ); + + // Connect the context to the window + glXMakeCurrent( _glfwLibrary.Dpy, _glfwWin.Win, _glfwWin.CX ); + + // Start by clearing the front buffer to black (avoid ugly desktop + // remains in our OpenGL window) + glClear( GL_COLOR_BUFFER_BIT ); + glXSwapBuffers( _glfwLibrary.Dpy, _glfwWin.Win ); + + // Initialize GLX-specific OpenGL extensions + _glfwInitGLXExtensions(); + + return GL_TRUE; +} + + +//======================================================================== +// Properly kill the window/video display +//======================================================================== + +void _glfwPlatformCloseWindow( void ) +{ +#if defined( _GLFW_HAS_XRANDR ) + XRRScreenConfiguration *sc; + Window root; +#endif + + // Free WM size hints + if( _glfwWin.Hints ) + { + XFree( _glfwWin.Hints ); + _glfwWin.Hints = NULL; + } + + // Do we have a rendering context? + if( _glfwWin.CX ) + { + // Release the context + glXMakeCurrent( _glfwLibrary.Dpy, None, NULL ); + + // Delete the context + glXDestroyContext( _glfwLibrary.Dpy, _glfwWin.CX ); + _glfwWin.CX = NULL; + } + + // Ungrab pointer and/or keyboard? + if( _glfwWin.KeyboardGrabbed ) + { + XUngrabKeyboard( _glfwLibrary.Dpy, CurrentTime ); + _glfwWin.KeyboardGrabbed = GL_FALSE; + } + if( _glfwWin.PointerGrabbed ) + { + XUngrabPointer( _glfwLibrary.Dpy, CurrentTime ); + _glfwWin.PointerGrabbed = GL_FALSE; + } + + // Do we have a window? + if( _glfwWin.Win ) + { + // Unmap the window + XUnmapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + + // Destroy the window + XDestroyWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + _glfwWin.Win = (Window) 0; + } + + // Did we change the fullscreen resolution? + if( _glfwWin.FS.ModeChanged ) + { +#if defined( _GLFW_HAS_XRANDR ) + if( _glfwLibrary.XRandR.Available ) + { + root = RootWindow( _glfwLibrary.Dpy, _glfwWin.Scrn ); + sc = XRRGetScreenInfo( _glfwLibrary.Dpy, root ); + + XRRSetScreenConfig( _glfwLibrary.Dpy, + sc, + root, + _glfwWin.FS.OldSizeID, + _glfwWin.FS.OldRotation, + CurrentTime ); + + XRRFreeScreenConfigInfo( sc ); + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + if( _glfwLibrary.XF86VidMode.Available ) + { + // Unlock mode switch + XF86VidModeLockModeSwitch( _glfwLibrary.Dpy, + _glfwWin.Scrn, + 0 ); + + // Change the video mode back to the old mode + XF86VidModeSwitchToMode( _glfwLibrary.Dpy, + _glfwWin.Scrn, &_glfwWin.FS.OldMode ); + } +#endif + _glfwWin.FS.ModeChanged = GL_FALSE; + } + + // Did we change the screen saver setting? + if( _glfwWin.Saver.Changed ) + { + // Restore old screen saver settings + XSetScreenSaver( _glfwLibrary.Dpy, _glfwWin.Saver.Timeout, + _glfwWin.Saver.Interval, _glfwWin.Saver.Blanking, + _glfwWin.Saver.Exposure ); + _glfwWin.Saver.Changed = GL_FALSE; + } + + XSync( _glfwLibrary.Dpy, True ); +} + + +//======================================================================== +// _glfwPlatformSetWindowTitle() - Set the window title. +//======================================================================== + +void _glfwPlatformSetWindowTitle( const char *title ) +{ + // Set window & icon title + XStoreName( _glfwLibrary.Dpy, _glfwWin.Win, title ); + XSetIconName( _glfwLibrary.Dpy, _glfwWin.Win, title ); +} + + +//======================================================================== +// _glfwPlatformSetWindowSize() - Set the window size. +//======================================================================== + +void _glfwPlatformSetWindowSize( int width, int height ) +{ + int mode = 0, rate, sizechanged = GL_FALSE; + GLint drawbuffer; + GLfloat clearcolor[4]; + + rate = _glfwWin.RefreshRate; + + // If we are in fullscreen mode, get some info about the current mode + if( _glfwWin.Fullscreen ) + { + // Get closest match for target video mode + mode = _glfwGetClosestVideoMode( _glfwWin.Scrn, &width, &height, &rate ); + } + + if( _glfwWin.WindowNoResize ) + { + _glfwWin.Hints->min_width = _glfwWin.Hints->max_width = width; + _glfwWin.Hints->min_height = _glfwWin.Hints->max_height = height; + } + + XSetWMNormalHints( _glfwLibrary.Dpy, _glfwWin.Win, _glfwWin.Hints ); + + // Change window size before changing fullscreen mode? + if( _glfwWin.Fullscreen && (width > _glfwWin.Width) ) + { + XResizeWindow( _glfwLibrary.Dpy, _glfwWin.Win, width, height ); + sizechanged = GL_TRUE; + } + + // Change fullscreen video mode? + if( _glfwWin.Fullscreen ) + { + // Change video mode (keeping current rate) + _glfwSetVideoModeMODE( _glfwWin.Scrn, mode, _glfwWin.RefreshRate ); + + // Clear the front buffer to black (avoid ugly desktop remains in + // our OpenGL window) + glGetIntegerv( GL_DRAW_BUFFER, &drawbuffer ); + glGetFloatv( GL_COLOR_CLEAR_VALUE, clearcolor ); + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); + glClear( GL_COLOR_BUFFER_BIT ); + if( drawbuffer == GL_BACK ) + { + glXSwapBuffers( _glfwLibrary.Dpy, _glfwWin.Win ); + } + glClearColor( clearcolor[0], clearcolor[1], clearcolor[2], + clearcolor[3] ); + } + + // Set window size (if not already changed) + if( !sizechanged ) + { + XResizeWindow( _glfwLibrary.Dpy, _glfwWin.Win, width, height ); + } +} + + +//======================================================================== +// _glfwPlatformSetWindowPos() - Set the window position. +//======================================================================== + +void _glfwPlatformSetWindowPos( int x, int y ) +{ + // Set window position + XMoveWindow( _glfwLibrary.Dpy, _glfwWin.Win, x, y ); +} + + +//======================================================================== +// _glfwPlatformIconfyWindow() - Window iconification +//======================================================================== + +void _glfwPlatformIconifyWindow( void ) +{ + // We can't do this for override redirect windows + if( _glfwWin.OverrideRedirect ) + { + return; + } + + // In fullscreen mode, we need to restore the desktop video mode + if( _glfwWin.Fullscreen ) + { +#if defined( _GLFW_HAS_XF86VIDMODE ) + if( _glfwLibrary.XF86VidMode.Available ) + { + // Unlock mode switch + XF86VidModeLockModeSwitch( _glfwLibrary.Dpy, + _glfwWin.Scrn, + 0 ); + + // Change the video mode back to the old mode + XF86VidModeSwitchToMode( _glfwLibrary.Dpy, + _glfwWin.Scrn, &_glfwWin.FS.OldMode ); + } +#endif + _glfwWin.FS.ModeChanged = GL_FALSE; + } + + // Show mouse pointer + if( _glfwWin.PointerHidden ) + { + XUndefineCursor( _glfwLibrary.Dpy, _glfwWin.Win ); + _glfwWin.PointerHidden = GL_FALSE; + } + + // Un-grab mouse pointer + if( _glfwWin.PointerGrabbed ) + { + XUngrabPointer( _glfwLibrary.Dpy, CurrentTime ); + _glfwWin.PointerGrabbed = GL_FALSE; + } + + // Iconify window + XIconifyWindow( _glfwLibrary.Dpy, _glfwWin.Win, + _glfwWin.Scrn ); + + // Window is now iconified + _glfwWin.Iconified = GL_TRUE; +} + + +//======================================================================== +// Window un-iconification +//======================================================================== + +void _glfwPlatformRestoreWindow( void ) +{ + // We can't do this for override redirect windows + if( _glfwWin.OverrideRedirect ) + { + return; + } + + // In fullscreen mode, change back video mode to user selected mode + if( _glfwWin.Fullscreen ) + { + _glfwSetVideoMode( _glfwWin.Scrn, + &_glfwWin.Width, &_glfwWin.Height, &_glfwWin.RefreshRate ); + } + + // Un-iconify window + XMapWindow( _glfwLibrary.Dpy, _glfwWin.Win ); + + // In fullscreen mode... + if( _glfwWin.Fullscreen ) + { + // Make sure window is in upper left corner + XMoveWindow( _glfwLibrary.Dpy, _glfwWin.Win, 0, 0 ); + + // Get input focus + XSetInputFocus( _glfwLibrary.Dpy, _glfwWin.Win, RevertToParent, + CurrentTime ); + } + + // Lock mouse, if necessary + if( _glfwWin.MouseLock ) + { + // Hide cursor + if( !_glfwWin.PointerHidden ) + { + XDefineCursor( _glfwLibrary.Dpy, _glfwWin.Win, + _glfwCreateNULLCursor( _glfwLibrary.Dpy, + _glfwWin.Win ) ); + _glfwWin.PointerHidden = GL_TRUE; + } + + // Grab cursor + if( !_glfwWin.PointerGrabbed ) + { + if( XGrabPointer( _glfwLibrary.Dpy, _glfwWin.Win, True, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask, GrabModeAsync, + GrabModeAsync, _glfwWin.Win, None, + CurrentTime ) == GrabSuccess ) + { + _glfwWin.PointerGrabbed = GL_TRUE; + } + } + } + + // Window is no longer iconified + _glfwWin.Iconified = GL_FALSE; +} + + +//======================================================================== +// _glfwPlatformSwapBuffers() - Swap buffers (double-buffering) and poll +// any new events. +//======================================================================== + +void _glfwPlatformSwapBuffers( void ) +{ + // Update display-buffer + glXSwapBuffers( _glfwLibrary.Dpy, _glfwWin.Win ); +} + + +//======================================================================== +// _glfwPlatformSwapInterval() - Set double buffering swap interval +//======================================================================== + +void _glfwPlatformSwapInterval( int interval ) +{ + if( _glfwWin.SwapInterval ) + { + _glfwWin.SwapInterval( interval ); + } +} + + +//======================================================================== +// _glfwPlatformRefreshWindowParams() +//======================================================================== + +void _glfwPlatformRefreshWindowParams( void ) +{ +#if defined( _GLFW_HAS_XRANDR ) + XRRScreenConfiguration *sc; +#elif defined( _GLFW_HAS_XF86VIDMODE ) + XF86VidModeModeLine modeline; + int dotclock; + float pixels_per_second, pixels_per_frame; +#endif + int sample_buffers; + + // AFAIK, there is no easy/sure way of knowing if OpenGL is hardware + // accelerated + _glfwWin.Accelerated = GL_TRUE; + + // "Standard" window parameters + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_RED_SIZE, + &_glfwWin.RedBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_GREEN_SIZE, + &_glfwWin.GreenBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_BLUE_SIZE, + &_glfwWin.BlueBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_ALPHA_SIZE, + &_glfwWin.AlphaBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_DEPTH_SIZE, + &_glfwWin.DepthBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_STENCIL_SIZE, + &_glfwWin.StencilBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_ACCUM_RED_SIZE, + &_glfwWin.AccumRedBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_ACCUM_GREEN_SIZE, + &_glfwWin.AccumGreenBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_ACCUM_BLUE_SIZE, + &_glfwWin.AccumBlueBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_ACCUM_ALPHA_SIZE, + &_glfwWin.AccumAlphaBits ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_AUX_BUFFERS, + &_glfwWin.AuxBuffers ); + + // Get stereo rendering setting + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_STEREO, + &_glfwWin.Stereo ); + _glfwWin.Stereo = _glfwWin.Stereo ? 1 : 0; + + // Get multisample buffer samples + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_SAMPLES, + &_glfwWin.Samples ); + glXGetConfig( _glfwLibrary.Dpy, _glfwWin.VI, GLX_SAMPLE_BUFFERS, + &sample_buffers ); + if( sample_buffers == 0 ) + _glfwWin.Samples = 0; + + // Default to refresh rate unknown (=0 according to GLFW spec) + _glfwWin.RefreshRate = 0; + + // Retrieve refresh rate, if possible +#if defined( _GLFW_HAS_XRANDR ) + if( _glfwLibrary.XRandR.Available ) + { + sc = XRRGetScreenInfo( _glfwLibrary.Dpy, + RootWindow( _glfwLibrary.Dpy, _glfwWin.Scrn ) ); + _glfwWin.RefreshRate = XRRConfigCurrentRate( sc ); + XRRFreeScreenConfigInfo( sc ); + } +#elif defined( _GLFW_HAS_XF86VIDMODE ) + if( _glfwLibrary.XF86VidMode.Available ) + { + // Use the XF86VidMode extension to get current video mode + XF86VidModeGetModeLine( _glfwLibrary.Dpy, _glfwWin.Scrn, + &dotclock, &modeline ); + pixels_per_second = 1000.0f * (float) dotclock; + pixels_per_frame = (float) modeline.htotal * modeline.vtotal; + _glfwWin.RefreshRate = (int)(pixels_per_second/pixels_per_frame+0.5); + } +#endif +} + + +//======================================================================== +// _glfwPlatformPollEvents() - Poll for new window and input events +//======================================================================== + +void _glfwPlatformPollEvents( void ) +{ + int winclosed = GL_FALSE; + + // Flag that the cursor has not moved + _glfwInput.MouseMoved = GL_FALSE; + + // Clear MapNotify and FocusIn counts + _glfwWin.MapNotifyCount = 0; + _glfwWin.FocusInCount = 0; + + // Use XSync to synchronise events to the X display. + // I don't know if this can have a serious performance impact. My + // benchmarks with a GeForce card under Linux shows no difference with + // or without XSync, but when the GL window is rendered over a slow + // network I have noticed bad event syncronisation problems when XSync + // is not used, so I decided to use it. + XSync( _glfwLibrary.Dpy, False ); + + // Empty the window event queue + while( XPending( _glfwLibrary.Dpy ) ) + { + if( _glfwGetNextEvent() ) + { + winclosed = GL_TRUE; + } + } + + // Did we get mouse movement in locked cursor mode? + if( _glfwInput.MouseMoved && _glfwWin.MouseLock ) + { + int maxx, minx, maxy, miny; + + // Calculate movement threshold + minx = _glfwWin.Width / 4; + maxx = (_glfwWin.Width * 3) / 4; + miny = _glfwWin.Height / 4; + maxy = (_glfwWin.Height * 3) / 4; + + // Did the mouse cursor move beyond our movement threshold + if(_glfwInput.CursorPosX < minx || _glfwInput.CursorPosX > maxx || + _glfwInput.CursorPosY < miny || _glfwInput.CursorPosY > maxy) + { + // Move the mouse pointer back to the window center so that it + // does not wander off... + _glfwPlatformSetMouseCursorPos( _glfwWin.Width/2, + _glfwWin.Height/2 ); + XSync( _glfwLibrary.Dpy, False ); + } + } + + // Was the window (un)iconified? + if( _glfwWin.MapNotifyCount < 0 && !_glfwWin.Iconified ) + { + // Show mouse pointer + if( _glfwWin.PointerHidden ) + { + XUndefineCursor( _glfwLibrary.Dpy, _glfwWin.Win ); + _glfwWin.PointerHidden = GL_FALSE; + } + + // Un-grab mouse pointer + if( _glfwWin.PointerGrabbed ) + { + XUngrabPointer( _glfwLibrary.Dpy, CurrentTime ); + _glfwWin.PointerGrabbed = GL_FALSE; + } + + _glfwWin.Iconified = GL_TRUE; + } + else if( _glfwWin.MapNotifyCount > 0 && _glfwWin.Iconified ) + { + // Restore fullscreen mode properties + if( _glfwWin.Fullscreen ) + { + // Change back video mode to user selected mode + _glfwSetVideoMode( _glfwWin.Scrn, &_glfwWin.Width, + &_glfwWin.Height, &_glfwWin.RefreshRate ); + + // Disable window manager decorations + _glfwEnableDecorations(); + + // Make sure window is in upper left corner + XMoveWindow( _glfwLibrary.Dpy, _glfwWin.Win, 0, 0 ); + + // Get input focus + XSetInputFocus( _glfwLibrary.Dpy, _glfwWin.Win, + RevertToParent, CurrentTime ); + } + + // Hide cursor if necessary + if( _glfwWin.MouseLock && !_glfwWin.PointerHidden ) + { + if( !_glfwWin.PointerHidden ) + { + XDefineCursor( _glfwLibrary.Dpy, _glfwWin.Win, + _glfwCreateNULLCursor( _glfwLibrary.Dpy, + _glfwWin.Win ) ); + _glfwWin.PointerHidden = GL_TRUE; + } + } + + // Grab cursor if necessary + if( (_glfwWin.MouseLock || _glfwWin.Fullscreen) && + !_glfwWin.PointerGrabbed ) + { + if( XGrabPointer( _glfwLibrary.Dpy, _glfwWin.Win, True, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask, GrabModeAsync, + GrabModeAsync, _glfwWin.Win, None, + CurrentTime ) == GrabSuccess ) + { + _glfwWin.PointerGrabbed = GL_TRUE; + } + } + + _glfwWin.Iconified = GL_FALSE; + } + + // Did the window get/lose focus + if( _glfwWin.FocusInCount > 0 && !_glfwWin.Active ) + { + // If we are in fullscreen mode, restore window + if( _glfwWin.Fullscreen && _glfwWin.Iconified ) + { + _glfwPlatformRestoreWindow(); + } + + // Window is now active + _glfwWin.Active = GL_TRUE; + } + else if( _glfwWin.FocusInCount < 0 && _glfwWin.Active ) + { + // If we are in fullscreen mode, iconfify window + if( _glfwWin.Fullscreen ) + { + _glfwPlatformIconifyWindow(); + } + + // Window is not active + _glfwWin.Active = GL_FALSE; + _glfwInputDeactivation(); + } + + // Was there a window close request? + if( winclosed && _glfwWin.WindowCloseCallback ) + { + // Check if the program wants us to close the window + winclosed = _glfwWin.WindowCloseCallback(); + } + if( winclosed ) + { + glfwCloseWindow(); + } +} + + +//======================================================================== +// _glfwPlatformWaitEvents() - Wait for new window and input events +//======================================================================== + +void _glfwPlatformWaitEvents( void ) +{ + XEvent event; + + // Wait for new events (blocking) + XNextEvent( _glfwLibrary.Dpy, &event ); + XPutBackEvent( _glfwLibrary.Dpy, &event ); + + // Poll events from queue + _glfwPlatformPollEvents(); +} + + +//======================================================================== +// _glfwPlatformHideMouseCursor() - Hide mouse cursor (lock it) +//======================================================================== + +void _glfwPlatformHideMouseCursor( void ) +{ + // Hide cursor + if( !_glfwWin.PointerHidden ) + { + XDefineCursor( _glfwLibrary.Dpy, _glfwWin.Win, + _glfwCreateNULLCursor( _glfwLibrary.Dpy, + _glfwWin.Win ) ); + _glfwWin.PointerHidden = GL_TRUE; + } + + // Grab cursor to user window + if( !_glfwWin.PointerGrabbed ) + { + if( XGrabPointer( _glfwLibrary.Dpy, _glfwWin.Win, True, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask, GrabModeAsync, GrabModeAsync, + _glfwWin.Win, None, CurrentTime ) == + GrabSuccess ) + { + _glfwWin.PointerGrabbed = GL_TRUE; + } + } +} + + +//======================================================================== +// _glfwPlatformShowMouseCursor() - Show mouse cursor (unlock it) +//======================================================================== + +void _glfwPlatformShowMouseCursor( void ) +{ + // Un-grab cursor (only in windowed mode: in fullscreen mode we still + // want the mouse grabbed in order to confine the cursor to the window + // area) + if( _glfwWin.PointerGrabbed && !_glfwWin.Fullscreen ) + { + XUngrabPointer( _glfwLibrary.Dpy, CurrentTime ); + _glfwWin.PointerGrabbed = GL_FALSE; + } + + // Show cursor + if( _glfwWin.PointerHidden ) + { + XUndefineCursor( _glfwLibrary.Dpy, _glfwWin.Win ); + _glfwWin.PointerHidden = GL_FALSE; + } +} + + +//======================================================================== +// _glfwPlatformSetMouseCursorPos() - Set physical mouse cursor position +//======================================================================== + +void _glfwPlatformSetMouseCursorPos( int x, int y ) +{ + // Change cursor position + _glfwInput.CursorPosX = x; + _glfwInput.CursorPosY = y; + XWarpPointer( _glfwLibrary.Dpy, None, _glfwWin.Win, 0,0,0,0, x, y ); +} + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..3d740f1 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,31 @@ +# find external software +find_package(OpenGL) + +# set includes +include_directories (${GREMLIN_SOURCE_DIR}/libs/glfw/include) +include_directories (${GREMLIN_SOURCE_DIR}/libs/enet/include) +include_directories (${GREMLIN_SOURCE_DIR}/src) + + +# define executable +add_executable( gremlin + main.cpp +) + +# set dependencies +add_dependencies( gremlin + glfw enet +) + +if (WIN32) + set(PLATFORM_LIBRARIES ws2_32 winmm) +endif(WIN32) + +if(UNIX) + set(PLATFORM_LIBRARIES GL X11 Xrandr -pthread) +endif(UNIX) + +target_link_libraries(gremlin + glfw enet ${OPENGL_LIBRARY} ${PLATFORM_LIBRARIES} +) + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..c8160a9 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,225 @@ +#include +#include +#include + +#include + +#define MAX_PLAYERS_PER_TEAM 8 +#define MAX_TEAMS 8 + +typedef struct _player { + unsigned int session; + double x, y, z; + double rx, ry, rz, rw; + double vx, vy, vz; +} player; + +typedef struct _team { + player players[MAX_PLAYERS_PER_TEAM]; + double x, y, z; + GLfloat color[4]; +} team; + + + + +GLUquadricObj *quadratic; + +void setup_opengl() +{ + // Initialise GLFW + if( !glfwInit() ) + { + fprintf( stderr, "Failed to initialize GLFW\n" ); + exit( EXIT_FAILURE ); + } + + // Open OpenGL window + if( !glfwOpenWindow( 640, 480, 0,0,0,0, 0,0, GLFW_FULLSCREEN ) ) + { + fprintf( stderr, "Failed to open GLFW window\n" ); + glfwTerminate(); + exit( EXIT_FAILURE ); + } + glfwDisable(GLFW_MOUSE_CURSOR); + glfwSetWindowTitle( "Trilinear interpolation" ); + + // Enable sticky keys + glfwEnable( GLFW_STICKY_KEYS ); + + // general settings + glShadeModel(GL_SMOOTH); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glEnable(GL_CULL_FACE); + + // setup depth buffer + glClearDepth(1.0f); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + + GLfloat LightAmbient[]= { 0.1f, 0.1f, 0.1f, 1.0f }; + GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f }; + GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 0.0f }; + + // setup directional light + glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); + glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); + glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); + glEnable(GL_LIGHT1); + glEnable(GL_LIGHTING); + + // Enable vertical sync (on cards that support it) + glfwSwapInterval( 1 ); +} + +void setup_team(team *team, size_t id) +{ + team->color[0] = 1.0f * (id+1 & (1 << 0)); + team->color[1] = 1.0f * (id+1 & (1 << 1)); + team->color[2] = 1.0f * (id+1 & (1 << 2)); + team->color[3] = 1.0f; + + team->x = 2000.0 * (id & (1 << 0)); + team->y = 2000.0 * (id & (1 << 1)); + team->z = 2000.0 * (id & (1 << 2)); + + size_t i = 0; + for (i = 0; i < MAX_PLAYERS_PER_TEAM; i++) + { + team->players[i].session = 0; + team->players[i].x = team->x + i * 50.; + team->players[i].y = team->y; + team->players[i].z = team->z; + team->players[i].vx = i * 5.; + team->players[i].vy = i * 5.; + team->players[i].vz = i * 5.; + } + +} + +void update_team(team *team, double dt) +{ + size_t i; + for (i = 0; i < MAX_PLAYERS_PER_TEAM; i++) + { + if (team->players[i].session == 0) + continue; + team->players[i].x += team->players[i].vx * dt; + team->players[i].y += team->players[i].vy * dt; + team->players[i].z += team->players[i].vz * dt; + } +} + +void draw_team(team *team) +{ + size_t i = 0; + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, team->color); + glMatrixMode( GL_MODELVIEW ); + + glPushMatrix(); + glTranslated(team->x, team->y, team->z); + gluSphere(quadratic,50.f,32,32); + glPopMatrix(); + + for (i = 0; i < MAX_PLAYERS_PER_TEAM; i++) + { + if (team->players[i].session == 0) + continue; + glPushMatrix(); + glTranslated(team->players[i].x, team->players[i].y, team->players[i].z); + gluSphere(quadratic,10.f,32,32); + glPopMatrix(); + } +} + +int main( void ) +{ + int width, height, x, y, last_x, last_y; + double time, last_time, phi = 0.0, theta = 0.0; + GLboolean running; + + quadratic = gluNewQuadric(); + gluQuadricNormals(quadratic, GLU_SMOOTH); + gluQuadricTexture(quadratic, GL_TRUE); + + team teams[MAX_TEAMS]; + + setup_opengl(); + + size_t i; + for (i = 0; i < MAX_TEAMS; i++) + setup_team(&teams[i], i); + + running = GL_TRUE; + last_time = glfwGetTime(); + glfwGetMousePos( &last_x, &last_y ); + while( running ) + { + // Get time and mouse position + time = glfwGetTime(); + glfwGetMousePos( &x, &y ); + phi += (x - last_x) * -0.001; + theta += (y - last_y) * 0.001; + if (theta > 1.5) + theta = 1.5; + if (theta < -1.5) + theta = -1.5; + last_x = x; + last_y = y; + + // Get window size (may be different than the requested size) + glfwGetWindowSize( &width, &height ); + height = height > 0 ? height : 1; + + // Set viewport + glViewport( 0, 0, width, height ); + + // Clear color buffer + glClearColor( 0.0f, 0.0f, 0.0f, 0.0f); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Select and setup the projection matrix + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( 60.0f, (GLfloat)width / (GLfloat)height, 1.0f, + 10000.0f ); + + // Select and setup the modelview matrix + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + gluLookAt( 100.0f, 100.0f, 100.0f, // Eye-position + 100.0f + cos(phi) * cos(theta) * 10.0f, 100.0f +sin(theta)*10.0f, 100.0f+ sin(phi)*cos(theta)*10.0f, // View-point + 0.0f, 1.0f, 0.0f ); // Up-vector + + // Draw a textured quad + glBegin( GL_QUADS ); + glVertex3f( -5000.0f, 5000.0f, -5000.0f ); + glVertex3f( 5000.0f, 5000.0f, -5000.0f ); + glVertex3f( 5000.0f, 5000.0f, 5000.0f ); + glVertex3f( -5000.0f, 5000.0f, 5000.0f ); + glEnd(); + + for (i = 0; i < MAX_TEAMS; i++) + update_team(&teams[i], time-last_time); + + for (i = 0; i < MAX_TEAMS; i++) + draw_team(&teams[i]); + + // Swap buffers + glfwSwapBuffers(); + + // Check if the ESC key was pressed or the window was closed + running = !glfwGetKey( GLFW_KEY_ESC ) && + glfwGetWindowParam( GLFW_OPENED ); + + last_time = time; + } + + gluDeleteQuadric(quadratic); + + // Close OpenGL window and terminate GLFW + glfwTerminate(); + + exit( EXIT_SUCCESS ); +} +