Merge branch 'raysan5:master' into test
This commit is contained in:
commit
b0ea362bcb
27 changed files with 20544 additions and 5252 deletions
21
src/Makefile
21
src/Makefile
|
|
@ -228,7 +228,6 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
|
|||
ifeq ($(ANDROID_ARCH),x86_64)
|
||||
ANDROID_COMPILER_ARCH = x86_64
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
# Define raylib graphics api depending on selected platform
|
||||
|
|
@ -261,17 +260,17 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_WIN32)
|
|||
#GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
|
||||
# On DRM OpenGL ES 2.0 must be used
|
||||
GRAPHICS = GRAPHICS_API_OPENGL_ES2
|
||||
GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
|
||||
# On HTML5 OpenGL ES 2.0 is used, emscripten translates it to WebGL 1.0
|
||||
GRAPHICS = GRAPHICS_API_OPENGL_ES2
|
||||
GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
|
||||
#GRAPHICS = GRAPHICS_API_OPENGL_ES3
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
|
||||
# By default use OpenGL ES 2.0 on Android
|
||||
GRAPHICS = GRAPHICS_API_OPENGL_ES2
|
||||
GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
|
||||
endif
|
||||
|
||||
# Define default C compiler and archiver to pack library: CC, AR
|
||||
|
|
@ -407,7 +406,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
|
|||
CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16
|
||||
endif
|
||||
ifeq ($(ANDROID_ARCH),arm64)
|
||||
CFLAGS += -target aarch64 -mfix-cortex-a53-835769
|
||||
CFLAGS += -mfix-cortex-a53-835769
|
||||
endif
|
||||
ifeq ($(ANDROID_ARCH),x86)
|
||||
CFLAGS += -march=i686
|
||||
|
|
@ -636,13 +635,19 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW)
|
|||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
|
||||
LDLIBS = -lGLESv2 -lEGL -ldrm -lgbm -lpthread -lrt -lm -ldl
|
||||
LDLIBS = -ldrm -lgbm -lpthread -lrt -lm -ldl
|
||||
ifeq ($(GRAPHICS),GRAPHICS_API_OPENGL_ES2)
|
||||
LDLIBS += -lGLESv2 -lEGL
|
||||
endif
|
||||
ifeq ($(RAYLIB_MODULE_AUDIO),TRUE)
|
||||
LDLIBS += -latomic
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_WIN32)
|
||||
LDLIBS = -lgdi32 -lwinmm -lopengl32 -lshcore
|
||||
LDLIBS = -lgdi32 -lwinmm -lshcore
|
||||
ifneq ($(GRAPHICS),GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
LDLIBS += -lopengl32
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
|
||||
LDLIBS = -llog -landroid -lEGL -lGLESv2 -lOpenSLES -lc -lm
|
||||
|
|
|
|||
13
src/config.h
13
src/config.h
|
|
@ -49,19 +49,18 @@
|
|||
#define SUPPORT_RPRAND_GENERATOR 1
|
||||
// Mouse gestures are directly mapped like touches and processed by gestures system
|
||||
#define SUPPORT_MOUSE_GESTURES 1
|
||||
// Reconfigure standard input to receive key inputs, works with SSH connection.
|
||||
// Reconfigure standard input to receive key inputs, works with SSH connection
|
||||
#define SUPPORT_SSH_KEYBOARD_RPI 1
|
||||
// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions.
|
||||
// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
|
||||
// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions
|
||||
// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often
|
||||
#define SUPPORT_WINMM_HIGHRES_TIMER 1
|
||||
// Use busy wait loop for timing sync, if not defined, a high-resolution timer is set up and used
|
||||
//#define SUPPORT_BUSY_WAIT_LOOP 1
|
||||
// Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy
|
||||
#define SUPPORT_PARTIALBUSY_WAIT_LOOP 1
|
||||
// Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
|
||||
// WARNING: It also requires SUPPORT_IMAGE_EXPORT and SUPPORT_FILEFORMAT_PNG flags
|
||||
#define SUPPORT_SCREEN_CAPTURE 1
|
||||
// Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()
|
||||
#define SUPPORT_GIF_RECORDING 1
|
||||
// Support CompressData() and DecompressData() functions
|
||||
#define SUPPORT_COMPRESSION_API 1
|
||||
// Support automatic generated events, loading and recording of those events when required
|
||||
|
|
@ -76,7 +75,7 @@
|
|||
#define SUPPORT_CLIPBOARD_IMAGE 1
|
||||
|
||||
// NOTE: Clipboard image loading requires support for some image file formats
|
||||
// TODO: Those defines should probably be removed from here, I prefer to let the user manage them
|
||||
// TODO: Those defines should probably be removed from here, letting the user manage them
|
||||
#if defined(SUPPORT_CLIPBOARD_IMAGE)
|
||||
#ifndef SUPPORT_MODULE_RTEXTURES
|
||||
#define SUPPORT_MODULE_RTEXTURES 1
|
||||
|
|
@ -226,7 +225,7 @@
|
|||
|
||||
// On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle
|
||||
// at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow
|
||||
// drawing text and shapes with a single draw call [SetShapesTexture()].
|
||||
// drawing text and shapes with a single draw call [SetShapesTexture()]
|
||||
#define SUPPORT_FONT_ATLAS_WHITE_REC 1
|
||||
|
||||
// Support conservative font atlas size estimation
|
||||
|
|
|
|||
717
src/external/msf_gif.h
vendored
717
src/external/msf_gif.h
vendored
|
|
@ -1,717 +0,0 @@
|
|||
/*
|
||||
HOW TO USE:
|
||||
|
||||
In exactly one translation unit (.c or .cpp file), #define MSF_GIF_IMPL before including the header, like so:
|
||||
|
||||
#define MSF_GIF_IMPL
|
||||
#include "msf_gif.h"
|
||||
|
||||
Everywhere else, just include the header like normal.
|
||||
|
||||
|
||||
USAGE EXAMPLE:
|
||||
|
||||
int width = 480, height = 320, centisecondsPerFrame = 5, bitDepth = 16;
|
||||
MsfGifState gifState = {};
|
||||
// msf_gif_bgra_flag = true; //optionally, set this flag if your pixels are in BGRA format instead of RGBA
|
||||
// msf_gif_alpha_threshold = 128; //optionally, enable transparency (see function documentation below for details)
|
||||
msf_gif_begin(&gifState, width, height);
|
||||
msf_gif_frame(&gifState, ..., centisecondsPerFrame, bitDepth, width * 4); //frame 1
|
||||
msf_gif_frame(&gifState, ..., centisecondsPerFrame, bitDepth, width * 4); //frame 2
|
||||
msf_gif_frame(&gifState, ..., centisecondsPerFrame, bitDepth, width * 4); //frame 3, etc...
|
||||
MsfGifResult result = msf_gif_end(&gifState);
|
||||
if (result.data) {
|
||||
FILE * fp = fopen("MyGif.gif", "wb");
|
||||
fwrite(result.data, result.dataSize, 1, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
msf_gif_free(result);
|
||||
|
||||
Detailed function documentation can be found in the header section below.
|
||||
|
||||
|
||||
ERROR HANDLING:
|
||||
|
||||
If memory allocation fails, the functions will signal the error via their return values.
|
||||
If one function call fails, the library will free all of its allocations,
|
||||
and all subsequent calls will safely no-op and return 0 until the next call to `msf_gif_begin()`.
|
||||
Therefore, it's safe to check only the return value of `msf_gif_end()`.
|
||||
|
||||
|
||||
REPLACING MALLOC:
|
||||
|
||||
This library uses malloc+realloc+free internally for memory allocation.
|
||||
To facilitate integration with custom memory allocators, these calls go through macros, which can be redefined.
|
||||
The expected function signature equivalents of the macros are as follows:
|
||||
|
||||
void * MSF_GIF_MALLOC(void * context, size_t newSize)
|
||||
void * MSF_GIF_REALLOC(void * context, void * oldMemory, size_t oldSize, size_t newSize)
|
||||
void MSF_GIF_FREE(void * context, void * oldMemory, size_t oldSize)
|
||||
|
||||
If your allocator needs a context pointer, you can set the `customAllocatorContext` field of the MsfGifState struct
|
||||
before calling msf_gif_begin(), and it will be passed to all subsequent allocator macro calls.
|
||||
|
||||
The maximum number of bytes the library will allocate to encode a single gif is bounded by the following formula:
|
||||
`(2 * 1024 * 1024) + (width * height * 8) + ((1024 + width * height * 1.5) * 3 * frameCount)`
|
||||
The peak heap memory usage in bytes, if using a general-purpose heap allocator, is bounded by the following formula:
|
||||
`(2 * 1024 * 1024) + (width * height * 9.5) + 1024 + (16 * frameCount) + (2 * sizeOfResultingGif)
|
||||
|
||||
|
||||
See end of file for license information.
|
||||
*/
|
||||
|
||||
//version 2.2
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// HEADER ///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef MSF_GIF_H
|
||||
#define MSF_GIF_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct {
|
||||
void * data;
|
||||
size_t dataSize;
|
||||
|
||||
size_t allocSize; //internal use
|
||||
void * contextPointer; //internal use
|
||||
} MsfGifResult;
|
||||
|
||||
typedef struct { //internal use
|
||||
uint32_t * pixels;
|
||||
int depth, count, rbits, gbits, bbits;
|
||||
} MsfCookedFrame;
|
||||
|
||||
typedef struct MsfGifBuffer {
|
||||
struct MsfGifBuffer * next;
|
||||
size_t size;
|
||||
uint8_t data[1];
|
||||
} MsfGifBuffer;
|
||||
|
||||
typedef size_t (* MsfGifFileWriteFunc) (const void * buffer, size_t size, size_t count, void * stream);
|
||||
typedef struct {
|
||||
MsfGifFileWriteFunc fileWriteFunc;
|
||||
void * fileWriteData;
|
||||
MsfCookedFrame previousFrame;
|
||||
MsfCookedFrame currentFrame;
|
||||
int16_t * lzwMem;
|
||||
MsfGifBuffer * listHead;
|
||||
MsfGifBuffer * listTail;
|
||||
int width, height;
|
||||
void * customAllocatorContext;
|
||||
int framesSubmitted; //needed for transparency to work correctly (because we reach into the previous frame)
|
||||
} MsfGifState;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif //__cplusplus
|
||||
|
||||
/**
|
||||
* @param width Image width in pixels.
|
||||
* @param height Image height in pixels.
|
||||
* @return Non-zero on success, 0 on error.
|
||||
*/
|
||||
int msf_gif_begin(MsfGifState * handle, int width, int height);
|
||||
|
||||
/**
|
||||
* @param pixelData Pointer to raw framebuffer data. Rows must be contiguous in memory, in RGBA8 format
|
||||
* (or BGRA8 if you have set `msf_gif_bgra_flag = true`).
|
||||
* Note: This function does NOT free `pixelData`. You must free it yourself afterwards.
|
||||
* @param centiSecondsPerFrame How many hundredths of a second this frame should be displayed for.
|
||||
* Note: This being specified in centiseconds is a limitation of the GIF format.
|
||||
* @param maxBitDepth Limits how many bits per pixel can be used when quantizing the gif.
|
||||
* The actual bit depth chosen for a given frame will be less than or equal to
|
||||
* the supplied maximum, depending on the variety of colors used in the frame.
|
||||
* `maxBitDepth` will be clamped between 1 and 16. The recommended default is 16.
|
||||
* Lowering this value can result in faster exports and smaller gifs,
|
||||
* but the quality may suffer.
|
||||
* Please experiment with this value to find what works best for your application.
|
||||
* @param pitchInBytes The number of bytes from the beginning of one row of pixels to the beginning of the next.
|
||||
* If you want to flip the image, just pass in a negative pitch.
|
||||
* @return Non-zero on success, 0 on error.
|
||||
*/
|
||||
int msf_gif_frame(MsfGifState * handle, uint8_t * pixelData, int centiSecondsPerFame, int maxBitDepth, int pitchInBytes);
|
||||
|
||||
/**
|
||||
* @return A block of memory containing the gif file data, or NULL on error.
|
||||
* You are responsible for freeing this via `msf_gif_free()`.
|
||||
*/
|
||||
MsfGifResult msf_gif_end(MsfGifState * handle);
|
||||
|
||||
/**
|
||||
* @param result The MsfGifResult struct, verbatim as it was returned from `msf_gif_end()`.
|
||||
*/
|
||||
void msf_gif_free(MsfGifResult result);
|
||||
|
||||
//The gif format only supports 1-bit transparency, meaning a pixel will either be fully transparent or fully opaque.
|
||||
//Pixels with an alpha value less than the alpha threshold will be treated as transparent.
|
||||
//To enable exporting transparent gifs, set it to a value between 1 and 255 (inclusive) before calling msf_gif_frame().
|
||||
//Setting it to 0 causes the alpha channel to be ignored. Its initial value is 0.
|
||||
extern int msf_gif_alpha_threshold;
|
||||
|
||||
//Set `msf_gif_bgra_flag = true` before calling `msf_gif_frame()` if your pixels are in BGRA byte order instead of RBGA.
|
||||
extern int msf_gif_bgra_flag;
|
||||
|
||||
|
||||
|
||||
//TO-FILE FUNCTIONS
|
||||
//These functions are equivalent to the ones above, but they write results to a file incrementally,
|
||||
//instead of building a buffer in memory. This can result in lower memory usage when saving large gifs,
|
||||
//because memory usage is bounded by only the size of a single frame, and is not dependent on the number of frames.
|
||||
//There is currently no reason to use these unless you are on a memory-constrained platform.
|
||||
//If in doubt about which API to use, for now you should use the normal (non-file) functions above.
|
||||
//The signature of MsfGifFileWriteFunc matches fwrite for convenience, so that you can use the C file API like so:
|
||||
// FILE * fp = fopen("MyGif.gif", "wb");
|
||||
// msf_gif_begin_to_file(&handle, width, height, (MsfGifFileWriteFunc) fwrite, (void *) fp);
|
||||
// msf_gif_frame_to_file(...)
|
||||
// msf_gif_end_to_file(&handle);
|
||||
// fclose(fp);
|
||||
//If you use a custom file write function, you must take care to return the same values that fwrite() would return.
|
||||
//Note that all three functions will potentially write to the file.
|
||||
int msf_gif_begin_to_file(MsfGifState * handle, int width, int height, MsfGifFileWriteFunc func, void * filePointer);
|
||||
int msf_gif_frame_to_file(MsfGifState * handle, uint8_t * pixelData, int centiSecondsPerFame, int maxBitDepth, int pitchInBytes);
|
||||
int msf_gif_end_to_file(MsfGifState * handle); //returns 0 on error and non-zero on success
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
||||
|
||||
#endif //MSF_GIF_H
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// IMPLEMENTATION ///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef MSF_GIF_IMPL
|
||||
#ifndef MSF_GIF_ALREADY_IMPLEMENTED_IN_THIS_TRANSLATION_UNIT
|
||||
#define MSF_GIF_ALREADY_IMPLEMENTED_IN_THIS_TRANSLATION_UNIT
|
||||
|
||||
//ensure the library user has either defined all of malloc/realloc/free, or none
|
||||
#if defined(MSF_GIF_MALLOC) && defined(MSF_GIF_REALLOC) && defined(MSF_GIF_FREE) //ok
|
||||
#elif !defined(MSF_GIF_MALLOC) && !defined(MSF_GIF_REALLOC) && !defined(MSF_GIF_FREE) //ok
|
||||
#else
|
||||
#error "You must either define all of MSF_GIF_MALLOC, MSF_GIF_REALLOC, and MSF_GIF_FREE, or define none of them"
|
||||
#endif
|
||||
|
||||
//provide default allocator definitions that redirect to the standard global allocator
|
||||
#if !defined(MSF_GIF_MALLOC)
|
||||
#include <stdlib.h> //malloc, etc.
|
||||
#define MSF_GIF_MALLOC(contextPointer, newSize) malloc(newSize)
|
||||
#define MSF_GIF_REALLOC(contextPointer, oldMemory, oldSize, newSize) realloc(oldMemory, newSize)
|
||||
#define MSF_GIF_FREE(contextPointer, oldMemory, oldSize) free(oldMemory)
|
||||
#endif
|
||||
|
||||
//instrumentation for capturing profiling traces (useless for the library user, but useful for the library author)
|
||||
#ifdef MSF_GIF_ENABLE_TRACING
|
||||
#define MsfTimeFunc TimeFunc
|
||||
#define MsfTimeLoop TimeLoop
|
||||
#define msf_init_profiling_thread init_profiling_thread
|
||||
#else
|
||||
#define MsfTimeFunc
|
||||
#define MsfTimeLoop(name)
|
||||
#define msf_init_profiling_thread()
|
||||
#endif //MSF_GIF_ENABLE_TRACING
|
||||
|
||||
#include <string.h> //memcpy
|
||||
|
||||
//TODO: use compiler-specific notation to force-inline functions currently marked inline
|
||||
#if defined(__GNUC__) //gcc, clang
|
||||
static inline int msf_bit_log(int i) { return 32 - __builtin_clz(i); }
|
||||
#elif defined(_MSC_VER) //msvc
|
||||
#include <intrin.h>
|
||||
static inline int msf_bit_log(int i) { unsigned long idx; _BitScanReverse(&idx, i); return idx + 1; }
|
||||
#else //fallback implementation for other compilers
|
||||
//from https://stackoverflow.com/a/31718095/3064745 - thanks!
|
||||
static inline int msf_bit_log(int i) {
|
||||
static const int MultiplyDeBruijnBitPosition[32] = {
|
||||
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
|
||||
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31,
|
||||
};
|
||||
i |= i >> 1;
|
||||
i |= i >> 2;
|
||||
i |= i >> 4;
|
||||
i |= i >> 8;
|
||||
i |= i >> 16;
|
||||
return MultiplyDeBruijnBitPosition[(uint32_t)(i * 0x07C4ACDDU) >> 27] + 1;
|
||||
}
|
||||
#endif
|
||||
static inline int msf_imin(int a, int b) { return a < b? a : b; }
|
||||
static inline int msf_imax(int a, int b) { return b < a? a : b; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Frame Cooking ///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if (defined (__SSE2__) || defined (_M_X64) || _M_IX86_FP == 2) && !defined(MSF_GIF_NO_SSE2)
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
int msf_gif_alpha_threshold = 0;
|
||||
int msf_gif_bgra_flag = 0;
|
||||
|
||||
static void msf_cook_frame(MsfCookedFrame * frame, uint8_t * raw, uint8_t * used,
|
||||
int width, int height, int pitch, int depth)
|
||||
{ MsfTimeFunc
|
||||
//bit depth for each channel
|
||||
static const int rdepthsArray[17] = { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5 };
|
||||
static const int gdepthsArray[17] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6 };
|
||||
static const int bdepthsArray[17] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5 };
|
||||
//this extra level of indirection looks unnecessary but we need to explicitly decay the arrays to pointers
|
||||
//in order to be able to swap them because of C's annoying not-quite-pointers, not-quite-value-types stack arrays.
|
||||
const int * rdepths = msf_gif_bgra_flag? bdepthsArray : rdepthsArray;
|
||||
const int * gdepths = gdepthsArray;
|
||||
const int * bdepths = msf_gif_bgra_flag? rdepthsArray : bdepthsArray;
|
||||
|
||||
static const int ditherKernel[16] = {
|
||||
0 << 12, 8 << 12, 2 << 12, 10 << 12,
|
||||
12 << 12, 4 << 12, 14 << 12, 6 << 12,
|
||||
3 << 12, 11 << 12, 1 << 12, 9 << 12,
|
||||
15 << 12, 7 << 12, 13 << 12, 5 << 12,
|
||||
};
|
||||
|
||||
uint32_t * cooked = frame->pixels;
|
||||
int count = 0;
|
||||
MsfTimeLoop("do") do {
|
||||
int rbits = rdepths[depth], gbits = gdepths[depth], bbits = bdepths[depth];
|
||||
int paletteSize = (1 << (rbits + gbits + bbits)) + 1;
|
||||
memset(used, 0, paletteSize * sizeof(uint8_t));
|
||||
|
||||
//TODO: document what this math does and why it's correct
|
||||
int rdiff = (1 << (8 - rbits)) - 1;
|
||||
int gdiff = (1 << (8 - gbits)) - 1;
|
||||
int bdiff = (1 << (8 - bbits)) - 1;
|
||||
short rmul = (short) ((255.0f - rdiff) / 255.0f * 257);
|
||||
short gmul = (short) ((255.0f - gdiff) / 255.0f * 257);
|
||||
short bmul = (short) ((255.0f - bdiff) / 255.0f * 257);
|
||||
|
||||
int gmask = ((1 << gbits) - 1) << rbits;
|
||||
int bmask = ((1 << bbits) - 1) << rbits << gbits;
|
||||
|
||||
MsfTimeLoop("cook") for (int y = 0; y < height; ++y) {
|
||||
int x = 0;
|
||||
|
||||
#if (defined (__SSE2__) || defined (_M_X64) || _M_IX86_FP == 2) && !defined(MSF_GIF_NO_SSE2)
|
||||
__m128i k = _mm_loadu_si128((__m128i *) &ditherKernel[(y & 3) * 4]);
|
||||
__m128i k2 = _mm_or_si128(_mm_srli_epi32(k, rbits), _mm_slli_epi32(_mm_srli_epi32(k, bbits), 16));
|
||||
for (; x < width - 3; x += 4) {
|
||||
uint8_t * pixels = &raw[y * pitch + x * 4];
|
||||
__m128i p = _mm_loadu_si128((__m128i *) pixels);
|
||||
|
||||
__m128i rb = _mm_and_si128(p, _mm_set1_epi32(0x00FF00FF));
|
||||
__m128i rb1 = _mm_mullo_epi16(rb, _mm_set_epi16(bmul, rmul, bmul, rmul, bmul, rmul, bmul, rmul));
|
||||
__m128i rb2 = _mm_adds_epu16(rb1, k2);
|
||||
__m128i r3 = _mm_srli_epi32(_mm_and_si128(rb2, _mm_set1_epi32(0x0000FFFF)), 16 - rbits);
|
||||
__m128i b3 = _mm_and_si128(_mm_srli_epi32(rb2, 32 - rbits - gbits - bbits), _mm_set1_epi32(bmask));
|
||||
|
||||
__m128i g = _mm_and_si128(_mm_srli_epi32(p, 8), _mm_set1_epi32(0x000000FF));
|
||||
__m128i g1 = _mm_mullo_epi16(g, _mm_set1_epi32(gmul));
|
||||
__m128i g2 = _mm_adds_epu16(g1, _mm_srli_epi32(k, gbits));
|
||||
__m128i g3 = _mm_and_si128(_mm_srli_epi32(g2, 16 - rbits - gbits), _mm_set1_epi32(gmask));
|
||||
|
||||
__m128i out = _mm_or_si128(_mm_or_si128(r3, g3), b3);
|
||||
|
||||
//mask in transparency based on threshold
|
||||
//NOTE: we can theoretically do a sub instead of srli by doing an unsigned compare via bias
|
||||
// to maybe save a TINY amount of throughput? but lol who cares maybe I'll do it later -m
|
||||
__m128i invAlphaMask = _mm_cmplt_epi32(_mm_srli_epi32(p, 24), _mm_set1_epi32(msf_gif_alpha_threshold));
|
||||
out = _mm_or_si128(_mm_and_si128(invAlphaMask, _mm_set1_epi32(paletteSize - 1)), _mm_andnot_si128(invAlphaMask, out));
|
||||
|
||||
//TODO: does storing this as a __m128i then reading it back as a uint32_t violate strict aliasing?
|
||||
uint32_t * c = &cooked[y * width + x];
|
||||
_mm_storeu_si128((__m128i *) c, out);
|
||||
}
|
||||
#endif
|
||||
|
||||
//scalar cleanup loop
|
||||
for (; x < width; ++x) {
|
||||
uint8_t * p = &raw[y * pitch + x * 4];
|
||||
|
||||
//transparent pixel if alpha is low
|
||||
if (p[3] < msf_gif_alpha_threshold) {
|
||||
cooked[y * width + x] = paletteSize - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
int dx = x & 3, dy = y & 3;
|
||||
int k = ditherKernel[dy * 4 + dx];
|
||||
cooked[y * width + x] =
|
||||
(msf_imin(65535, p[2] * bmul + (k >> bbits)) >> (16 - rbits - gbits - bbits) & bmask) |
|
||||
(msf_imin(65535, p[1] * gmul + (k >> gbits)) >> (16 - rbits - gbits ) & gmask) |
|
||||
msf_imin(65535, p[0] * rmul + (k >> rbits)) >> (16 - rbits );
|
||||
}
|
||||
}
|
||||
|
||||
count = 0;
|
||||
MsfTimeLoop("mark") for (int i = 0; i < width * height; ++i) {
|
||||
used[cooked[i]] = 1;
|
||||
}
|
||||
|
||||
//count used colors, transparent is ignored
|
||||
MsfTimeLoop("count") for (int j = 0; j < paletteSize - 1; ++j) {
|
||||
count += used[j];
|
||||
}
|
||||
} while (count >= 256 && --depth);
|
||||
|
||||
MsfCookedFrame ret = { cooked, depth, count, rdepths[depth], gdepths[depth], bdepths[depth] };
|
||||
*frame = ret;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Frame Compression ///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline void msf_put_code(uint8_t * * writeHead, uint32_t * blockBits, int len, uint32_t code) {
|
||||
//insert new code into block buffer
|
||||
int idx = *blockBits / 8;
|
||||
int bit = *blockBits % 8;
|
||||
(*writeHead)[idx + 0] |= code << bit ;
|
||||
(*writeHead)[idx + 1] |= code >> ( 8 - bit);
|
||||
(*writeHead)[idx + 2] |= code >> (16 - bit);
|
||||
*blockBits += len;
|
||||
|
||||
//prep the next block buffer if the current one is full
|
||||
if (*blockBits >= 256 * 8) {
|
||||
*blockBits -= 255 * 8;
|
||||
(*writeHead) += 256;
|
||||
(*writeHead)[2] = (*writeHead)[1];
|
||||
(*writeHead)[1] = (*writeHead)[0];
|
||||
(*writeHead)[0] = 255;
|
||||
memset((*writeHead) + 4, 0, 256);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int16_t * data;
|
||||
int len;
|
||||
int stride;
|
||||
} MsfStridedList;
|
||||
|
||||
static inline void msf_lzw_reset(MsfStridedList * lzw, int tableSize, int stride) { MsfTimeFunc
|
||||
memset(lzw->data, 0xFF, 4096 * stride * sizeof(int16_t));
|
||||
lzw->len = tableSize + 2;
|
||||
lzw->stride = stride;
|
||||
}
|
||||
|
||||
static MsfGifBuffer * msf_compress_frame(void * allocContext, int width, int height, int centiSeconds,
|
||||
MsfCookedFrame frame, MsfGifState * handle, uint8_t * used, int16_t * lzwMem)
|
||||
{ MsfTimeFunc
|
||||
//NOTE: we reserve enough memory for theoretical the worst case upfront because it's a reasonable amount,
|
||||
// and prevents us from ever having to check size or realloc during compression
|
||||
int maxBufSize = offsetof(MsfGifBuffer, data) + 32 + 256 * 3 + width * height * 3 / 2; //headers + color table + data
|
||||
MsfGifBuffer * buffer = (MsfGifBuffer *) MSF_GIF_MALLOC(allocContext, maxBufSize);
|
||||
if (!buffer) { return NULL; }
|
||||
uint8_t * writeHead = buffer->data;
|
||||
MsfStridedList lzw = { lzwMem, 0, 0 };
|
||||
|
||||
//allocate tlb
|
||||
int totalBits = frame.rbits + frame.gbits + frame.bbits;
|
||||
int tlbSize = (1 << totalBits) + 1;
|
||||
uint8_t tlb[(1 << 16) + 1]; //only 64k, so stack allocating is fine
|
||||
|
||||
//generate palette
|
||||
typedef struct { uint8_t r, g, b; } Color3;
|
||||
Color3 table[256] = { {0} };
|
||||
int tableIdx = 1; //we start counting at 1 because 0 is the transparent color
|
||||
//transparent is always last in the table
|
||||
tlb[tlbSize-1] = 0;
|
||||
MsfTimeLoop("table") for (int i = 0; i < tlbSize-1; ++i) {
|
||||
if (used[i]) {
|
||||
tlb[i] = tableIdx;
|
||||
int rmask = (1 << frame.rbits) - 1;
|
||||
int gmask = (1 << frame.gbits) - 1;
|
||||
//isolate components
|
||||
int r = i & rmask;
|
||||
int g = i >> frame.rbits & gmask;
|
||||
int b = i >> (frame.rbits + frame.gbits);
|
||||
//shift into highest bits
|
||||
r <<= 8 - frame.rbits;
|
||||
g <<= 8 - frame.gbits;
|
||||
b <<= 8 - frame.bbits;
|
||||
table[tableIdx].r = r | r >> frame.rbits | r >> (frame.rbits * 2) | r >> (frame.rbits * 3);
|
||||
table[tableIdx].g = g | g >> frame.gbits | g >> (frame.gbits * 2) | g >> (frame.gbits * 3);
|
||||
table[tableIdx].b = b | b >> frame.bbits | b >> (frame.bbits * 2) | b >> (frame.bbits * 3);
|
||||
if (msf_gif_bgra_flag) {
|
||||
uint8_t temp = table[tableIdx].r;
|
||||
table[tableIdx].r = table[tableIdx].b;
|
||||
table[tableIdx].b = temp;
|
||||
}
|
||||
++tableIdx;
|
||||
}
|
||||
}
|
||||
int hasTransparentPixels = used[tlbSize-1];
|
||||
|
||||
//SPEC: "Because of some algorithmic constraints however, black & white images which have one color bit
|
||||
// must be indicated as having a code size of 2."
|
||||
int tableBits = msf_imax(2, msf_bit_log(tableIdx - 1));
|
||||
int tableSize = 1 << tableBits;
|
||||
//NOTE: we don't just compare `depth` field here because it will be wrong for the first frame and we will segfault
|
||||
MsfCookedFrame previous = handle->previousFrame;
|
||||
int hasSamePal = frame.rbits == previous.rbits && frame.gbits == previous.gbits && frame.bbits == previous.bbits;
|
||||
int framesCompatible = hasSamePal && !hasTransparentPixels;
|
||||
|
||||
//NOTE: because __attribute__((__packed__)) is annoyingly compiler-specific, we do this unreadable weirdness
|
||||
char headerBytes[19] = "\x21\xF9\x04\x05\0\0\0\0" "\x2C\0\0\0\0\0\0\0\0\x80";
|
||||
//NOTE: we need to check the frame number because if we reach into the buffer prior to the first frame,
|
||||
// we'll just clobber the file header instead, which is a bug
|
||||
if (hasTransparentPixels && handle->framesSubmitted > 0) {
|
||||
handle->listTail->data[3] = 0x09; //set the previous frame's disposal to background, so transparency is possible
|
||||
}
|
||||
memcpy(&headerBytes[4], ¢iSeconds, 2);
|
||||
memcpy(&headerBytes[13], &width, 2);
|
||||
memcpy(&headerBytes[15], &height, 2);
|
||||
headerBytes[17] |= tableBits - 1;
|
||||
memcpy(writeHead, headerBytes, 18);
|
||||
writeHead += 18;
|
||||
|
||||
//local color table
|
||||
memcpy(writeHead, table, tableSize * sizeof(Color3));
|
||||
writeHead += tableSize * sizeof(Color3);
|
||||
*writeHead++ = tableBits;
|
||||
|
||||
//prep block
|
||||
memset(writeHead, 0, 260);
|
||||
writeHead[0] = 255;
|
||||
uint32_t blockBits = 8; //relative to block.head
|
||||
|
||||
//SPEC: "Encoders should output a Clear code as the first code of each image data stream."
|
||||
msf_lzw_reset(&lzw, tableSize, tableIdx);
|
||||
msf_put_code(&writeHead, &blockBits, msf_bit_log(lzw.len - 1), tableSize);
|
||||
|
||||
int lastCode = framesCompatible && frame.pixels[0] == previous.pixels[0]? 0 : tlb[frame.pixels[0]];
|
||||
MsfTimeLoop("compress") for (int i = 1; i < width * height; ++i) {
|
||||
//PERF: branching vs. branchless version of this line is observed to have no discernable impact on speed
|
||||
int color = framesCompatible && frame.pixels[i] == previous.pixels[i]? 0 : tlb[frame.pixels[i]];
|
||||
int code = (&lzw.data[lastCode * lzw.stride])[color];
|
||||
if (code < 0) {
|
||||
//write to code stream
|
||||
int codeBits = msf_bit_log(lzw.len - 1);
|
||||
msf_put_code(&writeHead, &blockBits, codeBits, lastCode);
|
||||
|
||||
if (lzw.len > 4095) {
|
||||
//reset buffer code table
|
||||
msf_put_code(&writeHead, &blockBits, codeBits, tableSize);
|
||||
msf_lzw_reset(&lzw, tableSize, tableIdx);
|
||||
} else {
|
||||
(&lzw.data[lastCode * lzw.stride])[color] = lzw.len;
|
||||
++lzw.len;
|
||||
}
|
||||
|
||||
lastCode = color;
|
||||
} else {
|
||||
lastCode = code;
|
||||
}
|
||||
}
|
||||
|
||||
//write code for leftover index buffer contents, then the end code
|
||||
msf_put_code(&writeHead, &blockBits, msf_imin(12, msf_bit_log(lzw.len - 1)), lastCode);
|
||||
msf_put_code(&writeHead, &blockBits, msf_imin(12, msf_bit_log(lzw.len)), tableSize + 1);
|
||||
|
||||
//flush remaining data
|
||||
if (blockBits > 8) {
|
||||
int bytes = (blockBits + 7) / 8; //round up
|
||||
writeHead[0] = bytes - 1;
|
||||
writeHead += bytes;
|
||||
}
|
||||
*writeHead++ = 0; //terminating block
|
||||
|
||||
//fill in buffer header and shrink buffer to fit data
|
||||
buffer->next = NULL;
|
||||
buffer->size = writeHead - buffer->data;
|
||||
MsfGifBuffer * moved =
|
||||
(MsfGifBuffer *) MSF_GIF_REALLOC(allocContext, buffer, maxBufSize, offsetof(MsfGifBuffer, data) + buffer->size);
|
||||
if (!moved) { MSF_GIF_FREE(allocContext, buffer, maxBufSize); return NULL; }
|
||||
return moved;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// To-memory API ///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const int lzwAllocSize = 4096 * 256 * sizeof(int16_t);
|
||||
|
||||
//NOTE: by C standard library conventions, freeing NULL should be a no-op,
|
||||
// but just in case the user's custom free doesn't follow that rule, we do null checks on our end as well.
|
||||
static void msf_free_gif_state(MsfGifState * handle) {
|
||||
if (handle->previousFrame.pixels) MSF_GIF_FREE(handle->customAllocatorContext, handle->previousFrame.pixels,
|
||||
handle->width * handle->height * sizeof(uint32_t));
|
||||
if (handle->currentFrame.pixels) MSF_GIF_FREE(handle->customAllocatorContext, handle->currentFrame.pixels,
|
||||
handle->width * handle->height * sizeof(uint32_t));
|
||||
if (handle->lzwMem) MSF_GIF_FREE(handle->customAllocatorContext, handle->lzwMem, lzwAllocSize);
|
||||
for (MsfGifBuffer * node = handle->listHead; node;) {
|
||||
MsfGifBuffer * next = node->next; //NOTE: we have to copy the `next` pointer BEFORE freeing the node holding it
|
||||
MSF_GIF_FREE(handle->customAllocatorContext, node, offsetof(MsfGifBuffer, data) + node->size);
|
||||
node = next;
|
||||
}
|
||||
handle->listHead = NULL; //this implicitly marks the handle as invalid until the next msf_gif_begin() call
|
||||
}
|
||||
|
||||
int msf_gif_begin(MsfGifState * handle, int width, int height) { MsfTimeFunc
|
||||
//NOTE: we cannot stomp the entire struct to zero because we must preserve `customAllocatorContext`.
|
||||
MsfCookedFrame empty = {0}; //god I hate MSVC...
|
||||
handle->previousFrame = empty;
|
||||
handle->currentFrame = empty;
|
||||
handle->width = width;
|
||||
handle->height = height;
|
||||
handle->framesSubmitted = 0;
|
||||
|
||||
//allocate memory for LZW buffer
|
||||
//NOTE: Unfortunately we can't just use stack memory for the LZW table because it's 2MB,
|
||||
// which is more stack space than most operating systems give by default,
|
||||
// and we can't realistically expect users to be willing to override that just to use our library,
|
||||
// so we have to allocate this on the heap.
|
||||
handle->lzwMem = (int16_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, lzwAllocSize);
|
||||
handle->previousFrame.pixels =
|
||||
(uint32_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, handle->width * handle->height * sizeof(uint32_t));
|
||||
handle->currentFrame.pixels =
|
||||
(uint32_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, handle->width * handle->height * sizeof(uint32_t));
|
||||
|
||||
//setup header buffer header (lol)
|
||||
handle->listHead = (MsfGifBuffer *) MSF_GIF_MALLOC(handle->customAllocatorContext, offsetof(MsfGifBuffer, data) + 32);
|
||||
if (!handle->listHead || !handle->lzwMem || !handle->previousFrame.pixels || !handle->currentFrame.pixels) {
|
||||
msf_free_gif_state(handle);
|
||||
return 0;
|
||||
}
|
||||
handle->listTail = handle->listHead;
|
||||
handle->listHead->next = NULL;
|
||||
handle->listHead->size = 32;
|
||||
|
||||
//NOTE: because __attribute__((__packed__)) is annoyingly compiler-specific, we do this unreadable weirdness
|
||||
char headerBytes[33] = "GIF89a\0\0\0\0\x70\0\0" "\x21\xFF\x0BNETSCAPE2.0\x03\x01\0\0\0";
|
||||
memcpy(&headerBytes[6], &width, 2);
|
||||
memcpy(&headerBytes[8], &height, 2);
|
||||
memcpy(handle->listHead->data, headerBytes, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int msf_gif_frame(MsfGifState * handle, uint8_t * pixelData, int centiSecondsPerFame, int maxBitDepth, int pitchInBytes)
|
||||
{ MsfTimeFunc
|
||||
if (!handle->listHead) { return 0; }
|
||||
|
||||
maxBitDepth = msf_imax(1, msf_imin(16, maxBitDepth));
|
||||
if (pitchInBytes == 0) pitchInBytes = handle->width * 4;
|
||||
if (pitchInBytes < 0) pixelData -= pitchInBytes * (handle->height - 1);
|
||||
|
||||
uint8_t used[(1 << 16) + 1]; //only 64k, so stack allocating is fine
|
||||
msf_cook_frame(&handle->currentFrame, pixelData, used, handle->width, handle->height, pitchInBytes,
|
||||
msf_imin(maxBitDepth, handle->previousFrame.depth + 160 / msf_imax(1, handle->previousFrame.count)));
|
||||
|
||||
MsfGifBuffer * buffer = msf_compress_frame(handle->customAllocatorContext, handle->width, handle->height,
|
||||
centiSecondsPerFame, handle->currentFrame, handle, used, handle->lzwMem);
|
||||
if (!buffer) { msf_free_gif_state(handle); return 0; }
|
||||
handle->listTail->next = buffer;
|
||||
handle->listTail = buffer;
|
||||
|
||||
//swap current and previous frames
|
||||
MsfCookedFrame tmp = handle->previousFrame;
|
||||
handle->previousFrame = handle->currentFrame;
|
||||
handle->currentFrame = tmp;
|
||||
|
||||
handle->framesSubmitted += 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
MsfGifResult msf_gif_end(MsfGifState * handle) { MsfTimeFunc
|
||||
if (!handle->listHead) { MsfGifResult empty = {0}; return empty; }
|
||||
|
||||
//first pass: determine total size
|
||||
size_t total = 1; //1 byte for trailing marker
|
||||
for (MsfGifBuffer * node = handle->listHead; node; node = node->next) { total += node->size; }
|
||||
|
||||
//second pass: write data
|
||||
uint8_t * buffer = (uint8_t *) MSF_GIF_MALLOC(handle->customAllocatorContext, total);
|
||||
if (buffer) {
|
||||
uint8_t * writeHead = buffer;
|
||||
for (MsfGifBuffer * node = handle->listHead; node; node = node->next) {
|
||||
memcpy(writeHead, node->data, node->size);
|
||||
writeHead += node->size;
|
||||
}
|
||||
*writeHead++ = 0x3B;
|
||||
}
|
||||
|
||||
//third pass: free buffers
|
||||
msf_free_gif_state(handle);
|
||||
|
||||
MsfGifResult ret = { buffer, total, total, handle->customAllocatorContext };
|
||||
return ret;
|
||||
}
|
||||
|
||||
void msf_gif_free(MsfGifResult result) { MsfTimeFunc
|
||||
if (result.data) { MSF_GIF_FREE(result.contextPointer, result.data, result.allocSize); }
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// To-file API ///
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int msf_gif_begin_to_file(MsfGifState * handle, int width, int height, MsfGifFileWriteFunc func, void * filePointer) {
|
||||
handle->fileWriteFunc = func;
|
||||
handle->fileWriteData = filePointer;
|
||||
return msf_gif_begin(handle, width, height);
|
||||
}
|
||||
|
||||
int msf_gif_frame_to_file(MsfGifState * handle, uint8_t * pixelData, int centiSecondsPerFame, int maxBitDepth, int pitchInBytes) {
|
||||
if (!msf_gif_frame(handle, pixelData, centiSecondsPerFame, maxBitDepth, pitchInBytes)) { return 0; }
|
||||
|
||||
//NOTE: this is a somewhat hacky implementation which is not perfectly efficient, but it's good enough for now
|
||||
MsfGifBuffer * head = handle->listHead;
|
||||
if (!handle->fileWriteFunc(head->data, head->size, 1, handle->fileWriteData)) { msf_free_gif_state(handle); return 0; }
|
||||
handle->listHead = head->next;
|
||||
MSF_GIF_FREE(handle->customAllocatorContext, head, offsetof(MsfGifBuffer, data) + head->size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int msf_gif_end_to_file(MsfGifState * handle) {
|
||||
//NOTE: this is a somewhat hacky implementation which is not perfectly efficient, but it's good enough for now
|
||||
MsfGifResult result = msf_gif_end(handle);
|
||||
int ret = (int) handle->fileWriteFunc(result.data, result.dataSize, 1, handle->fileWriteData);
|
||||
msf_gif_free(result);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif //MSF_GIF_ALREADY_IMPLEMENTED_IN_THIS_TRANSLATION_UNIT
|
||||
#endif //MSF_GIF_IMPL
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2021 Miles Fogle
|
||||
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.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
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 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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
8
src/external/rl_gputex.h
vendored
8
src/external/rl_gputex.h
vendored
|
|
@ -308,7 +308,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_
|
|||
unsigned char alpha = 0;
|
||||
|
||||
// NOTE: Data comes as A1R5G5B5, it must be reordered to R5G5B5A1
|
||||
for (int i = 0; i < image_pixel_size; i++)
|
||||
for (int i = 0; i < data_size/sizeof(unsigned short); i++)
|
||||
{
|
||||
alpha = ((unsigned short *)image_data)[i] >> 15;
|
||||
((unsigned short *)image_data)[i] = ((unsigned short *)image_data)[i] << 1;
|
||||
|
|
@ -328,7 +328,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_
|
|||
unsigned char alpha = 0;
|
||||
|
||||
// NOTE: Data comes as A4R4G4B4, it must be reordered R4G4B4A4
|
||||
for (int i = 0; i < image_pixel_size; i++)
|
||||
for (int i = 0; i < data_size/sizeof(unsigned short); i++)
|
||||
{
|
||||
alpha = ((unsigned short *)image_data)[i] >> 12;
|
||||
((unsigned short *)image_data)[i] = ((unsigned short *)image_data)[i] << 4;
|
||||
|
|
@ -339,7 +339,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_
|
|||
}
|
||||
}
|
||||
}
|
||||
else if ((header->ddspf.flags == 0x40) && (header->ddspf.rgb_bit_count == 24)) // DDS_RGB, no compressed
|
||||
else if ((header->ddspf.flags == 0x40) && (header->ddspf.rgb_bit_count == 24)) // DDS_RGB, no compressed
|
||||
{
|
||||
int data_size = image_pixel_size*3*sizeof(unsigned char);
|
||||
if (header->mipmap_count > 1) data_size = data_size + data_size/3;
|
||||
|
|
@ -362,7 +362,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_
|
|||
// NOTE: Data comes as A8R8G8B8, it must be reordered R8G8B8A8 (view next comment)
|
||||
// DirecX understand ARGB as a 32bit DWORD but the actual memory byte alignment is BGRA
|
||||
// So, we must realign B8G8R8A8 to R8G8B8A8
|
||||
for (int i = 0; i < image_pixel_size*4; i += 4)
|
||||
for (int i = 0; i < data_size; i += 4)
|
||||
{
|
||||
blue = ((unsigned char *)image_data)[i];
|
||||
((unsigned char *)image_data)[i] = ((unsigned char *)image_data)[i + 2];
|
||||
|
|
|
|||
1033
src/external/rlsw.h
vendored
1033
src/external/rlsw.h
vendored
File diff suppressed because it is too large
Load diff
2
src/external/sdefl.h
vendored
2
src/external/sdefl.h
vendored
|
|
@ -198,7 +198,7 @@ extern int zsdeflate(struct sdefl *s, void *o, const void *i, int n, int lvl);
|
|||
static int
|
||||
sdefl_ilog2(int n) {
|
||||
if (!n) return 0;
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && !defined(__llvm__) && !defined(__INTEL_COMPILER) // @raysan5, address PR #5367
|
||||
unsigned long msbp = 0;
|
||||
_BitScanReverse(&msbp, (unsigned long)n);
|
||||
return (int)msbp;
|
||||
|
|
|
|||
2
src/external/sinfl.h
vendored
2
src/external/sinfl.h
vendored
|
|
@ -171,7 +171,7 @@ extern int zsinflate(void *out, int cap, const void *in, int size);
|
|||
|
||||
static int
|
||||
sinfl_bsr(unsigned n) {
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && !defined(__llvm__) && !defined(__INTEL_COMPILER) // @raysan5, address PR #5367
|
||||
unsigned long uln = 0;
|
||||
_BitScanReverse(&uln, n);
|
||||
return (int)(uln);
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ typedef struct {
|
|||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
extern CoreData CORE; // Global CORE state context
|
||||
extern bool isGpuReady; // Flag to note GPU has been initialized successfully
|
||||
static PlatformData platform = { 0 }; // Platform specific data
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -268,6 +267,8 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd);
|
|||
static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event); // Process Android inputs
|
||||
static GamepadButton AndroidTranslateGamepadButton(int button); // Map Android gamepad button to raylib gamepad button
|
||||
|
||||
static void SetupFramebuffer(int width, int height); // Setup main framebuffer (required by InitPlatform())
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -358,13 +359,17 @@ void RestoreWindow(void)
|
|||
// Set window configuration state using flags
|
||||
void SetWindowState(unsigned int flags)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState() not available on target platform");
|
||||
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
|
||||
|
||||
// State change: FLAG_WINDOW_ALWAYS_RUN
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
|
||||
}
|
||||
|
||||
// Clear window configuration state flags
|
||||
void ClearWindowState(unsigned int flags)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState() not available on target platform");
|
||||
// State change: FLAG_WINDOW_ALWAYS_RUN
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
|
||||
}
|
||||
|
||||
// Set icon for window
|
||||
|
|
@ -602,7 +607,7 @@ void DisableCursor(void)
|
|||
// Swap back buffer with front buffer (screen drawing)
|
||||
void SwapScreenBuffer(void)
|
||||
{
|
||||
eglSwapBuffers(platform.device, platform.surface);
|
||||
if (platform.surface != EGL_NO_SURFACE) eglSwapBuffers(platform.device, platform.surface);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -623,10 +628,9 @@ double GetTime(void)
|
|||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if you control the URL given.
|
||||
// A user could craft a malicious string performing another action.
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself.
|
||||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Security check to (partially) avoid malicious code
|
||||
|
|
@ -687,7 +691,7 @@ void SetMouseCursor(int cursor)
|
|||
TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
|
||||
}
|
||||
|
||||
// Get physical key name.
|
||||
// Get physical key name
|
||||
const char *GetKeyName(int key)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");
|
||||
|
|
@ -742,15 +746,15 @@ void PollInputEvents(void)
|
|||
int pollEvents = 0;
|
||||
|
||||
// Poll Events (registered events) until we reach TIMEOUT which indicates there are no events left to poll
|
||||
// NOTE: Activity is paused if not enabled (platform.appEnabled)
|
||||
while ((pollResult = ALooper_pollOnce(platform.appEnabled? 0 : -1, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT))
|
||||
// NOTE: Activity is paused if not enabled (platform.appEnabled) and always run flag is not set (FLAG_WINDOW_ALWAYS_RUN)
|
||||
while ((pollResult = ALooper_pollOnce((platform.appEnabled || FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN))? 0 : -1, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT))
|
||||
{
|
||||
// Process this event
|
||||
if (platform.source != NULL) platform.source->process(platform.app, platform.source);
|
||||
|
||||
// NOTE: Allow closing the window in case a configuration change happened.
|
||||
// NOTE: Allow closing the window in case a configuration change happened
|
||||
// The android_main function should be allowed to return to its caller in order for the
|
||||
// Android OS to relaunch the activity.
|
||||
// Android OS to relaunch the activity
|
||||
if (platform.app->destroyRequested != 0)
|
||||
{
|
||||
CORE.Window.shouldClose = true;
|
||||
|
|
@ -796,10 +800,10 @@ int InitPlatform(void)
|
|||
//AConfiguration_getScreenLong(platform.app->config);
|
||||
|
||||
// Set some default window flags
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // false
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // false
|
||||
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // true
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // false
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_HIDDEN); // false
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // false
|
||||
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // true
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // false
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Initialize App command system
|
||||
|
|
@ -829,13 +833,13 @@ int InitPlatform(void)
|
|||
// Wait for window to be initialized (display and context)
|
||||
while (!CORE.Window.ready)
|
||||
{
|
||||
// Process events until we reach TIMEOUT, which indicates no more events queued.
|
||||
// Process events until we reach TIMEOUT, which indicates no more events queued
|
||||
while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT))
|
||||
{
|
||||
// Process this event
|
||||
if (platform.source != NULL) platform.source->process(platform.app, platform.source);
|
||||
|
||||
// NOTE: It's highly likely destroyRequested will never be non-zero at the start of the activity lifecycle.
|
||||
// NOTE: It's highly likely destroyRequested will never be non-zero at the start of the activity lifecycle
|
||||
//if (platform.app->destroyRequested != 0) CORE.Window.shouldClose = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -869,8 +873,9 @@ void ClosePlatform(void)
|
|||
platform.device = EGL_NO_DISPLAY;
|
||||
}
|
||||
|
||||
// NOTE: Reset global state in case the activity is being relaunched.
|
||||
if (platform.app->destroyRequested != 0) {
|
||||
// NOTE: Reset global state in case the activity is being relaunched
|
||||
if (platform.app->destroyRequested != 0)
|
||||
{
|
||||
CORE = (CoreData){0};
|
||||
platform = (PlatformData){0};
|
||||
}
|
||||
|
|
@ -882,12 +887,11 @@ void ClosePlatform(void)
|
|||
// NOTE: returns false in case graphic device could not be created
|
||||
static int InitGraphicsDevice(void)
|
||||
{
|
||||
CORE.Window.fullscreen = true;
|
||||
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
|
||||
EGLint samples = 0;
|
||||
EGLint sampleBuffer = 0;
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
|
||||
{
|
||||
samples = 4;
|
||||
sampleBuffer = 1;
|
||||
|
|
@ -925,7 +929,7 @@ static int InitGraphicsDevice(void)
|
|||
// Initialize the EGL device connection
|
||||
if (eglInitialize(platform.device, NULL, NULL) == EGL_FALSE)
|
||||
{
|
||||
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
|
||||
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -992,7 +996,7 @@ static int InitGraphicsDevice(void)
|
|||
|
||||
CORE.Window.ready = true;
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1042,7 +1046,6 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
|
|||
// Initialize OpenGL context (states and resources)
|
||||
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
|
||||
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
|
||||
isGpuReady = true;
|
||||
|
||||
// Setup default viewport
|
||||
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
|
||||
|
|
@ -1059,7 +1062,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
|
|||
// Set font white rectangle for shapes drawing, so shapes and text can be batched together
|
||||
// WARNING: rshapes module is required, if not available, default internal white rectangle is used
|
||||
Rectangle rec = GetFontDefault().recs[95];
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
|
||||
{
|
||||
// NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
|
||||
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
|
||||
|
|
@ -1081,41 +1084,26 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
|
|||
|
||||
// Initialize random seed
|
||||
SetRandomSeed((unsigned int)time(NULL));
|
||||
|
||||
// TODO: GPU assets reload in case of lost focus (lost context)
|
||||
// NOTE: This problem has been solved just unbinding and rebinding context from display
|
||||
/*
|
||||
if (assetsReloadRequired)
|
||||
{
|
||||
for (int i = 0; i < assetCount; i++)
|
||||
{
|
||||
// TODO: Unload old asset if required
|
||||
|
||||
// Load texture again to pointed texture
|
||||
(*textureAsset + i) = LoadTexture(assetPath[i]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case APP_CMD_GAINED_FOCUS:
|
||||
{
|
||||
platform.appEnabled = true;
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
|
||||
//ResumeMusicStream();
|
||||
} break;
|
||||
case APP_CMD_PAUSE: break;
|
||||
case APP_CMD_LOST_FOCUS:
|
||||
{
|
||||
platform.appEnabled = false;
|
||||
CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
|
||||
//PauseMusicStream();
|
||||
} break;
|
||||
case APP_CMD_TERM_WINDOW:
|
||||
{
|
||||
// Detach OpenGL context and destroy display surface
|
||||
// NOTE 1: This case is used when the user exits the app without closing it. We detach the context to ensure everything is recoverable upon resuming.
|
||||
// NOTE 1: This case is used when the user exits the app without closing it, context is detached to ensure everything is recoverable upon resuming
|
||||
// NOTE 2: Detaching context before destroying display surface avoids losing our resources (textures, shaders, VBOs...)
|
||||
// NOTE 3: In some cases (too many context loaded), OS could unload context automatically... :(
|
||||
if (platform.device != EGL_NO_DISPLAY)
|
||||
|
|
@ -1179,16 +1167,16 @@ static GamepadButton AndroidTranslateGamepadButton(int button)
|
|||
static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
||||
{
|
||||
// If additional inputs are required check:
|
||||
// https://developer.android.com/ndk/reference/group/input
|
||||
// https://developer.android.com/training/game-controllers/controller-input
|
||||
// REF: https://developer.android.com/ndk/reference/group/input
|
||||
// REF: https://developer.android.com/training/game-controllers/controller-input
|
||||
|
||||
int type = AInputEvent_getType(event);
|
||||
int source = AInputEvent_getSource(event);
|
||||
|
||||
if (type == AINPUT_EVENT_TYPE_MOTION)
|
||||
{
|
||||
if (((source & AINPUT_SOURCE_JOYSTICK) == AINPUT_SOURCE_JOYSTICK) ||
|
||||
((source & AINPUT_SOURCE_GAMEPAD) == AINPUT_SOURCE_GAMEPAD))
|
||||
if (FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) ||
|
||||
FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD))
|
||||
{
|
||||
// For now we'll assume a single gamepad which we "detect" on its input event
|
||||
CORE.Input.Gamepad.ready[0] = true;
|
||||
|
|
@ -1251,8 +1239,11 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
|||
//int32_t AKeyEvent_getMetaState(event);
|
||||
|
||||
// Handle gamepad button presses and releases
|
||||
if (((source & AINPUT_SOURCE_JOYSTICK) == AINPUT_SOURCE_JOYSTICK) ||
|
||||
((source & AINPUT_SOURCE_GAMEPAD) == AINPUT_SOURCE_GAMEPAD))
|
||||
// NOTE: Skip gamepad handling if this is a keyboard event, as some devices
|
||||
// report both AINPUT_SOURCE_KEYBOARD and AINPUT_SOURCE_GAMEPAD flags
|
||||
if ((FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) ||
|
||||
FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD)) &&
|
||||
!FLAG_IS_SET(source, AINPUT_SOURCE_KEYBOARD))
|
||||
{
|
||||
// For now we'll assume a single gamepad which we "detect" on its input event
|
||||
CORE.Input.Gamepad.ready[0] = true;
|
||||
|
|
@ -1290,7 +1281,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
|||
{
|
||||
// Let the OS handle input to avoid app stuck. Behaviour: CMD_PAUSE -> CMD_SAVE_STATE -> CMD_STOP -> CMD_CONFIG_CHANGED -> CMD_LOST_FOCUS
|
||||
// Resuming Behaviour: CMD_START -> CMD_RESUME -> CMD_CONFIG_CHANGED -> CMD_CONFIG_CHANGED -> CMD_GAINED_FOCUS
|
||||
// It seems like locking mobile, screen size (CMD_CONFIG_CHANGED) is affected.
|
||||
// It seems like locking mobile, screen size (CMD_CONFIG_CHANGED) is affected
|
||||
// NOTE: AndroidManifest.xml must have <activity android:configChanges="orientation|keyboardHidden|screenSize" >
|
||||
// Before that change, activity was calling CMD_TERM_WINDOW and CMD_DESTROY when locking mobile, so that was not a normal behaviour
|
||||
return 0;
|
||||
|
|
@ -1419,15 +1410,9 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
|||
if (CORE.Input.Touch.pointCount > 0) CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 1;
|
||||
else CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 0;
|
||||
|
||||
// Stores the previous position of touch[0] only while it's active to calculate the delta.
|
||||
if (flags == AMOTION_EVENT_ACTION_MOVE)
|
||||
{
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Touch.position[0];
|
||||
}
|
||||
// Stores the previous position of touch[0] only while it's active to calculate the delta
|
||||
if (flags == AMOTION_EVENT_ACTION_MOVE) CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
else CORE.Input.Mouse.previousPosition = CORE.Input.Touch.position[0];
|
||||
|
||||
// Map touch[0] as mouse input for convenience
|
||||
CORE.Input.Mouse.currentPosition = CORE.Input.Touch.position[0];
|
||||
|
|
@ -1436,4 +1421,82 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Compute framebuffer size relative to screen size and display size
|
||||
// NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified
|
||||
static void SetupFramebuffer(int width, int height)
|
||||
{
|
||||
// Calculate CORE.Window.render.width and CORE.Window.render.height, we have the display size (input params) and the desired screen size (global var)
|
||||
if ((CORE.Window.screen.width > CORE.Window.display.width) || (CORE.Window.screen.height > CORE.Window.display.height))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Downscaling required: Screen size (%ix%i) is bigger than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
|
||||
|
||||
// Downscaling to fit display with border-bars
|
||||
float widthRatio = (float)CORE.Window.display.width/(float)CORE.Window.screen.width;
|
||||
float heightRatio = (float)CORE.Window.display.height/(float)CORE.Window.screen.height;
|
||||
|
||||
if (widthRatio <= heightRatio)
|
||||
{
|
||||
CORE.Window.render.width = CORE.Window.display.width;
|
||||
CORE.Window.render.height = (int)round((float)CORE.Window.screen.height*widthRatio);
|
||||
CORE.Window.renderOffset.x = 0;
|
||||
CORE.Window.renderOffset.y = (CORE.Window.display.height - CORE.Window.render.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Window.render.width = (int)round((float)CORE.Window.screen.width*heightRatio);
|
||||
CORE.Window.render.height = CORE.Window.display.height;
|
||||
CORE.Window.renderOffset.x = (CORE.Window.display.width - CORE.Window.render.width);
|
||||
CORE.Window.renderOffset.y = 0;
|
||||
}
|
||||
|
||||
// Screen scaling required
|
||||
float scaleRatio = (float)CORE.Window.render.width/(float)CORE.Window.screen.width;
|
||||
CORE.Window.screenScale = MatrixScale(scaleRatio, scaleRatio, 1.0f);
|
||||
|
||||
// NOTE: We render to full display resolution!
|
||||
// We just need to calculate above parameters for downscale matrix and offsets
|
||||
CORE.Window.render.width = CORE.Window.display.width;
|
||||
CORE.Window.render.height = CORE.Window.display.height;
|
||||
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Downscale matrix generated, content will be rendered at (%ix%i)", CORE.Window.render.width, CORE.Window.render.height);
|
||||
}
|
||||
else if ((CORE.Window.screen.width < CORE.Window.display.width) || (CORE.Window.screen.height < CORE.Window.display.height))
|
||||
{
|
||||
// Required screen size is smaller than display size
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Upscaling required: Screen size (%ix%i) smaller than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
|
||||
|
||||
if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
|
||||
{
|
||||
CORE.Window.screen.width = CORE.Window.display.width;
|
||||
CORE.Window.screen.height = CORE.Window.display.height;
|
||||
}
|
||||
|
||||
// Upscaling to fit display with border-bars
|
||||
float displayRatio = (float)CORE.Window.display.width/(float)CORE.Window.display.height;
|
||||
float screenRatio = (float)CORE.Window.screen.width/(float)CORE.Window.screen.height;
|
||||
|
||||
if (displayRatio <= screenRatio)
|
||||
{
|
||||
CORE.Window.render.width = CORE.Window.screen.width;
|
||||
CORE.Window.render.height = (int)round((float)CORE.Window.screen.width/displayRatio);
|
||||
CORE.Window.renderOffset.x = 0;
|
||||
CORE.Window.renderOffset.y = (CORE.Window.render.height - CORE.Window.screen.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Window.render.width = (int)round((float)CORE.Window.screen.height*displayRatio);
|
||||
CORE.Window.render.height = CORE.Window.screen.height;
|
||||
CORE.Window.renderOffset.x = (CORE.Window.render.width - CORE.Window.screen.width);
|
||||
CORE.Window.renderOffset.y = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Window.render.width = CORE.Window.screen.width;
|
||||
CORE.Window.render.height = CORE.Window.screen.height;
|
||||
CORE.Window.renderOffset.x = 0;
|
||||
CORE.Window.renderOffset.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -48,11 +48,6 @@
|
|||
*
|
||||
**********************************************************************************************/
|
||||
|
||||
#ifndef RAYLIB_H /* this should never actually happen, it's only here for IDEs */
|
||||
#include "raylib.h"
|
||||
#include "../rcore.c"
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_WEB_RGFW)
|
||||
#define RGFW_NO_GL_HEADER
|
||||
#endif
|
||||
|
|
@ -295,23 +290,21 @@ bool WindowShouldClose(void)
|
|||
// Toggle fullscreen mode
|
||||
void ToggleFullscreen(void)
|
||||
{
|
||||
if (!CORE.Window.fullscreen)
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
|
||||
{
|
||||
// Store previous window position (in case we exit fullscreen)
|
||||
CORE.Window.previousPosition = CORE.Window.position;
|
||||
CORE.Window.previousScreen = CORE.Window.screen;
|
||||
|
||||
platform.mon = RGFW_window_getMonitor(platform.window);
|
||||
CORE.Window.fullscreen = true;
|
||||
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
|
||||
RGFW_monitor_scaleToWindow(platform.mon, platform.window);
|
||||
RGFW_window_setFullscreen(platform.window, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Window.fullscreen = false;
|
||||
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
|
||||
if (platform.mon.mode.area.w)
|
||||
{
|
||||
|
|
@ -330,13 +323,15 @@ void ToggleFullscreen(void)
|
|||
|
||||
// Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
|
||||
// NOTE: V-Sync can be enabled by graphic driver configuration
|
||||
if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT)) RGFW_window_swapInterval(platform.window, 1);
|
||||
}
|
||||
|
||||
// Toggle borderless windowed mode
|
||||
void ToggleBorderlessWindowed(void)
|
||||
{
|
||||
if (CORE.Window.fullscreen)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) ToggleFullscreen();
|
||||
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
|
||||
{
|
||||
CORE.Window.previousPosition = CORE.Window.position;
|
||||
CORE.Window.previousScreen = CORE.Window.screen;
|
||||
|
|
@ -353,8 +348,6 @@ void ToggleBorderlessWindowed(void)
|
|||
CORE.Window.position = CORE.Window.previousPosition;
|
||||
RGFW_window_resize(platform.window, RGFW_AREA(CORE.Window.previousScreen.width, CORE.Window.previousScreen.height));
|
||||
}
|
||||
|
||||
CORE.Window.fullscreen = !CORE.Window.fullscreen;
|
||||
}
|
||||
|
||||
// Set window state: maximized, if resizable
|
||||
|
|
@ -372,7 +365,7 @@ void MinimizeWindow(void)
|
|||
// Restore window from being minimized/maximized
|
||||
void RestoreWindow(void)
|
||||
{
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
|
||||
|
||||
RGFW_window_restore(platform.window);
|
||||
}
|
||||
|
|
@ -382,72 +375,72 @@ void SetWindowState(unsigned int flags)
|
|||
{
|
||||
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
|
||||
|
||||
CORE.Window.flags |= flags;
|
||||
FLAG_SET(CORE.Window.flags, flags);
|
||||
|
||||
if (flags & FLAG_VSYNC_HINT)
|
||||
if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
|
||||
{
|
||||
RGFW_window_swapInterval(platform.window, 1);
|
||||
}
|
||||
if (flags & FLAG_FULLSCREEN_MODE)
|
||||
if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
|
||||
{
|
||||
if (!CORE.Window.fullscreen) ToggleFullscreen();
|
||||
ToggleFullscreen();
|
||||
}
|
||||
if (flags & FLAG_WINDOW_RESIZABLE)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
|
||||
{
|
||||
RGFW_window_setMaxSize(platform.window, RGFW_AREA(0, 0));
|
||||
RGFW_window_setMinSize(platform.window, RGFW_AREA(0, 0));
|
||||
}
|
||||
if (flags & FLAG_WINDOW_UNDECORATED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
|
||||
{
|
||||
RGFW_window_setBorder(platform.window, 0);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_HIDDEN)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
|
||||
{
|
||||
RGFW_window_hide(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MINIMIZED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
|
||||
{
|
||||
RGFW_window_minimize(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MAXIMIZED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
|
||||
{
|
||||
RGFW_window_maximize(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_UNFOCUSED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
|
||||
{
|
||||
CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
|
||||
platform.window->_flags &= ~RGFW_windowFocusOnShow;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
|
||||
FLAG_CLEAR(platform.window->_flags, RGFW_windowFocusOnShow);
|
||||
RGFW_window_setFlags(platform.window, platform.window->_flags);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_TOPMOST)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
|
||||
{
|
||||
RGFW_window_setFloating(platform.window, RGFW_TRUE);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_ALWAYS_RUN)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
|
||||
{
|
||||
CORE.Window.flags |= FLAG_WINDOW_ALWAYS_RUN;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_TRANSPARENT)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
|
||||
}
|
||||
if (flags & FLAG_WINDOW_HIGHDPI)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
|
||||
{
|
||||
RGFW_window_setMousePassthrough(platform.window, 1);
|
||||
}
|
||||
if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
|
||||
if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
|
||||
{
|
||||
ToggleBorderlessWindowed();
|
||||
}
|
||||
if (flags & FLAG_MSAA_4X_HINT)
|
||||
if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
|
||||
{
|
||||
RGFW_setGLHint(RGFW_glSamples, 4);
|
||||
}
|
||||
if (flags & FLAG_INTERLACED_HINT)
|
||||
if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
|
||||
}
|
||||
|
|
@ -456,122 +449,86 @@ void SetWindowState(unsigned int flags)
|
|||
// Clear window configuration state flags
|
||||
void ClearWindowState(unsigned int flags)
|
||||
{
|
||||
CORE.Window.flags &= ~flags;
|
||||
FLAG_CLEAR(CORE.Window.flags, flags);
|
||||
|
||||
if (flags & FLAG_VSYNC_HINT)
|
||||
if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
|
||||
{
|
||||
RGFW_window_swapInterval(platform.window, 0);
|
||||
}
|
||||
if (flags & FLAG_FULLSCREEN_MODE)
|
||||
if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
|
||||
{
|
||||
if (CORE.Window.fullscreen) ToggleFullscreen();
|
||||
ToggleFullscreen();
|
||||
}
|
||||
if (flags & FLAG_WINDOW_RESIZABLE)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
|
||||
{
|
||||
RGFW_window_setMaxSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h));
|
||||
RGFW_window_setMinSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h));
|
||||
}
|
||||
if (flags & FLAG_WINDOW_UNDECORATED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
|
||||
{
|
||||
RGFW_window_setBorder(platform.window, 1);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_HIDDEN)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
|
||||
{
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
|
||||
|
||||
RGFW_window_show(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MINIMIZED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
|
||||
{
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
|
||||
|
||||
RGFW_window_restore(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MAXIMIZED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
|
||||
{
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
|
||||
|
||||
RGFW_window_restore(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_UNFOCUSED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
|
||||
{
|
||||
RGFW_window_setFlags(platform.window, platform.window->_flags | RGFW_windowFocusOnShow);
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;
|
||||
}
|
||||
if (flags & FLAG_WINDOW_TOPMOST)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
|
||||
{
|
||||
RGFW_window_setFloating(platform.window, RGFW_FALSE);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_ALWAYS_RUN)
|
||||
{
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_ALWAYS_RUN;
|
||||
}
|
||||
if (flags & FLAG_WINDOW_TRANSPARENT)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
|
||||
}
|
||||
if (flags & FLAG_WINDOW_HIGHDPI)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
|
||||
{
|
||||
RGFW_window_setMousePassthrough(platform.window, 0);
|
||||
}
|
||||
if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
|
||||
if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
|
||||
{
|
||||
if (CORE.Window.fullscreen) ToggleBorderlessWindowed();
|
||||
ToggleBorderlessWindowed();
|
||||
}
|
||||
if (flags & FLAG_MSAA_4X_HINT)
|
||||
if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
|
||||
{
|
||||
RGFW_setGLHint(RGFW_glSamples, 0);
|
||||
}
|
||||
if (flags & FLAG_INTERLACED_HINT)
|
||||
if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
|
||||
}
|
||||
}
|
||||
|
||||
int RGFW_formatToChannels(int format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
|
||||
case PIXELFORMAT_UNCOMPRESSED_R16: // 16 bpp (1 channel - half float)
|
||||
case PIXELFORMAT_UNCOMPRESSED_R32: // 32 bpp (1 channel - float)
|
||||
return 1;
|
||||
case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: // 8*2 bpp (2 channels)
|
||||
case PIXELFORMAT_UNCOMPRESSED_R5G6B5: // 16 bpp
|
||||
case PIXELFORMAT_UNCOMPRESSED_R8G8B8: // 24 bpp
|
||||
case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: // 16 bpp (1 bit alpha)
|
||||
case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: // 16 bpp (4 bit alpha)
|
||||
case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: // 32 bpp
|
||||
return 2;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R32G32B32: // 32*3 bpp (3 channels - float)
|
||||
case PIXELFORMAT_UNCOMPRESSED_R16G16B16: // 16*3 bpp (3 channels - half float)
|
||||
case PIXELFORMAT_COMPRESSED_DXT1_RGB: // 4 bpp (no alpha)
|
||||
case PIXELFORMAT_COMPRESSED_ETC1_RGB: // 4 bpp
|
||||
case PIXELFORMAT_COMPRESSED_ETC2_RGB: // 4 bpp
|
||||
case PIXELFORMAT_COMPRESSED_PVRT_RGB: // 4 bpp
|
||||
return 3;
|
||||
case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: // 32*4 bpp (4 channels - float)
|
||||
case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: // 16*4 bpp (4 channels - half float)
|
||||
case PIXELFORMAT_COMPRESSED_DXT1_RGBA: // 4 bpp (1 bit alpha)
|
||||
case PIXELFORMAT_COMPRESSED_DXT3_RGBA: // 8 bpp
|
||||
case PIXELFORMAT_COMPRESSED_DXT5_RGBA: // 8 bpp
|
||||
case PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: // 8 bpp
|
||||
case PIXELFORMAT_COMPRESSED_PVRT_RGBA: // 4 bpp
|
||||
case PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: // 8 bpp
|
||||
case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: // 2 bpp
|
||||
return 4;
|
||||
default: return 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Set icon for window
|
||||
void SetWindowIcon(Image image)
|
||||
{
|
||||
RGFW_window_setIcon(platform.window, (u8 *)image.data, RGFW_AREA(image.width, image.height), RGFW_formatToChannels(image.format));
|
||||
if (image.format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RGFW: Window icon image must be in R8G8B8A8 pixel format");
|
||||
return;
|
||||
}
|
||||
RGFW_window_setIcon(platform.window, (u8 *)image.data, RGFW_AREA(image.width, image.height), 4);
|
||||
}
|
||||
|
||||
// Set icon for window
|
||||
|
|
@ -588,12 +545,17 @@ void SetWindowIcons(Image *images, int count)
|
|||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (images[i].format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RGFW: Window icon image must be in R8G8B8A8 pixel format");
|
||||
continue;
|
||||
}
|
||||
if ((bigIcon == NULL) || ((images[i].width > bigIcon->width) && (images[i].height > bigIcon->height))) bigIcon = &images[i];
|
||||
if ((smallIcon == NULL) || ((images[i].width < smallIcon->width) && (images[i].height > smallIcon->height))) smallIcon = &images[i];
|
||||
}
|
||||
|
||||
if (smallIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)smallIcon->data, RGFW_AREA(smallIcon->width, smallIcon->height), RGFW_formatToChannels(smallIcon->format), RGFW_iconWindow);
|
||||
if (bigIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)bigIcon->data, RGFW_AREA(bigIcon->width, bigIcon->height), RGFW_formatToChannels(bigIcon->format), RGFW_iconTaskbar);
|
||||
if (smallIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)smallIcon->data, RGFW_AREA(smallIcon->width, smallIcon->height), 4, RGFW_iconWindow);
|
||||
if (bigIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)bigIcon->data, RGFW_AREA(bigIcon->width, bigIcon->height), 4, RGFW_iconTaskbar);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -843,8 +805,9 @@ void EnableCursor(void)
|
|||
|
||||
// Set cursor position in the middle
|
||||
SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
|
||||
RGFW_window_showMouse(platform.window, true);
|
||||
CORE.Input.Mouse.cursorHidden = false;
|
||||
ShowCursor();
|
||||
|
||||
CORE.Input.Mouse.cursorLocked = true;
|
||||
}
|
||||
|
||||
// Disables cursor (lock cursor)
|
||||
|
|
@ -853,6 +816,8 @@ void DisableCursor(void)
|
|||
RGFW_disableCursor = true;
|
||||
RGFW_window_mouseHold(platform.window, RGFW_AREA(0, 0));
|
||||
HideCursor();
|
||||
|
||||
CORE.Input.Mouse.cursorLocked = true;
|
||||
}
|
||||
|
||||
// Swap back buffer with front buffer (screen drawing)
|
||||
|
|
@ -872,17 +837,27 @@ double GetTime(void)
|
|||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if you control the URL given.
|
||||
// A user could craft a malicious string performing another action.
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself.
|
||||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Security check to (partially) avoid malicious code on target platform
|
||||
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
|
||||
else
|
||||
{
|
||||
// TODO: Open URL implementation
|
||||
char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
|
||||
#if defined(_WIN32)
|
||||
sprintf(cmd, "explorer \"%s\"", url);
|
||||
#endif
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
sprintf(cmd, "xdg-open '%s'", url); // Alternatives: firefox, x-www-browser
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
sprintf(cmd, "open '%s'", url);
|
||||
#endif
|
||||
int result = system(cmd);
|
||||
if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
|
||||
RL_FREE(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -917,7 +892,7 @@ void SetMouseCursor(int cursor)
|
|||
RGFW_window_setMouseStandard(platform.window, cursor);
|
||||
}
|
||||
|
||||
// Get physical key name.
|
||||
// Get physical key name
|
||||
const char *GetKeyName(int key)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetKeyName() unsupported on target platform");
|
||||
|
|
@ -983,7 +958,7 @@ void PollInputEvents(void)
|
|||
CORE.Window.resizedLastFrame = false;
|
||||
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
if (platform.window->_flags & RGFW_HOLD_MOUSE)
|
||||
if (FLAG_IS_SET(platform.window->_flags, RGFW_HOLD_MOUSE))
|
||||
{
|
||||
CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f };
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
|
||||
|
|
@ -1062,18 +1037,18 @@ void PollInputEvents(void)
|
|||
} break;
|
||||
case RGFW_windowMaximized:
|
||||
{
|
||||
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // The window was maximized
|
||||
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // The window was maximized
|
||||
} break;
|
||||
case RGFW_windowMinimized:
|
||||
{
|
||||
CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified
|
||||
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was iconified
|
||||
} break;
|
||||
case RGFW_windowRestored:
|
||||
{
|
||||
if (RGFW_window_isMaximized(platform.window))
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; // The window was restored
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // The window was restored
|
||||
if (RGFW_window_isMinimized(platform.window))
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was restored
|
||||
} break;
|
||||
case RGFW_windowMoved:
|
||||
{
|
||||
|
|
@ -1097,11 +1072,7 @@ void PollInputEvents(void)
|
|||
CORE.Input.Keyboard.currentKeyState[key] = 1;
|
||||
}
|
||||
|
||||
// TODO: Put exitKey verification outside the switch?
|
||||
if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey])
|
||||
{
|
||||
CORE.Window.shouldClose = true;
|
||||
}
|
||||
if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey]) CORE.Window.shouldClose = true;
|
||||
|
||||
// NOTE: event.text.text data comes an UTF-8 text sequence but we register codepoints (int)
|
||||
// Check if there is space available in the queue
|
||||
|
|
@ -1159,7 +1130,7 @@ void PollInputEvents(void)
|
|||
} break;
|
||||
case RGFW_mousePosChanged:
|
||||
{
|
||||
if (platform.window->_flags & RGFW_HOLD_MOUSE)
|
||||
if (FLAG_IS_SET(platform.window->_flags, RGFW_HOLD_MOUSE))
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition.x += (float)event->vector.x;
|
||||
CORE.Input.Mouse.currentPosition.y += (float)event->vector.y;
|
||||
|
|
@ -1283,24 +1254,22 @@ int InitPlatform(void)
|
|||
unsigned int flags = RGFW_windowCenter | RGFW_windowAllowDND;
|
||||
|
||||
// Check window creation flags
|
||||
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
|
||||
{
|
||||
CORE.Window.fullscreen = true;
|
||||
flags |= RGFW_windowFullscreen;
|
||||
FLAG_SET(flags, RGFW_windowFullscreen);
|
||||
}
|
||||
|
||||
if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
|
||||
{
|
||||
CORE.Window.fullscreen = true;
|
||||
flags |= RGFW_windowedFullscreen;
|
||||
FLAG_SET(flags, RGFW_windowedFullscreen);
|
||||
}
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) flags |= RGFW_windowNoBorder;
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) flags |= RGFW_windowNoResize;
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) flags |= RGFW_windowTransparent;
|
||||
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) flags |= RGFW_windowFullscreen;
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) flags |= RGFW_windowHide;
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) flags |= RGFW_windowMaximize;
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) FLAG_SET(flags, RGFW_windowNoBorder);
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) FLAG_SET(flags, RGFW_windowNoResize);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) FLAG_SET(flags, RGFW_windowTransparent);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) FLAG_SET(flags, RGFW_windowFullscreen);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_SET(flags, RGFW_windowHide);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(flags, RGFW_windowMaximize);
|
||||
|
||||
// NOTE: Some OpenGL context attributes must be set before window creation
|
||||
// Check selection OpenGL version
|
||||
|
|
@ -1320,9 +1289,9 @@ int InitPlatform(void)
|
|||
RGFW_setGLHint(RGFW_glMinor, 3);
|
||||
}
|
||||
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT) RGFW_setGLHint(RGFW_glSamples, 4);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) RGFW_setGLHint(RGFW_glSamples, 4);
|
||||
|
||||
if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) flags |= RGFW_windowFocusOnShow | RGFW_windowFocus;
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) FLAG_SET(flags, RGFW_windowFocusOnShow | RGFW_windowFocus);
|
||||
|
||||
platform.window = RGFW_createWindow(CORE.Window.title, RGFW_RECT(0, 0, CORE.Window.screen.width, CORE.Window.screen.height), flags);
|
||||
platform.mon.mode.area.w = 0;
|
||||
|
|
@ -1342,11 +1311,7 @@ int InitPlatform(void)
|
|||
CORE.Window.display.width = CORE.Window.screen.width;
|
||||
CORE.Window.display.height = CORE.Window.screen.height;
|
||||
#endif
|
||||
// TODO: Is this needed by raylib now?
|
||||
// If so, rcore_desktop_sdl should be updated too
|
||||
//SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
|
||||
|
||||
if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT)) RGFW_window_swapInterval(platform.window, 1);
|
||||
RGFW_window_makeCurrent(platform.window);
|
||||
|
||||
// Check surface and context activation
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
// SDL base library (window/rendered, input, timing... functionality)
|
||||
#ifdef USING_SDL3_PROJECT
|
||||
#include "SDL3/SDL.h"
|
||||
#elif USING_SDL2_PROJECT
|
||||
#elif defined(USING_SDL2_PROJECT)
|
||||
#include "SDL2/SDL.h"
|
||||
#else
|
||||
#include "SDL.h"
|
||||
|
|
@ -71,7 +71,7 @@
|
|||
// SDL OpenGL functionality (if required, instead of internal renderer)
|
||||
#ifdef USING_SDL3_PROJECT
|
||||
#include "SDL3/SDL_opengl.h"
|
||||
#elif USING_SDL2_PROJECT
|
||||
#elif defined(USING_SDL2_PROJECT)
|
||||
#include "SDL2/SDL_opengl.h"
|
||||
#else
|
||||
#include "SDL_opengl.h"
|
||||
|
|
@ -463,22 +463,20 @@ void ToggleFullscreen(void)
|
|||
const int monitorCount = SDL_GetNumVideoDisplays();
|
||||
|
||||
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
|
||||
if ((monitor > 0) && (monitor <= monitorCount))
|
||||
if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
|
||||
#else
|
||||
if ((monitor >= 0) && (monitor < monitorCount))
|
||||
#endif
|
||||
{
|
||||
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
|
||||
{
|
||||
SDL_SetWindowFullscreen(platform.window, 0);
|
||||
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
|
||||
CORE.Window.fullscreen = false;
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
|
||||
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
|
||||
CORE.Window.fullscreen = true;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
}
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
|
||||
|
|
@ -491,20 +489,20 @@ void ToggleBorderlessWindowed(void)
|
|||
const int monitorCount = SDL_GetNumVideoDisplays();
|
||||
|
||||
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
|
||||
if ((monitor > 0) && (monitor <= monitorCount))
|
||||
if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
|
||||
#else
|
||||
if ((monitor >= 0) && (monitor < monitorCount))
|
||||
#endif
|
||||
{
|
||||
if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
|
||||
{
|
||||
SDL_SetWindowFullscreen(platform.window, 0);
|
||||
CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||
CORE.Window.flags |= FLAG_BORDERLESS_WINDOWED_MODE;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
|
||||
}
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
|
||||
|
|
@ -514,14 +512,14 @@ void ToggleBorderlessWindowed(void)
|
|||
void MaximizeWindow(void)
|
||||
{
|
||||
SDL_MaximizeWindow(platform.window);
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
|
||||
}
|
||||
|
||||
// Set window state: minimized
|
||||
void MinimizeWindow(void)
|
||||
{
|
||||
SDL_MinimizeWindow(platform.window);
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED;
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
|
||||
}
|
||||
|
||||
// Restore window from being minimized/maximized
|
||||
|
|
@ -536,83 +534,83 @@ void SetWindowState(unsigned int flags)
|
|||
{
|
||||
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
|
||||
|
||||
CORE.Window.flags |= flags;
|
||||
FLAG_SET(CORE.Window.flags, flags);
|
||||
|
||||
if (flags & FLAG_VSYNC_HINT)
|
||||
if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
|
||||
{
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
}
|
||||
if (flags & FLAG_FULLSCREEN_MODE)
|
||||
if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
|
||||
{
|
||||
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
|
||||
const int monitorCount = SDL_GetNumVideoDisplays();
|
||||
|
||||
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
|
||||
if ((monitor > 0) && (monitor <= monitorCount))
|
||||
if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
|
||||
#else
|
||||
if ((monitor >= 0) && (monitor < monitorCount))
|
||||
#endif
|
||||
{
|
||||
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
|
||||
CORE.Window.fullscreen = true;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
|
||||
}
|
||||
if (flags & FLAG_WINDOW_RESIZABLE)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
|
||||
{
|
||||
SDL_SetWindowResizable(platform.window, SDL_TRUE);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_UNDECORATED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
|
||||
{
|
||||
SDL_SetWindowBordered(platform.window, SDL_FALSE);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_HIDDEN)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
|
||||
{
|
||||
SDL_HideWindow(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MINIMIZED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
|
||||
{
|
||||
SDL_MinimizeWindow(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MAXIMIZED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
|
||||
{
|
||||
SDL_MaximizeWindow(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_UNFOCUSED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
|
||||
{
|
||||
// NOTE: To be able to implement this part it seems that we should
|
||||
// do it ourselves, via 'windows.h', 'X11/Xlib.h' or even 'Cocoa.h'
|
||||
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_SDL");
|
||||
}
|
||||
if (flags & FLAG_WINDOW_TOPMOST)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
|
||||
{
|
||||
SDL_SetWindowAlwaysOnTop(platform.window, SDL_FALSE);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_ALWAYS_RUN)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
|
||||
{
|
||||
CORE.Window.flags |= FLAG_WINDOW_ALWAYS_RUN;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_TRANSPARENT)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_TRANSPARENT is not supported on PLATFORM_DESKTOP_SDL");
|
||||
}
|
||||
if (flags & FLAG_WINDOW_HIGHDPI)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
// NOTE: Such a function does not seem to exist
|
||||
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_HIGHDPI is not supported on PLATFORM_DESKTOP_SDL");
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
|
||||
{
|
||||
//SDL_SetWindowGrab(platform.window, SDL_FALSE);
|
||||
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_MOUSE_PASSTHROUGH is not supported on PLATFORM_DESKTOP_SDL");
|
||||
}
|
||||
if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
|
||||
if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
|
||||
{
|
||||
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
|
||||
const int monitorCount = SDL_GetNumVideoDisplays();
|
||||
|
||||
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
|
||||
if ((monitor > 0) && (monitor <= monitorCount))
|
||||
if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
|
||||
#else
|
||||
if ((monitor >= 0) && (monitor < monitorCount))
|
||||
#endif
|
||||
|
|
@ -621,12 +619,12 @@ void SetWindowState(unsigned int flags)
|
|||
}
|
||||
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
|
||||
}
|
||||
if (flags & FLAG_MSAA_4X_HINT)
|
||||
if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); // Enable multisampling buffers
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); // Enable multisampling
|
||||
}
|
||||
if (flags & FLAG_INTERLACED_HINT)
|
||||
if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_INTERLACED_HINT is not supported on PLATFORM_DESKTOP_SDL");
|
||||
}
|
||||
|
|
@ -635,74 +633,69 @@ void SetWindowState(unsigned int flags)
|
|||
// Clear window configuration state flags
|
||||
void ClearWindowState(unsigned int flags)
|
||||
{
|
||||
CORE.Window.flags &= ~flags;
|
||||
FLAG_CLEAR(CORE.Window.flags, flags);
|
||||
|
||||
if (flags & FLAG_VSYNC_HINT)
|
||||
if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
|
||||
{
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
}
|
||||
if (flags & FLAG_FULLSCREEN_MODE)
|
||||
if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
|
||||
{
|
||||
SDL_SetWindowFullscreen(platform.window, 0);
|
||||
CORE.Window.fullscreen = false;
|
||||
}
|
||||
if (flags & FLAG_WINDOW_RESIZABLE)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
|
||||
{
|
||||
SDL_SetWindowResizable(platform.window, SDL_FALSE);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_UNDECORATED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
|
||||
{
|
||||
SDL_SetWindowBordered(platform.window, SDL_TRUE);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_HIDDEN)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
|
||||
{
|
||||
SDL_ShowWindow(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MINIMIZED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
|
||||
{
|
||||
SDL_RestoreWindow(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MAXIMIZED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
|
||||
{
|
||||
SDL_RestoreWindow(platform.window);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_UNFOCUSED)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
|
||||
{
|
||||
//SDL_RaiseWindow(platform.window);
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_SDL");
|
||||
}
|
||||
if (flags & FLAG_WINDOW_TOPMOST)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
|
||||
{
|
||||
SDL_SetWindowAlwaysOnTop(platform.window, SDL_FALSE);
|
||||
}
|
||||
if (flags & FLAG_WINDOW_ALWAYS_RUN)
|
||||
{
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_ALWAYS_RUN;
|
||||
}
|
||||
if (flags & FLAG_WINDOW_TRANSPARENT)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_TRANSPARENT is not supported on PLATFORM_DESKTOP_SDL");
|
||||
}
|
||||
if (flags & FLAG_WINDOW_HIGHDPI)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
// NOTE: There also doesn't seem to be a feature to disable high DPI once enabled
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_HIGHDPI is not supported on PLATFORM_DESKTOP_SDL");
|
||||
}
|
||||
if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
|
||||
{
|
||||
//SDL_SetWindowGrab(platform.window, SDL_TRUE);
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_MOUSE_PASSTHROUGH is not supported on PLATFORM_DESKTOP_SDL");
|
||||
}
|
||||
if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
|
||||
if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
|
||||
{
|
||||
SDL_SetWindowFullscreen(platform.window, 0);
|
||||
}
|
||||
if (flags & FLAG_MSAA_4X_HINT)
|
||||
if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); // Disable multisampling buffers
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); // Disable multisampling
|
||||
}
|
||||
if (flags & FLAG_INTERLACED_HINT)
|
||||
if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_INTERLACED_HINT is not supported on PLATFORM_DESKTOP_SDL");
|
||||
}
|
||||
|
|
@ -838,7 +831,7 @@ void SetWindowMonitor(int monitor)
|
|||
{
|
||||
const int monitorCount = SDL_GetNumVideoDisplays();
|
||||
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
|
||||
if ((monitor > 0) && (monitor <= monitorCount))
|
||||
if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
|
||||
#else
|
||||
if ((monitor >= 0) && (monitor < monitorCount))
|
||||
#endif
|
||||
|
|
@ -847,7 +840,7 @@ void SetWindowMonitor(int monitor)
|
|||
// 1. SDL started supporting moving exclusive fullscreen windows between displays on SDL3,
|
||||
// see commit https://github.com/libsdl-org/SDL/commit/3f5ef7dd422057edbcf3e736107e34be4b75d9ba
|
||||
// 2. A workaround for SDL2 is leaving fullscreen, moving the window, then entering full screen again
|
||||
const bool wasFullscreen = ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)? true : false;
|
||||
const bool wasFullscreen = (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))? true : false;
|
||||
|
||||
const int screenWidth = CORE.Window.screen.width;
|
||||
const int screenHeight = CORE.Window.screen.height;
|
||||
|
|
@ -966,7 +959,7 @@ Vector2 GetMonitorPosition(int monitor)
|
|||
{
|
||||
const int monitorCount = SDL_GetNumVideoDisplays();
|
||||
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
|
||||
if ((monitor > 0) && (monitor <= monitorCount))
|
||||
if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
|
||||
#else
|
||||
if ((monitor >= 0) && (monitor < monitorCount))
|
||||
#endif
|
||||
|
|
@ -994,7 +987,7 @@ int GetMonitorWidth(int monitor)
|
|||
|
||||
const int monitorCount = SDL_GetNumVideoDisplays();
|
||||
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
|
||||
if ((monitor > 0) && (monitor <= monitorCount))
|
||||
if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
|
||||
#else
|
||||
if ((monitor >= 0) && (monitor < monitorCount))
|
||||
#endif
|
||||
|
|
@ -1015,7 +1008,7 @@ int GetMonitorHeight(int monitor)
|
|||
|
||||
const int monitorCount = SDL_GetNumVideoDisplays();
|
||||
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
|
||||
if ((monitor > 0) && (monitor <= monitorCount))
|
||||
if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
|
||||
#else
|
||||
if ((monitor >= 0) && (monitor < monitorCount))
|
||||
#endif
|
||||
|
|
@ -1036,7 +1029,7 @@ int GetMonitorPhysicalWidth(int monitor)
|
|||
|
||||
const int monitorCount = SDL_GetNumVideoDisplays();
|
||||
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
|
||||
if ((monitor > 0) && (monitor <= monitorCount))
|
||||
if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
|
||||
#else
|
||||
if ((monitor >= 0) && (monitor < monitorCount))
|
||||
#endif
|
||||
|
|
@ -1046,7 +1039,7 @@ int GetMonitorPhysicalWidth(int monitor)
|
|||
SDL_DisplayMode mode;
|
||||
SDL_GetCurrentDisplayMode(monitor, &mode);
|
||||
// Calculate size on inches, then convert to millimeter
|
||||
if (ddpi > 0.0f) width = (mode.w/ddpi)*25.4f;
|
||||
if (ddpi > 0.0f) width = (int)((mode.w/ddpi)*25.4f);
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
|
||||
|
||||
|
|
@ -1060,7 +1053,7 @@ int GetMonitorPhysicalHeight(int monitor)
|
|||
|
||||
const int monitorCount = SDL_GetNumVideoDisplays();
|
||||
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
|
||||
if ((monitor > 0) && (monitor <= monitorCount))
|
||||
if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
|
||||
#else
|
||||
if ((monitor >= 0) && (monitor < monitorCount))
|
||||
#endif
|
||||
|
|
@ -1070,7 +1063,7 @@ int GetMonitorPhysicalHeight(int monitor)
|
|||
SDL_DisplayMode mode;
|
||||
SDL_GetCurrentDisplayMode(monitor, &mode);
|
||||
// Calculate size on inches, then convert to millimeter
|
||||
if (ddpi > 0.0f) height = (mode.h/ddpi)*25.4f;
|
||||
if (ddpi > 0.0f) height = (int)((mode.h/ddpi)*25.4f);
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
|
||||
|
||||
|
|
@ -1084,7 +1077,7 @@ int GetMonitorRefreshRate(int monitor)
|
|||
|
||||
const int monitorCount = SDL_GetNumVideoDisplays();
|
||||
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
|
||||
if ((monitor > 0) && (monitor <= monitorCount))
|
||||
if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
|
||||
#else
|
||||
if ((monitor >= 0) && (monitor < monitorCount))
|
||||
#endif
|
||||
|
|
@ -1104,7 +1097,7 @@ const char *GetMonitorName(int monitor)
|
|||
const int monitorCount = SDL_GetNumVideoDisplays();
|
||||
|
||||
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
|
||||
if ((monitor > 0) && (monitor <= monitorCount))
|
||||
if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
|
||||
#else
|
||||
if ((monitor >= 0) && (monitor < monitorCount))
|
||||
#endif
|
||||
|
|
@ -1132,14 +1125,15 @@ Vector2 GetWindowScaleDPI(void)
|
|||
{
|
||||
Vector2 scale = { 1.0f, 1.0f };
|
||||
|
||||
#ifndef USING_VERSION_SDL3
|
||||
// NOTE: SDL_GetWindowDisplayScale was only added on SDL3
|
||||
// see https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale
|
||||
// TODO: Implement the window scale factor calculation manually
|
||||
TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
|
||||
#else
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
// NOTE: SDL_GetWindowDisplayScale added on SDL3
|
||||
// REF: https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale
|
||||
scale.x = SDL_GetWindowDisplayScale(platform.window);
|
||||
scale.y = scale.x;
|
||||
#else
|
||||
// NOTE: SDL_GetWindowDisplayScale not available on SDL2
|
||||
// TODO: Implement the window scale factor calculation manually
|
||||
TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
|
||||
#endif
|
||||
|
||||
return scale;
|
||||
|
|
@ -1193,14 +1187,14 @@ Image GetClipboardImage(void)
|
|||
size_t dataSize = 0;
|
||||
void *fileData = NULL;
|
||||
|
||||
for (int i = 0; i < SDL_arraysize(imageFormats); ++i)
|
||||
for (int i = 0; i < SDL_arraysize(imageFormats); i++)
|
||||
{
|
||||
// NOTE: This pointer should be free with SDL_free() at some point
|
||||
fileData = SDL_GetClipboardData(imageFormats[i], &dataSize);
|
||||
|
||||
if (fileData)
|
||||
{
|
||||
image = LoadImageFromMemory(imageExtensions[i], fileData, dataSize);
|
||||
image = LoadImageFromMemory(imageExtensions[i], fileData, (int)dataSize);
|
||||
if (IsImageValid(image))
|
||||
{
|
||||
TRACELOG(LOG_INFO, "Clipboard: Got image from clipboard successfully: %s", imageExtensions[i]);
|
||||
|
|
@ -1242,14 +1236,7 @@ void EnableCursor(void)
|
|||
{
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
// NOTE: SDL_ShowCursor() has been split into three functions:
|
||||
// SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible()
|
||||
SDL_ShowCursor();
|
||||
#else
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
#endif
|
||||
|
||||
ShowCursor();
|
||||
CORE.Input.Mouse.cursorLocked = false;
|
||||
}
|
||||
|
||||
|
|
@ -1258,6 +1245,7 @@ void DisableCursor(void)
|
|||
{
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
|
||||
HideCursor();
|
||||
CORE.Input.Mouse.cursorLocked = true;
|
||||
}
|
||||
|
||||
|
|
@ -1290,7 +1278,7 @@ double GetTime(void)
|
|||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself
|
||||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
// REF: https://github.com/raysan5/raylib/issues/686
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Security check to (partially) avoid malicious code
|
||||
|
|
@ -1406,11 +1394,11 @@ void PollInputEvents(void)
|
|||
//-----------------------------------------------------------------------------
|
||||
// WARNING: Indexes into this array are obtained by using SDL_Scancode values, not SDL_Keycode values
|
||||
//const Uint8 *keys = SDL_GetKeyboardState(NULL);
|
||||
//for (int i = 0; i < 256; ++i) CORE.Input.Keyboard.currentKeyState[i] = keys[i];
|
||||
//for (int i = 0; i < 256; i++) CORE.Input.Keyboard.currentKeyState[i] = keys[i];
|
||||
|
||||
CORE.Window.resizedLastFrame = false;
|
||||
|
||||
if ((CORE.Window.eventWaiting) || (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) && ((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) == 0)))
|
||||
if ((CORE.Window.eventWaiting) || (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED) && !FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN)))
|
||||
{
|
||||
SDL_WaitEvent(NULL);
|
||||
CORE.Time.previous = GetTime();
|
||||
|
|
@ -1436,11 +1424,13 @@ void PollInputEvents(void)
|
|||
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
|
||||
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
// const char *data; /**< The text for SDL_EVENT_DROP_TEXT and the file name for SDL_EVENT_DROP_FILE, NULL for other events */
|
||||
// Event memory is now managed by SDL, so you should not free the data in SDL_EVENT_DROP_FILE, and if you want to hold onto the text in SDL_EVENT_TEXT_EDITING and SDL_EVENT_TEXT_INPUT events, you should make a copy of it. SDL_TEXTINPUTEVENT_TEXT_SIZE is no longer necessary and has been removed.
|
||||
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
|
||||
// const char *data; // The text for SDL_EVENT_DROP_TEXT and the file name for SDL_EVENT_DROP_FILE, NULL for other events
|
||||
// Event memory is now managed by SDL, so you should not free the data in SDL_EVENT_DROP_FILE,
|
||||
// and if you want to hold onto the text in SDL_EVENT_TEXT_EDITING and SDL_EVENT_TEXT_INPUT events,
|
||||
// you should make a copy of it. SDL_TEXTINPUTEVENT_TEXT_SIZE is no longer necessary and has been removed
|
||||
strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data, MAX_FILEPATH_LENGTH - 1);
|
||||
#else
|
||||
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
|
||||
strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file, MAX_FILEPATH_LENGTH - 1);
|
||||
SDL_free(event.drop.file);
|
||||
#endif
|
||||
|
||||
|
|
@ -1451,9 +1441,9 @@ void PollInputEvents(void)
|
|||
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
|
||||
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
|
||||
strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data, MAX_FILEPATH_LENGTH - 1);
|
||||
#else
|
||||
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
|
||||
strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file, MAX_FILEPATH_LENGTH - 1);
|
||||
SDL_free(event.drop.file);
|
||||
#endif
|
||||
|
||||
|
|
@ -1463,13 +1453,13 @@ void PollInputEvents(void)
|
|||
|
||||
} break;
|
||||
|
||||
// Window events are also polled (Minimized, maximized, close...)
|
||||
// Window events are also polled (minimized, maximized, close...)
|
||||
|
||||
#ifndef USING_VERSION_SDL3
|
||||
// SDL3 states:
|
||||
// The SDL_WINDOWEVENT_* events have been moved to top level events, and SDL_WINDOWEVENT has been removed
|
||||
// In general, handling this change just means checking for the individual events instead of first checking for SDL_WINDOWEVENT
|
||||
// and then checking for window events. You can compare the event >= SDL_EVENT_WINDOW_FIRST and <= SDL_EVENT_WINDOW_LAST if you need to see whether it's a window event.
|
||||
// and then checking for window events. You can compare the event >= SDL_EVENT_WINDOW_FIRST and <= SDL_EVENT_WINDOW_LAST if you need to see whether it's a window event
|
||||
case SDL_WINDOWEVENT:
|
||||
{
|
||||
switch (event.window.event)
|
||||
|
|
@ -1482,7 +1472,7 @@ void PollInputEvents(void)
|
|||
const int height = event.window.data2;
|
||||
SetupViewport(width, height);
|
||||
// if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale
|
||||
if (IsWindowState(FLAG_WINDOW_HIGHDPI))
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
CORE.Window.screen.width = (int)(width/GetWindowScaleDPI().x);
|
||||
CORE.Window.screen.height = (int)(height/GetWindowScaleDPI().y);
|
||||
|
|
@ -1497,8 +1487,9 @@ void PollInputEvents(void)
|
|||
CORE.Window.resizedLastFrame = true;
|
||||
|
||||
#ifndef USING_VERSION_SDL3
|
||||
// Manually detect if the window was maximized (due to SDL2 restore being unreliable on some platforms) to remove the FLAG_WINDOW_MAXIMIZED accordingly
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0)
|
||||
// Manually detect if the window was maximized (due to SDL2 restore being unreliable on some platforms)
|
||||
// to remove the FLAG_WINDOW_MAXIMIZED accordingly
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED))
|
||||
{
|
||||
int borderTop = 0;
|
||||
int borderLeft = 0;
|
||||
|
|
@ -1508,59 +1499,53 @@ void PollInputEvents(void)
|
|||
SDL_Rect usableBounds;
|
||||
SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(platform.window), &usableBounds);
|
||||
|
||||
if ((width + borderLeft + borderRight != usableBounds.w) && (height + borderTop + borderBottom != usableBounds.h)) CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
|
||||
if ((width + borderLeft + borderRight != usableBounds.w) && (height + borderTop + borderBottom != usableBounds.h)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
|
||||
}
|
||||
#endif
|
||||
} break;
|
||||
|
||||
case SDL_WINDOWEVENT_ENTER:
|
||||
{
|
||||
CORE.Input.Mouse.cursorOnScreen = true;
|
||||
} break;
|
||||
case SDL_WINDOWEVENT_LEAVE:
|
||||
{
|
||||
CORE.Input.Mouse.cursorOnScreen = false;
|
||||
} break;
|
||||
case SDL_WINDOWEVENT_ENTER: CORE.Input.Mouse.cursorOnScreen = true; break;
|
||||
case SDL_WINDOWEVENT_LEAVE: CORE.Input.Mouse.cursorOnScreen = false; break;
|
||||
|
||||
case SDL_WINDOWEVENT_MINIMIZED:
|
||||
{
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED;
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
|
||||
} break;
|
||||
case SDL_WINDOWEVENT_MAXIMIZED:
|
||||
{
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
|
||||
} break;
|
||||
case SDL_WINDOWEVENT_RESTORED:
|
||||
{
|
||||
if ((SDL_GetWindowFlags(platform.window) & SDL_WINDOW_MINIMIZED) == 0)
|
||||
if (!FLAG_IS_SET(SDL_GetWindowFlags(platform.window), SDL_WINDOW_MINIMIZED))
|
||||
{
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED;
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
|
||||
}
|
||||
|
||||
#ifdef USING_VERSION_SDL3
|
||||
if ((SDL_GetWindowFlags(platform.window) & SDL_WINDOW_MAXIMIZED) == 0)
|
||||
if (!FLAG_IS_SET(SDL_GetWindowFlags(platform.window), SDL_WINDOW_MAXIMIZED))
|
||||
{
|
||||
if ((CORE.Window.flags & SDL_WINDOW_MAXIMIZED) > 0) CORE.Window.flags &= ~SDL_WINDOW_MAXIMIZED;
|
||||
if (FLAG_IS_SET(CORE.Window.flags, SDL_WINDOW_MAXIMIZED)) FLAG_CLEAR(CORE.Window.flags, SDL_WINDOW_MAXIMIZED);
|
||||
}
|
||||
#endif
|
||||
} break;
|
||||
|
||||
case SDL_WINDOWEVENT_HIDDEN:
|
||||
{
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) == 0) CORE.Window.flags |= FLAG_WINDOW_HIDDEN;
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN);
|
||||
} break;
|
||||
case SDL_WINDOWEVENT_SHOWN:
|
||||
{
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN;
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_HIDDEN);
|
||||
} break;
|
||||
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||
{
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
|
||||
} break;
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
{
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0) CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
|
||||
} break;
|
||||
|
||||
#ifndef USING_VERSION_SDL3
|
||||
|
|
@ -1573,7 +1558,7 @@ void PollInputEvents(void)
|
|||
case SDL_KEYDOWN:
|
||||
{
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
// SDL3 Migration: The following structures have been removed: * SDL_Keysym
|
||||
// SDL3 Migration: The following structures have been removed: SDL_Keysym
|
||||
KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
|
||||
#else
|
||||
KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
|
||||
|
|
@ -1593,11 +1578,9 @@ void PollInputEvents(void)
|
|||
|
||||
if (event.key.repeat) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
|
||||
|
||||
// TODO: Put exitKey verification outside the switch?
|
||||
if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey])
|
||||
{
|
||||
CORE.Window.shouldClose = true;
|
||||
}
|
||||
// Check for registered exit key to request exit game loop on next iteration
|
||||
if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey]) CORE.Window.shouldClose = true;
|
||||
|
||||
} break;
|
||||
|
||||
case SDL_KEYUP:
|
||||
|
|
@ -1708,7 +1691,7 @@ void PollInputEvents(void)
|
|||
int jid = event.jdevice.which; // Joystick device index
|
||||
|
||||
// check if already added at InitPlatform
|
||||
for (int i = 0; i < MAX_GAMEPADS; ++i)
|
||||
for (int i = 0; i < MAX_GAMEPADS; i++)
|
||||
{
|
||||
if (jid == platform.gamepadId[i])
|
||||
{
|
||||
|
|
@ -1734,12 +1717,11 @@ void PollInputEvents(void)
|
|||
CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
|
||||
CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
|
||||
memset(CORE.Input.Gamepad.name[nextAvailableSlot], 0, MAX_GAMEPAD_NAME_LENGTH);
|
||||
strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], SDL_GameControllerNameForIndex(nextAvailableSlot), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
|
||||
const char *controllerName = SDL_GameControllerNameForIndex(nextAvailableSlot);
|
||||
if (controllerName != NULL) strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], controllerName, MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
else strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], "noname", 6);
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
|
||||
}
|
||||
} break;
|
||||
case SDL_JOYDEVICEREMOVED:
|
||||
|
|
@ -1762,7 +1744,11 @@ void PollInputEvents(void)
|
|||
{
|
||||
int button = -1;
|
||||
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
switch (event.gbutton.button)
|
||||
#else
|
||||
switch (event.jbutton.button)
|
||||
#endif
|
||||
{
|
||||
case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break;
|
||||
case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break;
|
||||
|
|
@ -1790,7 +1776,11 @@ void PollInputEvents(void)
|
|||
{
|
||||
for (int i = 0; i < MAX_GAMEPADS; i++)
|
||||
{
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
if (platform.gamepadId[i] == event.gbutton.which)
|
||||
#else
|
||||
if (platform.gamepadId[i] == event.jbutton.which)
|
||||
#endif
|
||||
{
|
||||
CORE.Input.Gamepad.currentButtonState[i][button] = 1;
|
||||
CORE.Input.Gamepad.lastButtonPressed = button;
|
||||
|
|
@ -1803,7 +1793,11 @@ void PollInputEvents(void)
|
|||
{
|
||||
int button = -1;
|
||||
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
switch (event.gbutton.button)
|
||||
#else
|
||||
switch (event.jbutton.button)
|
||||
#endif
|
||||
{
|
||||
case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break;
|
||||
case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break;
|
||||
|
|
@ -1831,7 +1825,11 @@ void PollInputEvents(void)
|
|||
{
|
||||
for (int i = 0; i < MAX_GAMEPADS; i++)
|
||||
{
|
||||
#if defined(USING_VERSION_SDL3)
|
||||
if (platform.gamepadId[i] == event.gbutton.which)
|
||||
#else
|
||||
if (platform.gamepadId[i] == event.jbutton.which)
|
||||
#endif
|
||||
{
|
||||
CORE.Input.Gamepad.currentButtonState[i][button] = 0;
|
||||
if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
|
||||
|
|
@ -1930,38 +1928,30 @@ int InitPlatform(void)
|
|||
// Initialize graphic device: display/window and graphic context
|
||||
//----------------------------------------------------------------------------
|
||||
unsigned int flags = 0;
|
||||
flags |= SDL_WINDOW_SHOWN;
|
||||
flags |= SDL_WINDOW_INPUT_FOCUS;
|
||||
flags |= SDL_WINDOW_MOUSE_FOCUS;
|
||||
flags |= SDL_WINDOW_MOUSE_CAPTURE; // Window has mouse captured
|
||||
FLAG_SET(flags, SDL_WINDOW_SHOWN);
|
||||
FLAG_SET(flags, SDL_WINDOW_INPUT_FOCUS);
|
||||
FLAG_SET(flags, SDL_WINDOW_MOUSE_FOCUS);
|
||||
FLAG_SET(flags, SDL_WINDOW_MOUSE_CAPTURE); // Window has mouse captured
|
||||
|
||||
// Check window creation flags
|
||||
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) FLAG_SET(flags, SDL_WINDOW_FULLSCREEN);
|
||||
|
||||
//if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_SET(flags, SDL_WINDOW_HIDDEN);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) FLAG_SET(flags, SDL_WINDOW_BORDERLESS);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) FLAG_SET(flags, SDL_WINDOW_RESIZABLE);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) FLAG_SET(flags, SDL_WINDOW_MINIMIZED);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(flags, SDL_WINDOW_MAXIMIZED);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED))
|
||||
{
|
||||
CORE.Window.fullscreen = true;
|
||||
flags |= SDL_WINDOW_FULLSCREEN;
|
||||
FLAG_CLEAR(flags, SDL_WINDOW_INPUT_FOCUS);
|
||||
FLAG_CLEAR(flags, SDL_WINDOW_MOUSE_FOCUS);
|
||||
}
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TOPMOST)) FLAG_SET(flags, SDL_WINDOW_ALWAYS_ON_TOP);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) FLAG_CLEAR(flags, SDL_WINDOW_MOUSE_CAPTURE);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) FLAG_SET(flags, SDL_WINDOW_ALLOW_HIGHDPI);
|
||||
|
||||
//if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) == 0) flags |= SDL_WINDOW_HIDDEN;
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) flags |= SDL_WINDOW_BORDERLESS;
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) flags |= SDL_WINDOW_RESIZABLE;
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) flags |= SDL_WINDOW_MINIMIZED;
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) flags |= SDL_WINDOW_MAXIMIZED;
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0)
|
||||
{
|
||||
flags &= ~SDL_WINDOW_INPUT_FOCUS;
|
||||
flags &= ~SDL_WINDOW_MOUSE_FOCUS;
|
||||
}
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) flags |= SDL_WINDOW_ALWAYS_ON_TOP;
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) flags |= SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
|
||||
//if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) flags |= SDL_WINDOW_TRANSPARENT; // Alternative: SDL_GL_ALPHA_SIZE = 8
|
||||
|
||||
//if ((CORE.Window.flags & FLAG_FULLSCREEN_DESKTOP) > 0) flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
//if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) FLAG_SET(flags, SDL_WINDOW_TRANSPARENT); // Alternative: SDL_GL_ALPHA_SIZE = 8
|
||||
//if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_DESKTOP)) FLAG_SET(flags, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||
|
||||
// NOTE: Some OpenGL context attributes must be set before window creation
|
||||
|
||||
|
|
@ -2004,7 +1994,7 @@ int InitPlatform(void)
|
|||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
}
|
||||
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
|
||||
|
|
@ -2047,7 +2037,7 @@ int InitPlatform(void)
|
|||
|
||||
if (platform.glContext != NULL)
|
||||
{
|
||||
SDL_GL_SetSwapInterval((CORE.Window.flags & FLAG_VSYNC_HINT)? 1 : 0);
|
||||
SDL_GL_SetSwapInterval((FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT))? 1: 0);
|
||||
|
||||
// Load OpenGL extensions
|
||||
// NOTE: GL procedures address loader is required to load extensions
|
||||
|
|
@ -2070,33 +2060,28 @@ int InitPlatform(void)
|
|||
platform.gamepadId[i] = -1; // Set all gamepad initial instance ids as invalid to not conflict with instance id zero
|
||||
}
|
||||
|
||||
int numJoysticks = 0;
|
||||
SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks); // array of joystick IDs, they do not start from 0
|
||||
int numJoysticks = SDL_NumJoysticks();
|
||||
|
||||
if (joysticks)
|
||||
for (int i = 0; (i < numJoysticks) && (i < MAX_GAMEPADS); i++)
|
||||
{
|
||||
for (int i = 0; (i < numJoysticks) && (i < MAX_GAMEPADS); i++)
|
||||
{
|
||||
platform.gamepad[i] = SDL_GameControllerOpen(joysticks[i]);
|
||||
platform.gamepadId[i] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[i]));
|
||||
platform.gamepad[i] = SDL_GameControllerOpen(i);
|
||||
platform.gamepadId[i] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[i]));
|
||||
|
||||
if (platform.gamepad[i])
|
||||
{
|
||||
CORE.Input.Gamepad.ready[i] = true;
|
||||
CORE.Input.Gamepad.axisCount[i] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[i]));
|
||||
CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
|
||||
CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
|
||||
strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
CORE.Input.Gamepad.name[i][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0';
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
|
||||
if (platform.gamepad[i])
|
||||
{
|
||||
CORE.Input.Gamepad.ready[i] = true;
|
||||
CORE.Input.Gamepad.axisCount[i] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[i]));
|
||||
CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
|
||||
CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
|
||||
strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||
CORE.Input.Gamepad.name[i][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0';
|
||||
}
|
||||
SDL_free(joysticks);
|
||||
else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
|
||||
}
|
||||
|
||||
// Disable mouse events being interpreted as touch events
|
||||
// NOTE: This is wanted because there are SDL_FINGER* events available which provide unique data
|
||||
// Due to the way PollInputEvents() and rgestures.h are currently implemented, setting this won't break SUPPORT_MOUSE_GESTURES
|
||||
// Due to the way PollInputEvents() and rgestures.h are currently implemented, setting this won't break SUPPORT_MOUSE_GESTURES
|
||||
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||
|
||||
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
||||
|
|
@ -2212,7 +2197,7 @@ static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event)
|
|||
for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
|
||||
{
|
||||
SDL_Finger *finger = SDL_GetTouchFinger(event.touchId, i);
|
||||
CORE.Input.Touch.pointId[i] = finger->id;
|
||||
CORE.Input.Touch.pointId[i] = (int)finger->id;
|
||||
CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width;
|
||||
CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height;
|
||||
CORE.Input.Touch.currentTouchState[i] = 1;
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@
|
|||
#include <shellscalingapi.h>
|
||||
#include <versionhelpers.h>
|
||||
|
||||
#include <malloc.h> // Required for alloca()
|
||||
|
||||
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
|
|
@ -195,8 +197,8 @@ static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL;
|
|||
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
||||
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
||||
#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
|
||||
#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
|
||||
#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
|
||||
#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
|
|
@ -260,9 +262,9 @@ static bool DecoratedFromStyle(DWORD style)
|
|||
// Get window style from required flags
|
||||
static DWORD MakeWindowStyle(unsigned flags)
|
||||
{
|
||||
// We don't need this since we don't have any child windows, but I guess
|
||||
// it improves efficiency, plus, windows adds this flag automatically anyway
|
||||
// so it keeps our flags in sync with the OS
|
||||
// Flag is not needed because there are no child windows,
|
||||
// but supposedly it improves efficiency, plus, windows adds this
|
||||
// flag automatically anyway so it keeps flags in sync with the OS
|
||||
DWORD style = WS_CLIPSIBLINGS;
|
||||
|
||||
style |= (flags & FLAG_WINDOW_HIDDEN)? 0 : WS_VISIBLE;
|
||||
|
|
@ -271,7 +273,7 @@ static DWORD MakeWindowStyle(unsigned flags)
|
|||
|
||||
// Minimized takes precedence over maximized
|
||||
int mized = MIZED_NONE;
|
||||
if (FLAG_CHECK(flags, FLAG_WINDOW_MINIMIZED)) mized = MIZED_MIN;
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED)) mized = MIZED_MIN;
|
||||
if (flags & FLAG_WINDOW_MAXIMIZED) mized = MIZED_MAX;
|
||||
|
||||
switch (mized)
|
||||
|
|
@ -937,7 +939,7 @@ void SetWindowIcon(Image image)
|
|||
// Set icon for window
|
||||
void SetWindowIcons(Image *images, int count)
|
||||
{
|
||||
// TODO.
|
||||
// TODO: Implement SetWindowIcons()
|
||||
}
|
||||
|
||||
void SetWindowTitle(const char *title)
|
||||
|
|
@ -1228,7 +1230,7 @@ void SwapScreenBuffer(void)
|
|||
// Get elapsed time measure in seconds
|
||||
double GetTime(void)
|
||||
{
|
||||
LARGE_INTEGER now;
|
||||
LARGE_INTEGER now = 0;
|
||||
QueryPerformanceCounter(&now);
|
||||
return (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart;
|
||||
}
|
||||
|
|
@ -1237,14 +1239,18 @@ double GetTime(void)
|
|||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself
|
||||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
// REF: https://github.com/raysan5/raylib/issues/686
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Security check to (partially) avoid malicious code on target platform
|
||||
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "OpenURL not implemented");
|
||||
char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
|
||||
sprintf(cmd, "explorer \"%s\"", url);
|
||||
int result = system(cmd);
|
||||
if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
|
||||
RL_FREE(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1871,13 +1877,23 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
|
|||
} break;
|
||||
case WM_DPICHANGED:
|
||||
{
|
||||
// Get current dpi scale factor
|
||||
float scalex = HIWORD(wParam)/96.0f;
|
||||
float scaley = LOWORD(wParam)/96.0f;
|
||||
|
||||
RECT *suggestedRect = (RECT *)lparam;
|
||||
|
||||
// Never set the window size to anything other than the suggested rect here
|
||||
// Doing so can cause a window to stutter between monitors when transitioning between them
|
||||
int result = (int)SetWindowPos(hwnd, NULL, suggestedRect->left, suggestedRect->top,
|
||||
suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
int result = (int)SetWindowPos(hwnd, NULL,
|
||||
suggestedRect->left, suggestedRect->top,
|
||||
suggestedRect->right - suggestedRect->left,
|
||||
suggestedRect->bottom - suggestedRect->top,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
|
||||
if (result == 0) TRACELOG(LOG_ERROR, "Failed to set window position [ERROR: %lu]", GetLastError());
|
||||
|
||||
// TODO: Update screen data, render size, screen scaling, viewport...
|
||||
|
||||
} break;
|
||||
case WM_SETCURSOR:
|
||||
|
|
@ -1981,7 +1997,7 @@ static void HandleKey(WPARAM wparam, LPARAM lparam, char state)
|
|||
{
|
||||
CORE.Input.Keyboard.currentKeyState[key] = state;
|
||||
|
||||
if ((key == KEY_ESCAPE) && (state == 1)) CORE.Window.shouldClose = 1;
|
||||
if ((key == KEY_ESCAPE) && (state == 1)) CORE.Window.shouldClose = true;
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "INPUT: Unknown (or currently unhandled) virtual keycode %d (0x%x)", wparam, wparam);
|
||||
|
||||
|
|
@ -2033,8 +2049,7 @@ static void HandleWindowResize(HWND hwnd, int *width, int *height)
|
|||
// TODO: Update framebuffer on resize
|
||||
CORE.Window.currentFbo.width = (int)clientSize.cx;
|
||||
CORE.Window.currentFbo.height = (int)clientSize.cy;
|
||||
//glViewport(0, 0, clientSize.cx, clientSize.cy);
|
||||
//SetupFramebuffer(0, 0);
|
||||
//SetupViewport(0, 0, clientSize.cx, clientSize.cy);
|
||||
|
||||
SetupViewport(clientSize.cx, clientSize.cy);
|
||||
CORE.Window.resizedLastFrame = true;
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ static const short linuxToRaylibMap[KEYMAP_SIZE] = {
|
|||
248, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
// Gamepads are mapped according to:
|
||||
// https://www.kernel.org/doc/html/next/input/gamepad.html
|
||||
// REF: https://www.kernel.org/doc/html/next/input/gamepad.html
|
||||
// Those mappings are standardized, but that doesn't mean people follow
|
||||
// the standards, so this is more of an approximation
|
||||
[BTN_DPAD_UP] = GAMEPAD_BUTTON_LEFT_FACE_UP,
|
||||
|
|
@ -269,6 +269,8 @@ static int FindMatchingConnectorMode(const drmModeConnector *connector, const dr
|
|||
static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search exactly matching DRM connector mode in connector's list
|
||||
static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search the nearest matching DRM connector mode in connector's list
|
||||
|
||||
static void SetupFramebuffer(int width, int height); // Setup main framebuffer (required by InitPlatform())
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -641,7 +643,7 @@ static uint32_t GetOrCreateFbForBo(struct gbm_bo *bo)
|
|||
}
|
||||
|
||||
// Renders a blank frame to allocate initial buffers
|
||||
// TODO: WARNING: Platform layers do not include OpenGL code!
|
||||
// TODO: WARNING: Platform backend should not include OpenGL code
|
||||
void RenderBlankFrame()
|
||||
{
|
||||
glClearColor(0, 0, 0, 1);
|
||||
|
|
@ -828,15 +830,6 @@ void SwapScreenBuffer(void)
|
|||
return;
|
||||
}
|
||||
|
||||
// Get the software rendered color buffer
|
||||
int bufferWidth = 0, bufferHeight = 0;
|
||||
void *colorBuffer = swGetColorBuffer(&bufferWidth, &bufferHeight);
|
||||
if (!colorBuffer)
|
||||
{
|
||||
TRACELOG(LOG_ERROR, "DISPLAY: Failed to get software color buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieving the dimensions of the display mode used
|
||||
drmModeModeInfo *mode = &platform.connector->modes[platform.modeIndex];
|
||||
uint32_t width = mode->hdisplay;
|
||||
|
|
@ -904,16 +897,8 @@ void SwapScreenBuffer(void)
|
|||
}
|
||||
|
||||
// Copy the software rendered buffer to the dumb buffer with scaling if needed
|
||||
if (bufferWidth == width && bufferHeight == height)
|
||||
{
|
||||
// Direct copy if sizes match
|
||||
swCopyFramebuffer(0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scale the software buffer to match the display mode
|
||||
swBlitFramebuffer(0, 0, width, height, 0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
|
||||
}
|
||||
// NOTE: RLSW will make a simple copy if the dimensions match
|
||||
swBlitFramebuffer(0, 0, width, height, 0, 0, width, height, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
|
||||
|
||||
// Unmap the buffer
|
||||
munmap(dumbBuffer, creq.size);
|
||||
|
|
@ -1034,7 +1019,7 @@ double GetTime(void)
|
|||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself
|
||||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
// REF: https://github.com/raysan5/raylib/issues/686
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "OpenURL() not implemented on target platform");
|
||||
|
|
@ -1165,8 +1150,7 @@ int InitPlatform(void)
|
|||
|
||||
// Initialize graphic device: display/window and graphic context
|
||||
//----------------------------------------------------------------------------
|
||||
CORE.Window.fullscreen = true;
|
||||
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
|
||||
#if defined(DEFAULT_GRAPHIC_DEVICE_DRM)
|
||||
platform.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR);
|
||||
|
|
@ -1231,9 +1215,9 @@ int InitPlatform(void)
|
|||
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i modes detected: %i", i, con->count_modes);
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i status: %s", i,
|
||||
(con->connection == DRM_MODE_CONNECTED) ? "CONNECTED" :
|
||||
(con->connection == DRM_MODE_DISCONNECTED) ? "DISCONNECTED" :
|
||||
(con->connection == DRM_MODE_UNKNOWNCONNECTION) ? "UNKNOWN" : "OTHER");
|
||||
(con->connection == DRM_MODE_CONNECTED)? "CONNECTED" :
|
||||
(con->connection == DRM_MODE_DISCONNECTED)? "DISCONNECTED" :
|
||||
(con->connection == DRM_MODE_UNKNOWNCONNECTION)? "UNKNOWN" : "OTHER");
|
||||
|
||||
// In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected
|
||||
// This might be a hardware or software limitation like on Raspberry Pi Zero with composite output
|
||||
|
|
@ -1315,8 +1299,8 @@ int InitPlatform(void)
|
|||
CORE.Window.screen.height = CORE.Window.display.height;
|
||||
}
|
||||
|
||||
const bool allowInterlaced = CORE.Window.flags & FLAG_INTERLACED_HINT;
|
||||
const int fps = (CORE.Time.target > 0) ? (1.0/CORE.Time.target) : 60;
|
||||
const bool allowInterlaced = FLAG_IS_SET(CORE.Window.flags, FLAG_INTERLACED_HINT);
|
||||
const int fps = (CORE.Time.target > 0)? (1.0/CORE.Time.target) : 60;
|
||||
|
||||
// Try to find an exact matching mode
|
||||
platform.modeIndex = FindExactConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced);
|
||||
|
|
@ -1346,7 +1330,7 @@ int InitPlatform(void)
|
|||
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u)", platform.connector->modes[platform.modeIndex].name,
|
||||
platform.connector->modes[platform.modeIndex].hdisplay, platform.connector->modes[platform.modeIndex].vdisplay,
|
||||
(platform.connector->modes[platform.modeIndex].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p',
|
||||
FLAG_IS_SET(platform.connector->modes[platform.modeIndex].flags, DRM_MODE_FLAG_INTERLACE)? 'i' : 'p',
|
||||
platform.connector->modes[platform.modeIndex].vrefresh);
|
||||
|
||||
drmModeFreeEncoder(enc);
|
||||
|
|
@ -1363,7 +1347,7 @@ int InitPlatform(void)
|
|||
platform.connector->modes[0].name,
|
||||
platform.connector->modes[0].hdisplay,
|
||||
platform.connector->modes[0].vdisplay,
|
||||
(platform.connector->modes[0].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p',
|
||||
(platform.connector->modes[0].flags & DRM_MODE_FLAG_INTERLACE)? 'i' : 'p',
|
||||
platform.connector->modes[0].vrefresh);
|
||||
}
|
||||
else
|
||||
|
|
@ -1402,7 +1386,7 @@ int InitPlatform(void)
|
|||
|
||||
EGLint samples = 0;
|
||||
EGLint sampleBuffer = 0;
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
|
||||
{
|
||||
samples = 4;
|
||||
sampleBuffer = 1;
|
||||
|
|
@ -1474,7 +1458,7 @@ int InitPlatform(void)
|
|||
|
||||
// find the EGL config that matches the previously setup GBM format
|
||||
int found = 0;
|
||||
for (EGLint i = 0; i < matchingNumConfigs; ++i)
|
||||
for (EGLint i = 0; i < matchingNumConfigs; i++)
|
||||
{
|
||||
EGLint id = 0;
|
||||
if (!eglGetConfigAttrib(platform.device, configs[i], EGL_NATIVE_VISUAL_ID, &id))
|
||||
|
|
@ -1579,17 +1563,17 @@ int InitPlatform(void)
|
|||
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
|
||||
#endif
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
|
||||
|
||||
// If graphic device is no properly initialized, we end program
|
||||
if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; }
|
||||
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
|
||||
|
||||
// Set some default window flags
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // false
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // false
|
||||
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // true
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // false
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_HIDDEN); // false
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // false
|
||||
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // true
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // false
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Initialize timing system
|
||||
|
|
@ -1738,8 +1722,8 @@ static void InitKeyboard(void)
|
|||
|
||||
// New terminal settings for keyboard: turn off buffering (non-canonical mode), echo and key processing
|
||||
// NOTE: ISIG controls if ^C and ^Z generate break signals or not
|
||||
keyboardNewSettings.c_lflag &= ~(ICANON | ECHO | ISIG);
|
||||
//keyboardNewSettings.c_iflag &= ~(ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF);
|
||||
FLAG_CLEAR(keyboardNewSettings.c_lflag, ICANON | ECHO | ISIG);
|
||||
//FLAG_CLEAR(keyboardNewSettings.c_iflag, ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF);
|
||||
keyboardNewSettings.c_cc[VMIN] = 1;
|
||||
keyboardNewSettings.c_cc[VTIME] = 0;
|
||||
|
||||
|
|
@ -1758,10 +1742,10 @@ static void InitKeyboard(void)
|
|||
else
|
||||
{
|
||||
// Reconfigure keyboard mode to get:
|
||||
// - scancodes (K_RAW)
|
||||
// - keycodes (K_MEDIUMRAW)
|
||||
// - ASCII chars (K_XLATE)
|
||||
// - UNICODE chars (K_UNICODE)
|
||||
// - scancodes (K_RAW)
|
||||
// - keycodes (K_MEDIUMRAW)
|
||||
// - ASCII chars (K_XLATE)
|
||||
// - UNICODE chars (K_UNICODE)
|
||||
ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE); // ASCII chars
|
||||
}
|
||||
|
||||
|
|
@ -1883,7 +1867,7 @@ static void ProcessKeyboard(void)
|
|||
}
|
||||
#endif // SUPPORT_SSH_KEYBOARD_RPI
|
||||
|
||||
// Initialise user input from evdev(/dev/input/event<N>)
|
||||
// Initialize user input from evdev(/dev/input/event<N>)
|
||||
// this means mouse, keyboard or gamepad devices
|
||||
static void InitEvdevInput(void)
|
||||
{
|
||||
|
|
@ -1891,12 +1875,12 @@ static void InitEvdevInput(void)
|
|||
DIR *directory = NULL;
|
||||
struct dirent *entity = NULL;
|
||||
|
||||
// Initialise keyboard file descriptor
|
||||
// Initialize keyboard file descriptor
|
||||
platform.keyboardFd = -1;
|
||||
platform.mouseFd = -1;
|
||||
|
||||
// Reset variables
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; ++i)
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
||||
{
|
||||
CORE.Input.Touch.position[i].x = -1;
|
||||
CORE.Input.Touch.position[i].y = -1;
|
||||
|
|
@ -2578,7 +2562,7 @@ static int FindMatchingConnectorMode(const drmModeConnector *connector, const dr
|
|||
for (size_t i = 0; i < connector->count_modes; i++)
|
||||
{
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, connector->modes[i].hdisplay, connector->modes[i].vdisplay,
|
||||
connector->modes[i].vrefresh, (connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive");
|
||||
connector->modes[i].vrefresh, (FLAG_IS_SET(connector->modes[i].flags, DRM_MODE_FLAG_INTERLACE) > 0)? "interlaced" : "progressive");
|
||||
|
||||
if (0 == BINCMP(&platform.crtc->mode, &platform.connector->modes[i])) return i;
|
||||
}
|
||||
|
|
@ -2599,9 +2583,9 @@ static int FindExactConnectorMode(const drmModeConnector *connector, uint width,
|
|||
{
|
||||
const drmModeModeInfo *const mode = &platform.connector->modes[i];
|
||||
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM Mode %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh, (mode->flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive");
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM Mode %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh, (FLAG_IS_SET(mode->flags, DRM_MODE_FLAG_INTERLACE) > 0)? "interlaced" : "progressive");
|
||||
|
||||
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && !allowInterlaced) continue;
|
||||
if ((FLAG_IS_SET(mode->flags, DRM_MODE_FLAG_INTERLACE) > 0) && !allowInterlaced) continue;
|
||||
|
||||
if ((mode->hdisplay == width) && (mode->vdisplay == height) && (mode->vrefresh == fps)) return i;
|
||||
}
|
||||
|
|
@ -2625,7 +2609,7 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
|
|||
const drmModeModeInfo *const mode = &platform.connector->modes[i];
|
||||
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh,
|
||||
(mode->flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive");
|
||||
(FLAG_IS_SET(mode->flags, DRM_MODE_FLAG_INTERLACE) > 0)? "interlaced" : "progressive");
|
||||
|
||||
if ((mode->hdisplay < width) || (mode->vdisplay < height))
|
||||
{
|
||||
|
|
@ -2633,13 +2617,13 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
|
|||
continue;
|
||||
}
|
||||
|
||||
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && !allowInterlaced)
|
||||
if ((FLAG_IS_SET(mode->flags, DRM_MODE_FLAG_INTERLACE) > 0) && !allowInterlaced)
|
||||
{
|
||||
TRACELOG(LOG_TRACE, "DISPLAY: DRM shouldn't choose an interlaced mode");
|
||||
continue;
|
||||
}
|
||||
|
||||
const int unusedPixels = (mode->hdisplay - width) * (mode->vdisplay - height);
|
||||
const int unusedPixels = (mode->hdisplay - width)*(mode->vdisplay - height);
|
||||
const int fpsDiff = mode->vrefresh - fps;
|
||||
|
||||
if ((unusedPixels < minUnusedPixels) ||
|
||||
|
|
@ -2655,4 +2639,82 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
|
|||
return nearestIndex;
|
||||
}
|
||||
|
||||
// Compute framebuffer size relative to screen size and display size
|
||||
// NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified
|
||||
static void SetupFramebuffer(int width, int height)
|
||||
{
|
||||
// Calculate CORE.Window.render.width and CORE.Window.render.height, we have the display size (input params) and the desired screen size (global var)
|
||||
if ((CORE.Window.screen.width > CORE.Window.display.width) || (CORE.Window.screen.height > CORE.Window.display.height))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Downscaling required: Screen size (%ix%i) is bigger than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
|
||||
|
||||
// Downscaling to fit display with border-bars
|
||||
float widthRatio = (float)CORE.Window.display.width/(float)CORE.Window.screen.width;
|
||||
float heightRatio = (float)CORE.Window.display.height/(float)CORE.Window.screen.height;
|
||||
|
||||
if (widthRatio <= heightRatio)
|
||||
{
|
||||
CORE.Window.render.width = CORE.Window.display.width;
|
||||
CORE.Window.render.height = (int)round((float)CORE.Window.screen.height*widthRatio);
|
||||
CORE.Window.renderOffset.x = 0;
|
||||
CORE.Window.renderOffset.y = (CORE.Window.display.height - CORE.Window.render.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Window.render.width = (int)round((float)CORE.Window.screen.width*heightRatio);
|
||||
CORE.Window.render.height = CORE.Window.display.height;
|
||||
CORE.Window.renderOffset.x = (CORE.Window.display.width - CORE.Window.render.width);
|
||||
CORE.Window.renderOffset.y = 0;
|
||||
}
|
||||
|
||||
// Screen scaling required
|
||||
float scaleRatio = (float)CORE.Window.render.width/(float)CORE.Window.screen.width;
|
||||
CORE.Window.screenScale = MatrixScale(scaleRatio, scaleRatio, 1.0f);
|
||||
|
||||
// NOTE: We render to full display resolution!
|
||||
// We just need to calculate above parameters for downscale matrix and offsets
|
||||
CORE.Window.render.width = CORE.Window.display.width;
|
||||
CORE.Window.render.height = CORE.Window.display.height;
|
||||
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Downscale matrix generated, content will be rendered at (%ix%i)", CORE.Window.render.width, CORE.Window.render.height);
|
||||
}
|
||||
else if ((CORE.Window.screen.width < CORE.Window.display.width) || (CORE.Window.screen.height < CORE.Window.display.height))
|
||||
{
|
||||
// Required screen size is smaller than display size
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Upscaling required: Screen size (%ix%i) smaller than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
|
||||
|
||||
if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
|
||||
{
|
||||
CORE.Window.screen.width = CORE.Window.display.width;
|
||||
CORE.Window.screen.height = CORE.Window.display.height;
|
||||
}
|
||||
|
||||
// Upscaling to fit display with border-bars
|
||||
float displayRatio = (float)CORE.Window.display.width/(float)CORE.Window.display.height;
|
||||
float screenRatio = (float)CORE.Window.screen.width/(float)CORE.Window.screen.height;
|
||||
|
||||
if (displayRatio <= screenRatio)
|
||||
{
|
||||
CORE.Window.render.width = CORE.Window.screen.width;
|
||||
CORE.Window.render.height = (int)round((float)CORE.Window.screen.width/displayRatio);
|
||||
CORE.Window.renderOffset.x = 0;
|
||||
CORE.Window.renderOffset.y = (CORE.Window.render.height - CORE.Window.screen.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Window.render.width = (int)round((float)CORE.Window.screen.height*displayRatio);
|
||||
CORE.Window.render.height = CORE.Window.screen.height;
|
||||
CORE.Window.renderOffset.x = (CORE.Window.render.width - CORE.Window.screen.width);
|
||||
CORE.Window.renderOffset.y = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Window.render.width = CORE.Window.screen.width;
|
||||
CORE.Window.render.height = CORE.Window.screen.height;
|
||||
CORE.Window.renderOffset.x = 0;
|
||||
CORE.Window.renderOffset.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
|
|||
594
src/platforms/rcore_memory.c
Normal file
594
src/platforms/rcore_memory.c
Normal file
|
|
@ -0,0 +1,594 @@
|
|||
/**********************************************************************************************
|
||||
*
|
||||
* rcore_memory - Functions to manage window, graphics device and inputs
|
||||
*
|
||||
* PLATFORM: MEMORY (No OS)
|
||||
* - Memory framebuffer output (no os)
|
||||
*
|
||||
* LIMITATIONS:
|
||||
* - Software renderer (rlsw)
|
||||
* - No input system
|
||||
*
|
||||
* POSSIBLE IMPROVEMENTS:
|
||||
* - Improvement 01
|
||||
* - Improvement 02
|
||||
*
|
||||
* ADDITIONAL NOTES:
|
||||
* - TRACELOG() function is located in raylib [utils] module
|
||||
*
|
||||
* CONFIGURATION:
|
||||
* #define RCORE_PLATFORM_CUSTOM_FLAG
|
||||
* Custom flag for rcore on target platform -not used-
|
||||
*
|
||||
* DEPENDENCIES:
|
||||
* - rlsw: Software renderer
|
||||
* - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs)
|
||||
*
|
||||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2025 Ramon Santamaria (@raysan5) and contributors
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************************************/
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <conio.h> // Required for: kbhit()
|
||||
#else
|
||||
// Provide kbhit() function in non-Windows platforms
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
// Platform-specific required data for timming (Win32)
|
||||
#if defined(_WIN32)
|
||||
typedef struct _LARGE_INTEGER { int64_t QuadPart; } LARGE_INTEGER;
|
||||
__declspec(dllimport) int __stdcall QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
|
||||
__declspec(dllimport) int __stdcall QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
unsigned int *pixels; // Pointer to pixel data buffer (RGBA8888 format)
|
||||
#if defined(_WIN32)
|
||||
LARGE_INTEGER timerFrequency;
|
||||
#endif
|
||||
} PlatformData;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
extern CoreData CORE; // Global CORE state context
|
||||
|
||||
static PlatformData platform = { 0 }; // Platform specific data
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Internal Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
int InitPlatform(void); // Initialize platform (graphics, inputs and more)
|
||||
bool InitGraphicsDevice(void); // Initialize graphics device
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
// NOTE: Functions declaration is provided by raylib.h
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Internal Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
#if !defined(_WIN32)
|
||||
static int kbhit(void); // Check if a key has been pressed
|
||||
static char getch(void) { return getchar(); } // Get pressed character
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition: Window and Graphics Device
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Check if application should close
|
||||
bool WindowShouldClose(void)
|
||||
{
|
||||
if (CORE.Window.ready) return CORE.Window.shouldClose;
|
||||
else return true;
|
||||
}
|
||||
|
||||
// Toggle fullscreen mode
|
||||
void ToggleFullscreen(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ToggleFullscreen() not available on target platform");
|
||||
}
|
||||
|
||||
// Toggle borderless windowed mode
|
||||
void ToggleBorderlessWindowed(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform");
|
||||
}
|
||||
|
||||
// Set window state: maximized, if resizable
|
||||
void MaximizeWindow(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "MaximizeWindow() not available on target platform");
|
||||
}
|
||||
|
||||
// Set window state: minimized
|
||||
void MinimizeWindow(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform");
|
||||
}
|
||||
|
||||
// Restore window from being minimized/maximized
|
||||
void RestoreWindow(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
|
||||
}
|
||||
|
||||
// Set window configuration state using flags
|
||||
void SetWindowState(unsigned int flags)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState() not available on target platform");
|
||||
}
|
||||
|
||||
// Clear window configuration state flags
|
||||
void ClearWindowState(unsigned int flags)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState() not available on target platform");
|
||||
}
|
||||
|
||||
// Set icon for window
|
||||
void SetWindowIcon(Image image)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowIcon() not available on target platform");
|
||||
}
|
||||
|
||||
// Set icon for window
|
||||
void SetWindowIcons(Image *images, int count)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowIcons() not available on target platform");
|
||||
}
|
||||
|
||||
// Set title for window
|
||||
void SetWindowTitle(const char *title)
|
||||
{
|
||||
CORE.Window.title = title;
|
||||
}
|
||||
|
||||
// Set window position on screen (windowed mode)
|
||||
void SetWindowPosition(int x, int y)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowPosition() not available on target platform");
|
||||
}
|
||||
|
||||
// Set monitor for the current window
|
||||
void SetWindowMonitor(int monitor)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowMonitor() not available on target platform");
|
||||
}
|
||||
|
||||
// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
|
||||
void SetWindowMinSize(int width, int height)
|
||||
{
|
||||
CORE.Window.screenMin.width = width;
|
||||
CORE.Window.screenMin.height = height;
|
||||
}
|
||||
|
||||
// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
|
||||
void SetWindowMaxSize(int width, int height)
|
||||
{
|
||||
CORE.Window.screenMax.width = width;
|
||||
CORE.Window.screenMax.height = height;
|
||||
}
|
||||
|
||||
// Set window dimensions
|
||||
void SetWindowSize(int width, int height)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowSize() not available on target platform");
|
||||
}
|
||||
|
||||
// Set window opacity, value opacity is between 0.0 and 1.0
|
||||
void SetWindowOpacity(float opacity)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowOpacity() not available on target platform");
|
||||
}
|
||||
|
||||
// Set window focused
|
||||
void SetWindowFocused(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowFocused() not available on target platform");
|
||||
}
|
||||
|
||||
// Get native window handle
|
||||
void *GetWindowHandle(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetWindowHandle() not implemented on target platform");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get number of monitors
|
||||
int GetMonitorCount(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetMonitorCount() not implemented on target platform");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get current monitor where window is placed
|
||||
int GetCurrentMonitor(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get selected monitor position
|
||||
Vector2 GetMonitorPosition(int monitor)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetMonitorPosition() not implemented on target platform");
|
||||
return (Vector2){ 0, 0 };
|
||||
}
|
||||
|
||||
// Get selected monitor width (currently used by monitor)
|
||||
int GetMonitorWidth(int monitor)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetMonitorWidth() not implemented on target platform");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get selected monitor height (currently used by monitor)
|
||||
int GetMonitorHeight(int monitor)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetMonitorHeight() not implemented on target platform");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get selected monitor physical width in millimetres
|
||||
int GetMonitorPhysicalWidth(int monitor)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetMonitorPhysicalWidth() not implemented on target platform");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get selected monitor physical height in millimetres
|
||||
int GetMonitorPhysicalHeight(int monitor)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetMonitorPhysicalHeight() not implemented on target platform");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get selected monitor refresh rate
|
||||
int GetMonitorRefreshRate(int monitor)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetMonitorRefreshRate() not implemented on target platform");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the human-readable, UTF-8 encoded name of the selected monitor
|
||||
const char *GetMonitorName(int monitor)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetMonitorName() not implemented on target platform");
|
||||
return "";
|
||||
}
|
||||
|
||||
// Get window position XY on monitor
|
||||
Vector2 GetWindowPosition(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetWindowPosition() not implemented on target platform");
|
||||
return (Vector2){ 0, 0 };
|
||||
}
|
||||
|
||||
// Get window scale DPI factor for current monitor
|
||||
Vector2 GetWindowScaleDPI(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
|
||||
return (Vector2){ 1.0f, 1.0f };
|
||||
}
|
||||
|
||||
// Set clipboard text content
|
||||
void SetClipboardText(const char *text)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetClipboardText() not implemented on target platform");
|
||||
}
|
||||
|
||||
// Get clipboard text content
|
||||
// NOTE: returned string is allocated and freed by GLFW
|
||||
const char *GetClipboardText(void)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetClipboardText() not implemented on target platform");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get clipboard image
|
||||
Image GetClipboardImage(void)
|
||||
{
|
||||
Image image = { 0 };
|
||||
|
||||
TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
// Show mouse cursor
|
||||
void ShowCursor(void)
|
||||
{
|
||||
CORE.Input.Mouse.cursorHidden = false;
|
||||
}
|
||||
|
||||
// Hides mouse cursor
|
||||
void HideCursor(void)
|
||||
{
|
||||
CORE.Input.Mouse.cursorHidden = true;
|
||||
}
|
||||
|
||||
// Enables cursor (unlock cursor)
|
||||
void EnableCursor(void)
|
||||
{
|
||||
// Set cursor position in the middle
|
||||
SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
|
||||
|
||||
CORE.Input.Mouse.cursorHidden = false;
|
||||
}
|
||||
|
||||
// Disables cursor (lock cursor)
|
||||
void DisableCursor(void)
|
||||
{
|
||||
// Set cursor position in the middle
|
||||
SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
|
||||
|
||||
CORE.Input.Mouse.cursorHidden = true;
|
||||
}
|
||||
|
||||
// Swap back buffer with front buffer (screen drawing)
|
||||
void SwapScreenBuffer(void)
|
||||
{
|
||||
// Update framebuffer
|
||||
rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.pixels);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition: Misc
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Get elapsed time measure in seconds since InitTimer()
|
||||
double GetTime(void)
|
||||
{
|
||||
double time = 0.0;
|
||||
#if defined(_WIN32)
|
||||
LARGE_INTEGER now = { 0 };
|
||||
QueryPerformanceCounter(&now);
|
||||
return (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart;
|
||||
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
|
||||
struct timespec ts = { 0 };
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
|
||||
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
|
||||
#endif
|
||||
return time;
|
||||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if you control the URL given.
|
||||
// A user could craft a malicious string performing another action.
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself.
|
||||
// REF: https://github.com/raysan5/raylib/issues/686
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Security check to (partially) avoid malicious code on target platform
|
||||
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
|
||||
else
|
||||
{
|
||||
char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
|
||||
sprintf(cmd, "explorer \"%s\"", url);
|
||||
int result = system(cmd);
|
||||
if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
|
||||
RL_FREE(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition: Inputs
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Set internal gamepad mappings
|
||||
int SetGamepadMappings(const char *mappings)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetGamepadMappings() not implemented on target platform");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set gamepad vibration
|
||||
void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetGamepadVibration() not implemented on target platform");
|
||||
}
|
||||
|
||||
// Set mouse position XY
|
||||
void SetMousePosition(int x, int y)
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
}
|
||||
|
||||
// Set mouse cursor
|
||||
void SetMouseCursor(int cursor)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
|
||||
}
|
||||
|
||||
// Get physical key name
|
||||
const char *GetKeyName(int key)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");
|
||||
return "";
|
||||
}
|
||||
|
||||
// Register all input events
|
||||
void PollInputEvents(void)
|
||||
{
|
||||
#if defined(SUPPORT_GESTURES_SYSTEM)
|
||||
// NOTE: Gestures update must be called every frame to reset gestures correctly
|
||||
// because ProcessGestureEvent() is just called on an event, not every frame
|
||||
UpdateGestures();
|
||||
#endif
|
||||
|
||||
// Reset keys/chars pressed registered
|
||||
CORE.Input.Keyboard.keyPressedQueueCount = 0;
|
||||
CORE.Input.Keyboard.charPressedQueueCount = 0;
|
||||
|
||||
// Reset key repeats
|
||||
for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
|
||||
|
||||
// Reset last gamepad button/axis registered state
|
||||
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
|
||||
//CORE.Input.Gamepad.axisCount = 0;
|
||||
|
||||
// Register previous touch states
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
|
||||
|
||||
// Reset touch positions
|
||||
// TODO: It resets on target platform the mouse position and not filled again until a move-event,
|
||||
// so, if mouse is not moved it returns a (0, 0) position... this behaviour should be reviewed!
|
||||
//for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 };
|
||||
|
||||
// Register previous keys states
|
||||
// NOTE: Android supports up to 260 keys
|
||||
for (int i = 0; i < 260; i++)
|
||||
{
|
||||
CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
|
||||
CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
|
||||
}
|
||||
|
||||
// TODO: Poll input events for current platform
|
||||
|
||||
// Check for key pressed to exit
|
||||
if (kbhit())
|
||||
{
|
||||
int key = getch();
|
||||
if (key == 27) CORE.Window.shouldClose = true; // KEY_SCAPE
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Internal Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Initialize platform: graphics, inputs and more
|
||||
int InitPlatform(void)
|
||||
{
|
||||
// Memory framebuffer can only work with software renderer
|
||||
if (rlGetVersion() != RL_OPENGL_11_SOFTWARE)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Memory platform requires software renderer (GRAPHICS_API_OPENGL_11_SOFTWARE)");
|
||||
TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load memory framebuffer with desired screen size
|
||||
platform.pixels = (unsigned int *)RL_CALLOC(CORE.Window.screen.width*CORE.Window.screen.height, sizeof(int));
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// If everything work as expected, we can continue
|
||||
CORE.Window.render.width = CORE.Window.screen.width;
|
||||
CORE.Window.render.height = CORE.Window.screen.height;
|
||||
CORE.Window.currentFbo.width = CORE.Window.render.width;
|
||||
CORE.Window.currentFbo.height = CORE.Window.render.height;
|
||||
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
|
||||
TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
|
||||
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
|
||||
|
||||
CORE.Window.ready = true;
|
||||
|
||||
// TODO: Load OpenGL extensions
|
||||
// NOTE: GL procedures address loader is required to load extensions
|
||||
//----------------------------------------------------------------------------
|
||||
// ...
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// TODO: Initialize input events system
|
||||
// It could imply keyboard, mouse, gamepad, touch...
|
||||
// Depending on the platform libraries/SDK it could use a callback mechanism
|
||||
// For system events and inputs evens polling on a per-frame basis, use PollInputEvents()
|
||||
//----------------------------------------------------------------------------
|
||||
// ...
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Initialize timing system
|
||||
//----------------------------------------------------------------------------
|
||||
#if defined(_WIN32)
|
||||
LARGE_INTEGER time = { 0 };
|
||||
QueryPerformanceCounter(&time);
|
||||
QueryPerformanceFrequency(&platform.timerFrequency);
|
||||
CORE.Time.base = time.QuadPart;
|
||||
#endif
|
||||
InitTimer();
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Initialize storage system
|
||||
//----------------------------------------------------------------------------
|
||||
CORE.Storage.basePath = GetWorkingDirectory();
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
TRACELOG(LOG_INFO, "PLATFORM: MEMORY: Initialized successfully");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Close platform
|
||||
void ClosePlatform(void)
|
||||
{
|
||||
RL_FREE(platform.pixels);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Internal Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
#if !defined(_WIN32)
|
||||
// Check if a key has been pressed
|
||||
static int kbhit(void)
|
||||
{
|
||||
struct termios oldt = { 0 };
|
||||
struct termios newt = { 0 };
|
||||
int ch = 0;
|
||||
int oldf = 0;
|
||||
|
||||
tcgetattr(STDIN_FILENO, &oldt);
|
||||
newt = oldt;
|
||||
newt.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
||||
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
|
||||
|
||||
ch = getchar();
|
||||
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||
fcntl(STDIN_FILENO, F_SETFL, oldf);
|
||||
|
||||
if (ch != EOF)
|
||||
{
|
||||
ungetc(ch, stdin);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// EOF
|
||||
|
|
@ -54,11 +54,6 @@
|
|||
typedef struct {
|
||||
// TODO: Define the platform specific variables required
|
||||
|
||||
// Display data
|
||||
EGLDisplay device; // Native display device (physical screen connection)
|
||||
EGLSurface surface; // Surface to draw on, framebuffers (connected to context)
|
||||
EGLContext context; // Graphic context, mode in which drawing can be done
|
||||
EGLConfig config; // Graphic config
|
||||
} PlatformData;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -346,10 +341,10 @@ void SwapScreenBuffer(void)
|
|||
double GetTime(void)
|
||||
{
|
||||
double time = 0.0;
|
||||
|
||||
struct timespec ts = { 0 };
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
|
||||
|
||||
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
|
||||
|
||||
return time;
|
||||
|
|
@ -366,7 +361,7 @@ void OpenURL(const char *url)
|
|||
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
|
||||
else
|
||||
{
|
||||
// TODO:
|
||||
// TODO: Load url using default browser
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -459,89 +454,20 @@ int InitPlatform(void)
|
|||
// raylib uses OpenGL so, platform should create that kind of connection
|
||||
// Below example illustrates that process using EGL library
|
||||
//----------------------------------------------------------------------------
|
||||
CORE.Window.fullscreen = true;
|
||||
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
|
||||
EGLint samples = 0;
|
||||
EGLint sampleBuffer = 0;
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
|
||||
{
|
||||
samples = 4;
|
||||
sampleBuffer = 1;
|
||||
// TODO: Enable MSAA
|
||||
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4");
|
||||
}
|
||||
|
||||
const EGLint framebufferAttribs[] =
|
||||
{
|
||||
EGL_RENDERABLE_TYPE, (rlGetVersion() == RL_OPENGL_ES_30)? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, // Type of context support
|
||||
EGL_RED_SIZE, 8, // RED color bit depth (alternative: 5)
|
||||
EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6)
|
||||
EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5)
|
||||
//EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI)
|
||||
EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!)
|
||||
//EGL_STENCIL_SIZE, 8, // Stencil buffer size
|
||||
EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA
|
||||
EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs)
|
||||
EGL_NONE
|
||||
};
|
||||
// TODO: Init display and graphic device
|
||||
|
||||
const EGLint contextAttribs[] =
|
||||
{
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
EGLint numConfigs = 0;
|
||||
|
||||
// Get an EGL device connection
|
||||
platform.device = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
if (platform.device == EGL_NO_DISPLAY)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize the EGL device connection
|
||||
if (eglInitialize(platform.device, NULL, NULL) == EGL_FALSE)
|
||||
{
|
||||
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get an appropriate EGL framebuffer configuration
|
||||
eglChooseConfig(platform.device, framebufferAttribs, &platform.config, 1, &numConfigs);
|
||||
|
||||
// Set rendering API
|
||||
eglBindAPI(EGL_OPENGL_ES_API);
|
||||
|
||||
// Create an EGL rendering context
|
||||
platform.context = eglCreateContext(platform.device, platform.config, EGL_NO_CONTEXT, contextAttribs);
|
||||
if (platform.context == EGL_NO_CONTEXT)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create an EGL window surface
|
||||
EGLint displayFormat = 0;
|
||||
|
||||
// EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry()
|
||||
// As soon as we picked a EGLConfig, we can safely reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID
|
||||
eglGetConfigAttrib(platform.device, platform.config, EGL_NATIVE_VISUAL_ID, &displayFormat);
|
||||
|
||||
// Android specific call
|
||||
ANativeWindow_setBuffersGeometry(platform.app->window, 0, 0, displayFormat); // Force use of native display size
|
||||
|
||||
platform.surface = eglCreateWindowSurface(platform.device, platform.config, platform.app->window, NULL);
|
||||
|
||||
// There must be at least one frame displayed before the buffers are swapped
|
||||
eglSwapInterval(platform.device, 1);
|
||||
|
||||
EGLBoolean result = eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context);
|
||||
|
||||
// Check surface and context activation
|
||||
if (result != EGL_FALSE)
|
||||
// TODO: Check display, device and context activation
|
||||
bool result = true;
|
||||
if (result)
|
||||
{
|
||||
CORE.Window.ready = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,13 @@ typedef struct {
|
|||
bool ourFullscreen; // Internal var to filter our handling of fullscreen vs the user handling of fullscreen
|
||||
int unmaximizedWidth; // Internal var to store the unmaximized window (canvas) width
|
||||
int unmaximizedHeight; // Internal var to store the unmaximized window (canvas) height
|
||||
|
||||
char canvasId[64]; // Keep current canvas id where wasm app is running
|
||||
// NOTE: Useful when trying to run multiple wasms in different canvases in same webpage
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
unsigned int *pixels; // Pointer to pixel data buffer (RGBA 32bit format)
|
||||
#endif
|
||||
} PlatformData;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -129,7 +136,7 @@ static void MouseEnterCallback(GLFWwindow *window, int enter);
|
|||
|
||||
// Emscripten window callback events
|
||||
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);
|
||||
// static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
|
||||
//static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
|
||||
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
|
||||
static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData);
|
||||
static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData);
|
||||
|
|
@ -142,7 +149,11 @@ static EM_BOOL EmscriptenPointerlockCallback(int eventType, const EmscriptenPoin
|
|||
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
|
||||
static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData);
|
||||
|
||||
static const char *GetCanvasId(void);
|
||||
// JS: Set the canvas id provided by the module configuration
|
||||
EM_JS(void, SetCanvasIdJs, (char *out, int outSize), {
|
||||
var canvasId = "#" + Module.canvas.id;
|
||||
stringToUTF8(canvasId, out, outSize);
|
||||
});
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
|
|
@ -181,8 +192,8 @@ void ToggleFullscreen(void)
|
|||
const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
|
||||
if (wasFullscreen)
|
||||
{
|
||||
if (CORE.Window.flags & FLAG_FULLSCREEN_MODE) enterFullscreen = false;
|
||||
else if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) enterFullscreen = true;
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) enterFullscreen = false;
|
||||
else if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE)) enterFullscreen = true;
|
||||
else
|
||||
{
|
||||
const int canvasWidth = EM_ASM_INT( { return Module.canvas.width; }, 0);
|
||||
|
|
@ -193,24 +204,21 @@ void ToggleFullscreen(void)
|
|||
|
||||
EM_ASM(document.exitFullscreen(););
|
||||
|
||||
CORE.Window.fullscreen = false;
|
||||
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
|
||||
CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
|
||||
}
|
||||
else enterFullscreen = true;
|
||||
|
||||
if (enterFullscreen)
|
||||
{
|
||||
// NOTE: The setTimeouts handle the browser mode change delay
|
||||
EM_ASM
|
||||
(
|
||||
setTimeout(function()
|
||||
{
|
||||
EM_ASM(
|
||||
setTimeout(function(){
|
||||
Module.requestFullscreen(false, false);
|
||||
}, 100);
|
||||
);
|
||||
CORE.Window.fullscreen = true;
|
||||
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
|
||||
|
||||
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
}
|
||||
|
||||
// NOTE: Old notes below:
|
||||
|
|
@ -227,17 +235,17 @@ void ToggleFullscreen(void)
|
|||
*/
|
||||
// EM_ASM(Module.requestFullscreen(false, false););
|
||||
/*
|
||||
if (!CORE.Window.fullscreen)
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
|
||||
{
|
||||
// Option 1: Request fullscreen for the canvas element
|
||||
// This option does not seem to work at all:
|
||||
// emscripten_request_pointerlock() and emscripten_request_fullscreen() are affected by web security,
|
||||
// the user must click once on the canvas to hide the pointer or transition to full screen
|
||||
//emscripten_request_fullscreen("#canvas", false);
|
||||
//emscripten_request_fullscreen(platform.canvasId, false);
|
||||
|
||||
// Option 2: Request fullscreen for the canvas element with strategy
|
||||
// This option does not seem to work at all
|
||||
// Ref: https://github.com/emscripten-core/emscripten/issues/5124
|
||||
// REF: https://github.com/emscripten-core/emscripten/issues/5124
|
||||
// EmscriptenFullscreenStrategy strategy = {
|
||||
// .scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH, //EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT,
|
||||
// .canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF,
|
||||
|
|
@ -245,7 +253,7 @@ void ToggleFullscreen(void)
|
|||
// .canvasResizedCallback = EmscriptenWindowResizedCallback,
|
||||
// .canvasResizedCallbackUserData = NULL
|
||||
// };
|
||||
//emscripten_request_fullscreen_strategy("#canvas", EM_FALSE, &strategy);
|
||||
//emscripten_request_fullscreen_strategy(platform.canvasId, EM_FALSE, &strategy);
|
||||
|
||||
// Option 3: Request fullscreen for the canvas element with strategy
|
||||
// It works as expected but only inside the browser (client area)
|
||||
|
|
@ -256,14 +264,14 @@ void ToggleFullscreen(void)
|
|||
.canvasResizedCallback = EmscriptenWindowResizedCallback,
|
||||
.canvasResizedCallbackUserData = NULL
|
||||
};
|
||||
emscripten_enter_soft_fullscreen("#canvas", &strategy);
|
||||
emscripten_enter_soft_fullscreen(platform.canvasId, &strategy);
|
||||
|
||||
int width, height;
|
||||
emscripten_get_canvas_element_size("#canvas", &width, &height);
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
emscripten_get_canvas_element_size(platform.canvasId, &width, &height);
|
||||
TRACELOG(LOG_WARNING, "Emscripten: Enter fullscreen: Canvas size: %i x %i", width, height);
|
||||
|
||||
CORE.Window.fullscreen = true; // Toggle fullscreen flag
|
||||
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -271,11 +279,10 @@ void ToggleFullscreen(void)
|
|||
//emscripten_exit_soft_fullscreen();
|
||||
|
||||
int width, height;
|
||||
emscripten_get_canvas_element_size("#canvas", &width, &height);
|
||||
emscripten_get_canvas_element_size(platform.canvasId, &width, &height);
|
||||
TRACELOG(LOG_WARNING, "Emscripten: Exit fullscreen: Canvas size: %i x %i", width, height);
|
||||
|
||||
CORE.Window.fullscreen = false; // Toggle fullscreen flag
|
||||
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
@ -289,8 +296,8 @@ void ToggleBorderlessWindowed(void)
|
|||
const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
|
||||
if (wasFullscreen)
|
||||
{
|
||||
if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) enterBorderless = false;
|
||||
else if (CORE.Window.flags & FLAG_FULLSCREEN_MODE) enterBorderless = true;
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE)) enterBorderless = false;
|
||||
else if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) enterBorderless = true;
|
||||
else
|
||||
{
|
||||
const int canvasWidth = EM_ASM_INT( { return Module.canvas.width; }, 0);
|
||||
|
|
@ -301,16 +308,15 @@ void ToggleBorderlessWindowed(void)
|
|||
|
||||
EM_ASM(document.exitFullscreen(););
|
||||
|
||||
CORE.Window.fullscreen = false;
|
||||
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
|
||||
CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
|
||||
}
|
||||
else enterBorderless = true;
|
||||
|
||||
if (enterBorderless)
|
||||
{
|
||||
// NOTE: 1. The setTimeouts handle the browser mode change delay
|
||||
// 2. The style unset handles the possibility of a width="value%" like on the default shell.html file
|
||||
// 1. The setTimeouts handle the browser mode change delay
|
||||
// 2. The style unset handles the possibility of a width="value%" like on the default shell.html file
|
||||
EM_ASM
|
||||
(
|
||||
setTimeout(function()
|
||||
|
|
@ -322,14 +328,14 @@ void ToggleBorderlessWindowed(void)
|
|||
}, 100);
|
||||
}, 100);
|
||||
);
|
||||
CORE.Window.flags |= FLAG_BORDERLESS_WINDOWED_MODE;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
|
||||
}
|
||||
}
|
||||
|
||||
// Set window state: maximized, if resizable
|
||||
void MaximizeWindow(void)
|
||||
{
|
||||
if ((glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) && !(CORE.Window.flags & FLAG_WINDOW_MAXIMIZED))
|
||||
if ((glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) && !(FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)))
|
||||
{
|
||||
platform.unmaximizedWidth = CORE.Window.screen.width;
|
||||
platform.unmaximizedHeight = CORE.Window.screen.height;
|
||||
|
|
@ -339,7 +345,7 @@ void MaximizeWindow(void)
|
|||
|
||||
if (tabWidth && tabHeight) glfwSetWindowSize(platform.handle, tabWidth, tabHeight);
|
||||
|
||||
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -352,11 +358,11 @@ void MinimizeWindow(void)
|
|||
// Restore window from being minimized/maximized
|
||||
void RestoreWindow(void)
|
||||
{
|
||||
if ((glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) && (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED))
|
||||
if ((glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) && (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)))
|
||||
{
|
||||
if (platform.unmaximizedWidth && platform.unmaximizedHeight) glfwSetWindowSize(platform.handle, platform.unmaximizedWidth, platform.unmaximizedHeight);
|
||||
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -369,13 +375,13 @@ void SetWindowState(unsigned int flags)
|
|||
// NOTE: In most cases the functions already change the flags internally
|
||||
|
||||
// State change: FLAG_VSYNC_HINT
|
||||
if ((flags & FLAG_VSYNC_HINT) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_VSYNC_HINT) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_BORDERLESS_WINDOWED_MODE
|
||||
if ((flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
|
||||
{
|
||||
// NOTE: Window state flag updated inside ToggleBorderlessWindowed() function
|
||||
const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
|
||||
|
|
@ -383,13 +389,13 @@ void SetWindowState(unsigned int flags)
|
|||
{
|
||||
const int canvasWidth = EM_ASM_INT( { return Module.canvas.width; }, 0);
|
||||
const int canvasStyleWidth = EM_ASM_INT( { return parseInt(Module.canvas.style.width); }, 0);
|
||||
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) || canvasStyleWidth > canvasWidth) ToggleBorderlessWindowed();
|
||||
if ((FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) || canvasStyleWidth > canvasWidth) ToggleBorderlessWindowed();
|
||||
}
|
||||
else ToggleBorderlessWindowed();
|
||||
}
|
||||
|
||||
// State change: FLAG_FULLSCREEN_MODE
|
||||
if ((flags & FLAG_FULLSCREEN_MODE) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
|
||||
{
|
||||
// NOTE: Window state flag updated inside ToggleFullscreen() function
|
||||
const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
|
||||
|
|
@ -397,38 +403,38 @@ void SetWindowState(unsigned int flags)
|
|||
{
|
||||
const int canvasWidth = EM_ASM_INT( { return Module.canvas.width; }, 0);
|
||||
const int screenWidth = EM_ASM_INT( { return screen.width; }, 0);
|
||||
if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) || screenWidth == canvasWidth ) ToggleFullscreen();
|
||||
if ((FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE)) || screenWidth == canvasWidth ) ToggleFullscreen();
|
||||
}
|
||||
else ToggleFullscreen();
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_RESIZABLE
|
||||
if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) != (flags & FLAG_WINDOW_RESIZABLE)) && ((flags & FLAG_WINDOW_RESIZABLE) > 0))
|
||||
if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) != FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE)) && (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE)))
|
||||
{
|
||||
glfwSetWindowAttrib(platform.handle, GLFW_RESIZABLE, GLFW_TRUE);
|
||||
CORE.Window.flags |= FLAG_WINDOW_RESIZABLE;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE);
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_UNDECORATED
|
||||
if ((flags & FLAG_WINDOW_UNDECORATED) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_UNDECORATED) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_HIDDEN
|
||||
if ((flags & FLAG_WINDOW_HIDDEN) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_HIDDEN) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_MINIMIZED
|
||||
if ((flags & FLAG_WINDOW_MINIMIZED) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_MINIMIZED) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_MAXIMIZED
|
||||
if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) != (flags & FLAG_WINDOW_MAXIMIZED)) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0))
|
||||
if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED) != FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED)) && (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED)))
|
||||
{
|
||||
if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
|
||||
{
|
||||
|
|
@ -440,24 +446,24 @@ void SetWindowState(unsigned int flags)
|
|||
|
||||
if (tabWidth && tabHeight) glfwSetWindowSize(platform.handle, tabWidth, tabHeight);
|
||||
|
||||
CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
|
||||
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
|
||||
}
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_UNFOCUSED
|
||||
if ((flags & FLAG_WINDOW_UNFOCUSED) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_UNFOCUSED) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_TOPMOST
|
||||
if ((flags & FLAG_WINDOW_TOPMOST) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_TOPMOST) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_ALWAYS_RUN
|
||||
if ((flags & FLAG_WINDOW_ALWAYS_RUN) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_ALWAYS_RUN) not available on target platform");
|
||||
}
|
||||
|
|
@ -466,31 +472,31 @@ void SetWindowState(unsigned int flags)
|
|||
// NOTE: Review for PLATFORM_WEB
|
||||
|
||||
// State change: FLAG_WINDOW_TRANSPARENT
|
||||
if ((flags & FLAG_WINDOW_TRANSPARENT) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_TRANSPARENT) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_HIGHDPI
|
||||
if ((flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_HIGHDPI) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
|
||||
if ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_MOUSE_PASSTHROUGH) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_MSAA_4X_HINT
|
||||
if ((flags & FLAG_MSAA_4X_HINT) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_MSAA_4X_HINT) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_INTERLACED_HINT
|
||||
if ((flags & FLAG_INTERLACED_HINT) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_INTERLACED_HINT) not available on target platform");
|
||||
}
|
||||
|
|
@ -503,90 +509,89 @@ void ClearWindowState(unsigned int flags)
|
|||
// NOTE: In most cases the functions already change the flags internally
|
||||
|
||||
// State change: FLAG_VSYNC_HINT
|
||||
if ((flags & FLAG_VSYNC_HINT) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_VSYNC_HINT) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_BORDERLESS_WINDOWED_MODE
|
||||
if ((flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
|
||||
{
|
||||
const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
|
||||
if (wasFullscreen)
|
||||
{
|
||||
const int canvasWidth = EM_ASM_INT( { return Module.canvas.width; }, 0);
|
||||
const int screenWidth = EM_ASM_INT( { return screen.width; }, 0);
|
||||
if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) || (screenWidth == canvasWidth)) EM_ASM(document.exitFullscreen(););
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE) || (screenWidth == canvasWidth)) EM_ASM(document.exitFullscreen(););
|
||||
}
|
||||
|
||||
CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
|
||||
}
|
||||
|
||||
// State change: FLAG_FULLSCREEN_MODE
|
||||
if ((flags & FLAG_FULLSCREEN_MODE) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
|
||||
{
|
||||
const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
|
||||
if (wasFullscreen)
|
||||
{
|
||||
const int canvasWidth = EM_ASM_INT( { return Module.canvas.width; }, 0);
|
||||
const int canvasStyleWidth = EM_ASM_INT( { return parseInt(Module.canvas.style.width); }, 0);
|
||||
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) || (canvasStyleWidth > canvasWidth)) EM_ASM(document.exitFullscreen(););
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE) || (canvasStyleWidth > canvasWidth)) EM_ASM(document.exitFullscreen(););
|
||||
}
|
||||
|
||||
CORE.Window.fullscreen = false;
|
||||
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_RESIZABLE
|
||||
if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) && ((flags & FLAG_WINDOW_RESIZABLE) > 0))
|
||||
if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) && (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE)))
|
||||
{
|
||||
glfwSetWindowAttrib(platform.handle, GLFW_RESIZABLE, GLFW_FALSE);
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_RESIZABLE;
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_RESIZABLE);
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_HIDDEN
|
||||
if ((flags & FLAG_WINDOW_HIDDEN) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_HIDDEN) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_MINIMIZED
|
||||
if ((flags & FLAG_WINDOW_MINIMIZED) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_MINIMIZED) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_MAXIMIZED
|
||||
if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0))
|
||||
if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) && (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED)))
|
||||
{
|
||||
if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
|
||||
{
|
||||
if (platform.unmaximizedWidth && platform.unmaximizedHeight) glfwSetWindowSize(platform.handle, platform.unmaximizedWidth, platform.unmaximizedHeight);
|
||||
|
||||
CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
|
||||
}
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_UNDECORATED
|
||||
if ((flags & FLAG_WINDOW_UNDECORATED) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_UNDECORATED) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_UNFOCUSED
|
||||
if ((flags & FLAG_WINDOW_UNFOCUSED) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_UNFOCUSED) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_TOPMOST
|
||||
if ((flags & FLAG_WINDOW_TOPMOST) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_TOPMOST) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_ALWAYS_RUN
|
||||
if ((flags & FLAG_WINDOW_ALWAYS_RUN) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_ALWAYS_RUN) not available on target platform");
|
||||
}
|
||||
|
|
@ -595,31 +600,31 @@ void ClearWindowState(unsigned int flags)
|
|||
// NOTE: Review for PLATFORM_WEB
|
||||
|
||||
// State change: FLAG_WINDOW_TRANSPARENT
|
||||
if ((flags & FLAG_WINDOW_TRANSPARENT) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_TRANSPARENT) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_HIGHDPI
|
||||
if ((flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_HIGHDPI) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
|
||||
if ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_MOUSE_PASSTHROUGH) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_MSAA_4X_HINT
|
||||
if ((flags & FLAG_MSAA_4X_HINT) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_MSAA_4X_HINT) not available on target platform");
|
||||
}
|
||||
|
||||
// State change: FLAG_INTERLACED_HINT
|
||||
if ((flags & FLAG_INTERLACED_HINT) > 0)
|
||||
if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_INTERLACED_HINT) not available on target platform");
|
||||
}
|
||||
|
|
@ -663,7 +668,7 @@ void SetWindowMinSize(int width, int height)
|
|||
CORE.Window.screenMin.height = height;
|
||||
|
||||
// Trigger the resize event once to update the window minimum width and height
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) != 0) EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) != 0) EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
|
||||
}
|
||||
|
||||
// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
|
||||
|
|
@ -673,7 +678,7 @@ void SetWindowMaxSize(int width, int height)
|
|||
CORE.Window.screenMax.height = height;
|
||||
|
||||
// Trigger the resize event once to update the window maximum width and height
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) != 0) EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) != 0) EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
|
||||
}
|
||||
|
||||
// Set window dimensions
|
||||
|
|
@ -866,8 +871,7 @@ void EnableCursor(void)
|
|||
// Disables cursor (lock cursor)
|
||||
void DisableCursor(void)
|
||||
{
|
||||
// TODO: figure out how not to hard code the canvas ID here.
|
||||
emscripten_request_pointerlock(GetCanvasId(), 1);
|
||||
emscripten_request_pointerlock(platform.canvasId, 1);
|
||||
|
||||
// Set cursor position in the middle
|
||||
SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
|
||||
|
|
@ -878,7 +882,32 @@ void DisableCursor(void)
|
|||
// Swap back buffer with front buffer (screen drawing)
|
||||
void SwapScreenBuffer(void)
|
||||
{
|
||||
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
// Update framebuffer
|
||||
rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.pixels);
|
||||
|
||||
// Copy framebuffer data into canvas
|
||||
EM_ASM({
|
||||
const width = $0;
|
||||
const height = $1;
|
||||
const ptr = $2;
|
||||
|
||||
// Get canvas and 2d context created
|
||||
const canvas = Module.canvas;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
if (!Module.__img || (Module.__img.width !== width) || (Module.__img.height !== height)) {
|
||||
Module.__img = ctx.createImageData(width, height);
|
||||
}
|
||||
|
||||
const src = HEAPU8.subarray(ptr, ptr + width*height*4); // RGBA (4 bytes)
|
||||
Module.__img.data.set(src);
|
||||
ctx.putImageData(Module.__img, 0, 0);
|
||||
|
||||
}, CORE.Window.screen.width, CORE.Window.screen.height, platform.pixels);
|
||||
#else
|
||||
glfwSwapBuffers(platform.handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -893,10 +922,9 @@ double GetTime(void)
|
|||
}
|
||||
|
||||
// Open URL with default system browser (if available)
|
||||
// NOTE: This function is only safe to use if you control the URL given.
|
||||
// A user could craft a malicious string performing another action.
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself.
|
||||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
// NOTE: This function is only safe to use if you control the URL given
|
||||
// A user could craft a malicious string performing another action
|
||||
// Only call this function yourself not with user input or make sure to check the string yourself
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Security check to (partially) avoid malicious code on target platform
|
||||
|
|
@ -970,7 +998,7 @@ void SetMouseCursor(int cursor)
|
|||
}
|
||||
}
|
||||
|
||||
// Get physical key name.
|
||||
// Get physical key name
|
||||
const char *GetKeyName(int key)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");
|
||||
|
|
@ -1090,10 +1118,6 @@ void PollInputEvents(void)
|
|||
}
|
||||
|
||||
CORE.Window.resizedLastFrame = false;
|
||||
|
||||
// TODO: This code does not seem to do anything??
|
||||
//if (CORE.Window.eventWaiting) glfwWaitEvents(); // Wait for in input events before continue (drawing is paused)
|
||||
//else glfwPollEvents(); // Poll input events: keyboard/mouse/window events (callbacks) --> WARNING: Where is key input reset?
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -1103,6 +1127,8 @@ void PollInputEvents(void)
|
|||
// Initialize platform: graphics, inputs and more
|
||||
int InitPlatform(void)
|
||||
{
|
||||
SetCanvasIdJs(platform.canvasId, 64); // Get the current canvas id
|
||||
|
||||
glfwSetErrorCallback(ErrorCallback);
|
||||
|
||||
// Initialize GLFW internal global state
|
||||
|
|
@ -1122,27 +1148,25 @@ int InitPlatform(void)
|
|||
// glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers
|
||||
|
||||
// Check window creation flags
|
||||
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true;
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // Visible window
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // Visible window
|
||||
else glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); // Window initially hidden
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // Border and buttons on Window
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // Border and buttons on Window
|
||||
else glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); // Decorated window
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // Resizable window
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // Resizable window
|
||||
else glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); // Avoid window being resizable
|
||||
|
||||
// Disable FLAG_WINDOW_MINIMIZED, not supported on initialization
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED;
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
|
||||
|
||||
// Disable FLAG_WINDOW_MAXIMIZED, not supported on initialization
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE);
|
||||
else glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE);
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) glfwWindowHint(GLFW_FLOATING, GLFW_TRUE);
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TOPMOST)) glfwWindowHint(GLFW_FLOATING, GLFW_TRUE);
|
||||
else glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
|
||||
|
||||
// NOTE: Some GLFW flags are not supported on HTML5
|
||||
|
|
@ -1150,10 +1174,10 @@ int InitPlatform(void)
|
|||
|
||||
// Scale content area based on the monitor content scale where window is placed on
|
||||
// NOTE: This feature requires emscripten 3.1.51
|
||||
//if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
|
||||
//if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
|
||||
//else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);
|
||||
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
|
||||
{
|
||||
// NOTE: MSAA is only enabled for main framebuffer, not user-created FBOs
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4");
|
||||
|
|
@ -1161,8 +1185,8 @@ int InitPlatform(void)
|
|||
}
|
||||
|
||||
// NOTE: When asking for an OpenGL context version, most drivers provide the highest supported version
|
||||
// with backward compatibility to older OpenGL versions.
|
||||
// For example, if using OpenGL 1.1, driver can provide a 4.3 backwards compatible context.
|
||||
// with backward compatibility to older OpenGL versions
|
||||
// For example, if using OpenGL 1.1, driver can provide a 4.3 backwards compatible context
|
||||
|
||||
// Check selection OpenGL version
|
||||
if (rlGetVersion() == RL_OPENGL_21)
|
||||
|
|
@ -1172,10 +1196,12 @@ int InitPlatform(void)
|
|||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_33)
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint)
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint)
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.3 and above!
|
||||
// Values: GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint)
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint)
|
||||
// Profiles Hint, only OpenGL 3.3 and above
|
||||
// Possible values: GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_FALSE); // Forward Compatibility Hint: Only 3.3 and above!
|
||||
// glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Request OpenGL DEBUG context
|
||||
}
|
||||
|
|
@ -1198,7 +1224,6 @@ int InitPlatform(void)
|
|||
}
|
||||
else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context
|
||||
{
|
||||
// TODO: It seems WebGL 2.0 context is not set despite being requested
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
||||
|
|
@ -1211,14 +1236,28 @@ int InitPlatform(void)
|
|||
|
||||
// Init fullscreen toggle required var:
|
||||
platform.ourFullscreen = false;
|
||||
|
||||
if (CORE.Window.fullscreen)
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
// Avoid creating a WebGL canvas, avoid calling glfwCreateWindow()
|
||||
emscripten_set_canvas_element_size(platform.canvasId, CORE.Window.screen.width, CORE.Window.screen.height);
|
||||
EM_ASM({
|
||||
const canvas = document.getElementById("canvas");
|
||||
Module.canvas = canvas;
|
||||
});
|
||||
|
||||
// Load memory framebuffer with desired screen size
|
||||
// NOTE: Despite using a software framebuffer for blitting, GLFW still creates a WebGL canvas,
|
||||
// but it is not being used, on SwapScreenBuffer() the pure software renderer is used
|
||||
// TODO: Consider requesting another type of canvas, not a WebGL one --> Replace GLFW-web by Emscripten?
|
||||
platform.pixels = (unsigned int *)RL_CALLOC(CORE.Window.screen.width*CORE.Window.screen.height, sizeof(unsigned int));
|
||||
#else
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
|
||||
{
|
||||
// remember center for switchinging from fullscreen to window
|
||||
if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width))
|
||||
{
|
||||
// If screen width/height equal to the display, we can't calculate the window pos for toggling full-screened/windowed.
|
||||
// Toggling full-screened/windowed with pos(0, 0) can cause problems in some platforms, such as X11.
|
||||
// If screen width/height equal to the display, we can't calculate the window pos for toggling full-screened/windowed
|
||||
// Toggling full-screened/windowed with pos(0, 0) can cause problems in some platforms, such as X11
|
||||
CORE.Window.position.x = CORE.Window.display.width/4;
|
||||
CORE.Window.position.y = CORE.Window.display.height/4;
|
||||
}
|
||||
|
|
@ -1251,18 +1290,6 @@ int InitPlatform(void)
|
|||
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
|
||||
|
||||
// NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example,
|
||||
// for a desired screen size of 800x450 (16:9), closest supported videomode is 800x600 (4:3),
|
||||
// framebuffer is rendered correctly but once displayed on a 16:9 monitor, it gets stretched
|
||||
// by the sides to fit all monitor space...
|
||||
|
||||
// Try to setup the most appropriate fullscreen framebuffer for the requested screenWidth/screenHeight
|
||||
// It considers device display resolution mode and setups a framebuffer with black bars if required (render size/offset)
|
||||
// Modified global variables: CORE.Window.screen.width/CORE.Window.screen.height - CORE.Window.render.width/CORE.Window.render.height - CORE.Window.renderOffset.x/CORE.Window.renderOffset.y - CORE.Window.screenScale
|
||||
// TODO: It is a quite cumbersome solution to display size vs requested size, it should be reviewed or removed...
|
||||
// HighDPI monitors are properly considered in a following similar function: SetupViewport()
|
||||
SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
|
||||
|
||||
platform.handle = glfwCreateWindow(CORE.Window.display.width, CORE.Window.display.height, (CORE.Window.title != 0)? CORE.Window.title : " ", glfwGetPrimaryMonitor(), NULL);
|
||||
|
||||
// NOTE: Full-screen change, not working properly...
|
||||
|
|
@ -1286,6 +1313,7 @@ int InitPlatform(void)
|
|||
TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// WARNING: glfwCreateWindow() title doesn't work with emscripten
|
||||
emscripten_set_window_title((CORE.Window.title != 0)? CORE.Window.title : " ");
|
||||
|
|
@ -1296,7 +1324,7 @@ int InitPlatform(void)
|
|||
glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback);
|
||||
glfwSetDropCallback(platform.handle, WindowDropCallback);
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
// Window content (framebuffer) scale callback
|
||||
glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback);
|
||||
|
|
@ -1338,7 +1366,7 @@ int InitPlatform(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
|
||||
|
||||
// If graphic device is no properly initialized, we end program
|
||||
if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; }
|
||||
|
|
@ -1352,14 +1380,14 @@ int InitPlatform(void)
|
|||
//----------------------------------------------------------------------------
|
||||
// Setup window events callbacks
|
||||
emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenFullscreenChangeCallback);
|
||||
emscripten_set_blur_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
|
||||
emscripten_set_focus_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
|
||||
emscripten_set_blur_callback(platform.canvasId, platform.handle, 1, EmscriptenFocusCallback);
|
||||
emscripten_set_focus_callback(platform.canvasId, platform.handle, 1, EmscriptenFocusCallback);
|
||||
emscripten_set_visibilitychange_callback(NULL, 1, EmscriptenVisibilityChangeCallback);
|
||||
|
||||
// WARNING: Below resize code was breaking fullscreen mode for sample games and examples, it needs review
|
||||
// Check fullscreen change events(note this is done on the window since most browsers don't support this on #canvas)
|
||||
// Check fullscreen change events(note this is done on the window since most browsers don't support this on canvas)
|
||||
// emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
|
||||
// Check Resize event (note this is done on the window since most browsers don't support this on #canvas)
|
||||
// Check Resize event (note this is done on the window since most browsers don't support this on canvas)
|
||||
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
|
||||
|
||||
// Trigger resize callback to force initial size
|
||||
|
|
@ -1367,15 +1395,15 @@ int InitPlatform(void)
|
|||
|
||||
// Setup input events
|
||||
// NOTE: Keyboard callbacks only used to consume some events, libglfw.js takes care of the actual input
|
||||
//emscripten_set_keypress_callback(GetCanvasId(), NULL, 1, EmscriptenKeyboardCallback); // WRNING: Breaks input
|
||||
//emscripten_set_keydown_callback(GetCanvasId(), NULL, 1, EmscriptenKeyboardCallback);
|
||||
emscripten_set_click_callback(GetCanvasId(), NULL, 1, EmscriptenMouseCallback);
|
||||
//emscripten_set_keypress_callback(platform.canvasId, NULL, 1, EmscriptenKeyboardCallback); // WRNING: Breaks input
|
||||
//emscripten_set_keydown_callback(platform.canvasId, NULL, 1, EmscriptenKeyboardCallback);
|
||||
emscripten_set_click_callback(platform.canvasId, NULL, 1, EmscriptenMouseCallback);
|
||||
emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenPointerlockCallback);
|
||||
emscripten_set_mousemove_callback(GetCanvasId(), NULL, 1, EmscriptenMouseMoveCallback);
|
||||
emscripten_set_touchstart_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_touchend_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_touchmove_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_touchcancel_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_mousemove_callback(platform.canvasId, NULL, 1, EmscriptenMouseMoveCallback);
|
||||
emscripten_set_touchstart_callback(platform.canvasId, NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_touchend_callback(platform.canvasId, NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_touchmove_callback(platform.canvasId, NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_touchcancel_callback(platform.canvasId, NULL, 1, EmscriptenTouchCallback);
|
||||
emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback);
|
||||
emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback);
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
@ -1423,7 +1451,7 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
|
|||
if (IsWindowFullscreen()) return;
|
||||
|
||||
// Set current screen size
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
|
||||
{
|
||||
Vector2 windowScaleDPI = GetWindowScaleDPI();
|
||||
|
||||
|
|
@ -1448,15 +1476,15 @@ static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float s
|
|||
// GLFW3: Called on windows minimized/restored
|
||||
static void WindowIconifyCallback(GLFWwindow *window, int iconified)
|
||||
{
|
||||
if (iconified) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified
|
||||
else CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored
|
||||
if (iconified) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was iconified
|
||||
else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was restored
|
||||
}
|
||||
|
||||
// GLFW3: Called on windows get/lose focus
|
||||
static void WindowFocusCallback(GLFWwindow *window, int focused)
|
||||
{
|
||||
if (focused) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // The window was focused
|
||||
else CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; // The window lost focus
|
||||
if (focused) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // The window was focused
|
||||
else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // The window lost focus
|
||||
}
|
||||
|
||||
// GLFW3: Called on file-drop over the window
|
||||
|
|
@ -1482,7 +1510,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
|
|||
for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++)
|
||||
{
|
||||
CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
|
||||
strcpy(CORE.Window.dropFilepaths[i], paths[i]);
|
||||
strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1517,8 +1545,8 @@ static void CharCallback(GLFWwindow *window, unsigned int key)
|
|||
|
||||
// NOTE: Registers any key down considering OS keyboard layout but
|
||||
// does not detect action events, those should be managed by user...
|
||||
// Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907
|
||||
// Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char
|
||||
// REF: https://github.com/glfw/glfw/issues/668#issuecomment-166794907
|
||||
// REF: https://www.glfw.org/docs/latest/input_guide.html#input_char
|
||||
|
||||
// Check if there is space available in the queue
|
||||
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
|
||||
|
|
@ -1671,8 +1699,8 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE
|
|||
eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state",
|
||||
gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping);
|
||||
|
||||
for (int i = 0; i < gamepadEvent->numAxes; ++i) TRACELOGD("Axis %d: %g", i, gamepadEvent->axis[i]);
|
||||
for (int i = 0; i < gamepadEvent->numButtons; ++i) TRACELOGD("Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]);
|
||||
for (int i = 0; i < gamepadEvent->numAxes; i++) TRACELOGD("Axis %d: %g", i, gamepadEvent->axis[i]);
|
||||
for (int i = 0; i < gamepadEvent->numButtons; i++) TRACELOGD("Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]);
|
||||
*/
|
||||
|
||||
if (gamepadEvent->connected && (gamepadEvent->index < MAX_GAMEPADS))
|
||||
|
|
@ -1696,7 +1724,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
|
|||
// NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but
|
||||
// we are looking for actual CSS size: canvas.style.width and canvas.style.height
|
||||
// EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight);
|
||||
emscripten_get_element_css_size(GetCanvasId(), &canvasWidth, &canvasHeight);
|
||||
emscripten_get_element_css_size(platform.canvasId, &canvasWidth, &canvasHeight);
|
||||
|
||||
for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
|
|
@ -1714,7 +1742,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
|
|||
else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0;
|
||||
}
|
||||
|
||||
// Update mouse position if we detect a single touch.
|
||||
// Update mouse position if we detect a single touch
|
||||
if (CORE.Input.Touch.pointCount == 1)
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition.x = CORE.Input.Touch.position[0].x;
|
||||
|
|
@ -1781,9 +1809,8 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
|
|||
const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
|
||||
if (!wasFullscreen)
|
||||
{
|
||||
CORE.Window.fullscreen = false;
|
||||
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
|
||||
CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
|
||||
FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1794,7 +1821,7 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
|
|||
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
|
||||
{
|
||||
// Don't resize non-resizeable windows
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) return 1;
|
||||
if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) return 1;
|
||||
|
||||
// This event is called whenever the window changes sizes,
|
||||
// so the size of the canvas object is explicitly retrieved below
|
||||
|
|
@ -1807,7 +1834,7 @@ static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *
|
|||
if (height < (int)CORE.Window.screenMin.height) height = CORE.Window.screenMin.height;
|
||||
else if ((height > (int)CORE.Window.screenMax.height) && (CORE.Window.screenMax.height > 0)) height = CORE.Window.screenMax.height;
|
||||
|
||||
emscripten_set_canvas_element_size(GetCanvasId(), width, height);
|
||||
emscripten_set_canvas_element_size(platform.canvasId, width, height);
|
||||
|
||||
SetupViewport(width, height); // Reset viewport and projection matrix for new size
|
||||
|
||||
|
|
@ -1844,27 +1871,10 @@ static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent
|
|||
// Emscripten: Called on visibility change events
|
||||
static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData)
|
||||
{
|
||||
if (visibilityChangeEvent->hidden) CORE.Window.flags |= FLAG_WINDOW_HIDDEN; // The window was hidden
|
||||
else CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // The window was restored
|
||||
if (visibilityChangeEvent->hidden) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN); // The window was hidden
|
||||
else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_HIDDEN); // The window was restored
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
|
||||
// JS: Get the canvas id provided by the module configuration
|
||||
EM_JS(char *, GetCanvasIdJs, (), {
|
||||
var canvasId = "#" + Module.canvas.id;
|
||||
var lengthBytes = lengthBytesUTF8(canvasId) + 1;
|
||||
var stringOnWasmHeap = _malloc(lengthBytes);
|
||||
stringToUTF8(canvasId, stringOnWasmHeap, lengthBytes);
|
||||
return stringOnWasmHeap;
|
||||
});
|
||||
|
||||
// Get canvas id (using embedded JS function)
|
||||
static const char *GetCanvasId(void)
|
||||
{
|
||||
static char *canvasId = NULL;
|
||||
if (canvasId == NULL) canvasId = GetCanvasIdJs();
|
||||
return canvasId;
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
|
|||
1693
src/platforms/rcore_web_emscripten.c
Normal file
1693
src/platforms/rcore_web_emscripten.c
Normal file
File diff suppressed because it is too large
Load diff
41
src/raudio.c
41
src/raudio.c
|
|
@ -593,7 +593,7 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
|
|||
// Init audio buffer values
|
||||
audioBuffer->volume = 1.0f;
|
||||
audioBuffer->pitch = 1.0f;
|
||||
audioBuffer->pan = 0.5f;
|
||||
audioBuffer->pan = 0.0f; // Center
|
||||
|
||||
audioBuffer->callback = NULL;
|
||||
audioBuffer->processor = NULL;
|
||||
|
|
@ -720,7 +720,7 @@ void SetAudioBufferPitch(AudioBuffer *buffer, float pitch)
|
|||
// Set pan for an audio buffer
|
||||
void SetAudioBufferPan(AudioBuffer *buffer, float pan)
|
||||
{
|
||||
if (pan < 0.0f) pan = 0.0f;
|
||||
if (pan < -1.0f) pan = -1.0f;
|
||||
else if (pan > 1.0f) pan = 1.0f;
|
||||
|
||||
if (buffer != NULL)
|
||||
|
|
@ -985,10 +985,10 @@ Sound LoadSoundAlias(Sound source)
|
|||
audioBuffer->sizeInFrames = source.stream.buffer->sizeInFrames;
|
||||
audioBuffer->data = source.stream.buffer->data;
|
||||
|
||||
// initalize the buffer as if it was new
|
||||
// Initalize the buffer as if it was new
|
||||
audioBuffer->volume = 1.0f;
|
||||
audioBuffer->pitch = 1.0f;
|
||||
audioBuffer->pan = 0.5f;
|
||||
audioBuffer->pan = 0.0f; // Center
|
||||
|
||||
sound.frameCount = source.frameCount;
|
||||
sound.stream.sampleRate = AUDIO.System.device.sampleRate;
|
||||
|
|
@ -1040,8 +1040,8 @@ void UnloadSoundAlias(Sound alias)
|
|||
}
|
||||
|
||||
// Update sound buffer with new data
|
||||
// NOTE 1: data format must match sound.stream.sampleSize
|
||||
// NOTE 2: frameCount must not exceed sound.frameCount
|
||||
// PARAMS: [data], format must match sound.stream.sampleSize, default 32 bit float - stereo
|
||||
// PARAMS: [frameCount] must not exceed sound.frameCount
|
||||
void UpdateSound(Sound sound, const void *data, int frameCount)
|
||||
{
|
||||
if (sound.stream.buffer != NULL)
|
||||
|
|
@ -1140,7 +1140,7 @@ bool ExportWaveAsCode(Wave wave, const char *fileName)
|
|||
|
||||
// Get file name from path and convert variable name to uppercase
|
||||
char varFileName[256] = { 0 };
|
||||
strcpy(varFileName, GetFileNameWithoutExt(fileName));
|
||||
strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1);
|
||||
for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; }
|
||||
|
||||
// Add wave information
|
||||
|
|
@ -2092,9 +2092,7 @@ float GetMusicTimePlayed(Music music)
|
|||
int framesInFirstBuffer = music.stream.buffer->isSubBufferProcessed[0]? 0 : subBufferSize;
|
||||
int framesInSecondBuffer = music.stream.buffer->isSubBufferProcessed[1]? 0 : subBufferSize;
|
||||
int framesInBuffers = framesInFirstBuffer + framesInSecondBuffer;
|
||||
if ((unsigned int)framesInBuffers > music.frameCount) {
|
||||
if (!music.looping) framesInBuffers = music.frameCount;
|
||||
}
|
||||
if (((unsigned int)framesInBuffers > music.frameCount) && !music.looping) framesInBuffers = music.frameCount;
|
||||
int framesSentToMix = music.stream.buffer->frameCursorPos%subBufferSize;
|
||||
int framesPlayed = (framesProcessed - framesInBuffers + framesSentToMix)%(int)music.frameCount;
|
||||
if (framesPlayed < 0) framesPlayed += music.frameCount;
|
||||
|
|
@ -2125,7 +2123,7 @@ AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
|
|||
if (deviceBitsPerSample > 4) deviceBitsPerSample = 4;
|
||||
deviceBitsPerSample *= AUDIO.System.device.playback.channels;
|
||||
|
||||
unsigned int subBufferSize = (AUDIO.Buffer.defaultSize == 0) ? (AUDIO.System.device.sampleRate/30*deviceBitsPerSample) : AUDIO.Buffer.defaultSize;
|
||||
unsigned int subBufferSize = (AUDIO.Buffer.defaultSize == 0)? (AUDIO.System.device.sampleRate/30*deviceBitsPerSample) : AUDIO.Buffer.defaultSize;
|
||||
|
||||
if (subBufferSize < periodSize) subBufferSize = periodSize;
|
||||
|
||||
|
|
@ -2605,8 +2603,8 @@ static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 fr
|
|||
|
||||
if (channels == 2) // We consider panning
|
||||
{
|
||||
const float left = buffer->pan;
|
||||
const float right = 1.0f - left;
|
||||
const float right = (buffer->pan + 1.0f)/2.0f; // Normalize: [-1..1] -> [0..1]
|
||||
const float left = 1.0f - right;
|
||||
|
||||
// Fast sine approximation in [0..1] for pan law: y = 0.5f*x*(3 - x*x);
|
||||
const float levels[2] = { localVolume*0.5f*left*(3.0f - left*left), localVolume*0.5f*right*(3.0f - right*right) };
|
||||
|
|
@ -2741,11 +2739,13 @@ static const char *GetFileExtension(const char *fileName)
|
|||
return dot;
|
||||
}
|
||||
|
||||
// String pointer reverse break: returns right-most occurrence of charset in s
|
||||
static const char *strprbrk(const char *s, const char *charset)
|
||||
// String pointer reverse break: returns right-most occurrence of charset in text
|
||||
static const char *strprbrk(const char *text, const char *charset)
|
||||
{
|
||||
const char *latestMatch = NULL;
|
||||
for (; s = strpbrk(s, charset), s != NULL; latestMatch = s++) { }
|
||||
|
||||
for (; (text != NULL) && (text = strpbrk(text, charset)); latestMatch = text++) { }
|
||||
|
||||
return latestMatch;
|
||||
}
|
||||
|
||||
|
|
@ -2768,11 +2768,11 @@ static const char *GetFileNameWithoutExt(const char *filePath)
|
|||
static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH] = { 0 };
|
||||
memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH);
|
||||
|
||||
if (filePath != NULL) strcpy(fileName, GetFileName(filePath)); // Get filename with extension
|
||||
if (filePath != NULL) strncpy(fileName, GetFileName(filePath), MAX_FILENAMEWITHOUTEXT_LENGTH - 1); // Get filename with extension
|
||||
|
||||
int size = (int)strlen(fileName); // Get size in bytes
|
||||
int fileNameLength = (int)strlen(fileName); // Get size in bytes
|
||||
|
||||
for (int i = 0; (i < size) && (i < MAX_FILENAMEWITHOUTEXT_LENGTH); i++)
|
||||
for (int i = 0; (i < fileNameLength) && (i < MAX_FILENAMEWITHOUTEXT_LENGTH); i++)
|
||||
{
|
||||
if (fileName[i] == '.')
|
||||
{
|
||||
|
|
@ -2866,7 +2866,8 @@ static bool SaveFileText(const char *fileName, char *text)
|
|||
|
||||
if (file != NULL)
|
||||
{
|
||||
int count = fprintf(file, "%s", text);
|
||||
int count = 0;
|
||||
if (text != NULL) count = fprintf(file, "%s", text);
|
||||
|
||||
if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write text file", fileName);
|
||||
else TRACELOG(LOG_INFO, "FILEIO: [%s] Text file saved successfully", fileName);
|
||||
|
|
|
|||
25
src/raylib.h
25
src/raylib.h
|
|
@ -33,7 +33,6 @@
|
|||
* [raudio] miniaudio (David Reid - github.com/mackron/miniaudio) for audio device/context management
|
||||
*
|
||||
* OPTIONAL DEPENDENCIES (included):
|
||||
* [rcore] msf_gif (Miles Fogle) for GIF recording
|
||||
* [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorithm
|
||||
* [rcore] sdefl (Micha Mettke) for DEFLATE compression algorithm
|
||||
* [rcore] rprand (Ramon Santamaria) for pseudo-random numbers generation
|
||||
|
|
@ -100,13 +99,13 @@
|
|||
#define __declspec(x) __attribute__((x))
|
||||
#endif
|
||||
#if defined(BUILD_LIBTYPE_SHARED)
|
||||
#define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
|
||||
#define RLAPI __declspec(dllexport) // Building the library as a Win32 shared library (.dll)
|
||||
#elif defined(USE_LIBTYPE_SHARED)
|
||||
#define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
|
||||
#define RLAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll)
|
||||
#endif
|
||||
#else
|
||||
#if defined(BUILD_LIBTYPE_SHARED)
|
||||
#define RLAPI __attribute__((visibility("default"))) // We are building as a Unix shared library (.so/.dylib)
|
||||
#define RLAPI __attribute__((visibility("default"))) // Building as a Unix shared library (.so/.dylib)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
@ -158,7 +157,7 @@
|
|||
#error "C++11 or later is required. Add -std=c++11"
|
||||
#endif
|
||||
|
||||
// NOTE: We set some defines with some data types declared by raylib
|
||||
// NOTE: Set some defines with some data types declared by raylib
|
||||
// Other modules (raymath, rlgl) also require some of those types, so,
|
||||
// to be able to use those other modules as standalone (not depending on raylib)
|
||||
// this defines are very useful for internal check and avoid type (re)definitions
|
||||
|
|
@ -335,10 +334,10 @@ typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D
|
|||
|
||||
// Camera2D, defines position/orientation in 2d space
|
||||
typedef struct Camera2D {
|
||||
Vector2 offset; // Camera offset (displacement from target)
|
||||
Vector2 target; // Camera target (rotation and zoom origin)
|
||||
float rotation; // Camera rotation in degrees
|
||||
float zoom; // Camera zoom (scaling), should be 1.0f by default
|
||||
Vector2 offset; // Camera offset (screen space offset from window origin)
|
||||
Vector2 target; // Camera target (world space target point that is mapped to screen space offset)
|
||||
float rotation; // Camera rotation in degrees (pivots around target)
|
||||
float zoom; // Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale
|
||||
} Camera2D;
|
||||
|
||||
// Mesh, vertex data and vao/vbo
|
||||
|
|
@ -1146,7 +1145,7 @@ RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previ
|
|||
RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string)
|
||||
RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string)
|
||||
RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success
|
||||
RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success
|
||||
RLAPI bool ChangeDirectory(const char *dirPath); // Change working directory, return true on success
|
||||
RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory
|
||||
RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS
|
||||
RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths
|
||||
|
|
@ -1658,7 +1657,7 @@ RLAPI Sound LoadSound(const char *fileName); // Load so
|
|||
RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
|
||||
RLAPI Sound LoadSoundAlias(Sound source); // Create a new sound that shares the same sample data as the source sound, does not own the sound data
|
||||
RLAPI bool IsSoundValid(Sound sound); // Checks if a sound is valid (data loaded and buffers initialized)
|
||||
RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data (data and frame count should fit in sound)
|
||||
RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data (default data format: 32 bit float, stereo)
|
||||
RLAPI void UnloadWave(Wave wave); // Unload wave data
|
||||
RLAPI void UnloadSound(Sound sound); // Unload sound
|
||||
RLAPI void UnloadSoundAlias(Sound alias); // Unload a sound alias (does not deallocate sample data)
|
||||
|
|
@ -1673,7 +1672,7 @@ RLAPI void ResumeSound(Sound sound); // Resume
|
|||
RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing
|
||||
RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level)
|
||||
RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
|
||||
RLAPI void SetSoundPan(Sound sound, float pan); // Set pan for a sound (0.5 is center)
|
||||
RLAPI void SetSoundPan(Sound sound, float pan); // Set pan for a sound (-1.0 left, 0.0 center, 1.0 right)
|
||||
RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave
|
||||
RLAPI void WaveCrop(Wave *wave, int initFrame, int finalFrame); // Crop a wave to defined frames range
|
||||
RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format
|
||||
|
|
@ -1694,7 +1693,7 @@ RLAPI void ResumeMusicStream(Music music); // Resume
|
|||
RLAPI void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds)
|
||||
RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
|
||||
RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
|
||||
RLAPI void SetMusicPan(Music music, float pan); // Set pan for a music (0.5 is center)
|
||||
RLAPI void SetMusicPan(Music music, float pan); // Set pan for a music (-1.0 left, 0.0 center, 1.0 right)
|
||||
RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds)
|
||||
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
|
||||
|
||||
|
|
|
|||
|
|
@ -2552,7 +2552,38 @@ RMAPI int QuaternionEquals(Quaternion p, Quaternion q)
|
|||
return result;
|
||||
}
|
||||
|
||||
// Compose a transformation matrix from rotational, translational and scaling components
|
||||
// TODO: This function is not following raymath conventions defined in header: NOT self-contained
|
||||
RMAPI Matrix MatrixCompose(Vector3 translation, Quaternion rotation, Vector3 scale)
|
||||
{
|
||||
// Initialize vectors
|
||||
Vector3 right = { 1.0f, 0.0f, 0.0f };
|
||||
Vector3 up = { 0.0f, 1.0f, 0.0f };
|
||||
Vector3 forward = { 0.0f, 0.0f, 1.0f };
|
||||
|
||||
// Scale vectors
|
||||
right = Vector3Scale(right, scale.x);
|
||||
up = Vector3Scale(up, scale.y);
|
||||
forward = Vector3Scale(forward , scale.z);
|
||||
|
||||
// Rotate vectors
|
||||
right = Vector3RotateByQuaternion(right, rotation);
|
||||
up = Vector3RotateByQuaternion(up, rotation);
|
||||
forward = Vector3RotateByQuaternion(forward, rotation);
|
||||
|
||||
// Set result matrix output
|
||||
Matrix result = {
|
||||
right.x, up.x, forward.x, translation.x,
|
||||
right.y, up.y, forward.y, translation.y,
|
||||
right.z, up.z, forward.z, translation.z,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Decompose a transformation matrix into its rotational, translational and scaling components and remove shear
|
||||
// TODO: This function is not following raymath conventions defined in header: NOT self-contained
|
||||
RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale)
|
||||
{
|
||||
float eps = (float)1e-9;
|
||||
|
|
@ -2587,10 +2618,7 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio
|
|||
|
||||
// X Scale
|
||||
scl.x = Vector3Length(matColumns[0]);
|
||||
if (scl.x > eps)
|
||||
{
|
||||
matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x);
|
||||
}
|
||||
if (scl.x > eps) matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x);
|
||||
|
||||
// Compute XY shear and make col2 orthogonal
|
||||
shear[0] = Vector3DotProduct(matColumns[0], matColumns[1]);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue