This commit is contained in:
Tyler Bezera 2020-02-28 17:23:42 -08:00
commit 7b4c13d22f
19 changed files with 787 additions and 376 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"cmake.configureOnOpen": true
}

View File

@ -12,7 +12,10 @@
#include "raylib.h" #include "raylib.h"
// NOTE: Storage positions must start with 0, directly related to file memory layout // NOTE: Storage positions must start with 0, directly related to file memory layout
typedef enum { STORAGE_SCORE = 0, STORAGE_HISCORE } StorageData; typedef enum {
STORAGE_POSITION_SCORE = 0,
STORAGE_POSITION_HISCORE = 1
} StorageData;
int main(void) int main(void)
{ {
@ -43,14 +46,14 @@ int main(void)
if (IsKeyPressed(KEY_ENTER)) if (IsKeyPressed(KEY_ENTER))
{ {
StorageSaveValue(STORAGE_SCORE, score); SaveStorageValue(STORAGE_POSITION_SCORE, score);
StorageSaveValue(STORAGE_HISCORE, hiscore); SaveStorageValue(STORAGE_POSITION_HISCORE, hiscore);
} }
else if (IsKeyPressed(KEY_SPACE)) else if (IsKeyPressed(KEY_SPACE))
{ {
// NOTE: If requested position could not be found, value 0 is returned // NOTE: If requested position could not be found, value 0 is returned
score = StorageLoadValue(STORAGE_SCORE); score = LoadStorageValue(STORAGE_POSITION_SCORE);
hiscore = StorageLoadValue(STORAGE_HISCORE); hiscore = LoadStorageValue(STORAGE_POSITION_HISCORE);
} }
framesCounter++; framesCounter++;

View File

@ -0,0 +1,105 @@
/*******************************************************************************************
*
* raylib [models] example - Load 3d model with animations and play them
*
* This example has been created using raylib 3.0 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
* Example contributed by Tyler Bezera (@gamerfiend) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2019 Tyler Bezera (@gamerfiend) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include <stdlib.h>
#include "raylib.h"
#define RGLTFANIMATION_IMPLEMENTATION
#include "rgltfanim.h"
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [models] example - model animation gltf");
// Define the camera to look into our 3d world
Camera camera = { 0 };
camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position
camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target)
camera.fovy = 45.0f; // Camera field-of-view Y
camera.type = CAMERA_PERSPECTIVE; // Camera mode type
// Load the animated model mesh and basic data
Model model = LoadModel("resources/models/RiggedFigure.glb");
Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
// Load animation data
// int animsCount = 0;
ModelAnimationsGLTF anims = LoadModelGLTFAnimations("resources/models/RiggedFigure.glb");
// int animFrameCounter = 0;
SetCameraMode(camera, CAMERA_FREE); // Set free camera mode
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(&camera);
// Play animation when spacebar is held down
if (IsKeyDown(KEY_SPACE))
{
// animFrameCounter++;
UpdateModelAnimationGLTF(model, 0, 0.5);
// if (animFrameCounter >= anims[0].frameCount) animFrameCounter = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginMode3D(camera);
DrawModelEx(model, position, (Vector3){ 1.0f, 0.0f, 0.0f }, -90.0f, (Vector3){ 1.0f, 1.0f, 1.0f }, WHITE);
for (int i = 0; i < model.boneCount; i++)
{
//DrawCube(anims[0].framePoses[animFrameCounter][i].translation, 0.2f, 0.2f, 0.2f, RED);
}
DrawGrid(10, 1.0f); // Draw a grid
EndMode3D();
DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, 10, 20, MAROON);
DrawText("(c) Guy IQM 3D model by @culacant", screenWidth - 200, screenHeight - 20, 10, GRAY);
EndDrawing();
//----------------------------------------------------------------------------------
}
// Unload model animations data
// for (int i = 0; i < animsCount; i++) UnloadModelAnimation(anims[i]);
// RL_FREE(anims);
UnloadModel(model); // Unload model
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

Binary file not shown.

257
examples/models/rgltfanim.h Normal file
View File

@ -0,0 +1,257 @@
/**********************************************************************************************
*
* raylib.gltfanimation - Simple module to have animation support with GLTF models, based on the
* implementation work for Google's Filament engine.
*
* CONFIGURATION:
*
* #define RGLTFANIMATION_IMPLEMENTATION
* Generates the implementation of the library into the included file.
* If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation.
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2020 Tyler Bezera and Ramon Santamaria
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#ifndef RGLTFANIM_H
#define RGLTFANIM_H
#include "raylib.h"
#include "../../src/external/cgltf.h"
typedef enum
{
TYPE_LINEAR,
TYPE_STEP,
TYPE_CUBICSPLINE
} AnimationGLTFInterpolationType;
typedef enum
{
TYPE_TRANSLATION,
TYPE_ROTATION,
TYPE_SCALE,
TYPE_WEIGHTS
} AnimationGLTFPathType;
typedef struct ModelGLTFAnimationSampler
{
AnimationGLTFInterpolationType interpolationType;
float *sourceValues;
int sourceValuesCount;
} ModelGLTFAnimationSampler;
typedef struct ModelGLTFAnimationChannel
{
AnimationGLTFPathType pathType;
ModelGLTFAnimationSampler *sourceData;
Model targetModel;
} ModelGLTFAnimationChannel;
typedef struct ModelAnimationGLTF
{
char animationName[50];
ModelGLTFAnimationSampler *samplers;
int samplersCount;
ModelGLTFAnimationChannel *channels;
int channelsCount;
float duration;
float start;
float end;
} ModelAnimationGLTF;
typedef struct ModelAnimationsGLTF
{
ModelAnimationGLTF *animations;
int animationsCount;
Matrix *boneMatrices;
int boneMatricesCount;
} ModelAnimationsGLTF;
#ifdef __cplusplus
extern "C"
{ // Prevents name mangling of functions
#endif
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
ModelAnimationsGLTF LoadModelGLTFAnimations(const char *filename);
void UpdateModelAnimationGLTF(Model model, int animationIndex, float time);
void createSampler(cgltf_animation_sampler *src, ModelGLTFAnimationSampler *dst);
#ifdef __cplusplus
}
#endif
#endif //RGLTFANIM_H
/***********************************************************************************
*
* RGLTFANIM IMPLEMENTATION
*
************************************************************************************/
#if defined(RGLTFANIMATION_IMPLEMENTATION)
#include "raylib.h"
#include <stdio.h>
//#define CGLTF_IMPLEMENTATION
#include "../../src/external/cgltf.h"
void createSampler(cgltf_animation_sampler *src, ModelGLTFAnimationSampler *dst) {
//uint8_t *tileLineBlob = (uint8_t*)src->input->buffer_view->buffer->data;
//float *tileLineFloats = (float*)(tileLineBlob + src->input->offset + src->input->buffer_view->offset);
for (int i = 0, len = src->input->count; i < len; ++i) {
//TODO: Need to support map
//dst->times
switch (src->output->type) {
case cgltf_type_scalar:
dst->sourceValues = RL_CALLOC(src->output->count, sizeof(float));
cgltf_accessor_unpack_floats(src->output, &dst->sourceValues[0], src->output->count);
break;
case cgltf_type_vec3:
dst->sourceValues = RL_CALLOC(src->output->count * 3, sizeof(float));
cgltf_accessor_unpack_floats(src->output, &dst->sourceValues[0], src->output->count * 3);
break;
case cgltf_type_vec4:
dst->sourceValues = RL_CALLOC(src->output->count * 3, sizeof(float));
cgltf_accessor_unpack_floats(src->output, &dst->sourceValues[0], src->output->count * 3);
break;
default:
break;
}
switch (src->interpolation) {
case cgltf_interpolation_type_linear:
dst->interpolationType = TYPE_LINEAR;
break;
case cgltf_interpolation_type_step:
dst->interpolationType = TYPE_STEP;
break;
case cgltf_interpolation_type_cubic_spline:
dst->interpolationType = TYPE_CUBICSPLINE;
break;
}
}
}
void setTransformType(cgltf_animation_channel *src, ModelGLTFAnimationChannel *dst) {
switch (src->target_path) {
case cgltf_animation_path_type_translation:
dst->pathType = TYPE_TRANSLATION;
break;
case cgltf_animation_path_type_rotation:
dst->pathType = TYPE_ROTATION;
break;
case cgltf_animation_path_type_scale:
dst->pathType = TYPE_SCALE;
break;
case cgltf_animation_path_type_weights:
dst->pathType = TYPE_WEIGHTS;
break;
}
}
ModelAnimationsGLTF LoadModelGLTFAnimations(const char *fileName) {
ModelAnimationsGLTF animationsGLTF = { 0 };
// glTF file loading
FILE *gltfFile = fopen(fileName, "rb");
if (gltfFile == NULL)
{
TraceLog(LOG_WARNING, "[%s] glTF file could not be opened", fileName);
return animationsGLTF;
}
fseek(gltfFile, 0, SEEK_END);
int size = ftell(gltfFile);
fseek(gltfFile, 0, SEEK_SET);
void *buffer = RL_MALLOC(size);
fread(buffer, size, 1, gltfFile);
fclose(gltfFile);
// glTF data loading
cgltf_options options = { 0 };
cgltf_data *data = NULL;
cgltf_result result = cgltf_parse(&options, buffer, size, &data);
if (result == cgltf_result_success)
{
// Read data buffers
result = cgltf_load_buffers(&options, data, fileName);
if (result != cgltf_result_success) TraceLog(LOG_INFO, "[%s][%s] Error loading mesh/material buffers", fileName, (data->file_type == 2)? "glb" : "gltf");
//Animation count
int animationsCount = data->animations_count;
//Initialize our animations array
animationsGLTF.animationsCount = animationsCount;
animationsGLTF.animations = RL_CALLOC(animationsCount, sizeof(ModelAnimationGLTF));
//Loop through each Animation
for (int i = 0; i < animationsCount; i++) {
//Copy Animation name
if(data->animations[i].name) TextCopy(animationsGLTF.animations[i].animationName, data->animations[i].name);
int samplerCount = data->animations[i].samplers_count;
animationsGLTF.animations[i].samplersCount = samplerCount;
animationsGLTF.animations[i].samplers = RL_CALLOC(samplerCount, sizeof(ModelGLTFAnimationSampler));
for (int j = 0; j < samplerCount; j++) {
createSampler(&data->animations[i].samplers[j], &animationsGLTF.animations[i].samplers[j]);
//TODO handle map times
}
int channelCount = data->animations[i].channels_count;
animationsGLTF.animations[i].channelsCount = channelCount;
animationsGLTF.animations[i].channels = RL_CALLOC(channelCount, sizeof(ModelGLTFAnimationChannel));
for (int j = 0; j < channelCount; j++) {
//TODO Model stuff? Also... strange pointer arthmetic? data->animations[i].channels[j].sampler - data->animations[i].samplers??
animationsGLTF.animations[i].channels[j].sourceData = &animationsGLTF.animations[i].samplers[data->animations[i].channels[j].sampler - data->animations[i].samplers];
setTransformType(&data->animations[i].channels[j], &animationsGLTF.animations[i].channels[j]);
}
}
}
return animationsGLTF;
}
void UpdateModelAnimationGLTF(Model model, int animationIndex, float time) {
}
#endif

View File

@ -54,6 +54,8 @@
#include <GLFW/glfw3.h> // Windows/Context and inputs management #include <GLFW/glfw3.h> // Windows/Context and inputs management
#include <stdio.h> // Required for: printf()
#define RED (Color){ 230, 41, 55, 255 } // Red #define RED (Color){ 230, 41, 55, 255 } // Red
#define RAYWHITE (Color){ 245, 245, 245, 255 } // My own White (raylib logo) #define RAYWHITE (Color){ 245, 245, 245, 255 } // My own White (raylib logo)
#define DARKGRAY (Color){ 80, 80, 80, 255 } // Dark Gray #define DARKGRAY (Color){ 80, 80, 80, 255 } // Dark Gray
@ -61,8 +63,8 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static void ErrorCallback(int error, const char* description); static void ErrorCallback(int error, const char *description);
static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods);
// Drawing functions (uses rlgl functionality) // Drawing functions (uses rlgl functionality)
static void DrawGrid(int slices, float spacing); static void DrawGrid(int slices, float spacing);
@ -86,10 +88,10 @@ int main(void)
if (!glfwInit()) if (!glfwInit())
{ {
TraceLog(LOG_WARNING, "GLFW3: Can not initialize GLFW"); printf("GLFW3: Can not initialize GLFW\n");
return 1; return 1;
} }
else TraceLog(LOG_INFO, "GLFW3: GLFW initialized successfully"); else printf("GLFW3: GLFW initialized successfully\n");
glfwWindowHint(GLFW_SAMPLES, 4); glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_DEPTH_BITS, 16); glfwWindowHint(GLFW_DEPTH_BITS, 16);
@ -105,7 +107,7 @@ int main(void)
glfwTerminate(); glfwTerminate();
return 2; return 2;
} }
else TraceLog(LOG_INFO, "GLFW3: Window created successfully"); else printf("GLFW3: Window created successfully\n");
glfwSetWindowPos(window, 200, 200); glfwSetWindowPos(window, 200, 200);
@ -215,13 +217,13 @@ int main(void)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// GLFW3: Error callback // GLFW3: Error callback
static void ErrorCallback(int error, const char* description) static void ErrorCallback(int error, const char *description)
{ {
TraceLog(LOG_ERROR, description); fprintf(stderr, description);
} }
// GLFW3: Keyboard callback // GLFW3: Keyboard callback
static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
{ {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
{ {

View File

@ -150,7 +150,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
EMSDK_PATH ?= C:/emsdk EMSDK_PATH ?= C:/emsdk
EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten
CLANG_PATH = $(EMSDK_PATH)/upstream/bin CLANG_PATH = $(EMSDK_PATH)/upstream/bin
PYTHON_PATH = $(EMSDK_PATH)/python/2.7.13.1_64bit/python-2.7.13.amd64 PYTHON_PATH = $(EMSDK_PATH)/python/3.7.4_64bit
NODE_PATH = $(EMSDK_PATH)/node/12.9.1_64bit/bin NODE_PATH = $(EMSDK_PATH)/node/12.9.1_64bit/bin
export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH);C:\raylib\MinGW\bin:$$(PATH) export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH);C:\raylib\MinGW\bin:$$(PATH)
endif endif
@ -291,9 +291,16 @@ endif
ifeq ($(RAYLIB_BUILD_MODE),DEBUG) ifeq ($(RAYLIB_BUILD_MODE),DEBUG)
CFLAGS += -g CFLAGS += -g
ifeq ($(PLATFORM),PLATFORM_WEB)
CFLAGS += -s ASSERTIONS=1 --profiling
endif
endif endif
ifeq ($(RAYLIB_BUILD_MODE),RELEASE) ifeq ($(RAYLIB_BUILD_MODE),RELEASE)
CFLAGS += -O1 ifeq ($(PLATFORM),PLATFORM_WEB)
CFLAGS += -Os
else
CFLAGS += -s -O1
endif
endif endif
# Additional flags for compiler (if desired) # Additional flags for compiler (if desired)
@ -311,18 +318,12 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
# -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing -> WARNING: Audio buffers could FAIL! # -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing -> WARNING: Audio buffers could FAIL!
# -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) # -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB)
# -s USE_PTHREADS=1 # multithreading support # -s USE_PTHREADS=1 # multithreading support
# -s WASM=0 # disable Web Assembly, emitted by default
# -s EMTERPRETIFY=1 # enable emscripten code interpreter (very slow)
# -s EMTERPRETIFY_ASYNC=1 # support synchronous loops by emterpreter
# -s FORCE_FILESYSTEM=1 # force filesystem to load/save files data # -s FORCE_FILESYSTEM=1 # force filesystem to load/save files data
# -s ASSERTIONS=1 # enable runtime checks for common memory allocation errors (-O1 and above turn it off) # -s ASSERTIONS=1 # enable runtime checks for common memory allocation errors (-O1 and above turn it off)
# --profiling # include information for code profiling # --profiling # include information for code profiling
# --memory-init-file 0 # to avoid an external memory initialization code file (.mem) # --memory-init-file 0 # to avoid an external memory initialization code file (.mem)
# --preload-file resources # specify a resources folder for data compilation # --preload-file resources # specify a resources folder for data compilation
CFLAGS += -s USE_GLFW=3 CFLAGS += -s USE_GLFW=3
ifeq ($(RAYLIB_BUILD_MODE),DEBUG)
CFLAGS += -s ASSERTIONS=1 --profiling
endif
endif endif
ifeq ($(PLATFORM),PLATFORM_ANDROID) ifeq ($(PLATFORM),PLATFORM_ANDROID)
# Compiler flags for arquitecture # Compiler flags for arquitecture
@ -477,7 +478,7 @@ endif
raylib: $(OBJS) raylib: $(OBJS)
ifeq ($(PLATFORM),PLATFORM_WEB) ifeq ($(PLATFORM),PLATFORM_WEB)
# Compile raylib for web. # Compile raylib for web.
emcc -O1 $(OBJS) -o $(RAYLIB_RELEASE_PATH)/libraylib.bc $(CC) -O1 $(OBJS) -o $(RAYLIB_RELEASE_PATH)/libraylib.bc
@echo "raylib library generated (libraylib.bc)!" @echo "raylib library generated (libraylib.bc)!"
else else
ifeq ($(RAYLIB_LIBTYPE),SHARED) ifeq ($(RAYLIB_LIBTYPE),SHARED)

View File

@ -53,13 +53,15 @@
// Wait for events passively (sleeping while no events) instead of polling them actively every frame // Wait for events passively (sleeping while no events) instead of polling them actively every frame
//#define SUPPORT_EVENTS_WAITING 1 //#define SUPPORT_EVENTS_WAITING 1
// Allow automatic screen capture of current screen pressing F12, defined in KeyCallback() // Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
#define SUPPORT_SCREEN_CAPTURE 1 //#define SUPPORT_SCREEN_CAPTURE 1
// Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() // Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()
#define SUPPORT_GIF_RECORDING 1 //#define SUPPORT_GIF_RECORDING 1
// Allow scale all the drawn content to match the high-DPI equivalent size (only PLATFORM_DESKTOP) // Allow scale all the drawn content to match the high-DPI equivalent size (only PLATFORM_DESKTOP)
//#define SUPPORT_HIGH_DPI 1 //#define SUPPORT_HIGH_DPI 1
// Support CompressData() and DecompressData() functions // Support CompressData() and DecompressData() functions
#define SUPPORT_COMPRESSION_API 1 #define SUPPORT_COMPRESSION_API 1
// Support saving binary data automatically to a generated storage.data file. This file is managed internally.
#define SUPPORT_DATA_STORAGE 1
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: rlgl - Configuration Flags // Module: rlgl - Configuration Flags
@ -85,14 +87,15 @@
//#define SUPPORT_FILEFORMAT_BMP 1 //#define SUPPORT_FILEFORMAT_BMP 1
//#define SUPPORT_FILEFORMAT_TGA 1 //#define SUPPORT_FILEFORMAT_TGA 1
//#define SUPPORT_FILEFORMAT_JPG 1 //#define SUPPORT_FILEFORMAT_JPG 1
#define SUPPORT_FILEFORMAT_GIF 1 #define SUPPORT_FILEFORMAT_GIF 1
//#define SUPPORT_FILEFORMAT_PSD 1 //#define SUPPORT_FILEFORMAT_PSD 1
#define SUPPORT_FILEFORMAT_DDS 1 //#define SUPPORT_FILEFORMAT_DDS 1
#define SUPPORT_FILEFORMAT_HDR 1 //#define SUPPORT_FILEFORMAT_HDR 1
//#define SUPPORT_FILEFORMAT_KTX 1 //#define SUPPORT_FILEFORMAT_KTX 1
//#define SUPPORT_FILEFORMAT_ASTC 1 //#define SUPPORT_FILEFORMAT_ASTC 1
//#define SUPPORT_FILEFORMAT_PKM 1 //#define SUPPORT_FILEFORMAT_PKM 1
//#define SUPPORT_FILEFORMAT_PVR 1 //#define SUPPORT_FILEFORMAT_PVR 1
// Support image export functionality (.png, .bmp, .tga, .jpg) // Support image export functionality (.png, .bmp, .tga, .jpg)
#define SUPPORT_IMAGE_EXPORT 1 #define SUPPORT_IMAGE_EXPORT 1
// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop... // Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
@ -117,7 +120,7 @@
// Selected desired model fileformats to be supported for loading // Selected desired model fileformats to be supported for loading
#define SUPPORT_FILEFORMAT_OBJ 1 #define SUPPORT_FILEFORMAT_OBJ 1
#define SUPPORT_FILEFORMAT_MTL 1 #define SUPPORT_FILEFORMAT_MTL 1
#define SUPPORT_FILEFORMAT_IQM 1 //#define SUPPORT_FILEFORMAT_IQM 1
#define SUPPORT_FILEFORMAT_GLTF 1 #define SUPPORT_FILEFORMAT_GLTF 1
// Support procedural mesh generation functions, uses external par_shapes.h library // Support procedural mesh generation functions, uses external par_shapes.h library
// NOTE: Some generated meshes DO NOT include generated texture coordinates // NOTE: Some generated meshes DO NOT include generated texture coordinates
@ -131,8 +134,8 @@
#define SUPPORT_FILEFORMAT_OGG 1 #define SUPPORT_FILEFORMAT_OGG 1
#define SUPPORT_FILEFORMAT_XM 1 #define SUPPORT_FILEFORMAT_XM 1
#define SUPPORT_FILEFORMAT_MOD 1 #define SUPPORT_FILEFORMAT_MOD 1
#define SUPPORT_FILEFORMAT_FLAC 1 //#define SUPPORT_FILEFORMAT_FLAC 1
#define SUPPORT_FILEFORMAT_MP3 1 //#define SUPPORT_FILEFORMAT_MP3 1
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: utils - Configuration Flags // Module: utils - Configuration Flags

View File

@ -82,6 +82,9 @@
* provided by stb_image and stb_image_write libraries, so, those libraries must be enabled on textures module * provided by stb_image and stb_image_write libraries, so, those libraries must be enabled on textures module
* for linkage * for linkage
* *
* #define SUPPORT_DATA_STORAGE
* Support saving binary data automatically to a generated storage.data file. This file is managed internally.
*
* DEPENDENCIES: * DEPENDENCIES:
* rglfw - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX. FreeBSD, OpenBSD, NetBSD, DragonFly) * rglfw - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX. FreeBSD, OpenBSD, NetBSD, DragonFly)
* raymath - 3D math functionality (Vector2, Vector3, Matrix, Quaternion) * raymath - 3D math functionality (Vector2, Vector3, Matrix, Quaternion)
@ -152,7 +155,6 @@
#endif #endif
#include <stdlib.h> // Required for: srand(), rand(), atexit() #include <stdlib.h> // Required for: srand(), rand(), atexit()
#include <stdio.h> // Required for: FILE, fopen(), fseek(), fread(), fwrite(), fclose() [Used in StorageSaveValue()/StorageLoadValue()]
#include <string.h> // Required for: strrchr(), strcmp(), strlen() #include <string.h> // Required for: strrchr(), strcmp(), strlen()
#include <time.h> // Required for: time() [Used in InitTimer()] #include <time.h> // Required for: time() [Used in InitTimer()]
#include <math.h> // Required for: tan() [Used in BeginMode3D()] #include <math.h> // Required for: tan() [Used in BeginMode3D()]
@ -219,33 +221,33 @@
#include <android/window.h> // Defines AWINDOW_FLAG_FULLSCREEN and others #include <android/window.h> // Defines AWINDOW_FLAG_FULLSCREEN and others
#include <android_native_app_glue.h> // Defines basic app state struct and manages activity #include <android_native_app_glue.h> // Defines basic app state struct and manages activity
#include <EGL/egl.h> // Khronos EGL library - Native platform display device control functions #include <EGL/egl.h> // Khronos EGL library - Native platform display device control functions
#include <GLES2/gl2.h> // Khronos OpenGL ES 2.0 library #include <GLES2/gl2.h> // Khronos OpenGL ES 2.0 library
#endif #endif
#if defined(PLATFORM_RPI) #if defined(PLATFORM_RPI)
#include <fcntl.h> // POSIX file control definitions - open(), creat(), fcntl() #include <fcntl.h> // POSIX file control definitions - open(), creat(), fcntl()
#include <unistd.h> // POSIX standard function definitions - read(), close(), STDIN_FILENO #include <unistd.h> // POSIX standard function definitions - read(), close(), STDIN_FILENO
#include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr() #include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr()
#include <pthread.h> // POSIX threads management (inputs reading) #include <pthread.h> // POSIX threads management (inputs reading)
#include <dirent.h> // POSIX directory browsing #include <dirent.h> // POSIX directory browsing
#include <sys/ioctl.h> // UNIX System call for device-specific input/output operations - ioctl() #include <sys/ioctl.h> // UNIX System call for device-specific input/output operations - ioctl()
#include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition #include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
#include <linux/input.h> // Linux: Keycodes constants definition (KEY_A, ...) #include <linux/input.h> // Linux: Keycodes constants definition (KEY_A, ...)
#include <linux/joystick.h> // Linux: Joystick support library #include <linux/joystick.h> // Linux: Joystick support library
#include "bcm_host.h" // Raspberry Pi VideoCore IV access functions #include "bcm_host.h" // Raspberry Pi VideoCore IV access functions
#include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions #include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions
#include "EGL/eglext.h" // Khronos EGL library - Extensions #include "EGL/eglext.h" // Khronos EGL library - Extensions
#include "GLES2/gl2.h" // Khronos OpenGL ES 2.0 library #include "GLES2/gl2.h" // Khronos OpenGL ES 2.0 library
#endif #endif
#if defined(PLATFORM_UWP) #if defined(PLATFORM_UWP)
#include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions #include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions
#include "EGL/eglext.h" // Khronos EGL library - Extensions #include "EGL/eglext.h" // Khronos EGL library - Extensions
#include "GLES2/gl2.h" // Khronos OpenGL ES 2.0 library #include "GLES2/gl2.h" // Khronos OpenGL ES 2.0 library
#endif #endif
#if defined(PLATFORM_WEB) #if defined(PLATFORM_WEB)
@ -283,34 +285,36 @@
#endif #endif
#define MAX_GAMEPADS 4 // Max number of gamepads supported #define MAX_GAMEPADS 4 // Max number of gamepads supported
#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad)
#define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) #define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad)
#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad)
#define MAX_CHARS_QUEUE 16 // Max number of characters in the input queue #define MAX_CHARS_QUEUE 16 // Max number of characters in the input queue
#define STORAGE_FILENAME "storage.data" #if defined(SUPPORT_DATA_STORAGE)
#define STORAGE_DATA_FILE "storage.data"
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(PLATFORM_RPI) #if defined(PLATFORM_RPI)
typedef struct { typedef struct {
pthread_t threadId; // Event reading thread id pthread_t threadId; // Event reading thread id
int fd; // File descriptor to the device it is assigned to int fd; // File descriptor to the device it is assigned to
int eventNum; // Number of 'event<N>' device int eventNum; // Number of 'event<N>' device
Rectangle absRange; // Range of values for absolute pointing devices (touchscreens) Rectangle absRange; // Range of values for absolute pointing devices (touchscreens)
int touchSlot; // Hold the touch slot number of the currently being sent multitouch block int touchSlot; // Hold the touch slot number of the currently being sent multitouch block
bool isMouse; // True if device supports relative X Y movements bool isMouse; // True if device supports relative X Y movements
bool isTouch; // True if device supports absolute X Y movements and has BTN_TOUCH bool isTouch; // True if device supports absolute X Y movements and has BTN_TOUCH
bool isMultitouch; // True if device supports multiple absolute movevents and has BTN_TOUCH bool isMultitouch; // True if device supports multiple absolute movevents and has BTN_TOUCH
bool isKeyboard; // True if device has letter keycodes bool isKeyboard; // True if device has letter keycodes
bool isGamepad; // True if device has gamepad buttons bool isGamepad; // True if device has gamepad buttons
} InputEventWorker; } InputEventWorker;
typedef struct{ typedef struct {
int Contents[8]; int contents[8]; // Key events FIFO contents (8 positions)
char Head; char head; // Key events FIFO head position
char Tail; char tail; // Key events FIFO tail position
} KeyEventFifo; } KeyEventFifo;
#endif #endif
@ -498,7 +502,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
#endif #endif
#if defined(PLATFORM_WEB) #if defined(PLATFORM_WEB)
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData); static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);
static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData); static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData); static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData); static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
@ -703,7 +707,8 @@ void InitWindow(int width, int height, const char *title)
#endif #endif
#if defined(PLATFORM_WEB) #if defined(PLATFORM_WEB)
emscripten_set_fullscreenchange_callback(0, 0, 1, EmscriptenFullscreenChangeCallback); // Detect fullscreen change events
emscripten_set_fullscreenchange_callback("#canvas", NULL, 1, EmscriptenFullscreenChangeCallback);
// Support keyboard events // Support keyboard events
emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback); emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
@ -867,9 +872,9 @@ bool IsWindowHidden(void)
// Toggle fullscreen mode (only PLATFORM_DESKTOP) // Toggle fullscreen mode (only PLATFORM_DESKTOP)
void ToggleFullscreen(void) void ToggleFullscreen(void)
{ {
#if defined(PLATFORM_DESKTOP)
CORE.Window.fullscreen = !CORE.Window.fullscreen; // Toggle fullscreen flag CORE.Window.fullscreen = !CORE.Window.fullscreen; // Toggle fullscreen flag
#if defined(PLATFORM_DESKTOP)
// NOTE: glfwSetWindowMonitor() doesn't work properly (bugs) // NOTE: glfwSetWindowMonitor() doesn't work properly (bugs)
if (CORE.Window.fullscreen) if (CORE.Window.fullscreen)
{ {
@ -893,7 +898,10 @@ void ToggleFullscreen(void)
} }
else glfwSetWindowMonitor(CORE.Window.handle, NULL, CORE.Window.position.x, CORE.Window.position.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); else glfwSetWindowMonitor(CORE.Window.handle, NULL, CORE.Window.position.x, CORE.Window.position.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
#endif #endif
#if defined(PLATFORM_WEB)
if (CORE.Window.fullscreen) EM_ASM(Module.requestFullscreen(false, false););
else EM_ASM(document.exitFullscreen(););
#endif
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
TRACELOG(LOG_WARNING, "Could not toggle to windowed mode"); TRACELOG(LOG_WARNING, "Could not toggle to windowed mode");
#endif #endif
@ -971,6 +979,14 @@ void SetWindowSize(int width, int height)
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
glfwSetWindowSize(CORE.Window.handle, width, height); glfwSetWindowSize(CORE.Window.handle, width, height);
#endif #endif
#if defined(PLATFORM_WEB)
emscripten_set_canvas_size(width, height); // DEPRECATED!
// TODO: Below functions should be used to replace previous one but
// they do not seem to work properly
//emscripten_set_canvas_element_size("canvas", width, height);
//emscripten_set_element_css_size("canvas", width, height);
#endif
} }
// Show the window // Show the window
@ -1622,7 +1638,7 @@ int GetFPS(void)
static float history[FPS_CAPTURE_FRAMES_COUNT] = { 0 }; static float history[FPS_CAPTURE_FRAMES_COUNT] = { 0 };
static float average = 0, last = 0; static float average = 0, last = 0;
float fpsFrame = GetFrameTime(); float fpsFrame = GetFrameTime();
if (fpsFrame == 0) return 0; if (fpsFrame == 0) return 0;
if ((GetTime() - last) > FPS_STEP) if ((GetTime() - last) > FPS_STEP)
@ -1633,7 +1649,7 @@ int GetFPS(void)
history[index] = fpsFrame/FPS_CAPTURE_FRAMES_COUNT; history[index] = fpsFrame/FPS_CAPTURE_FRAMES_COUNT;
average += history[index]; average += history[index];
} }
return (int)roundf(1.0f/average); return (int)roundf(1.0f/average);
} }
@ -2168,80 +2184,84 @@ unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *
// Save integer value to storage file (to defined position) // Save integer value to storage file (to defined position)
// NOTE: Storage positions is directly related to file memory layout (4 bytes each integer) // NOTE: Storage positions is directly related to file memory layout (4 bytes each integer)
void StorageSaveValue(int position, int value) void SaveStorageValue(int position, int value)
{ {
FILE *storageFile = NULL; #if defined(SUPPORT_DATA_STORAGE)
char path[512] = { 0 }; char path[512] = { 0 };
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
strcpy(path, CORE.Android.internalDataPath); strcpy(path, CORE.Android.internalDataPath);
strcat(path, "/"); strcat(path, "/");
strcat(path, STORAGE_FILENAME); strcat(path, STORAGE_DATA_FILE);
#else #else
strcpy(path, STORAGE_FILENAME); strcpy(path, STORAGE_DATA_FILE);
#endif #endif
// Try open existing file to append data int dataSize = 0;
storageFile = fopen(path, "rb+"); unsigned char *fileData = LoadFileData(path, &dataSize);
// If file doesn't exist, create a new storage data file if (fileData != NULL)
if (!storageFile) storageFile = fopen(path, "wb");
if (!storageFile) TRACELOG(LOG_WARNING, "Storage data file could not be created");
else
{ {
// Get file size if (dataSize <= (position*sizeof(int)))
fseek(storageFile, 0, SEEK_END); {
int fileSize = ftell(storageFile); // Size in bytes // Increase data size up to position and store value
fseek(storageFile, 0, SEEK_SET); dataSize = (position + 1)*sizeof(int);
fileData = (unsigned char *)RL_REALLOC(fileData, dataSize);
if (fileSize < (position*sizeof(int))) TRACELOG(LOG_WARNING, "Storage position could not be found"); int *dataPtr = (int *)fileData;
dataPtr[position] = value;
}
else else
{ {
fseek(storageFile, (position*sizeof(int)), SEEK_SET); // Replace value on selected position
fwrite(&value, 1, sizeof(int), storageFile); int *dataPtr = (int *)fileData;
dataPtr[position] = value;
} }
fclose(storageFile); SaveFileData(path, fileData, dataSize);
RL_FREE(fileData);
} }
else
{
dataSize = (position + 1)*sizeof(int);
fileData = (unsigned char *)RL_MALLOC(dataSize);
int *dataPtr = (int *)fileData;
dataPtr[position] = value;
SaveFileData(path, fileData, dataSize);
RL_FREE(fileData);
}
#endif
} }
// Load integer value from storage file (from defined position) // Load integer value from storage file (from defined position)
// NOTE: If requested position could not be found, value 0 is returned // NOTE: If requested position could not be found, value 0 is returned
int StorageLoadValue(int position) int LoadStorageValue(int position)
{ {
int value = 0; int value = 0;
#if defined(SUPPORT_DATA_STORAGE)
char path[512] = { 0 }; char path[512] = { 0 };
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
strcpy(path, CORE.Android.internalDataPath); strcpy(path, CORE.Android.internalDataPath);
strcat(path, "/"); strcat(path, "/");
strcat(path, STORAGE_FILENAME); strcat(path, STORAGE_DATA_FILE);
#else #else
strcpy(path, STORAGE_FILENAME); strcpy(path, STORAGE_DATA_FILE);
#endif #endif
// Try open existing file to append data int dataSize = 0;
FILE *storageFile = fopen(path, "rb"); unsigned char *fileData = LoadFileData(path, &dataSize);
if (!storageFile) TRACELOG(LOG_WARNING, "Storage data file could not be found"); if (fileData != NULL)
else
{ {
// Get file size if (dataSize < (position*4)) TRACELOG(LOG_WARNING, "Storage position could not be found");
fseek(storageFile, 0, SEEK_END);
int fileSize = ftell(storageFile); // Size in bytes
fseek(storageFile, 0, SEEK_SET); // Reset file pointer
if (fileSize < (position*4)) TRACELOG(LOG_WARNING, "Storage position could not be found");
else else
{ {
fseek(storageFile, (position*4), SEEK_SET); int *dataPtr = (int *)fileData;
fread(&value, 4, 1, storageFile); // Read 1 element of 4 bytes size value = dataPtr[position];
} }
fclose(storageFile); RL_FREE(fileData);
} }
#endif
return value; return value;
} }
@ -2511,7 +2531,11 @@ bool IsMouseButtonReleased(int button)
{ {
bool released = false; bool released = false;
#if !defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
# if defined(SUPPORT_GESTURES_SYSTEM)
released = GetGestureDetected() == GESTURE_TAP;
# endif
#else
if ((CORE.Input.Mouse.currentButtonState[button] != CORE.Input.Mouse.previousButtonState[button]) && if ((CORE.Input.Mouse.currentButtonState[button] != CORE.Input.Mouse.previousButtonState[button]) &&
(GetMouseButtonStatus(button) == 0)) released = true; (GetMouseButtonStatus(button) == 0)) released = true;
#endif #endif
@ -3574,12 +3598,12 @@ static void PollInputEvents(void)
for (int i = 0; i < 512; i++)CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; for (int i = 0; i < 512; i++)CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
// Grab a keypress from the evdev fifo if avalable // Grab a keypress from the evdev fifo if avalable
if (CORE.Input.Keyboard.lastKeyPressed.Head != CORE.Input.Keyboard.lastKeyPressed.Tail) if (CORE.Input.Keyboard.lastKeyPressed.head != CORE.Input.Keyboard.lastKeyPressed.tail)
{ {
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = CORE.Input.Keyboard.lastKeyPressed.Contents[CORE.Input.Keyboard.lastKeyPressed.Tail]; // Read the key from the buffer CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = CORE.Input.Keyboard.lastKeyPressed.contents[CORE.Input.Keyboard.lastKeyPressed.tail]; // Read the key from the buffer
CORE.Input.Keyboard.keyPressedQueueCount++; CORE.Input.Keyboard.keyPressedQueueCount++;
CORE.Input.Keyboard.lastKeyPressed.Tail = (CORE.Input.Keyboard.lastKeyPressed.Tail + 1) & 0x07; // Increment the tail pointer forwards and binary wraparound after 7 (fifo is 8 elements long) CORE.Input.Keyboard.lastKeyPressed.tail = (CORE.Input.Keyboard.lastKeyPressed.tail + 1) & 0x07; // Increment the tail pointer forwards and binary wraparound after 7 (fifo is 8 elements long)
} }
// Register previous mouse states // Register previous mouse states
@ -4230,37 +4254,84 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
{ {
// If additional inputs are required check: // If additional inputs are required check:
// https://developer.android.com/ndk/reference/group/input // https://developer.android.com/ndk/reference/group/input
// https://developer.android.com/training/game-controllers/controller-input
int type = AInputEvent_getType(event); int type = AInputEvent_getType(event);
int source = AInputEvent_getSource(event);
if (type == AINPUT_EVENT_TYPE_MOTION) if (type == AINPUT_EVENT_TYPE_MOTION)
{ {
// Get first touch position if ((source & AINPUT_SOURCE_JOYSTICK) == AINPUT_SOURCE_JOYSTICK || (source & AINPUT_SOURCE_GAMEPAD) == AINPUT_SOURCE_GAMEPAD)
CORE.Input.Touch.position[0].x = AMotionEvent_getX(event, 0);
CORE.Input.Touch.position[0].y = AMotionEvent_getY(event, 0);
// Get second touch position
CORE.Input.Touch.position[1].x = AMotionEvent_getX(event, 1);
CORE.Input.Touch.position[1].y = AMotionEvent_getY(event, 1);
// Useful functions for gamepad inputs:
//AMotionEvent_getAction()
//AMotionEvent_getAxisValue()
//AMotionEvent_getButtonState()
// Gamepad dpad button presses capturing
// TODO: That's weird, key input (or button)
// shouldn't come as a TYPE_MOTION event...
int32_t keycode = AKeyEvent_getKeyCode(event);
if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN)
{ {
CORE.Input.Keyboard.currentKeyState[keycode] = 1; // Key down // Get first touch position
CORE.Input.Touch.position[0].x = AMotionEvent_getX(event, 0);
CORE.Input.Touch.position[0].y = AMotionEvent_getY(event, 0);
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode; // Get second touch position
CORE.Input.Keyboard.keyPressedQueueCount++; CORE.Input.Touch.position[1].x = AMotionEvent_getX(event, 1);
CORE.Input.Touch.position[1].y = AMotionEvent_getY(event, 1);
int32_t keycode = AKeyEvent_getKeyCode(event);
if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN)
{
CORE.Input.Keyboard.currentKeyState[keycode] = 1; // Key down
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode;
CORE.Input.Keyboard.keyPressedQueueCount++;
}
else CORE.Input.Keyboard.currentKeyState[keycode] = 0; // Key up
// Stop processing gamepad buttons
return 1;
} }
else CORE.Input.Keyboard.currentKeyState[keycode] = 0; // Key up
int32_t action = AMotionEvent_getAction(event);
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
// Simple touch position
if (flags == AMOTION_EVENT_ACTION_DOWN)
{
// Get first touch position
CORE.Input.Touch.position[0].x = AMotionEvent_getX(event, 0);
CORE.Input.Touch.position[0].y = AMotionEvent_getY(event, 0);
}
#if defined(SUPPORT_GESTURES_SYSTEM)
GestureEvent gestureEvent;
// Register touch actions
if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.touchAction = TOUCH_DOWN;
else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.touchAction = TOUCH_UP;
else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.touchAction = TOUCH_MOVE;
// Register touch points count
// NOTE: Documentation says pointerCount is Always >= 1,
// but in practice it can be 0 or over a million
gestureEvent.pointCount = AMotionEvent_getPointerCount(event);
// Only enable gestures for 1-3 touch points
if ((gestureEvent.pointCount > 0) && (gestureEvent.pointCount < 4))
{
// Register touch points id
// NOTE: Only two points registered
gestureEvent.pointerId[0] = AMotionEvent_getPointerId(event, 0);
gestureEvent.pointerId[1] = AMotionEvent_getPointerId(event, 1);
// Register touch points position
gestureEvent.position[0] = (Vector2){ AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0) };
gestureEvent.position[1] = (Vector2){ AMotionEvent_getX(event, 1), AMotionEvent_getY(event, 1) };
// Normalize gestureEvent.position[x] for screenWidth and screenHeight
gestureEvent.position[0].x /= (float)GetScreenWidth();
gestureEvent.position[0].y /= (float)GetScreenHeight();
gestureEvent.position[1].x /= (float)GetScreenWidth();
gestureEvent.position[1].y /= (float)GetScreenHeight();
// Gesture data is sent to gestures system for processing
ProcessGestureEvent(gestureEvent);
}
#endif
} }
else if (type == AINPUT_EVENT_TYPE_KEY) else if (type == AINPUT_EVENT_TYPE_KEY)
{ {
@ -4297,11 +4368,29 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
// Set default OS behaviour // Set default OS behaviour
return 0; return 0;
} }
return 0;
} }
int32_t action = AMotionEvent_getAction(event); int32_t action = AMotionEvent_getAction(event);
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK; unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
// Support only simple touch position
if (flags == AMOTION_EVENT_ACTION_DOWN)
{
// Get first touch position
CORE.Input.Touch.position[0].x = AMotionEvent_getX(event, 0);
CORE.Input.Touch.position[0].y = AMotionEvent_getY(event, 0);
}
else if (flags == AMOTION_EVENT_ACTION_UP)
{
// Get first touch position
CORE.Input.Touch.position[0].x = 0;
CORE.Input.Touch.position[0].y = 0;
}
else // TODO:Not sure what else should be handled
return 0;
#if defined(SUPPORT_GESTURES_SYSTEM) #if defined(SUPPORT_GESTURES_SYSTEM)
GestureEvent gestureEvent = { 0 }; GestureEvent gestureEvent = { 0 };
@ -4337,17 +4426,6 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
// Gesture data is sent to gestures system for processing // Gesture data is sent to gestures system for processing
ProcessGestureEvent(gestureEvent); ProcessGestureEvent(gestureEvent);
} }
#else
// Support only simple touch position
if (flags == AMOTION_EVENT_ACTION_DOWN)
{
// Get first touch position
CORE.Input.Touch.position[0].x = AMotionEvent_getX(event, 0);
CORE.Input.Touch.position[0].y = AMotionEvent_getY(event, 0);
CORE.Input.Touch.position[0].x /= (float)GetScreenWidth();
CORE.Input.Touch.position[0].y /= (float)GetScreenHeight();
}
#endif #endif
return 0; return 0;
@ -4355,7 +4433,6 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
#endif #endif
#if defined(PLATFORM_WEB) #if defined(PLATFORM_WEB)
// Register fullscreen change events // Register fullscreen change events
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData) static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData)
{ {
@ -4368,10 +4445,12 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
if (event->isFullscreen) if (event->isFullscreen)
{ {
CORE.Window.fullscreen = true;
TRACELOG(LOG_INFO, "Canvas scaled to fullscreen. ElementSize: (%ix%i), ScreenSize(%ix%i)", event->elementWidth, event->elementHeight, event->screenWidth, event->screenHeight); TRACELOG(LOG_INFO, "Canvas scaled to fullscreen. ElementSize: (%ix%i), ScreenSize(%ix%i)", event->elementWidth, event->elementHeight, event->screenWidth, event->screenHeight);
} }
else else
{ {
CORE.Window.fullscreen = false;
TRACELOG(LOG_INFO, "Canvas scaled to windowed. ElementSize: (%ix%i), ScreenSize(%ix%i)", event->elementWidth, event->elementHeight, event->screenWidth, event->screenHeight); TRACELOG(LOG_INFO, "Canvas scaled to windowed. ElementSize: (%ix%i), ScreenSize(%ix%i)", event->elementWidth, event->elementHeight, event->screenWidth, event->screenHeight);
} }
@ -4688,8 +4767,8 @@ static void InitEvdevInput(void)
} }
// Reset keypress buffer // Reset keypress buffer
CORE.Input.Keyboard.lastKeyPressed.Head = 0; CORE.Input.Keyboard.lastKeyPressed.head = 0;
CORE.Input.Keyboard.lastKeyPressed.Tail = 0; CORE.Input.Keyboard.lastKeyPressed.tail = 0;
// Reset keyboard key state // Reset keyboard key state
for (int i = 0; i < 512; i++) CORE.Input.Keyboard.currentKeyState[i] = 0; for (int i = 0; i < 512; i++) CORE.Input.Keyboard.currentKeyState[i] = 0;
@ -5052,8 +5131,8 @@ static void *EventThread(void *arg)
if (event.value > 0) if (event.value > 0)
{ {
// Add the key int the fifo // Add the key int the fifo
CORE.Input.Keyboard.lastKeyPressed.Contents[CORE.Input.Keyboard.lastKeyPressed.Head] = keycode; // Put the data at the front of the fifo snake CORE.Input.Keyboard.lastKeyPressed.contents[CORE.Input.Keyboard.lastKeyPressed.head] = keycode; // Put the data at the front of the fifo snake
CORE.Input.Keyboard.lastKeyPressed.Head = (CORE.Input.Keyboard.lastKeyPressed.Head + 1) & 0x07; // Increment the head pointer forwards and binary wraparound after 7 (fifo is 8 elements long) CORE.Input.Keyboard.lastKeyPressed.head = (CORE.Input.Keyboard.lastKeyPressed.head + 1) & 0x07; // Increment the head pointer forwards and binary wraparound after 7 (fifo is 8 elements long)
// TODO: This fifo is not fully threadsafe with multiple writers, so multiple keyboards hitting a key at the exact same time could miss a key (double write to head before it was incremented) // TODO: This fifo is not fully threadsafe with multiple writers, so multiple keyboards hitting a key at the exact same time could miss a key (double write to head before it was incremented)
} }
*/ */

View File

@ -45,10 +45,10 @@
#include "utils.h" // Required for: fopen() Android mapping #include "utils.h" // Required for: fopen() Android mapping
#include <stdlib.h> // Required for: malloc(), free(), fabs() #include <stdlib.h> // Required for: malloc(), free()
#include <stdio.h> // Required for: FILE, fopen(), fclose() #include <stdio.h> // Required for: FILE, fopen(), fclose()
#include <string.h> // Required for: strncmp() [Used in LoadModelAnimations()], strlen() [Used in LoadTextureFromCgltfImage()] #include <string.h> // Required for: strncmp() [Used in LoadModelAnimations()], strlen() [Used in LoadTextureFromCgltfImage()]
#include <math.h> // Required for: sinf(), cosf(), sqrtf() #include <math.h> // Required for: sinf(), cosf(), sqrtf(), fabsf()
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
@ -2513,9 +2513,9 @@ void DrawBoundingBox(BoundingBox box, Color color)
{ {
Vector3 size; Vector3 size;
size.x = (float)fabs(box.max.x - box.min.x); size.x = fabsf(box.max.x - box.min.x);
size.y = (float)fabs(box.max.y - box.min.y); size.y = fabsf(box.max.y - box.min.y);
size.z = (float)fabs(box.max.z - box.min.z); size.z = fabsf(box.max.z - box.min.z);
Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f }; Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f };
@ -2761,7 +2761,7 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight)
RayHitInfo result = { 0 }; RayHitInfo result = { 0 };
if (fabs(ray.direction.y) > EPSILON) if (fabsf(ray.direction.y) > EPSILON)
{ {
float distance = (ray.position.y - groundHeight)/-ray.direction.y; float distance = (ray.position.y - groundHeight)/-ray.direction.y;

View File

@ -80,7 +80,7 @@
#if defined(_WIN32) #if defined(_WIN32)
// To avoid conflicting windows.h symbols with raylib, some flags are defined // To avoid conflicting windows.h symbols with raylib, some flags are defined
// WARNING: Those flags avoid inclusion of some Win32 headers that could be required // WARNING: Those flags avoid inclusion of some Win32 headers that could be required
// by user at some point and won't be included... // by user at some point and won't be included...
//------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------
@ -165,6 +165,10 @@ typedef struct tagBITMAPINFOHEADER {
#if defined(RAUDIO_STANDALONE) #if defined(RAUDIO_STANDALONE)
#include <string.h> // Required for: strcmp() [Used in IsFileExtension()] #include <string.h> // Required for: strcmp() [Used in IsFileExtension()]
#if !defined(TRACELOG)
#define TRACELOG(level, ...) (void)0
#endif
#endif #endif
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
@ -740,9 +744,8 @@ void ExportWave(Wave wave, const char *fileName)
{ {
// Export raw sample data (without header) // Export raw sample data (without header)
// NOTE: It's up to the user to track wave parameters // NOTE: It's up to the user to track wave parameters
FILE *rawFile = fopen(fileName, "wb"); SaveFileData(fileName, wave.data, wave.sampleCount*wave.channels*wave.sampleSize/8);
success = fwrite(wave.data, wave.sampleCount*wave.channels*wave.sampleSize/8, 1, rawFile); success = true;
fclose(rawFile);
} }
if (success) TRACELOG(LOG_INFO, "Wave exported successfully: %s", fileName); if (success) TRACELOG(LOG_INFO, "Wave exported successfully: %s", fileName);
@ -1552,11 +1555,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
ma_uint32 subBufferSizeInFrames = (audioBuffer->sizeInFrames > 1)? audioBuffer->sizeInFrames/2 : audioBuffer->sizeInFrames; ma_uint32 subBufferSizeInFrames = (audioBuffer->sizeInFrames > 1)? audioBuffer->sizeInFrames/2 : audioBuffer->sizeInFrames;
ma_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames; ma_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames;
if (currentSubBufferIndex > 1) if (currentSubBufferIndex > 1) return 0;
{
TRACELOGD("Frame cursor position moved too far forward in audio stream");
return 0;
}
// Another thread can update the processed state of buffers so // Another thread can update the processed state of buffers so
// we just take a copy here to try and avoid potential synchronization problems // we just take a copy here to try and avoid potential synchronization problems
@ -1639,7 +1638,7 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
// Reads audio data from an AudioBuffer object in device format. Returned data will be in a format appropriate for mixing. // Reads audio data from an AudioBuffer object in device format. Returned data will be in a format appropriate for mixing.
static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, float *framesOut, ma_uint32 frameCount) static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, float *framesOut, ma_uint32 frameCount)
{ {
// What's going on here is that we're continuously converting data from the AudioBuffer's internal format to the mixing format, which // What's going on here is that we're continuously converting data from the AudioBuffer's internal format to the mixing format, which
// should be defined by the output format of the data converter. We do this until frameCount frames have been output. The important // should be defined by the output format of the data converter. We do this until frameCount frames have been output. The important
// detail to remember here is that we never, ever attempt to read more input data than is required for the specified number of output // detail to remember here is that we never, ever attempt to read more input data than is required for the specified number of output
// frames. This can be achieved with ma_data_converter_get_required_input_frame_count(). // frames. This can be achieved with ma_data_converter_get_required_input_frame_count().
@ -1663,7 +1662,7 @@ static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, f
ma_uint64 inputFramesProcessedThisIteration = ReadAudioBufferFramesInInternalFormat(audioBuffer, inputBuffer, (ma_uint32)inputFramesToProcessThisIteration); /* Safe cast. */ ma_uint64 inputFramesProcessedThisIteration = ReadAudioBufferFramesInInternalFormat(audioBuffer, inputBuffer, (ma_uint32)inputFramesToProcessThisIteration); /* Safe cast. */
ma_uint64 outputFramesProcessedThisIteration = outputFramesToProcessThisIteration; ma_uint64 outputFramesProcessedThisIteration = outputFramesToProcessThisIteration;
ma_data_converter_process_pcm_frames(&audioBuffer->converter, inputBuffer, &inputFramesProcessedThisIteration, runningFramesOut, &outputFramesProcessedThisIteration); ma_data_converter_process_pcm_frames(&audioBuffer->converter, inputBuffer, &inputFramesProcessedThisIteration, runningFramesOut, &outputFramesProcessedThisIteration);
totalOutputFramesProcessed += (ma_uint32)outputFramesProcessedThisIteration; /* Safe cast. */ totalOutputFramesProcessed += (ma_uint32)outputFramesProcessedThisIteration; /* Safe cast. */
if (inputFramesProcessedThisIteration < inputFramesToProcessThisIteration) if (inputFramesProcessedThisIteration < inputFramesToProcessThisIteration)
@ -1704,13 +1703,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const
while (1) while (1)
{ {
if (framesRead > frameCount) if (framesRead >= frameCount) break;
{
TRACELOGD("Mixed too many frames from audio buffer");
break;
}
if (framesRead == frameCount) break;
// Just read as much data as we can from the stream // Just read as much data as we can from the stream
ma_uint32 framesToRead = (frameCount - framesRead); ma_uint32 framesToRead = (frameCount - framesRead);
@ -2037,9 +2030,7 @@ static Wave LoadOGG(const char *fileName)
wave.data = (short *)RL_MALLOC(wave.sampleCount*wave.channels*sizeof(short)); wave.data = (short *)RL_MALLOC(wave.sampleCount*wave.channels*sizeof(short));
// NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!)
int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, (short *)wave.data, wave.sampleCount*wave.channels); stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, (short *)wave.data, wave.sampleCount*wave.channels);
TRACELOGD("[%s] Samples obtained: %i", fileName, numSamplesOgg);
TRACELOG(LOG_INFO, "[%s] OGG file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo"); TRACELOG(LOG_INFO, "[%s] OGG file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
stb_vorbis_close(oggFile); stb_vorbis_close(oggFile);
@ -2115,29 +2106,6 @@ bool IsFileExtension(const char *fileName, const char *ext)
return result; return result;
} }
// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
void TRACELOG(int msgType, const char *text, ...)
{
va_list args;
va_start(args, text);
switch (msgType)
{
case LOG_INFO: fprintf(stdout, "INFO: "); break;
case LOG_ERROR: fprintf(stdout, "ERROR: "); break;
case LOG_WARNING: fprintf(stdout, "WARNING: "); break;
case LOG_DEBUG: fprintf(stdout, "DEBUG: "); break;
default: break;
}
vfprintf(stdout, text, args);
fprintf(stdout, "\n");
va_end(args);
if (msgType == LOG_ERROR) exit(1);
}
#endif #endif
#undef AudioBuffer #undef AudioBuffer

View File

@ -107,10 +107,10 @@
#define RL_CALLOC(n,sz) calloc(n,sz) #define RL_CALLOC(n,sz) calloc(n,sz)
#endif #endif
#ifndef RL_REALLOC #ifndef RL_REALLOC
#define RL_REALLOC(n,sz) realloc(n,sz) #define RL_REALLOC(ptr,sz) realloc(ptr,sz)
#endif #endif
#ifndef RL_FREE #ifndef RL_FREE
#define RL_FREE(p) free(p) #define RL_FREE(ptr) free(ptr)
#endif #endif
// NOTE: MSC C++ compiler does not support compound literals (C99 feature) // NOTE: MSC C++ compiler does not support compound literals (C99 feature)
@ -949,6 +949,8 @@ RLAPI void TakeScreenshot(const char *fileName); // Takes a scr
RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included)
// Files management functions // Files management functions
RLAPI unsigned char *LoadFileData(const char *fileName, int *bytesRead); // Load file data as byte array (read)
RLAPI void SaveFileData(const char *fileName, void *data, int bytesToWrite); // Save data to file from byte array (write)
RLAPI bool FileExists(const char *fileName); // Check if file exists RLAPI bool FileExists(const char *fileName); // Check if file exists
RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension
RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists
@ -970,8 +972,8 @@ RLAPI unsigned char *CompressData(unsigned char *data, int dataLength, int *comp
RLAPI unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength); // Decompress data (DEFLATE algorythm) RLAPI unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength); // Decompress data (DEFLATE algorythm)
// Persistent storage management // Persistent storage management
RLAPI void StorageSaveValue(int position, int value); // Save integer value to storage file (to defined position) RLAPI void SaveStorageValue(int position, int value); // Save integer value to storage file (to defined position)
RLAPI int StorageLoadValue(int position); // Load integer value from storage file (from defined position) RLAPI int LoadStorageValue(int position); // Load integer value from storage file (from defined position)
RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available) RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available)

View File

@ -1135,8 +1135,8 @@ RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount); else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount);
else else
{ {
float halfTheta = (float) acos(cosHalfTheta); float halfTheta = acosf(cosHalfTheta);
float sinHalfTheta = (float) sqrt(1.0f - cosHalfTheta*cosHalfTheta); float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta);
if (fabs(sinHalfTheta) < 0.001f) if (fabs(sinHalfTheta) < 0.001f)
{ {
@ -1191,7 +1191,7 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
if (trace > 0.0f) if (trace > 0.0f)
{ {
float s = (float)sqrt(trace + 1)*2.0f; float s = sqrtf(trace + 1)*2.0f;
float invS = 1.0f/s; float invS = 1.0f/s;
result.w = s*0.25f; result.w = s*0.25f;
@ -1215,7 +1215,7 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
} }
else if (m11 > m22) else if (m11 > m22)
{ {
float s = (float)sqrt(1.0f + m11 - m00 - m22)*2.0f; float s = sqrtf(1.0f + m11 - m00 - m22)*2.0f;
float invS = 1.0f/s; float invS = 1.0f/s;
result.w = (mat.m8 - mat.m2)*invS; result.w = (mat.m8 - mat.m2)*invS;
@ -1225,7 +1225,7 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
} }
else else
{ {
float s = (float)sqrt(1.0f + m22 - m00 - m11)*2.0f; float s = sqrtf(1.0f + m22 - m00 - m11)*2.0f;
float invS = 1.0f/s; float invS = 1.0f/s;
result.w = (mat.m1 - mat.m4)*invS; result.w = (mat.m1 - mat.m4)*invS;
@ -1317,8 +1317,8 @@ RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle
Vector3 resAxis = { 0.0f, 0.0f, 0.0f }; Vector3 resAxis = { 0.0f, 0.0f, 0.0f };
float resAngle = 0.0f; float resAngle = 0.0f;
resAngle = 2.0f*(float)acos(q.w); resAngle = 2.0f*acosf(q.w);
float den = (float)sqrt(1.0f - q.w*q.w); float den = sqrtf(1.0f - q.w*q.w);
if (den > 0.0001f) if (den > 0.0001f)
{ {

View File

@ -76,15 +76,7 @@
#endif #endif
// Support TRACELOG macros // Support TRACELOG macros
#if defined(RLGL_SUPPORT_TRACELOG) #if !defined(TRACELOG)
#define TRACELOG(level, ...) TraceLog(level, __VA_ARGS__)
#if defined(RLGL_SUPPORT_TRACELOG_DEBUG)
#define TRACELOGD(...) TraceLog(LOG_DEBUG, __VA_ARGS__)
#else
#define TRACELOGD(...) (void)0
#endif
#else
#define TRACELOG(level, ...) (void)0 #define TRACELOG(level, ...) (void)0
#define TRACELOGD(...) (void)0 #define TRACELOGD(...) (void)0
#endif #endif
@ -596,7 +588,6 @@ RLAPI void ToggleVrMode(void); // Enable/Disable VR exp
RLAPI void BeginVrDrawing(void); // Begin VR simulator stereo rendering RLAPI void BeginVrDrawing(void); // Begin VR simulator stereo rendering
RLAPI void EndVrDrawing(void); // End VR simulator stereo rendering RLAPI void EndVrDrawing(void); // End VR simulator stereo rendering
RLAPI void TRACELOG(int msgType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data size in bytes (image or texture) RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data size in bytes (image or texture)
#endif #endif
@ -621,10 +612,10 @@ RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data
#endif #endif
#endif #endif
#include <stdlib.h> // Required for: malloc(), free(), fabs() #include <stdlib.h> // Required for: malloc(), free()
#include <stdio.h> // Required for: fopen(), fseek(), fread(), fclose() [LoadText] #include <stdio.h> // Required for: fopen(), fseek(), fread(), fclose() [LoadText]
#include <string.h> // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading] #include <string.h> // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading]
#include <math.h> // Required for: atan2f() #include <math.h> // Required for: atan2f(), fabs()
#if !defined(RLGL_STANDALONE) #if !defined(RLGL_STANDALONE)
#include "raymath.h" // Required for: Vector3 and Matrix functions #include "raymath.h" // Required for: Vector3 and Matrix functions
@ -676,10 +667,6 @@ RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data
#include <GLES2/gl2ext.h> // OpenGL ES 2.0 extensions library #include <GLES2/gl2ext.h> // OpenGL ES 2.0 extensions library
#endif #endif
#if defined(RLGL_STANDALONE)
#include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end() [Used in TraceLog()]
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -3001,15 +2988,17 @@ Shader GetShaderDefault(void)
// NOTE: text chars array should be freed manually // NOTE: text chars array should be freed manually
char *LoadText(const char *fileName) char *LoadText(const char *fileName)
{ {
FILE *textFile = NULL;
char *text = NULL; char *text = NULL;
if (fileName != NULL) if (fileName != NULL)
{ {
textFile = fopen(fileName,"rt"); FILE *textFile = fopen(fileName, "rt");
if (textFile != NULL) if (textFile != NULL)
{ {
// WARNING: When reading a file as 'text' file,
// text mode causes carriage return-linefeed translation...
// ...but using fseek() should return correct byte-offset
fseek(textFile, 0, SEEK_END); fseek(textFile, 0, SEEK_END);
int size = ftell(textFile); int size = ftell(textFile);
fseek(textFile, 0, SEEK_SET); fseek(textFile, 0, SEEK_SET);
@ -3018,6 +3007,15 @@ char *LoadText(const char *fileName)
{ {
text = (char *)RL_MALLOC(sizeof(char)*(size + 1)); text = (char *)RL_MALLOC(sizeof(char)*(size + 1));
int count = fread(text, sizeof(char), size, textFile); int count = fread(text, sizeof(char), size, textFile);
// WARNING: \r\n is converted to \n on reading, so,
// read bytes count gets reduced by the number of lines
if (count < size)
{
text = RL_REALLOC(text, count + 1);
}
// zero-terminate the string
text[count] = '\0'; text[count] = '\0';
} }
@ -3664,7 +3662,7 @@ void SetVrConfiguration(VrDeviceInfo hmd, Shader distortion)
// Compute distortion scale parameters // Compute distortion scale parameters
// NOTE: To get lens max radius, lensShift must be normalized to [-1..1] // NOTE: To get lens max radius, lensShift must be normalized to [-1..1]
float lensRadius = (float)fabs(-1.0f - 4.0f*lensShift); float lensRadius = fabsf(-1.0f - 4.0f*lensShift);
float lensRadiusSq = lensRadius*lensRadius; float lensRadiusSq = lensRadius*lensRadius;
float distortionScale = hmd.lensDistortionValues[0] + float distortionScale = hmd.lensDistortionValues[0] +
hmd.lensDistortionValues[1]*lensRadiusSq + hmd.lensDistortionValues[1]*lensRadiusSq +
@ -4645,29 +4643,6 @@ static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight)
#endif #endif
#if defined(RLGL_STANDALONE) #if defined(RLGL_STANDALONE)
// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
void TraceLog(int msgType, const char *text, ...)
{
va_list args;
va_start(args, text);
switch (msgType)
{
case LOG_INFO: fprintf(stdout, "INFO: "); break;
case LOG_ERROR: fprintf(stdout, "ERROR: "); break;
case LOG_WARNING: fprintf(stdout, "WARNING: "); break;
case LOG_DEBUG: fprintf(stdout, "DEBUG: "); break;
default: break;
}
vfprintf(stdout, text, args);
fprintf(stdout, "\n");
va_end(args);
if (msgType == LOG_ERROR) exit(1);
}
// Get pixel data size in bytes (image or texture) // Get pixel data size in bytes (image or texture)
// NOTE: Size depends on pixel format // NOTE: Size depends on pixel format
int GetPixelDataSize(int width, int height, int format) int GetPixelDataSize(int width, int height, int format)

View File

@ -42,8 +42,7 @@
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
#include <stdlib.h> // Required for: fabs() #include <math.h> // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf(), fabsf()
#include <math.h> // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf()
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
@ -1471,8 +1470,8 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
int recCenterX = (int)(rec.x + rec.width/2.0f); int recCenterX = (int)(rec.x + rec.width/2.0f);
int recCenterY = (int)(rec.y + rec.height/2.0f); int recCenterY = (int)(rec.y + rec.height/2.0f);
float dx = (float)fabs(center.x - recCenterX); float dx = fabsf(center.x - (float)recCenterX);
float dy = (float)fabs(center.y - recCenterY); float dy = fabsf(center.y - (float)recCenterY);
if (dx > (rec.width/2.0f + radius)) { return false; } if (dx > (rec.width/2.0f + radius)) { return false; }
if (dy > (rec.height/2.0f + radius)) { return false; } if (dy > (rec.height/2.0f + radius)) { return false; }
@ -1493,8 +1492,8 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
if (CheckCollisionRecs(rec1, rec2)) if (CheckCollisionRecs(rec1, rec2))
{ {
float dxx = (float)fabs(rec1.x - rec2.x); float dxx = fabsf(rec1.x - rec2.x);
float dyy = (float)fabs(rec1.y - rec2.y); float dyy = fabsf(rec1.y - rec2.y);
if (rec1.x <= rec2.x) if (rec1.x <= rec2.x)
{ {

View File

@ -241,8 +241,8 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
canvas: (function() { canvas: (function() {
var canvas = document.querySelector('#canvas'); var canvas = document.querySelector('#canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your // As a default initial behavior, pop up an alert when webgl context is lost.
// application robust, you may want to override this behavior before shipping! // To make your application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false); canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);

View File

@ -333,11 +333,11 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
{ {
Font font = { 0 }; Font font = { 0 };
#if defined(SUPPORT_FILEFORMAT_TTF)
font.baseSize = fontSize; font.baseSize = fontSize;
font.charsCount = (charsCount > 0)? charsCount : 95; font.charsCount = (charsCount > 0)? charsCount : 95;
font.chars = LoadFontData(fileName, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT); font.chars = LoadFontData(fileName, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT);
#if defined(SUPPORT_FILEFORMAT_TTF)
if (font.chars != NULL) if (font.chars != NULL)
{ {
Image atlas = GenImageFontAtlas(font.chars, &font.recs, font.charsCount, font.baseSize, 2, 0); Image atlas = GenImageFontAtlas(font.chars, &font.recs, font.charsCount, font.baseSize, 2, 0);
@ -354,7 +354,6 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
} }
else font = GetFontDefault(); else font = GetFontDefault();
#else #else
UnloadFont(font);
font = GetFontDefault(); font = GetFontDefault();
#endif #endif
@ -498,24 +497,16 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
// Load font data (including pixel data) from TTF file // Load font data (including pixel data) from TTF file
// NOTE: Loaded information should be enough to generate font image atlas, // NOTE: Loaded information should be enough to generate
// using any packaging method // font image atlas, using any packaging method
FILE *fontFile = fopen(fileName, "rb"); // Load font file int dataSize = 0;
unsigned char *fileData = LoadFileData(fileName, &dataSize);
if (fontFile != NULL) if (fileData != NULL)
{ {
fseek(fontFile, 0, SEEK_END);
long size = ftell(fontFile); // Get file size
fseek(fontFile, 0, SEEK_SET); // Reset file pointer
unsigned char *fontBuffer = (unsigned char *)RL_MALLOC(size);
fread(fontBuffer, size, 1, fontFile);
fclose(fontFile);
// Init font for data reading // Init font for data reading
stbtt_fontinfo fontInfo; stbtt_fontinfo fontInfo;
if (!stbtt_InitFont(&fontInfo, fontBuffer, 0)) TRACELOG(LOG_WARNING, "Failed to init font!"); if (!stbtt_InitFont(&fontInfo, fileData, 0)) TRACELOG(LOG_WARNING, "Failed to init font!");
// Calculate font scale factor // Calculate font scale factor
float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize); float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize);
@ -595,12 +586,9 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
*/ */
} }
RL_FREE(fontBuffer); RL_FREE(fileData);
if (genFontChars) RL_FREE(fontChars); if (genFontChars) RL_FREE(fontChars);
} }
else TRACELOG(LOG_WARNING, "[%s] TTF file could not be opened", fileName);
#else
TRACELOG(LOG_WARNING, "[%s] TTF support is disabled", fileName);
#endif #endif
return chars; return chars;
@ -1149,6 +1137,7 @@ const char *TextFormat(const char *text, ...)
static int index = 0; static int index = 0;
char *currentBuffer = buffers[index]; char *currentBuffer = buffers[index];
memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using
va_list args; va_list args;
va_start(args, text); va_start(args, text);
@ -1445,7 +1434,7 @@ char *TextToUtf8(int *codepoints, int length)
// Resize memory to text length + string NULL terminator // Resize memory to text length + string NULL terminator
void *ptr = RL_REALLOC(text, size + 1); void *ptr = RL_REALLOC(text, size + 1);
if (ptr != NULL) text = (char *)ptr; if (ptr != NULL) text = (char *)ptr;
return text; return text;
@ -1655,7 +1644,6 @@ static Font LoadBMFont(const char *fileName)
#define MAX_BUFFER_SIZE 256 #define MAX_BUFFER_SIZE 256
Font font = { 0 }; Font font = { 0 };
font.texture.id = 0;
char buffer[MAX_BUFFER_SIZE] = { 0 }; char buffer[MAX_BUFFER_SIZE] = { 0 };
char *searchPoint = NULL; char *searchPoint = NULL;

View File

@ -64,9 +64,10 @@
#include "config.h" // Defines module configuration flags #include "config.h" // Defines module configuration flags
#endif #endif
#include <stdlib.h> // Required for: malloc(), free(), fabs() #include <stdlib.h> // Required for: malloc(), free()
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fread() #include <stdio.h> // Required for: FILE, fopen(), fclose(), fread()
#include <string.h> // Required for: strlen() [Used in ImageTextEx()] #include <string.h> // Required for: strlen() [Used in ImageTextEx()]
#include <math.h> // Required for: fabsf()
#include "utils.h" // Required for: fopen() Android mapping #include "utils.h" // Required for: fopen() Android mapping
@ -195,6 +196,7 @@ Image LoadImage(const char *fileName)
defined(SUPPORT_FILEFORMAT_TGA) || \ defined(SUPPORT_FILEFORMAT_TGA) || \
defined(SUPPORT_FILEFORMAT_GIF) || \ defined(SUPPORT_FILEFORMAT_GIF) || \
defined(SUPPORT_FILEFORMAT_PIC) || \ defined(SUPPORT_FILEFORMAT_PIC) || \
defined(SUPPORT_FILEFORMAT_HDR) || \
defined(SUPPORT_FILEFORMAT_PSD) defined(SUPPORT_FILEFORMAT_PSD)
#define STBI_REQUIRED #define STBI_REQUIRED
#endif #endif
@ -225,53 +227,53 @@ Image LoadImage(const char *fileName)
) )
{ {
#if defined(STBI_REQUIRED) #if defined(STBI_REQUIRED)
int imgWidth = 0; // NOTE: Using stb_image to load images (Supports multiple image formats)
int imgHeight = 0;
int imgBpp = 0;
FILE *imFile = fopen(fileName, "rb"); int dataSize = 0;
unsigned char *fileData = LoadFileData(fileName, &dataSize);
if (imFile != NULL) if (fileData != NULL)
{ {
// NOTE: Using stb_image to load images (Supports multiple image formats) int comp = 0;
image.data = stbi_load_from_file(imFile, &imgWidth, &imgHeight, &imgBpp, 0); image.data = stbi_load_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0);
fclose(imFile);
image.width = imgWidth;
image.height = imgHeight;
image.mipmaps = 1; image.mipmaps = 1;
if (imgBpp == 1) image.format = UNCOMPRESSED_GRAYSCALE; if (comp == 1) image.format = UNCOMPRESSED_GRAYSCALE;
else if (imgBpp == 2) image.format = UNCOMPRESSED_GRAY_ALPHA; else if (comp == 2) image.format = UNCOMPRESSED_GRAY_ALPHA;
else if (imgBpp == 3) image.format = UNCOMPRESSED_R8G8B8; else if (comp == 3) image.format = UNCOMPRESSED_R8G8B8;
else if (imgBpp == 4) image.format = UNCOMPRESSED_R8G8B8A8; else if (comp == 4) image.format = UNCOMPRESSED_R8G8B8A8;
RL_FREE(fileData);
} }
#endif #endif
} }
#if defined(SUPPORT_FILEFORMAT_HDR) #if defined(SUPPORT_FILEFORMAT_HDR)
else if (IsFileExtension(fileName, ".hdr")) else if (IsFileExtension(fileName, ".hdr"))
{ {
int imgBpp = 0; #if defined(STBI_REQUIRED)
int dataSize = 0;
unsigned char *fileData = LoadFileData(fileName, &dataSize);
FILE *imFile = fopen(fileName, "rb"); if (fileData != NULL)
// Load 32 bit per channel floats data
//stbi_set_flip_vertically_on_load(true);
image.data = stbi_loadf_from_file(imFile, &image.width, &image.height, &imgBpp, 0);
fclose(imFile);
image.mipmaps = 1;
if (imgBpp == 1) image.format = UNCOMPRESSED_R32;
else if (imgBpp == 3) image.format = UNCOMPRESSED_R32G32B32;
else if (imgBpp == 4) image.format = UNCOMPRESSED_R32G32B32A32;
else
{ {
TRACELOG(LOG_WARNING, "[%s] Image fileformat not supported", fileName); int comp = 0;
UnloadImage(image); image.data = stbi_loadf_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0);
image.mipmaps = 1;
if (comp == 1) image.format = UNCOMPRESSED_R32;
else if (comp == 3) image.format = UNCOMPRESSED_R32G32B32;
else if (comp == 4) image.format = UNCOMPRESSED_R32G32B32A32;
else
{
TRACELOG(LOG_WARNING, "[%s] HDR Image fileformat not supported", fileName);
UnloadImage(image);
}
RL_FREE(fileData);
} }
#endif
} }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_DDS) #if defined(SUPPORT_FILEFORMAT_DDS)
@ -346,40 +348,24 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int
{ {
Image image = { 0 }; Image image = { 0 };
FILE *rawFile = fopen(fileName, "rb"); int dataSize = 0;
unsigned char *fileData = LoadFileData(fileName, &dataSize);
if (rawFile == NULL) if (fileData != NULL)
{ {
TRACELOG(LOG_WARNING, "[%s] RAW image file could not be opened", fileName); unsigned char *dataPtr = fileData;
}
else
{
if (headerSize > 0) fseek(rawFile, headerSize, SEEK_SET);
unsigned int size = GetPixelDataSize(width, height, format); unsigned int size = GetPixelDataSize(width, height, format);
if (headerSize > 0) dataPtr += headerSize;
image.data = RL_MALLOC(size); // Allocate required memory in bytes image.data = RL_MALLOC(size); // Allocate required memory in bytes
memcpy(image.data, dataPtr, size); // Copy required data to image
image.width = width;
image.height = height;
image.mipmaps = 1;
image.format = format;
// NOTE: fread() returns num read elements instead of bytes, RL_FREE(fileData);
// to get bytes we need to read (1 byte size, elements) instead of (x byte size, 1 element)
int bytes = fread(image.data, 1, size, rawFile);
// Check if data has been read successfully
if (bytes < size)
{
TRACELOG(LOG_WARNING, "[%s] RAW image data can not be read, wrong requested format or size", fileName);
RL_FREE(image.data);
}
else
{
image.width = width;
image.height = height;
image.mipmaps = 1;
image.format = format;
}
fclose(rawFile);
} }
return image; return image;
@ -844,9 +830,8 @@ void ExportImage(Image image, const char *fileName)
{ {
// Export raw pixel data (without header) // Export raw pixel data (without header)
// NOTE: It's up to the user to track image parameters // NOTE: It's up to the user to track image parameters
FILE *rawFile = fopen(fileName, "wb"); SaveFileData(fileName, image.data, GetPixelDataSize(image.width, image.height, image.format));
success = fwrite(image.data, GetPixelDataSize(image.width, image.height, image.format), 1, rawFile); success = true;
fclose(rawFile);
} }
RL_FREE(imgData); RL_FREE(imgData);
@ -2704,7 +2689,7 @@ void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float sc
// Draw a part of a texture (defined by a rectangle) // Draw a part of a texture (defined by a rectangle)
void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint) void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint)
{ {
Rectangle destRec = { position.x, position.y, (float)fabs(sourceRec.width), (float)fabs(sourceRec.height) }; Rectangle destRec = { position.x, position.y, fabsf(sourceRec.width), fabsf(sourceRec.height) };
Vector2 origin = { 0.0f, 0.0f }; Vector2 origin = { 0.0f, 0.0f };
DrawTexturePro(texture, sourceRec, destRec, origin, 0.0f, tint); DrawTexturePro(texture, sourceRec, destRec, origin, 0.0f, tint);
@ -2983,30 +2968,18 @@ static Image LoadAnimatedGIF(const char *fileName, int *frames, int **delays)
{ {
Image image = { 0 }; Image image = { 0 };
FILE *gifFile = fopen(fileName, "rb"); int dataSize = 0;
unsigned char *fileData = LoadFileData(fileName, &dataSize);
if (gifFile == NULL) if (fileData != NULL)
{ {
TRACELOG(LOG_WARNING, "[%s] Animated GIF file could not be opened", fileName);
}
else
{
fseek(gifFile, 0L, SEEK_END);
int size = ftell(gifFile);
fseek(gifFile, 0L, SEEK_SET);
unsigned char *buffer = (unsigned char *)RL_CALLOC(size, sizeof(char));
fread(buffer, sizeof(char), size, gifFile);
fclose(gifFile); // Close file pointer
int comp = 0; int comp = 0;
image.data = stbi_load_gif_from_memory(buffer, size, delays, &image.width, &image.height, frames, &comp, 4); image.data = stbi_load_gif_from_memory(fileData, dataSize, delays, &image.width, &image.height, frames, &comp, 4);
image.mipmaps = 1; image.mipmaps = 1;
image.format = UNCOMPRESSED_R8G8B8A8; image.format = UNCOMPRESSED_R8G8B8A8;
free(buffer); RL_FREE(fileData);
} }
return image; return image;
@ -3071,7 +3044,7 @@ static Image LoadDDS(const char *fileName)
else else
{ {
// Verify the type of file // Verify the type of file
char ddsHeaderId[4]; char ddsHeaderId[4] = { 0 };
fread(ddsHeaderId, 4, 1, ddsFile); fread(ddsHeaderId, 4, 1, ddsFile);
@ -3081,7 +3054,7 @@ static Image LoadDDS(const char *fileName)
} }
else else
{ {
DDSHeader ddsHeader; DDSHeader ddsHeader = { 0 };
// Get the image header // Get the image header
fread(&ddsHeader, sizeof(DDSHeader), 1, ddsFile); fread(&ddsHeader, sizeof(DDSHeader), 1, ddsFile);
@ -3250,7 +3223,7 @@ static Image LoadPKM(const char *fileName)
} }
else else
{ {
PKMHeader pkmHeader; PKMHeader pkmHeader = { 0 };
// Get the image header // Get the image header
fread(&pkmHeader, sizeof(PKMHeader), 1, pkmFile); fread(&pkmHeader, sizeof(PKMHeader), 1, pkmFile);
@ -3343,7 +3316,7 @@ static Image LoadKTX(const char *fileName)
} }
else else
{ {
KTXHeader ktxHeader; KTXHeader ktxHeader = { 0 };
// Get the image header // Get the image header
fread(&ktxHeader, sizeof(KTXHeader), 1, ktxFile); fread(&ktxHeader, sizeof(KTXHeader), 1, ktxFile);
@ -3424,7 +3397,7 @@ static int SaveKTX(Image image, const char *fileName)
if (ktxFile == NULL) TRACELOG(LOG_WARNING, "[%s] KTX image file could not be created", fileName); if (ktxFile == NULL) TRACELOG(LOG_WARNING, "[%s] KTX image file could not be created", fileName);
else else
{ {
KTXHeader ktxHeader; KTXHeader ktxHeader = { 0 };
// KTX identifier (v1.1) // KTX identifier (v1.1)
//unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' }; //unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' };
@ -3560,7 +3533,7 @@ static Image LoadPVR(const char *fileName)
// Load different PVR data formats // Load different PVR data formats
if (pvrVersion == 0x50) if (pvrVersion == 0x50)
{ {
PVRHeaderV3 pvrHeader; PVRHeaderV3 pvrHeader = { 0 };
// Get PVR image header // Get PVR image header
fread(&pvrHeader, sizeof(PVRHeaderV3), 1, pvrFile); fread(&pvrHeader, sizeof(PVRHeaderV3), 1, pvrFile);
@ -3670,7 +3643,7 @@ static Image LoadASTC(const char *fileName)
} }
else else
{ {
ASTCHeader astcHeader; ASTCHeader astcHeader = { 0 };
// Get ASTC image header // Get ASTC image header
fread(&astcHeader, sizeof(ASTCHeader), 1, astcFile); fread(&astcHeader, sizeof(ASTCHeader), 1, astcFile);

View File

@ -64,7 +64,7 @@ static int logTypeExit = LOG_ERROR; // Log type that exits
static TraceLogCallback logCallback = NULL; // Log callback function pointer static TraceLogCallback logCallback = NULL; // Log callback function pointer
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
static AAssetManager *assetManager = NULL; // Android assets manager pointer static AAssetManager *assetManager = NULL; // Android assets manager pointer
#endif #endif
#if defined(PLATFORM_UWP) #if defined(PLATFORM_UWP)
@ -163,6 +163,59 @@ void TraceLog(int logType, const char *text, ...)
#endif // SUPPORT_TRACELOG #endif // SUPPORT_TRACELOG
} }
// Load data from file into a buffer
unsigned char *LoadFileData(const char *fileName, int *bytesRead)
{
unsigned char *data = NULL;
*bytesRead = 0;
FILE *file = fopen(fileName, "rb");
if (file != NULL)
{
// WARNING: On binary streams SEEK_END could not be found,
// using fseek() and ftell() could not work in some (rare) cases
fseek(file, 0, SEEK_END);
int size = ftell(file);
fseek(file, 0, SEEK_SET);
if (size > 0)
{
data = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*size);
// NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements]
int count = fread(data, sizeof(unsigned char), size, file);
*bytesRead = count;
if (count != size) TRACELOG(LOG_WARNING, "[%s] File partially loaded", fileName);
else TRACELOG(LOG_INFO, "[%s] File loaded successfully", fileName);
}
else TRACELOG(LOG_WARNING, "[%s] File could not be read", fileName);
fclose(file);
}
else TRACELOG(LOG_WARNING, "[%s] File could not be opened", fileName);
return data;
}
// Save data to file from buffer
void SaveFileData(const char *fileName, void *data, int bytesToWrite)
{
FILE *file = fopen(fileName, "wb");
if (file != NULL)
{
int count = fwrite(data, sizeof(unsigned char), bytesToWrite, file);
if (count == 0) TRACELOG(LOG_WARNING, "[%s] File could not be written", fileName);
else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "[%s] File partially written", fileName);
fclose(file);
}
else TRACELOG(LOG_WARNING, "[%s] File could not be opened", fileName);
}
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
// Initialize asset manager from android app // Initialize asset manager from android app
void InitAssetManager(AAssetManager *manager) void InitAssetManager(AAssetManager *manager)