Merge branch 'master' into embedded-optimizations-pico

This commit is contained in:
Colin James Wood 2026-07-19 14:43:39 +01:00
commit 739b78c43d
64 changed files with 9694 additions and 3281 deletions

View file

@ -44,7 +44,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@master
with:
submodules: recursive
@ -71,7 +71,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@ -90,7 +90,7 @@ jobs:
cmake --build . --config $BUILD_TYPE
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v4
with:
category: "/language:${{matrix.language}}"
upload: false
@ -99,7 +99,7 @@ jobs:
# Filter out rules with low severity or high false positve rate
# Also filter out warnings in third-party code
- name: Filter out unwanted errors and warnings
uses: advanced-security/filter-sarif@v1
uses: advanced-security/filter-sarif@v1.1
with:
patterns: |
-**:cpp/path-injection
@ -121,14 +121,14 @@ jobs:
output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif
- name: Upload CodeQL results to code scanning
uses: github/codeql-action/upload-sarif@v2
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: ${{ steps.step1.outputs.sarif-output }}
category: "/language:${{matrix.language}}"
- name: Upload CodeQL results as an artifact
if: success() || failure()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: codeql-results
path: ${{ steps.step1.outputs.sarif-output }}

View file

@ -21,7 +21,7 @@ permissions:
jobs:
build:
permissions:
contents: write # for actions/upload-release-asset to upload release asset
contents: write # Required for actions/upload-release-asset to upload release asset
runs-on: windows-latest
strategy:
fail-fast: false
@ -82,7 +82,7 @@ jobs:
tar -czvf ${{ env.RELEASE_NAME }}.tar.gz ${{ env.RELEASE_NAME }}
- name: Upload Artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: ${{ env.RELEASE_NAME }}
path: |
@ -90,7 +90,7 @@ jobs:
!./build/${{ env.RELEASE_NAME }}.tar.gz
- name: Upload Artifact to Release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v3
with:
files: ./build/${{ env.RELEASE_NAME }}.tar.gz
env:

View file

@ -36,7 +36,7 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@master
- name: Create Build Environment
# Some projects don't allow in-source building, so create a separate build directory
@ -75,7 +75,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@master
- name: Create Build Environment
# Some projects don't allow in-source building, so create a separate build directory

View file

@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@master
- name: Setup Environment
run: |

View file

@ -22,10 +22,10 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@master
- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@v1
uses: microsoft/setup-msbuild@v3
- name: Build Library (MSVC16)
run: |

View file

@ -21,7 +21,7 @@ permissions:
jobs:
build:
permissions:
contents: write # for actions/upload-release-asset to upload release asset
contents: write # Required for actions/upload-release-asset to upload release asset
strategy:
fail-fast: false
max-parallel: 1
@ -112,7 +112,7 @@ jobs:
tar -czvf ${{ env.RELEASE_NAME }}.tar.gz ${{ env.RELEASE_NAME }}
- name: Upload Artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: ${{ env.RELEASE_NAME }}
path: |
@ -120,7 +120,7 @@ jobs:
!./build/${{ env.RELEASE_NAME }}.tar.gz
- name: Upload Artifact to Release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v3
with:
files: ./build/${{ env.RELEASE_NAME }}.tar.gz
env:

View file

@ -21,7 +21,7 @@ permissions:
jobs:
build:
permissions:
contents: write # for actions/upload-release-asset to upload release asset
contents: write # Required for actions/upload-release-asset to upload release asset
runs-on: macos-latest
env:
@ -99,7 +99,7 @@ jobs:
tar -czvf ${{ env.RELEASE_NAME }}.tar.gz ${{ env.RELEASE_NAME }}
- name: Upload Artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: ${{ env.RELEASE_NAME }}
path: |
@ -107,7 +107,7 @@ jobs:
!./build/${{ env.RELEASE_NAME }}.tar.gz
- name: Upload Artifact to Release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v3
with:
files: ./build/${{ env.RELEASE_NAME }}.tar.gz
env:

View file

@ -27,7 +27,7 @@ jobs:
uses: actions/checkout@master
- name: Setup emsdk
uses: mymindstorm/setup-emsdk@v14
uses: emscripten-core/setup-emsdk@v15
with:
version: 5.0.3
actions-cache-folder: 'emsdk-cache'
@ -69,7 +69,7 @@ jobs:
shell: cmd
- name: Upload Artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: ${{ env.RELEASE_NAME }}
path: |
@ -77,7 +77,7 @@ jobs:
!./build/${{ env.RELEASE_NAME }}.zip
- name: Upload Artifact to Release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v3
with:
files: ./build/${{ env.RELEASE_NAME }}.zip
env:

View file

@ -21,7 +21,7 @@ permissions:
jobs:
build:
permissions:
contents: write # for actions/upload-release-asset to upload release asset
contents: write # Required for actions/upload-release-asset to upload release asset
runs-on: windows-latest
strategy:
fail-fast: false
@ -81,7 +81,7 @@ jobs:
# Setup MSBuild.exe path if required
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v2
uses: microsoft/setup-msbuild@v3
if: matrix.compiler == 'msvc16'
- name: Build Library (MinGW-w64 32bit)
@ -140,7 +140,7 @@ jobs:
shell: cmd
- name: Upload Artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: ${{ env.RELEASE_NAME }}
path: |
@ -148,7 +148,7 @@ jobs:
!./build/${{ env.RELEASE_NAME }}.zip
- name: Upload Artifact to Release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v3
with:
files: ./build/${{ env.RELEASE_NAME }}.zip
env:

View file

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@master
- name: Update parse files
working-directory: tools/rlparser

View file

@ -15,10 +15,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@master
- name: Setup emsdk
uses: mymindstorm/setup-emsdk@v14
uses: emscripten-core/setup-emsdk@v15
with:
version: 'latest'
actions-cache-folder: 'emsdk-cache'

View file

@ -52,7 +52,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [KaylibKit](https://codeberg.org/Kenta/KaylibKit) | 4.5 | [Kotlin/native](https://kotlinlang.org) | Zlib |
| [raylib-lua](https://github.com/TSnake41/raylib-lua) | 5.5 | [Lua](http://www.lua.org) | ISC |
| [raylib-lua-bindings (WIP)](https://github.com/legendaryredfox/raylib-lua-bindings) | 5.5 | [Lua](http://www.lua.org) | ISC |
| [ReiLua](https://github.com/nullstare/ReiLua) | 5.5 | [Lua](http://www.lua.org) | MIT |
| [ReiLua](https://github.com/nullstare/ReiLua) | 6.0 | [Lua](http://www.lua.org) | MIT |
| [raylib-lua-sol](https://github.com/RobLoach/raylib-lua-sol) | 5.5 | [Lua](http://www.lua.org) | Zlib |
| [raylib-luajit](https://github.com/homma/raylib-luajit) | 5.5 | [Lua](http://www.lua.org) | MIT |
| [raylib-luajit-generated](https://github.com/james2doyle/raylib-luajit-generated) | 5.5 | [Lua](http://www.lua.org) | MIT |

View file

@ -11,8 +11,4 @@ Most considerations of errors and defects can be handled using the project Issue
## Reporting a Vulnerability
Discovered vulnerability can be directly reported using the project Issues and/or Discussions.
_TODO: Tell them where to go, how often they can expect to get an update on a
reported vulnerability, what to expect if the vulnerability is accepted or
declined, etc._
Discovered vulnerability can be directly reported using the project Issues and/or Discussions. They will be reviewed as soon as possible.

View file

@ -99,7 +99,7 @@ vec3 ComputePBR()
vec3 N = normalize(fragNormal);
if (useTexNormal == 1)
{
N = texture2D(normalMap, vec2(fragTexCoord.x*tiling.x + offset.y, fragTexCoord.y*tiling.y + offset.y)).rgb;
N = texture2D(normalMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb;
N = normalize(N*2.0 - 1.0);
N = normalize(N*TBN);
}

View file

@ -97,7 +97,7 @@ vec3 ComputePBR()
vec3 N = normalize(fragNormal);
if (useTexNormal == 1)
{
N = texture2D(normalMap, vec2(fragTexCoord.x*tiling.x + offset.y, fragTexCoord.y*tiling.y + offset.y)).rgb;
N = texture2D(normalMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb;
N = normalize(N*2.0 - 1.0);
N = normalize(N*TBN);
}

View file

@ -100,7 +100,7 @@ vec3 ComputePBR()
vec3 N = normalize(fragNormal);
if (useTexNormal == 1)
{
N = texture(normalMap, vec2(fragTexCoord.x*tiling.x + offset.y, fragTexCoord.y*tiling.y + offset.y)).rgb;
N = texture(normalMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb;
N = normalize(N*2.0 - 1.0);
N = normalize(N*TBN);
}

View file

@ -1,401 +0,0 @@
#**************************************************************************************************
#
# raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5
#
# Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
#
# 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.
#
#**************************************************************************************************
.PHONY: all clean
# Define required raylib variables
PROJECT_NAME ?= game
RAYLIB_VERSION ?= 4.2.0
RAYLIB_PATH ?= ..\..
# Define default options
# One of PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
PLATFORM ?= PLATFORM_DESKTOP
# Locations of your newly installed library and associated headers. See ../src/Makefile
# On Linux, if you have installed raylib but cannot compile the examples, check that
# the *_INSTALL_PATH values here are the same as those in src/Makefile or point to known locations.
# To enable system-wide compile-time and runtime linking to libraylib.so, run ../src/$ sudo make install RAYLIB_LIBTYPE_SHARED.
# To enable compile-time linking to a special version of libraylib.so, change these variables here.
# To enable runtime linking to a special version of libraylib.so, see EXAMPLE_RUNTIME_PATH below.
# If there is a libraylib in both EXAMPLE_RUNTIME_PATH and RAYLIB_INSTALL_PATH, at runtime,
# the library at EXAMPLE_RUNTIME_PATH, if present, will take precedence over the one at RAYLIB_INSTALL_PATH.
# RAYLIB_INSTALL_PATH should be the desired full path to libraylib. No relative paths.
DESTDIR ?= /usr/local
RAYLIB_INSTALL_PATH ?= $(DESTDIR)/lib
# RAYLIB_H_INSTALL_PATH locates the installed raylib header and associated source files.
RAYLIB_H_INSTALL_PATH ?= $(DESTDIR)/include
# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll)
RAYLIB_LIBTYPE ?= STATIC
# Build mode for project: DEBUG or RELEASE
BUILD_MODE ?= RELEASE
# Use external GLFW library instead of rglfw module
# TODO: Review usage on Linux. Target version of choice. Switch on -lglfw or -lglfw3
USE_EXTERNAL_GLFW ?= FALSE
# Use Wayland display server protocol on Linux desktop
# by default it uses X11 windowing system
USE_WAYLAND_DISPLAY ?= FALSE
# Determine PLATFORM_OS in case PLATFORM_DESKTOP selected
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
# No uname.exe on MinGW!, but OS=Windows_NT on Windows!
# ifeq ($(UNAME),Msys) -> Windows
ifeq ($(OS),Windows_NT)
PLATFORM_OS=WINDOWS
else
UNAMEOS=$(shell uname)
ifeq ($(UNAMEOS),Linux)
PLATFORM_OS=LINUX
endif
ifeq ($(UNAMEOS),FreeBSD)
PLATFORM_OS=BSD
endif
ifeq ($(UNAMEOS),OpenBSD)
PLATFORM_OS=BSD
endif
ifeq ($(UNAMEOS),NetBSD)
PLATFORM_OS=BSD
endif
ifeq ($(UNAMEOS),DragonFly)
PLATFORM_OS=BSD
endif
ifeq ($(UNAMEOS),Darwin)
PLATFORM_OS=OSX
endif
endif
endif
ifeq ($(PLATFORM),PLATFORM_RPI)
UNAMEOS=$(shell uname)
ifeq ($(UNAMEOS),Linux)
PLATFORM_OS=LINUX
endif
endif
# RAYLIB_PATH adjustment for different platforms.
# If using GNU make, we can get the full path to the top of the tree. Windows? BSD?
# Required for ldconfig or other tools that do not perform path expansion.
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
ifeq ($(PLATFORM_OS),LINUX)
RAYLIB_PREFIX ?= ..
RAYLIB_PATH = $(realpath $(RAYLIB_PREFIX))
endif
endif
# Default path for raylib on Raspberry Pi, if installed in different path, update it!
# This is not currently used by src/Makefile. Not sure of its origin or usage. Refer to wiki.
# TODO: update install: target in src/Makefile for RPI, consider relation to LINUX.
ifeq ($(PLATFORM),PLATFORM_RPI)
RAYLIB_PATH ?= /home/pi/raylib
endif
ifeq ($(PLATFORM),PLATFORM_WEB)
# Emscripten required variables
EMSDK_PATH ?= C:/raylib/emsdk
EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten
CLANG_PATH = $(EMSDK_PATH)/upstream/bin
PYTHON_PATH = $(EMSDK_PATH)/python/3.13.3_64bit
NODE_PATH = $(EMSDK_PATH)/node/22.16.0_64bit/bin
export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH);C:\raylib\MinGW\bin:$$(PATH)
endif
# Define raylib release directory for compiled library.
# RAYLIB_RELEASE_PATH points to provided binaries or your freshly built version
RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/src
# EXAMPLE_RUNTIME_PATH embeds a custom runtime location of libraylib.so or other desired libraries
# into each example binary compiled with RAYLIB_LIBTYPE=SHARED. It defaults to RAYLIB_RELEASE_PATH
# so that these examples link at runtime with your version of libraylib.so in ../release/libs/linux
# without formal installation from ../src/Makefile. It aids portability and is useful if you have
# multiple versions of raylib, have raylib installed to a non-standard location, or want to
# bundle libraylib.so with your game. Change it to your liking.
# NOTE: If, at runtime, there is a libraylib.so at both EXAMPLE_RUNTIME_PATH and RAYLIB_INSTALL_PATH,
# The library at EXAMPLE_RUNTIME_PATH, if present, will take precedence over RAYLIB_INSTALL_PATH,
# Implemented for LINUX below with CFLAGS += -Wl,-rpath,$(EXAMPLE_RUNTIME_PATH)
# To see the result, run readelf -d core/core_basic_window; looking at the RPATH or RUNPATH attribute.
# To see which libraries a built example is linking to, ldd core/core_basic_window;
# Look for libraylib.so.1 => $(RAYLIB_INSTALL_PATH)/libraylib.so.1 or similar listing.
EXAMPLE_RUNTIME_PATH ?= $(RAYLIB_RELEASE_PATH)
# Define default C compiler: gcc
# NOTE: define g++ compiler if using C++
CC = gcc
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
ifeq ($(PLATFORM_OS),OSX)
# OSX default compiler
CC = clang
endif
ifeq ($(PLATFORM_OS),BSD)
# FreeBSD, OpenBSD, NetBSD, DragonFly default compiler
CC = clang
endif
endif
ifeq ($(PLATFORM),PLATFORM_RPI)
ifeq ($(USE_RPI_CROSS_COMPILER),TRUE)
# Define RPI cross-compiler
#CC = armv6j-hardfloat-linux-gnueabi-gcc
CC = $(RPI_TOOLCHAIN)/bin/arm-linux-gnueabihf-gcc
endif
endif
ifeq ($(PLATFORM),PLATFORM_WEB)
# HTML5 emscripten compiler
# WARNING: To compile to HTML5, code must be redesigned
# to use emscripten.h and emscripten_set_main_loop()
CC = emcc
endif
# Define default make program: Mingw32-make
MAKE = mingw32-make
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
ifeq ($(PLATFORM_OS),LINUX)
MAKE = make
endif
ifeq ($(PLATFORM_OS),OSX)
MAKE = make
endif
endif
# Define compiler flags:
# -O1 defines optimization level
# -g include debug information on compilation
# -s strip unnecessary data from build
# -Wall turns on most, but not all, compiler warnings
# -std=c99 defines C language mode (standard C from 1999 revision)
# -std=gnu99 defines C language mode (GNU C from 1999 revision)
# -Wno-missing-braces ignore invalid warning (GCC bug 53119)
# -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec
CFLAGS += -O1 -s -Wall -std=c99 -D_DEFAULT_SOURCE -Wno-missing-braces
ifeq ($(BUILD_MODE),DEBUG)
CFLAGS += -g
endif
# Additional flags for compiler (if desired)
#CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
ifeq ($(PLATFORM_OS),WINDOWS)
# resource file contains windows executable icon and properties
# -Wl,--subsystem,windows hides the console window
CFLAGS += $(RAYLIB_PATH)/src/raylib.rc.data -Wl,--subsystem,windows
endif
ifeq ($(PLATFORM_OS),LINUX)
ifeq ($(RAYLIB_LIBTYPE),STATIC)
CFLAGS += -D_DEFAULT_SOURCE
endif
ifeq ($(RAYLIB_LIBTYPE),SHARED)
# Explicitly enable runtime link to libraylib.so
CFLAGS += -Wl,-rpath,$(EXAMPLE_RUNTIME_PATH)
endif
endif
endif
ifeq ($(PLATFORM),PLATFORM_RPI)
CFLAGS += -std=gnu99
endif
ifeq ($(PLATFORM),PLATFORM_WEB)
# -Os # size optimization
# -O2 # optimization level 2, if used, also set --memory-init-file 0
# -sUSE_GLFW=3 # Use glfw3 library (context/input management)
# -sALLOW_MEMORY_GROWTH=1 # to allow memory resizing -> WARNING: Audio buffers could FAIL!
# -sTOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) (67108864 = 64MB)
# -sUSE_PTHREADS=1 # multithreading support
# -sWASM=0 # disable Web Assembly, emitted by default
# -sASYNCIFY # lets synchronous C/C++ code interact with asynchronous JS
# -sFORCE_FILESYSTEM=1 # force filesystem to load/save files data
# -sASSERTIONS=1 # enable runtime checks for common memory allocation errors (-O1 and above turn it off)
# -sMINIFY_HTML=0 # minify generated html from shell.html
# --profiling # include information for code profiling
# --memory-init-file 0 # to avoid an external memory initialization code file (.mem)
# --preload-file resources # specify a resources folder for data compilation
# --source-map-base # allow debugging in browser with source map
# --shell-file shell.html # define a custom shell .html and output extension
CFLAGS += -Os -sUSE_GLFW=3 -sTOTAL_MEMORY=16777216 --preload-file resources -sMINIFY_HTML=0
ifeq ($(BUILD_MODE), DEBUG)
CFLAGS += -sASSERTIONS=1 --profiling
endif
# Define a custom shell .html and output extension
CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html
EXT = .html
endif
# Define include paths for required headers
# NOTE: Several external required libraries (stb and others)
INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external
# Define additional directories containing required header files
ifeq ($(PLATFORM),PLATFORM_RPI)
# RPI required libraries
INCLUDE_PATHS += -I/opt/vc/include
INCLUDE_PATHS += -I/opt/vc/include/interface/vmcs_host/linux
INCLUDE_PATHS += -I/opt/vc/include/interface/vcos/pthreads
endif
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
ifeq ($(PLATFORM_OS),BSD)
# Consider -L$(RAYLIB_H_INSTALL_PATH)
INCLUDE_PATHS += -I/usr/local/include
endif
ifeq ($(PLATFORM_OS),LINUX)
# Reset everything.
# Precedence: immediately local, installed version, raysan5 provided libs -I$(RAYLIB_H_INSTALL_PATH) -I$(RAYLIB_PATH)/release/include
INCLUDE_PATHS = -I$(RAYLIB_H_INSTALL_PATH) -isystem. -isystem$(RAYLIB_PATH)/src -isystem$(RAYLIB_PATH)/release/include -isystem$(RAYLIB_PATH)/src/external
endif
endif
# Define library paths containing required libs.
LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
ifeq ($(PLATFORM_OS),BSD)
# Consider -L$(RAYLIB_INSTALL_PATH)
LDFLAGS += -L. -Lsrc -L/usr/local/lib
endif
ifeq ($(PLATFORM_OS),LINUX)
# Reset everything.
# Precedence: immediately local, installed version, raysan5 provided libs
LDFLAGS = -L. -L$(RAYLIB_INSTALL_PATH) -L$(RAYLIB_RELEASE_PATH)
endif
endif
ifeq ($(PLATFORM),PLATFORM_RPI)
LDFLAGS += -L/opt/vc/lib
endif
# Define any libraries required on linking
# if you want to link libraries (libname.so or libname.a), use the -lname
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
ifeq ($(PLATFORM_OS),WINDOWS)
# Libraries for Windows desktop compilation
# NOTE: WinMM library required to set high-res timer resolution
LDLIBS = -lraylib -lopengl32 -lgdi32 -lwinmm
endif
ifeq ($(PLATFORM_OS),LINUX)
# Libraries for Debian GNU/Linux desktop compiling
# NOTE: Required packages: libegl1-mesa-dev
LDLIBS = -lraylib -lGL -lm -lpthread -ldl -lrt
# On X11 requires also below libraries
LDLIBS += -lX11
# NOTE: It seems additional libraries are not required any more, latest GLFW just dlopen them
#LDLIBS += -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor
# On Wayland windowing system, additional libraries requires
ifeq ($(USE_WAYLAND_DISPLAY),TRUE)
LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon
endif
# Explicit link to libc
ifeq ($(RAYLIB_LIBTYPE),SHARED)
LDLIBS += -lc
endif
endif
ifeq ($(PLATFORM_OS),OSX)
# Libraries for OSX 10.9 desktop compiling
# NOTE: Required packages: libopenal-dev libegl1-mesa-dev
LDLIBS = -lraylib -framework OpenGL -framework OpenAL -framework Cocoa
endif
ifeq ($(PLATFORM_OS),BSD)
# Libraries for FreeBSD, OpenBSD, NetBSD, DragonFly desktop compiling
# NOTE: Required packages: mesa-libs
LDLIBS = -lraylib -lGL -lpthread -lm
# On XWindow requires also below libraries
LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor
endif
ifeq ($(USE_EXTERNAL_GLFW),TRUE)
# NOTE: It could require additional packages installed: libglfw3-dev
LDLIBS += -lglfw
endif
endif
ifeq ($(PLATFORM),PLATFORM_RPI)
# Libraries for Raspberry Pi compiling
# NOTE: Required packages: libasound2-dev (ALSA)
LDLIBS = -lraylib -lbrcmGLESv2 -lbrcmEGL -lpthread -lrt -lm -lbcm_host -ldl
endif
ifeq ($(PLATFORM),PLATFORM_WEB)
# Libraries for web (HTML5) compiling
LDLIBS = $(RAYLIB_RELEASE_PATH)/libraylib.bc
endif
# Define a recursive wildcard function
rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
# Define all source files required
SRC_DIR = src
OBJ_DIR = obj
# Define all object files from source files
SRC = $(call rwildcard, *.c, *.h)
#OBJS = $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
OBJS = main.c
# For Android platform we call a custom Makefile.Android
ifeq ($(PLATFORM),PLATFORM_ANDROID)
MAKEFILE_PARAMS = -f Makefile.Android
export PROJECT_NAME
export SRC_DIR
else
MAKEFILE_PARAMS = $(PROJECT_NAME)
endif
# Default target entry
# NOTE: We call this Makefile target or Makefile.Android target
all:
$(MAKE) $(MAKEFILE_PARAMS)
# Project target defined by PROJECT_NAME
$(PROJECT_NAME): $(OBJS)
$(CC) -o $(PROJECT_NAME)$(EXT) $(OBJS) $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
# Compile source files
# NOTE: This pattern will compile every module defined on $(OBJS)
#%.o: %.c
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) -c $< -o $@ $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM)
# Clean everything
clean:
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
ifeq ($(PLATFORM_OS),WINDOWS)
del *.o *.exe /s
endif
ifeq ($(PLATFORM_OS),LINUX)
find -type f -executable | xargs file -i | grep -E 'x-object|x-archive|x-sharedlib|x-executable' | rev | cut -d ':' -f 2- | rev | xargs rm -fv
endif
ifeq ($(PLATFORM_OS),OSX)
find . -type f -perm +ugo+x -delete
rm -f *.o
endif
endif
ifeq ($(PLATFORM),PLATFORM_RPI)
find . -type f -executable -delete
rm -fv *.o
endif
ifeq ($(PLATFORM),PLATFORM_WEB)
del *.o *.html *.js
endif
@echo Cleaning done

View file

@ -1,300 +0,0 @@
#**************************************************************************************************
#
# raylib makefile for Android project (APK building)
#
# Copyright (c) 2017 Ramon Santamaria (@raysan5)
#
# This software is provided "as-is", without any express or implied warranty. In no event
# will the authors be held liable for any damages arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose, including commercial
# applications, and to alter it and redistribute it freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not claim that you
# wrote the original software. If you use this software in a product, an acknowledgment
# in the product documentation would be appreciated but is not required.
#
# 2. Altered source versions must be plainly marked as such, and must not be misrepresented
# as being the original software.
#
# 3. This notice may not be removed or altered from any source distribution.
#
#**************************************************************************************************
# Define required raylib variables
PLATFORM ?= PLATFORM_ANDROID
RAYLIB_PATH ?= ..\..
# Define Android architecture (armeabi-v7a, arm64-v8a, x86, x86-64) and API version
ANDROID_ARCH ?= ARM
ANDROID_API_VERSION = 21
ifeq ($(ANDROID_ARCH),ARM)
ANDROID_ARCH_NAME = armeabi-v7a
endif
ifeq ($(ANDROID_ARCH),ARM64)
ANDROID_ARCH_NAME = arm64-v8a
endif
# Required path variables
# NOTE: JAVA_HOME must be set to JDK
JAVA_HOME ?= C:/JavaJDK
ANDROID_HOME = C:/android-sdk
ANDROID_TOOLCHAIN = C:/android_toolchain_$(ANDROID_ARCH)_API$(ANDROID_API_VERSION)
ANDROID_BUILD_TOOLS = $(ANDROID_HOME)/build-tools/28.0.1
ANDROID_PLATFORM_TOOLS = $(ANDROID_HOME)/platform-tools
# Android project configuration variables
PROJECT_NAME ?= raylib_game
PROJECT_LIBRARY_NAME ?= main
PROJECT_BUILD_PATH ?= android.$(PROJECT_NAME)
PROJECT_RESOURCES_PATH ?= resources
PROJECT_SOURCE_FILES ?= raylib_game.c
# Some source files are placed in directories, when compiling to some
# output directory other than source, that directory must pre-exist.
# Here we get a list of required folders that need to be created on
# code output folder $(PROJECT_BUILD_PATH)\obj to avoid GCC errors.
PROJECT_SOURCE_DIRS = $(sort $(dir $(PROJECT_SOURCE_FILES)))
# Android app configuration variables
APP_LABEL_NAME ?= rGame
APP_COMPANY_NAME ?= raylib
APP_PRODUCT_NAME ?= rgame
APP_VERSION_CODE ?= 1
APP_VERSION_NAME ?= 1.0
APP_ICON_LDPI ?= $(RAYLIB_PATH)\logo\raylib_36x36.png
APP_ICON_MDPI ?= $(RAYLIB_PATH)\logo\raylib_48x48.png
APP_ICON_HDPI ?= $(RAYLIB_PATH)\logo\raylib_72x72.png
APP_SCREEN_ORIENTATION ?= landscape
APP_KEYSTORE_PASS ?= raylib
# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll)
RAYLIB_LIBTYPE ?= STATIC
# Library path for libraylib.a/libraylib.so
RAYLIB_LIB_PATH = $(RAYLIB_PATH)\src
# Shared libs must be added to APK if required
# NOTE: Generated NativeLoader.java automatically load those libraries
ifeq ($(RAYLIB_LIBTYPE),SHARED)
PROJECT_SHARED_LIBS = lib/$(ANDROID_ARCH_NAME)/libraylib.so
endif
# Compiler and archiver
# NOTE: GCC is being deprecated in Android NDK r16
ifeq ($(ANDROID_ARCH),ARM)
CC = $(ANDROID_TOOLCHAIN)/bin/arm-linux-androideabi-clang
AR = $(ANDROID_TOOLCHAIN)/bin/arm-linux-androideabi-ar
endif
ifeq ($(ANDROID_ARCH),ARM64)
CC = $(ANDROID_TOOLCHAIN)/bin/aarch64-linux-android-clang
AR = $(ANDROID_TOOLCHAIN)/bin/aarch64-linux-android-ar
endif
# Compiler flags for arquitecture
ifeq ($(ANDROID_ARCH),ARM)
CFLAGS = -std=c99 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16
endif
ifeq ($(ANDROID_ARCH),ARM64)
CFLAGS = -std=c99 -mfix-cortex-a53-835769
endif
# Compilation functions attributes options
CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC
# Compiler options for the linker
CFLAGS += -Wall -Wa,--noexecstack -Wformat -Werror=format-security -no-canonical-prefixes
# Preprocessor macro definitions
CFLAGS += -DANDROID -DPLATFORM_ANDROID -D__ANDROID_API__=$(ANDROID_API_VERSION)
# Paths containing required header files
INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external/android/native_app_glue
# Linker options
LDFLAGS = -Wl,-soname,lib$(PROJECT_LIBRARY_NAME).so -Wl,--exclude-libs,libatomic.a
LDFLAGS += -Wl,--build-id -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings
# Force linking of library module to define symbol
LDFLAGS += -u ANativeActivity_onCreate
# Library paths containing required libs
LDFLAGS += -L. -L$(PROJECT_BUILD_PATH)/obj -L$(PROJECT_BUILD_PATH)/lib/$(ANDROID_ARCH_NAME) -L$(ANDROID_TOOLCHAIN)\sysroot\usr\lib
# Define any libraries to link into executable
# if you want to link libraries (libname.so or libname.a), use the -lname
LDLIBS = -lm -lc -lraylib -llog -landroid -lEGL -lGLESv2 -lOpenSLES -ldl
# Generate target objects list from PROJECT_SOURCE_FILES
OBJS = $(patsubst %.c, $(PROJECT_BUILD_PATH)/obj/%.o, $(PROJECT_SOURCE_FILES))
# Android APK building process... some steps required...
# NOTE: typing 'make' will invoke the default target entry called 'all',
all: create_temp_project_dirs \
copy_project_required_libs \
copy_project_resources \
generate_loader_script \
generate_android_manifest \
generate_apk_keystore \
config_project_package \
compile_project_code \
compile_project_class \
compile_project_class_dex \
create_project_apk_package \
sign_project_apk_package \
zipalign_project_apk_package
# Create required temp directories for APK building
create_temp_project_dirs:
if not exist $(PROJECT_BUILD_PATH) mkdir $(PROJECT_BUILD_PATH)
if not exist $(PROJECT_BUILD_PATH)\obj mkdir $(PROJECT_BUILD_PATH)\obj
if not exist $(PROJECT_BUILD_PATH)\src mkdir $(PROJECT_BUILD_PATH)\src
if not exist $(PROJECT_BUILD_PATH)\src\com mkdir $(PROJECT_BUILD_PATH)\src\com
if not exist $(PROJECT_BUILD_PATH)\src\com\$(APP_COMPANY_NAME) mkdir $(PROJECT_BUILD_PATH)\src\com\$(APP_COMPANY_NAME)
if not exist $(PROJECT_BUILD_PATH)\src\com\$(APP_COMPANY_NAME)\$(APP_PRODUCT_NAME) mkdir $(PROJECT_BUILD_PATH)\src\com\$(APP_COMPANY_NAME)\$(APP_PRODUCT_NAME)
if not exist $(PROJECT_BUILD_PATH)\lib mkdir $(PROJECT_BUILD_PATH)\lib
if not exist $(PROJECT_BUILD_PATH)\lib\$(ANDROID_ARCH_NAME) mkdir $(PROJECT_BUILD_PATH)\lib\$(ANDROID_ARCH_NAME)
if not exist $(PROJECT_BUILD_PATH)\bin mkdir $(PROJECT_BUILD_PATH)\bin
if not exist $(PROJECT_BUILD_PATH)\res mkdir $(PROJECT_BUILD_PATH)\res
if not exist $(PROJECT_BUILD_PATH)\res\drawable-ldpi mkdir $(PROJECT_BUILD_PATH)\res\drawable-ldpi
if not exist $(PROJECT_BUILD_PATH)\res\drawable-mdpi mkdir $(PROJECT_BUILD_PATH)\res\drawable-mdpi
if not exist $(PROJECT_BUILD_PATH)\res\drawable-hdpi mkdir $(PROJECT_BUILD_PATH)\res\drawable-hdpi
if not exist $(PROJECT_BUILD_PATH)\res\values mkdir $(PROJECT_BUILD_PATH)\res\values
if not exist $(PROJECT_BUILD_PATH)\assets mkdir $(PROJECT_BUILD_PATH)\assets
if not exist $(PROJECT_BUILD_PATH)\assets\$(PROJECT_RESOURCES_PATH) mkdir $(PROJECT_BUILD_PATH)\assets\$(PROJECT_RESOURCES_PATH)
if not exist $(PROJECT_BUILD_PATH)\obj\screens mkdir $(PROJECT_BUILD_PATH)\obj\screens
$(foreach dir, $(PROJECT_SOURCE_DIRS), $(call create_dir, $(dir)))
define create_dir
if not exist $(PROJECT_BUILD_PATH)\obj\$(1) mkdir $(PROJECT_BUILD_PATH)\obj\$(1)
endef
# Copy required shared libs for integration into APK
# NOTE: If using shared libs they are loaded by generated NativeLoader.java
copy_project_required_libs:
ifeq ($(RAYLIB_LIBTYPE),SHARED)
copy /Y $(RAYLIB_LIB_PATH)\libraylib.so $(PROJECT_BUILD_PATH)\lib\$(ANDROID_ARCH_NAME)\libraylib.so
endif
ifeq ($(RAYLIB_LIBTYPE),STATIC)
copy /Y $(RAYLIB_LIB_PATH)\libraylib.a $(PROJECT_BUILD_PATH)\lib\$(ANDROID_ARCH_NAME)\libraylib.a
endif
# Copy project required resources: strings.xml, icon.png, assets
# NOTE: Required strings.xml is generated and game resources are copied to assets folder
# TODO: Review xcopy usage, it can not be found in some systems!
copy_project_resources:
copy $(APP_ICON_LDPI) $(PROJECT_BUILD_PATH)\res\drawable-ldpi\icon.png /Y
copy $(APP_ICON_MDPI) $(PROJECT_BUILD_PATH)\res\drawable-mdpi\icon.png /Y
copy $(APP_ICON_HDPI) $(PROJECT_BUILD_PATH)\res\drawable-hdpi\icon.png /Y
@echo ^<?xml version="1.0" encoding="utf-8"^?^> > $(PROJECT_BUILD_PATH)/res/values/strings.xml
@echo ^<resources^>^<string name="app_name"^>$(APP_LABEL_NAME)^</string^>^</resources^> >> $(PROJECT_BUILD_PATH)/res/values/strings.xml
if exist $(PROJECT_RESOURCES_PATH) C:\Windows\System32\xcopy $(PROJECT_RESOURCES_PATH) $(PROJECT_BUILD_PATH)\assets\$(PROJECT_RESOURCES_PATH) /Y /E /F
# Generate NativeLoader.java to load required shared libraries
# NOTE: Probably not the bet way to generate this file... but it works.
generate_loader_script:
@echo package com.$(APP_COMPANY_NAME).$(APP_PRODUCT_NAME); > $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
@echo. >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
@echo public class NativeLoader extends android.app.NativeActivity { >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
@echo static { >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
ifeq ($(RAYLIB_LIBTYPE),SHARED)
@echo System.loadLibrary("raylib"); >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
endif
@echo System.loadLibrary("$(PROJECT_LIBRARY_NAME)"); >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
@echo } >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
@echo } >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
# Generate AndroidManifest.xml with all the required options
# NOTE: Probably not the bet way to generate this file... but it works.
generate_android_manifest:
@echo ^<?xml version="1.0" encoding="utf-8"^?^> > $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo ^<manifest xmlns:android="http://schemas.android.com/apk/res/android" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo package="com.$(APP_COMPANY_NAME).$(APP_PRODUCT_NAME)" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo android:versionCode="$(APP_VERSION_CODE)" android:versionName="$(APP_VERSION_NAME)" ^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo ^<uses-sdk android:minSdkVersion="$(ANDROID_API_VERSION)" /^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo ^<uses-feature android:glEsVersion="0x00020000" android:required="true" /^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo ^<application android:allowBackup="false" android:label="@string/app_name" android:icon="@drawable/icon" ^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo ^<activity android:name="com.$(APP_COMPANY_NAME).$(APP_PRODUCT_NAME).NativeLoader" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo android:configChanges="orientation|keyboardHidden|screenSize" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo android:screenOrientation="$(APP_SCREEN_ORIENTATION)" android:launchMode="singleTask" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo android:clearTaskOnLaunch="true"^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo ^<meta-data android:name="android.app.lib_name" android:value="$(PROJECT_LIBRARY_NAME)" /^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo ^<intent-filter^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo ^<action android:name="android.intent.action.MAIN" /^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo ^<category android:name="android.intent.category.LAUNCHER" /^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo ^</intent-filter^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo ^</activity^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo ^</application^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
@echo ^</manifest^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml
# Generate storekey for APK signing: $(PROJECT_NAME).keystore
# NOTE: Configure here your Distinguished Names (-dname) if required!
generate_apk_keystore:
if not exist $(PROJECT_BUILD_PATH)/$(PROJECT_NAME).keystore $(JAVA_HOME)/bin/keytool -genkeypair -validity 1000 -dname "CN=$(APP_COMPANY_NAME),O=Android,C=ES" -keystore $(PROJECT_BUILD_PATH)/$(PROJECT_NAME).keystore -storepass $(APP_KEYSTORE_PASS) -keypass $(APP_KEYSTORE_PASS) -alias $(PROJECT_NAME)Key -keyalg RSA
# Config project package and resource using AndroidManifest.xml and res/values/strings.xml
# NOTE: Generates resources file: src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/R.java
config_project_package:
$(ANDROID_BUILD_TOOLS)/aapt package -f -m -S $(PROJECT_BUILD_PATH)/res -J $(PROJECT_BUILD_PATH)/src -M $(PROJECT_BUILD_PATH)/AndroidManifest.xml -I $(ANDROID_HOME)/platforms/android-$(ANDROID_API_VERSION)/android.jar
# Compile native_app_glue code as static library: obj/libnative_app_glue.a
compile_native_app_glue:
$(CC) -c $(RAYLIB_PATH)/src/external/android/native_app_glue/android_native_app_glue.c -o $(PROJECT_BUILD_PATH)/obj/native_app_glue.o $(CFLAGS)
$(AR) rcs $(PROJECT_BUILD_PATH)/obj/libnative_app_glue.a $(PROJECT_BUILD_PATH)/obj/native_app_glue.o
# Compile project code into a shared library: lib/lib$(PROJECT_LIBRARY_NAME).so
compile_project_code: $(OBJS)
$(CC) -o $(PROJECT_BUILD_PATH)/lib/$(ANDROID_ARCH_NAME)/lib$(PROJECT_LIBRARY_NAME).so $(OBJS) -shared $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS)
# Compile all .c files required into object (.o) files
# NOTE: Those files will be linked into a shared library
$(PROJECT_BUILD_PATH)/obj/%.o:%.c
$(CC) -c $^ -o $@ $(INCLUDE_PATHS) $(CFLAGS) --sysroot=$(ANDROID_TOOLCHAIN)/sysroot
# Compile project .java code into .class (Java bytecode)
compile_project_class:
$(JAVA_HOME)/bin/javac -verbose -source 1.7 -target 1.7 -d $(PROJECT_BUILD_PATH)/obj -bootclasspath $(JAVA_HOME)/jre/lib/rt.jar -classpath $(ANDROID_HOME)/platforms/android-$(ANDROID_API_VERSION)/android.jar;$(PROJECT_BUILD_PATH)/obj -sourcepath $(PROJECT_BUILD_PATH)/src $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/R.java $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
# Compile .class files into Dalvik executable bytecode (.dex)
# NOTE: Since Android 5.0, Dalvik interpreter (JIT) has been replaced by ART (AOT)
compile_project_class_dex:
$(ANDROID_BUILD_TOOLS)/dx --verbose --dex --output=$(PROJECT_BUILD_PATH)/bin/classes.dex $(PROJECT_BUILD_PATH)/obj
# Create Android APK package: bin/$(PROJECT_NAME).unsigned.apk
# NOTE: Requires compiled classes.dex and lib$(PROJECT_LIBRARY_NAME).so
# NOTE: Use -A resources to define additional directory in which to find raw asset files
create_project_apk_package:
$(ANDROID_BUILD_TOOLS)/aapt package -f -M $(PROJECT_BUILD_PATH)/AndroidManifest.xml -S $(PROJECT_BUILD_PATH)/res -A $(PROJECT_BUILD_PATH)/assets -I $(ANDROID_HOME)/platforms/android-$(ANDROID_API_VERSION)/android.jar -F $(PROJECT_BUILD_PATH)/bin/$(PROJECT_NAME).unsigned.apk $(PROJECT_BUILD_PATH)/bin
cd $(PROJECT_BUILD_PATH) && $(ANDROID_BUILD_TOOLS)/aapt add bin/$(PROJECT_NAME).unsigned.apk lib/$(ANDROID_ARCH_NAME)/lib$(PROJECT_LIBRARY_NAME).so $(PROJECT_SHARED_LIBS)
# Create signed APK package using generated Key: bin/$(PROJECT_NAME).signed.apk
sign_project_apk_package:
$(JAVA_HOME)/bin/jarsigner -keystore $(PROJECT_BUILD_PATH)/$(PROJECT_NAME).keystore -storepass $(APP_KEYSTORE_PASS) -keypass $(APP_KEYSTORE_PASS) -signedjar $(PROJECT_BUILD_PATH)/bin/$(PROJECT_NAME).signed.apk $(PROJECT_BUILD_PATH)/bin/$(PROJECT_NAME).unsigned.apk $(PROJECT_NAME)Key
# Create zip-aligned APK package: $(PROJECT_NAME).apk
zipalign_project_apk_package:
$(ANDROID_BUILD_TOOLS)/zipalign -f 4 $(PROJECT_BUILD_PATH)/bin/$(PROJECT_NAME).signed.apk $(PROJECT_NAME).apk
# Install $(PROJECT_NAME).apk to default emulator/device
# NOTE: Use -e (emulator) or -d (device) parameters if required
install:
$(ANDROID_PLATFORM_TOOLS)/adb install --abi $(ANDROID_ARCH_NAME) -rds $(PROJECT_NAME).apk
# Check supported ABI for the device (armeabi-v7a, arm64-v8a, x86, x86_64)
check_device_abi:
$(ANDROID_PLATFORM_TOOLS)/adb shell getprop ro.product.cpu.abi
# Monitorize output log coming from device, only raylib tag
logcat:
$(ANDROID_PLATFORM_TOOLS)/adb logcat -c
$(ANDROID_PLATFORM_TOOLS)/adb logcat raylib:V *:S
# Install and monitorize $(PROJECT_NAME).apk to default emulator/device
deploy:
$(ANDROID_PLATFORM_TOOLS)/adb install -r $(PROJECT_NAME).apk
$(ANDROID_PLATFORM_TOOLS)/adb logcat -c
$(ANDROID_PLATFORM_TOOLS)/adb logcat raylib:V *:S
#$(ANDROID_PLATFORM_TOOLS)/adb logcat *:W
# Clean everything
clean:
del $(PROJECT_BUILD_PATH)\* /f /s /q
rmdir $(PROJECT_BUILD_PATH) /s /q
@echo Cleaning done

View file

@ -1,40 +0,0 @@
#include <math.h>
#include "raylib.h"
int main()
{
int screenWidth = 800;
int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib");
Camera cam;
cam.position = (Vector3){ 0.0f, 10.0f, 8.f };
cam.target = (Vector3){ 0.0f, 0.0f, 0.0f };
cam.up = (Vector3){ 0.0f, 1.f, 0.0f };
cam.fovy = 60.0f;
Vector3 cubePos = { 0.0f, 0.0f, 0.0f };
SetTargetFPS(60);
while (!WindowShouldClose())
{
cam.position.x = sin(GetTime())*10.0f;
cam.position.z = cos(GetTime())*10.0f;
BeginDrawing();
ClearBackground(RAYWHITE);
BeginMode3D(cam);
DrawCube(cubePos, 2.f, 2.f, 2.f, RED);
DrawCubeWires(cubePos, 2.f, 2.f, 2.f, MAROON);
DrawGrid(10, 1.f);
EndMode3D();
DrawText("This is a raylib example", 10, 40, 20, DARKGRAY);
DrawFPS(10, 10);
EndDrawing();
}
CloseWindow();
return 0;
}

View file

@ -1,54 +0,0 @@
version(1);
project_name = "raylib-example";
patterns = {
"*.cpp",
"*.c",
"*.h",
"*.bat",
"*.sh",
"*.4coder",
"Makefile",
};
blacklist_patterns = {
".*",
};
load_paths = {
{ { {".", .relative = true, .recursive = true, } }, .os = "win" },
{ { {".", .relative = true, .recursive = true, } }, .os = "linux" },
{ { {".", .relative = true, .recursive = true, } }, .os = "mac" },
};
command_list = {
{ .name = "clean",
.out = "*clean*", .footer_panel = true, .save_dirty_files = false, .cursor_at_end = true,
.cmd = {
{"mingw32-make clean", .os = "win"},
{"make clean", .os = "linux"},
{"make clean", .os = "mac"},
},
},
{ .name = "build",
.out = "*compile*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false,
.cmd = {
{"mingw32-make", .os = "win"},
{"make", .os = "linux"},
{"make", .os = "mac"},
},
},
{ .name = "run",
.out = "*run*", .footer_panel = true, .save_dirty_files = false, .cursor_at_end = true,
.cmd = {
{".\game.exe", .os = "win"},
{"./game", .os = "linux"},
{"./game", .os = "mac"},
},
},
};
fkey_command[3] = "clean";
fkey_command[4] = "build";
fkey_command[5] = "run";

View file

@ -4,15 +4,14 @@ This folder contains raylib templates for some common IDEs.
IDE | Platform(s) | Source | Example(s)
----| ------------| :-------: | :-----:
[4coder](http://4coder.net/) | Windows | ❌ | ✔️
[Builder](https://wiki.gnome.org/Apps/Builder) | Linux | ❌ | ✔️
[CMake](https://cmake.org/) | Windows, Linux, macOS, Web | ✔️ | ✔️
[CodeBlocks](http://www.codeblocks.org/) | Windows, Linux, macOS | ❌ | ✔️
[Geany](https://www.geany.org/) | Windows, Linux | ✔️ | ✔️
[Notepad++](https://notepad-plus-plus.org/) | Windows | ✔️ | ✔️
[Notepad++](https://notepad-plus-plus.org/) | Windows, Web | ✔️ | ✔️
[SublimeText](https://www.sublimetext.com/) | Windows, Linux, macOS | ✔️ | ✔️
[VS2019](https://www.visualstudio.com) | Windows | ✔️ | ✔️
[VSCode](https://code.visualstudio.com/) | Windows, macOS | ❌ | ✔️
[VS2022](https://www.visualstudio.com) | Windows | ✔️ | ✔️
[VSCode](https://code.visualstudio.com/) | Windows, Linux, macOS | ❌ | ✔️
[Zig](https://ziglang.org) | Windows, Linux, macOS, Web | ✔️ | ✔️
scripts | Windows, Linux, macOS | ✔️ | ✔️

View file

@ -1,75 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31702.278
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "raylib_android", "raylib_android", "{5C24BC76-8848-40EA-9BBB-A544648D8D5B}"
EndProject
Project("{39E2626F-3545-4960-A6E8-258AD8476CE5}") = "raylib_android.Packaging", "raylib_android\raylib_android.Packaging\raylib_android.Packaging.androidproj", "{B2231F0D-52DA-4C55-8998-5886F766553C}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "raylib_android.NativeActivity", "raylib_android\raylib_android.NativeActivity\raylib_android.NativeActivity.vcxproj", "{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|ARM.ActiveCfg = Debug|ARM
{B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|ARM.Build.0 = Debug|ARM
{B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|ARM.Deploy.0 = Debug|ARM
{B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|ARM64.ActiveCfg = Debug|ARM64
{B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|ARM64.Build.0 = Debug|ARM64
{B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|ARM64.Deploy.0 = Debug|ARM64
{B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|x64.ActiveCfg = Debug|x64
{B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|x64.Build.0 = Debug|x64
{B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|x64.Deploy.0 = Debug|x64
{B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|x86.ActiveCfg = Debug|x86
{B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|x86.Build.0 = Debug|x86
{B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|x86.Deploy.0 = Debug|x86
{B2231F0D-52DA-4C55-8998-5886F766553C}.Release|ARM.ActiveCfg = Release|ARM
{B2231F0D-52DA-4C55-8998-5886F766553C}.Release|ARM.Build.0 = Release|ARM
{B2231F0D-52DA-4C55-8998-5886F766553C}.Release|ARM.Deploy.0 = Release|ARM
{B2231F0D-52DA-4C55-8998-5886F766553C}.Release|ARM64.ActiveCfg = Release|ARM64
{B2231F0D-52DA-4C55-8998-5886F766553C}.Release|ARM64.Build.0 = Release|ARM64
{B2231F0D-52DA-4C55-8998-5886F766553C}.Release|ARM64.Deploy.0 = Release|ARM64
{B2231F0D-52DA-4C55-8998-5886F766553C}.Release|x64.ActiveCfg = Release|x64
{B2231F0D-52DA-4C55-8998-5886F766553C}.Release|x64.Build.0 = Release|x64
{B2231F0D-52DA-4C55-8998-5886F766553C}.Release|x64.Deploy.0 = Release|x64
{B2231F0D-52DA-4C55-8998-5886F766553C}.Release|x86.ActiveCfg = Release|x86
{B2231F0D-52DA-4C55-8998-5886F766553C}.Release|x86.Build.0 = Release|x86
{B2231F0D-52DA-4C55-8998-5886F766553C}.Release|x86.Deploy.0 = Release|x86
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|ARM.ActiveCfg = Debug|ARM
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|ARM.Build.0 = Debug|ARM
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|ARM64.ActiveCfg = Debug|ARM64
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|ARM64.Build.0 = Debug|ARM64
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|x64.ActiveCfg = Debug|x64
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|x64.Build.0 = Debug|x64
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|x86.ActiveCfg = Debug|x86
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|x86.Build.0 = Debug|x86
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|ARM.ActiveCfg = Release|ARM
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|ARM.Build.0 = Release|ARM
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|ARM64.ActiveCfg = Release|ARM64
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|ARM64.Build.0 = Release|ARM64
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|x64.ActiveCfg = Release|x64
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|x64.Build.0 = Release|x64
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|x86.ActiveCfg = Release|x86
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{B2231F0D-52DA-4C55-8998-5886F766553C} = {5C24BC76-8848-40EA-9BBB-A544648D8D5B}
{BFB31759-4FCA-4503-BC7C-A97F705EFDB2} = {5C24BC76-8848-40EA-9BBB-A544648D8D5B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B7ED0AA6-6B00-40AC-BF71-526D5BEEFC78}
EndGlobalSection
EndGlobal

View file

@ -1,437 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* лицензировано по лицензии Apache License, версия 2.0 ( "Лицензия");
*этот файл можно использовать только в соответствии с лицензией.
*Копию лицензии можно получить на веб-сайте
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Если только не требуется в соответствии с применимым законодательством или согласовано в письменном виде, программное обеспечение
* распространяется в рамках лицензии на УСЛОВИЯХ "КАК ЕСТЬ",
* БЕЗ ГАРАНТИЙ И УСЛОВИЙ ЛЮБОГО РОДА, явно выраженных и подразумеваемых.
* См. лицензию для получения информации об определенных разрешениях по использованию языка и
* ограничениях в рамках лицензии.
*
*/
#include <jni.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>
#include "android_native_app_glue.h"
#include <android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__))
/* Для отладочных построений необходимо всегда включать трассировку отладки в этой библиотеке*/
#ifndef NDEBUG
# define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__))
#else
# define LOGV(...) ((void)0)
#endif
static void free_saved_state(struct android_app* android_app) {
pthread_mutex_lock(&android_app->mutex);
if (android_app->savedState != NULL) {
free(android_app->savedState);
android_app->savedState = NULL;
android_app->savedStateSize = 0;
}
pthread_mutex_unlock(&android_app->mutex);
}
int8_t android_app_read_cmd(struct android_app* android_app) {
int8_t cmd;
if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {
switch (cmd) {
case APP_CMD_SAVE_STATE:
free_saved_state(android_app);
break;
}
return cmd;
} else {
LOGE("No data on command pipe!");
}
return -1;
}
static void print_cur_config(struct android_app* android_app) {
char lang[2], country[2];
AConfiguration_getLanguage(android_app->config, lang);
AConfiguration_getCountry(android_app->config, country);
LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
"keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
"modetype=%d modenight=%d",
AConfiguration_getMcc(android_app->config),
AConfiguration_getMnc(android_app->config),
lang[0], lang[1], country[0], country[1],
AConfiguration_getOrientation(android_app->config),
AConfiguration_getTouchscreen(android_app->config),
AConfiguration_getDensity(android_app->config),
AConfiguration_getKeyboard(android_app->config),
AConfiguration_getNavigation(android_app->config),
AConfiguration_getKeysHidden(android_app->config),
AConfiguration_getNavHidden(android_app->config),
AConfiguration_getSdkVersion(android_app->config),
AConfiguration_getScreenSize(android_app->config),
AConfiguration_getScreenLong(android_app->config),
AConfiguration_getUiModeType(android_app->config),
AConfiguration_getUiModeNight(android_app->config));
}
void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {
switch (cmd) {
case APP_CMD_INPUT_CHANGED:
LOGV("APP_CMD_INPUT_CHANGED\n");
pthread_mutex_lock(&android_app->mutex);
if (android_app->inputQueue != NULL) {
AInputQueue_detachLooper(android_app->inputQueue);
}
android_app->inputQueue = android_app->pendingInputQueue;
if (android_app->inputQueue != NULL) {
LOGV("Attaching input queue to looper");
AInputQueue_attachLooper(android_app->inputQueue,
android_app->looper, LOOPER_ID_INPUT, NULL,
&android_app->inputPollSource);
}
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
break;
case APP_CMD_INIT_WINDOW:
LOGV("APP_CMD_INIT_WINDOW\n");
pthread_mutex_lock(&android_app->mutex);
android_app->window = android_app->pendingWindow;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
break;
case APP_CMD_TERM_WINDOW:
LOGV("APP_CMD_TERM_WINDOW\n");
pthread_cond_broadcast(&android_app->cond);
break;
case APP_CMD_RESUME:
case APP_CMD_START:
case APP_CMD_PAUSE:
case APP_CMD_STOP:
LOGV("activityState=%d\n", cmd);
pthread_mutex_lock(&android_app->mutex);
android_app->activityState = cmd;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
break;
case APP_CMD_CONFIG_CHANGED:
LOGV("APP_CMD_CONFIG_CHANGED\n");
AConfiguration_fromAssetManager(android_app->config,
android_app->activity->assetManager);
print_cur_config(android_app);
break;
case APP_CMD_DESTROY:
LOGV("APP_CMD_DESTROY\n");
android_app->destroyRequested = 1;
break;
}
}
void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) {
switch (cmd) {
case APP_CMD_TERM_WINDOW:
LOGV("APP_CMD_TERM_WINDOW\n");
pthread_mutex_lock(&android_app->mutex);
android_app->window = NULL;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
break;
case APP_CMD_SAVE_STATE:
LOGV("APP_CMD_SAVE_STATE\n");
pthread_mutex_lock(&android_app->mutex);
android_app->stateSaved = 1;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
break;
case APP_CMD_RESUME:
free_saved_state(android_app);
break;
}
}
static void android_app_destroy(struct android_app* android_app) {
LOGV("android_app_destroy!");
free_saved_state(android_app);
pthread_mutex_lock(&android_app->mutex);
if (android_app->inputQueue != NULL) {
AInputQueue_detachLooper(android_app->inputQueue);
}
AConfiguration_delete(android_app->config);
android_app->destroyed = 1;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
// После этого нельзя изменять объект android_app.
}
static void process_input(struct android_app* app, struct android_poll_source* source) {
AInputEvent* event = NULL;
while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
LOGV("New input event: type=%d\n", AInputEvent_getType(event));
if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
continue;
}
int32_t handled = 0;
if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
AInputQueue_finishEvent(app->inputQueue, event, handled);
}
}
static void process_cmd(struct android_app* app, struct android_poll_source* source) {
int8_t cmd = android_app_read_cmd(app);
android_app_pre_exec_cmd(app, cmd);
if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);
android_app_post_exec_cmd(app, cmd);
}
static void* android_app_entry(void* param) {
struct android_app* android_app = (struct android_app*)param;
android_app->config = AConfiguration_new();
AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
print_cur_config(android_app);
android_app->cmdPollSource.id = LOOPER_ID_MAIN;
android_app->cmdPollSource.app = android_app;
android_app->cmdPollSource.process = process_cmd;
android_app->inputPollSource.id = LOOPER_ID_INPUT;
android_app->inputPollSource.app = android_app;
android_app->inputPollSource.process = process_input;
ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
&android_app->cmdPollSource);
android_app->looper = looper;
pthread_mutex_lock(&android_app->mutex);
android_app->running = 1;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
android_main(android_app);
android_app_destroy(android_app);
return NULL;
}
// --------------------------------------------------------------------
// Взаимодействие NativeАctivity (вызванное из основного потока)
// --------------------------------------------------------------------
static struct android_app* android_app_create(ANativeActivity* activity,
void* savedState, size_t savedStateSize) {
struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
memset(android_app, 0, sizeof(struct android_app));
android_app->activity = activity;
pthread_mutex_init(&android_app->mutex, NULL);
pthread_cond_init(&android_app->cond, NULL);
if (savedState != NULL) {
android_app->savedState = malloc(savedStateSize);
android_app->savedStateSize = savedStateSize;
memcpy(android_app->savedState, savedState, savedStateSize);
}
int msgpipe[2];
if (pipe(msgpipe)) {
LOGE("could not create pipe: %s", strerror(errno));
return NULL;
}
android_app->msgread = msgpipe[0];
android_app->msgwrite = msgpipe[1];
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
// Дождитесь запуска потока.
pthread_mutex_lock(&android_app->mutex);
while (!android_app->running) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
pthread_mutex_unlock(&android_app->mutex);
return android_app;
}
static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {
if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {
LOGE("Failure writing android_app cmd: %s\n", strerror(errno));
}
}
static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {
pthread_mutex_lock(&android_app->mutex);
android_app->pendingInputQueue = inputQueue;
android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
while (android_app->inputQueue != android_app->pendingInputQueue) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
pthread_mutex_unlock(&android_app->mutex);
}
static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
pthread_mutex_lock(&android_app->mutex);
if (android_app->pendingWindow != NULL) {
android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
}
android_app->pendingWindow = window;
if (window != NULL) {
android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
}
while (android_app->window != android_app->pendingWindow) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
pthread_mutex_unlock(&android_app->mutex);
}
static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {
pthread_mutex_lock(&android_app->mutex);
android_app_write_cmd(android_app, cmd);
while (android_app->activityState != cmd) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
pthread_mutex_unlock(&android_app->mutex);
}
static void android_app_free(struct android_app* android_app) {
pthread_mutex_lock(&android_app->mutex);
android_app_write_cmd(android_app, APP_CMD_DESTROY);
while (!android_app->destroyed) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
pthread_mutex_unlock(&android_app->mutex);
close(android_app->msgread);
close(android_app->msgwrite);
pthread_cond_destroy(&android_app->cond);
pthread_mutex_destroy(&android_app->mutex);
free(android_app);
}
static void onDestroy(ANativeActivity* activity) {
LOGV("Destroy: %p\n", activity);
android_app_free((struct android_app*)activity->instance);
}
static void onStart(ANativeActivity* activity) {
LOGV("Start: %p\n", activity);
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
}
static void onResume(ANativeActivity* activity) {
LOGV("Resume: %p\n", activity);
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
}
static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
struct android_app* android_app = (struct android_app*)activity->instance;
void* savedState = NULL;
LOGV("SaveInstanceState: %p\n", activity);
pthread_mutex_lock(&android_app->mutex);
android_app->stateSaved = 0;
android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
while (!android_app->stateSaved) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
if (android_app->savedState != NULL) {
savedState = android_app->savedState;
*outLen = android_app->savedStateSize;
android_app->savedState = NULL;
android_app->savedStateSize = 0;
}
pthread_mutex_unlock(&android_app->mutex);
return savedState;
}
static void onPause(ANativeActivity* activity) {
LOGV("Pause: %p\n", activity);
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
}
static void onStop(ANativeActivity* activity) {
LOGV("Stop: %p\n", activity);
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
}
static void onConfigurationChanged(ANativeActivity* activity) {
struct android_app* android_app = (struct android_app*)activity->instance;
LOGV("ConfigurationChanged: %p\n", activity);
android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);
}
static void onLowMemory(ANativeActivity* activity) {
struct android_app* android_app = (struct android_app*)activity->instance;
LOGV("LowMemory: %p\n", activity);
android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
}
static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
LOGV("WindowFocusChanged: %p -- %d\n", activity, focused);
android_app_write_cmd((struct android_app*)activity->instance,
focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
}
static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {
LOGV("NativeWindowCreated: %p -- %p\n", activity, window);
android_app_set_window((struct android_app*)activity->instance, window);
}
static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window);
android_app_set_window((struct android_app*)activity->instance, NULL);
}
static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
LOGV("InputQueueCreated: %p -- %p\n", activity, queue);
android_app_set_input((struct android_app*)activity->instance, queue);
}
static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue);
android_app_set_input((struct android_app*)activity->instance, NULL);
}
void ANativeActivity_onCreate(ANativeActivity* activity,
void* savedState, size_t savedStateSize) {
LOGV("Creating: %p\n", activity);
activity->callbacks->onDestroy = onDestroy;
activity->callbacks->onStart = onStart;
activity->callbacks->onResume = onResume;
activity->callbacks->onSaveInstanceState = onSaveInstanceState;
activity->callbacks->onPause = onPause;
activity->callbacks->onStop = onStop;
activity->callbacks->onConfigurationChanged = onConfigurationChanged;
activity->callbacks->onLowMemory = onLowMemory;
activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
activity->callbacks->onInputQueueCreated = onInputQueueCreated;
activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
activity->instance = android_app_create(activity, savedState, savedStateSize);
}

View file

@ -1,344 +0,0 @@
/*
* © 2010 The Android Open Source Project
*
* Лицензировано по лицензии Apache License, версия 2.0 ( "Лицензия");
*этот файл можно использовать только в соответствии с лицензией.
*Копию лицензии можно получить на веб-сайте
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Если только не требуется в соответствии с применимым законодательством или согласовано в письменном виде, программное обеспечение
* распространяется в рамках лицензии на УСЛОВИЯХ "КАК ЕСТЬ",
* БЕЗ ГАРАНТИЙ И УСЛОВИЙ ЛЮБОГО РОДА, явно выраженных и подразумеваемых.
* См. лицензию для получения информации об определенных разрешениях по использованию языка и
* ограничениях в рамках лицензии.
*
*/
#ifndef _ANDROID_NATIVE_APP_GLUE_H
#define _ANDROID_NATIVE_APP_GLUE_H
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <android/configuration.h>
#include <android/looper.h>
#include <android/native_activity.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Интерфейс NativeActivity, предоставленный <android/native_activity.h>,
* основан на наборе предоставленных приложением обратных вызовов, которые вызываются
*основным потоком действия при возникновении определенных событий.
*
* Это означает, что ни один из данных обратных вызовов _не_ _должен_ блокироваться, иначе
* существует риск принудительного закрытия приложения системой. Эта модель программирования
* прямая, простая, но имеет ограничения.
*
* Статическая библиотека threaded_native_app используется для обеспечения другой
* модели выполнения, в которой приложение может реализовать свой собственный цикл главного события
* в другом потоке вместо этого. Это работает так:
*
* 1/ Приложение должно предоставить функцию с именем android_main(), которая
* будет вызываться при создании действия в новом потоке,
* отличающемся от основного потока действия.
*
* 2/ android_main() получает указатель на допустимую структуру android_app,
* которая содержит ссылки на другие важные объекты, например экземпляр объекта
* ANativeActivity, где выполняется приложение.
*
* 3/ Объект android_app содержит экземпляр ALooper, который уже
* ожидает две важных вещи:
*
* - событий жизненного цикла действия (например, "pause", "resume"). См. объявления APP_CMD_XXX
* ниже.
*
* - входных событий, поступающих из очереди AInputQueue, присоединенной к действию.
*
* Каждое из этих событий соответствует идентификатору ALooper, возвращенному
* ALooper_pollOnce со значениями LOOPER_ID_MAIN и LOOPER_ID_INPUT,
*, соответственно.
*
* Ваше приложение может использовать тот же ALooper для прослушивания дополнительных
* дескрипторов файла. Они могут быть основаны либо на обратных вызовах, либо поступают с идентификаторами возврата,
* начинающимися с LOOPER_ID_USER.
*
* 4/ При получении события LOOPER_ID_MAIN или LOOPER_ID_INPUT
* возвращенные данные будут указывать на структуру android_poll_source. Для нее
* можно вызвать функцию process() и заполнить android_app->onAppCmd
* и android_app->onInputEvent, для того чтобы они вызывались для вашей собственной обработки
* события.
*
* Вместо этого можно вызвать функции нижнего уровня для чтения и обработки
* данных непосредственно... посмотрите на реализации process_cmd() и process_input()
* в приклеивании, чтобы выяснить, как это делается.
*
* См. пример "native-activity" в NDK с
* полной демонстрацией использования. Также посмотрите JavaDoc в NativeActivity.
*/
struct android_app;
/**
* Данные, связанные с ALooper fd, которые будут возвращаться как outData
* при готовности данных в этом источнике.
*/
struct android_poll_source {
// Идентификатор данного источника. Может быть LOOPER_ID_MAIN или
// LOOPER_ID_INPUT.
int32_t id;
// android_app, с которым связан данный идентификатор.
struct android_app* app;
// Функция, вызываемая для стандартной обработки данных из
// этого источника.
void (*process)(struct android_app* app, struct android_poll_source* source);
};
/**
* Это интерфейс стандартного кода приклеивания поточного
* приложения. В этой модели код приложения выполняется
* в своем собственном потоке, отдельном от основного потока процесса.
* Не требуется связь данного потока с ВМ Java
*, хотя это необходимо для выполнения вызовов JNI любых
* объектов Java.
*/
struct android_app {
// Приложение может поместить указатель на свой собственный объект состояния
// здесь, если нужно.
void* userData;
// Введите здесь код функции для обработки основных команд приложения (APP_CMD_*)
void (*onAppCmd)(struct android_app* app, int32_t cmd);
// Введите здесь код функции для обработки входных событий. Сейчас
// событие уже было предварительно отправлено и будет завершено при
// возврате. Верните 1, если событие обработано, 0 — для любой диспетчеризации
// по умолчанию.
int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
// Экземпляр объекта ANativeActivity, в котором выполняется это приложение.
ANativeActivity* activity;
// Текущая конфигурация, в которой выполняется это приложение.
AConfiguration* config;
// Это последнее сохраненное состояние экземпляра, предоставленное во время создания.
// Значение равно NULL, если состояния не было. Можно использовать это по мере необходимости;
// память останется доступной до вызова android_app_exec_cmd() для
// APP_CMD_RESUME, после чего она будет освобождена, а savedState получит значение NULL.
// Эти переменные необходимо изменять только при обработке APP_CMD_SAVE_STATE,
// когда их значения будут инициализироваться в NULL и можно будет выполнить malloc для
// состояния и поместить здесь информацию. В этом случае память будет
// освобождена позднее.
void* savedState;
size_t savedStateSize;
// ALooper, связанный с потоком приложения.
ALooper* looper;
// Если значение не равно NULL, то это входная очередь, из которой приложение будет
// получать входные события пользователя.
AInputQueue* inputQueue;
// Если значение не равно NULL, то это поверхность окна, в котором приложение может рисовать.
ANativeWindow* window;
// Текущий прямоугольник содержимого окна. Это область, в которой
// должно помещаться содержимое окна, чтобы его видел пользователь.
ARect contentRect;
// Текущее состояние действия приложения. Может быть APP_CMD_START,
// APP_CMD_RESUME, APP_CMD_PAUSE или APP_CMD_STOP; см. ниже.
int activityState;
// Значение не равно нулю, когда NativeActivity приложения
// разрушается и ожидает завершения потока приложения.
int destroyRequested;
// -------------------------------------------------
// Ниже показан "частная" реализация кода прилипания.
pthread_mutex_t mutex;
pthread_cond_t cond;
int msgread;
int msgwrite;
pthread_t thread;
struct android_poll_source cmdPollSource;
struct android_poll_source inputPollSource;
int running;
int stateSaved;
int destroyed;
int redrawNeeded;
AInputQueue* pendingInputQueue;
ANativeWindow* pendingWindow;
ARect pendingContentRect;
};
enum {
/**
* Идентификатор данных Looper команд, поступающих из основного потока приложения, который
* возвращается как идентификатор от ALooper_pollOnce(). Данные для этого идентификатора
* являются указателем на структуру android_poll_source.
* Их можно извлечь и обработать с помощью android_app_read_cmd()
* и android_app_exec_cmd().
*/
LOOPER_ID_MAIN = 1,
/**
* Идентификатор данных Looper событий, поступающий из AInputQueue окна
* приложения, который возвращается как идентификатор из
* ALooper_pollOnce(). Данные этого идентификатора являются указателем на структуру
* android_poll_source. Их можно прочитать через объект inputQueue
* приложения android_app.
*/
LOOPER_ID_INPUT = 2,
/**
* Запуск определяемых пользователем идентификаторов ALooper.
*/
LOOPER_ID_USER = 3,
};
enum {
/**
* Команда из основного потока: AInputQueue изменена. После обработки
* этой команды android_app->inputQueue будет обновлена в новую очередь
* (или NULL).
*/
APP_CMD_INPUT_CHANGED,
/**
* Команда из основного потока: новое окно ANativeWindow готово к использованию. После
* получения этой команды окно android_app-> будет содержать новую поверхность
*окна.
*/
APP_CMD_INIT_WINDOW,
/**
* Команда из основного потока: существующее окно ANativeWindow необходимо
* прекратить. После получения этой команды окно android_app->по-прежнему
* содержит существующее окно; после вызова android_app_exec_cmd
* оно получит значение NULL.
*/
APP_CMD_TERM_WINDOW,
/**
* Команда из основного потока: текущее окно ANativeWindow изменило размер.
* Перерисуйте согласно новом размеру.
*/
APP_CMD_WINDOW_RESIZED,
/**
* Команда из основного потока: системе необходимо, чтобы текущее окно ANativeWindow
* было перерисовано. Необходимо перерисовать окно перед ее передачей в
* android_app_exec_cmd(), чтобы избежать переходных сбоев рисования.
*/
APP_CMD_WINDOW_REDRAW_NEEDED,
/**
* Команда из основного потока: область содержимого окна изменена
* таким образом, что из функционального ввода окно показывается или скрывается. Можно
* найти новый прямоугольник содержимого в android_app::contentRect.
*/
APP_CMD_CONTENT_RECT_CHANGED,
/**
* Команда из основного потока: окно действия приложения получило
* фокус ввода.
*/
APP_CMD_GAINED_FOCUS,
/**
* Команда из основного потока: окно действия приложения потеряло
* фокус ввода.
*/
APP_CMD_LOST_FOCUS,
/**
* Команда из основного потока: изменена текущая конфигурация устройства.
*/
APP_CMD_CONFIG_CHANGED,
/**
* Команда из основного потока: системе не хватает памяти.
* Попробуйте уменьшить использование памяти.
*/
APP_CMD_LOW_MEMORY,
/**
* Команда из основного потока: действие приложения было запущено.
*/
APP_CMD_START,
/**
* Команда из основного потока: действие приложения было возобновлено.
*/
APP_CMD_RESUME,
/**
* Команда из основного потока: приложение должно создать новое сохраненное состояние
* для себя, чтобы восстанавливаться из него позднее в случае необходимости. Если вы сохранили состояние,
* выделите его с использованием malloc и поместите в android_app.savedState с
* размером android_app.savedStateSize. Память будет освобождена
* позднее.
*/
APP_CMD_SAVE_STATE,
/**
* Команда из основного потока: пауза в действии приложения.
*/
APP_CMD_PAUSE,
/**
* Команда из основного потока: действие приложения было остановлено.
*/
APP_CMD_STOP,
/**
* Команда из основного потока: действие приложения уничтожается,
* и ожидает очистки потока приложения и выхода перед обработкой.
*/
APP_CMD_DESTROY,
};
/**
* Вызовите, когда ALooper_pollAll() возвращает LOOPER_ID_MAIN, при чтении следующего сообщения команды
*приложения.
*/
int8_t android_app_read_cmd(struct android_app* android_app);
/**
* Вызовите с помощью команды, возвращенной android_app_read_cmd() для выполнения
* начальной предварительной обработки данной команды. Можно выполнить собственные
* действия для команды после вызова этой функции.
*/
void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd);
/**
* Вызовите с помощью команды, возвращенной android_app_read_cmd(), для
* окончательной предварительной обработки данной команды. Необходимо завершить собственные
* действия с командой до вызова этой функции.
*/
void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd);
/**
* Это функция, которую должен реализовать код приложения, представляет собой
* главный вход в приложение.
*/
extern void android_main(struct android_app* app);
#ifdef __cplusplus
}
#endif
#endif /* _ANDROID_NATIVE_APP_GLUE_H */

View file

@ -1,64 +0,0 @@
/*******************************************************************************************
*
* raylib [core] example - Basic window
*
* This example has been created using raylib 3.8 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
* Example contributed by <user_name> (@<user_github>) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2021 <user_name> (@<user_github>)
* Adapt for Visual Studio: Vadim Boev (Kronka Dev)
*
********************************************************************************************/
#include "android_native_app_glue.h"
#include "../../../../src/raylib.h"
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
// TODO: Load resources / Initialize variables at this point
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// TODO: Update variables / Implement example logic at this point
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
// TODO: Draw everything that requires to be drawn at this point:
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); // Example
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
// TODO: Unload all loaded resources at this point
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

View file

@ -1,226 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x86">
<Configuration>Debug</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x86">
<Configuration>Release</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{bfb31759-4fca-4503-bc7c-a97f705efdb2}</ProjectGuid>
<Keyword>Android</Keyword>
<RootNamespace>raylib_android</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<ApplicationType>Android</ApplicationType>
<ApplicationTypeRevision>3.0</ApplicationTypeRevision>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>Clang_5_0</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>Clang_5_0</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>Clang_5_0</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>Clang_5_0</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>Clang_5_0</PlatformToolset>
<AndroidAPILevel>android-29</AndroidAPILevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>Clang_5_0</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>Clang_5_0</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>Clang_5_0</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<TargetName>libmain</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<CompileAs>CompileAsC</CompileAs>
<CLanguageStandard>c99</CLanguageStandard>
<CppLanguageStandard>Default</CppLanguageStandard>
<PrecompiledHeaderCompileAs>CompileAsC</PrecompiledHeaderCompileAs>
</ClCompile>
<Link>
<LibraryDependencies>%(LibraryDependencies);EGL;GLESv2;log;android;c;m;raylib</LibraryDependencies>
<AdditionalLibraryDirectories>../../../../src/;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<CompileAs>CompileAsC</CompileAs>
<CLanguageStandard>c99</CLanguageStandard>
<CppLanguageStandard>Default</CppLanguageStandard>
<PrecompiledHeaderCompileAs>CompileAsC</PrecompiledHeaderCompileAs>
</ClCompile>
<Link>
<LibraryDependencies>%(LibraryDependencies);GLESv1_CM;EGL;</LibraryDependencies>
<AdditionalLibraryDirectories>.;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<CompileAs>CompileAsCpp</CompileAs>
</ClCompile>
<Link>
<LibraryDependencies>%(LibraryDependencies);GLESv1_CM;EGL;</LibraryDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<CompileAs>CompileAsCpp</CompileAs>
</ClCompile>
<Link>
<LibraryDependencies>%(LibraryDependencies);GLESv1_CM;EGL;</LibraryDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<CompileAs>CompileAsCpp</CompileAs>
</ClCompile>
<Link>
<LibraryDependencies>%(LibraryDependencies);GLESv1_CM;EGL;</LibraryDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<CompileAs>CompileAsCpp</CompileAs>
</ClCompile>
<Link>
<LibraryDependencies>%(LibraryDependencies);GLESv1_CM;EGL;</LibraryDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<CompileAs>CompileAsCpp</CompileAs>
</ClCompile>
<Link>
<LibraryDependencies>%(LibraryDependencies);GLESv1_CM;EGL;</LibraryDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<CompileAs>CompileAsCpp</CompileAs>
</ClCompile>
<Link>
<LibraryDependencies>%(LibraryDependencies);GLESv1_CM;EGL;</LibraryDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="android_native_app_glue.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="android_native_app_glue.c" />
<ClCompile Include="main.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="android_native_app_glue.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="android_native_app_glue.c" />
<ClCompile Include="main.c" />
</ItemGroup>
</Project>

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

View file

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Changes made to Package Name should also be reflected in the Debugging - Package Name property, in the Property Pages -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.$(ApplicationName)" android:versionCode="1" android:versionName="1.0">
<!-- This is the platform API where NativeActivity was introduced. -->
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"/>
<!-- This .apk has no Java code itself, so set hasCode to false. -->
<application android:label="@string/app_name" android:hasCode="false">
<!-- Our activity is the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
<activity android:name="android.app.NativeActivity" android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:configChanges="orientation|keyboardHidden|screenSize" android:screenOrientation="landscape">
<!-- Tell NativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name" android:value="main"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -1,90 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="$(projectname)" default="help">
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- if sdk.dir was not set from one of the property file, then
get it from the ANDROID_HOME env var. -->
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<!-- The project.properties file contains project specific properties such as
project target, and library dependencies. Lower level build properties are
stored in ant.properties
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure ANDROID_HOME environment variable is correctly set."
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
<target name="-pre-compile">
<path id="project.all.jars.path">
<path path="${toString:project.all.jars.path}"/>
<fileset dir="${jar.libs.dir}">
<include name="*.jar"/>
</fileset>
</path>
</target>
</project>

View file

@ -1,3 +0,0 @@
# Project target
target=$(androidapilevel)
# Provide path to the directory where prebuilt external jar files are by setting jar.libs.dir=

View file

@ -1,134 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x86">
<Configuration>Debug</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x86">
<Configuration>Release</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<RootNamespace>raylib_android</RootNamespace>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<ProjectVersion>1.0</ProjectVersion>
<ProjectGuid>{b2231f0d-52da-4c55-8998-5886f766553c}</ProjectGuid>
</PropertyGroup>
<Import Project="$(AndroidTargetsPath)\Android.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<Import Project="$(AndroidTargetsPath)\Android.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="Shared" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<AntPackage>
<AndroidAppLibName>$(RootNamespace)</AndroidAppLibName>
</AntPackage>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<AntPackage>
<AndroidAppLibName>$(RootNamespace)</AndroidAppLibName>
</AntPackage>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<AntPackage>
<AndroidAppLibName>$(RootNamespace)</AndroidAppLibName>
</AntPackage>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<AntPackage>
<AndroidAppLibName>$(RootNamespace)</AndroidAppLibName>
</AntPackage>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<AntPackage>
<AndroidAppLibName>$(RootNamespace)</AndroidAppLibName>
</AntPackage>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<AntPackage>
<AndroidAppLibName>$(RootNamespace)</AndroidAppLibName>
</AntPackage>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<AntPackage>
<AndroidAppLibName>$(RootNamespace)</AndroidAppLibName>
</AntPackage>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<AntPackage>
<AndroidAppLibName>$(RootNamespace)</AndroidAppLibName>
</AntPackage>
</ItemDefinitionGroup>
<ItemGroup>
<Content Include="res\values\strings.xml" />
<AntBuildXml Include="build.xml" />
<AndroidManifest Include="AndroidManifest.xml" />
<AntProjectPropertiesFile Include="project.properties" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\raylib_android.NativeActivity\raylib_android.NativeActivity.vcxproj">
<Project>{bfb31759-4fca-4503-bc7c-a97f705efdb2}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(AndroidTargetsPath)\Android.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">raylib_android.Packaging</string>
</resources>

View file

@ -107,6 +107,20 @@ endif ()
target_link_libraries(raylib PRIVATE $<BUILD_INTERFACE:${LIBS_PRIVATE}>)
target_link_libraries(raylib PUBLIC ${LIBS_PUBLIC})
# Static libraries must export their private link dependencies for installed consumers.
# LINK_ONLY keeps those dependencies out of the compile interface.
if (NOT BUILD_SHARED_LIBS)
set(raylib_install_private_libs ${LIBS_PRIVATE})
if (NOT glfw3_FOUND)
list(REMOVE_ITEM raylib_install_private_libs glfw)
endif()
foreach(lib IN LISTS raylib_install_private_libs)
target_link_libraries(raylib INTERFACE $<INSTALL_INTERFACE:$<LINK_ONLY:${lib}>>)
endforeach()
endif()
# Sets some compile time definitions for the pre-processor
# If CUSTOMIZE_BUILD option is on you will not use config.h by default
# and you will be able to select more build options

View file

@ -173,6 +173,7 @@
//#define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance
// Default shader vertex attribute locations
// NOTE: Locations can be redefined by user if required
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1
//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2
@ -186,7 +187,8 @@
// Default shader vertex attribute/uniform names to set location points
// NOTE: When a new shader is loaded, locations are tried to be set for convenience, looking for the names defined here
// In case custom shader names are used, it's up to the user to set locations with GetShaderLocation*() functions
// WARNING: Location pre-defined names can not be changed, they are used by default shaders and all raylib examples shaders, they are just listed here for reference
// WARNING: In case custom shader names are used, it's up to the user to set locations with GetShaderLocation*() functions
//#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION
//#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD
//#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL
@ -196,6 +198,7 @@
//#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES
//#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS
//#define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM
//#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
//#define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
//#define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
@ -203,6 +206,7 @@
//#define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))
//#define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (tint color, multiplied by texture color)
//#define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices
//#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0)
//#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
//#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
@ -240,6 +244,9 @@
#ifndef SUPPORT_FILEFORMAT_QOI
#define SUPPORT_FILEFORMAT_QOI 1
#endif
#ifndef SUPPORT_FILEFORMAT_PEP
#define SUPPORT_FILEFORMAT_PEP 0
#endif
#ifndef SUPPORT_FILEFORMAT_PSD
#define SUPPORT_FILEFORMAT_PSD 0 // Disabled by default
#endif

1328
src/external/pep.h vendored Normal file

File diff suppressed because it is too large Load diff

8
src/external/rlsw.h vendored
View file

@ -3924,7 +3924,6 @@ static void sw_immediate_set_color(const float color[4])
RLSW.primitive.color[2] = color[2];
RLSW.primitive.color[3] = color[3];
RLSW.primitive.hasColorAlpha |= (color[3] < 1.0f);
}
static void sw_immediate_set_texcoord(const float texcoord[2])
@ -3963,6 +3962,9 @@ static void sw_immediate_push_vertex(const float position[4])
for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.primitive.color[i];
for (int i = 0; i < 2; i++) vertex->texcoord[i] = RLSW.primitive.texcoord[i];
// Track whether any vertex in this primitive has alpha < 1.0
RLSW.primitive.hasColorAlpha |= (vertex->color[3] < 1.0f);
// Immediate rendering of the primitive if the required number is reached
if (RLSW.primitive.vertexCount == SW_PRIMITIVE_VERTEX_COUNT[RLSW.drawMode])
{
@ -4341,8 +4343,8 @@ void swScissor(int x, int y, int width, int height)
RLSW.scClipMin[0] = (2.0f*(float)RLSW.scMin[0]/(float)RLSW.vpSize[0]) - 1.0f;
RLSW.scClipMax[0] = (2.0f*(float)RLSW.scMax[0]/(float)RLSW.vpSize[0]) - 1.0f;
RLSW.scClipMax[1] = 1.0f - (2.0f*(float)RLSW.scMin[1]/(float)RLSW.vpSize[1]);
RLSW.scClipMin[1] = 1.0f - (2.0f*(float)RLSW.scMax[1]/(float)RLSW.vpSize[1]);
RLSW.scClipMin[1] = (2.0f*(float)RLSW.scMin[1]/(float)RLSW.vpSize[1]) - 1.0f;
RLSW.scClipMax[1] = (2.0f*(float)RLSW.scMax[1]/(float)RLSW.vpSize[1]) - 1.0f;
}
void swClearColor(float r, float g, float b, float a)

View file

@ -1020,7 +1020,12 @@ static int parseLine(Command *command, const char *p, unsigned int p_len,
int triangulate) {
char linebuf[4096];
const char *token;
assert(p_len < 4095);
// @raysan5:
// WARNING: If -DNDEBUG is set when compiling, assertions will not
// be present in the compiled binary, replacing by a runtime check
//assert(p_len < 4095);
if (p_len > 4095) return 0;
memcpy(linebuf, p, p_len);
linebuf[p_len] = '\0';
@ -1102,7 +1107,11 @@ static int parseLine(Command *command, const char *p, unsigned int p_len,
tinyobj_vertex_index_t i1;
tinyobj_vertex_index_t i2 = f[1];
assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
// @raysan5:
// WARNING: If -DNDEBUG is set when compiling, assertions will not
// be present in the compiled binary, replacing by a runtime check
//assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
if (3*num_f > TINYOBJ_MAX_FACES_PER_F_LINE) return 0;
for (k = 2; k < num_f; k++) {
i1 = i2;
@ -1119,7 +1128,13 @@ static int parseLine(Command *command, const char *p, unsigned int p_len,
} else {
unsigned int k = 0;
assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
// @raysan5:
// WARNING: If -DNDEBUG is set when compiling, assertions will not
// be present in the compiled binary, replacing by a runtime check
//assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
if (num_f > TINYOBJ_MAX_FACES_PER_F_LINE) return 0;
for (k = 0; k < num_f; k++) {
command->f[k] = f[k];
}

View file

@ -663,13 +663,22 @@ double GetTime(void)
}
// Open URL with default system browser (if available)
// NOTE: This function is only safe to use if the provided URL is safe
// A user could craft a malicious string performing another action
// Avoid calling this function with user input non-validated strings
// WARNING: This function is only safe to use if you control the URL given,
// a user could craft a malicious string to perform and undesired action
// NOTE: Some safety checks have been added to mitigate security issues
void OpenURL(const char *url)
{
// Security check to (partially) avoid malicious code
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
{
// Filter characters: ' and "
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
}
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
{
// Only allow URL starting with "http://" or "https://" protocols
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
}
else
{
JNIEnv *env = NULL;
@ -717,7 +726,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
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

View file

@ -151,7 +151,7 @@ static void CharCallback(GLFWwindow *window, unsigned int codepoint);
static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed
static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move
static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Scrolling Callback, runs on mouse wheel
static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area
static void CursorEnterCallback(GLFWwindow *window, int entered); // GLFW3 Cursor Enter Callback, cursor enters client area
static void JoystickCallback(int jid, int event); // GLFW3 Joystick Connected/Disconnected Callback
// Memory allocator wrappers [used by glfwInitAllocator()]
@ -1181,17 +1181,25 @@ 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
// WARNING: This function is only safe to use if you control the URL given,
// a user could craft a malicious string to perform and undesired action
// NOTE: Some safety checks have been added to mitigate security issues
void OpenURL(const char *url)
{
// Security check to (partially) avoid malicious code
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
{
// Filter characters: ' and "
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
}
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
{
// Only allow URL starting with "http://" or "https://" protocols
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
}
else
{
char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
char *cmd = (char *)RL_CALLOC(strlen(url) + 16, sizeof(char));
#if defined(_WIN32)
sprintf(cmd, "explorer \"%s\"", url);
#endif
@ -1201,7 +1209,9 @@ void OpenURL(const char *url)
#if defined(__APPLE__)
sprintf(cmd, "open '%s'", url);
#endif
// TODO: Replace system() call by custom process
int result = system(cmd);
if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
RL_FREE(cmd);
}
@ -1227,7 +1237,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
void SetMousePosition(int x, int y)
{
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
// NOTE: emscripten not implemented
glfwSetCursorPos(platform.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y);
@ -1316,7 +1325,7 @@ void PollInputEvents(void)
// Register previous gamepad states
for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
// Get current gamepad state
// Get current gamepad state using internal GLFW mapping, instead of the immediate joystick API
// NOTE: There is no callback available, getting it manually
GLFWgamepadstate state = { 0 };
int result = glfwGetGamepadState(i, &state); // This remaps all gamepads so they have their buttons mapped like an xbox controller
@ -1683,6 +1692,14 @@ int InitPlatform(void)
return -1;
}
#if defined(__APPLE__)
// AppKit can constrain the requested window size to the visible work area during creation
int windowWidth = 0;
int windowHeight = 0;
glfwGetWindowSize(platform.handle, &windowWidth, &windowHeight);
if ((windowWidth > 0) && (windowHeight > 0)) CORE.Window.screen = (Size){ windowWidth, windowHeight };
#endif
// NOTE: Not considering scale factor now, considered below
CORE.Window.render.width = CORE.Window.screen.width;
CORE.Window.render.height = CORE.Window.screen.height;
@ -1829,7 +1846,7 @@ int InitPlatform(void)
{
CORE.Input.Gamepad.ready[i] = true;
CORE.Input.Gamepad.axisCount[i] = GLFW_GAMEPAD_AXIS_LAST + 1;
strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
snprintf(CORE.Input.Gamepad.name[i], MAX_GAMEPAD_NAME_LENGTH, "%s", glfwGetJoystickName(i));
}
}
//----------------------------------------------------------------------------
@ -2044,7 +2061,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));
strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1);
snprintf(CORE.Window.dropFilepaths[i], MAX_FILEPATH_LENGTH, "%s", paths[i]);
}
}
}
@ -2167,10 +2184,18 @@ static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffs
}
// GLFW3: Cursor ennter callback, when cursor enters the window
static void CursorEnterCallback(GLFWwindow *window, int enter)
static void CursorEnterCallback(GLFWwindow *window, int entered)
{
if (enter) CORE.Input.Mouse.cursorOnScreen = true;
else CORE.Input.Mouse.cursorOnScreen = false;
if (entered)
{
// NOTE: Mouse position updated by MouseCursorPosCallback()
CORE.Input.Mouse.cursorOnScreen = true;
}
else
{
CORE.Input.Mouse.cursorOnScreen = false;
CORE.Input.Mouse.currentPosition = (Vector2){ 0 };
}
}
// GLFW3: Joystick connected/disconnected callback
@ -2183,7 +2208,7 @@ static void JoystickCallback(int jid, int event)
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
// only copy up to (MAX_GAMEPAD_NAME_LENGTH -1) to destination string
memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
snprintf(CORE.Input.Gamepad.name[jid], MAX_GAMEPAD_NAME_LENGTH, "%s", glfwGetJoystickName(jid));
}
else if (event == GLFW_DISCONNECTED)
{

View file

@ -486,14 +486,14 @@ static void RGFW_cb_dropfunc(const RGFW_event *e)
CORE.Window.dropFilepaths = (char **)RL_CALLOC(1024, sizeof(char *));
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], e->drop.value->data);
snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", e->drop.value->data);
CORE.Window.dropFileCount++;
}
else if (CORE.Window.dropFileCount < 1024)
{
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], e->drop.value->data);
snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", e->drop.value->data);
CORE.Window.dropFileCount++;
}
@ -1471,15 +1471,25 @@ 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
// WARNING: This function is only safe to use if you control the URL given,
// a user could craft a malicious string to perform and undesired action
// NOTE: Some safety checks have been added to mitigate security issues
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");
// Security check to (partially) avoid malicious code
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
{
// Filter characters: ' and "
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
}
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
{
// Only allow URL starting with "http://" or "https://" protocols
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
}
else
{
char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
char *cmd = (char *)RL_CALLOC(strlen(url) + 16, sizeof(char));
#if defined(_WIN32)
sprintf(cmd, "explorer \"%s\"", url);
#endif
@ -1516,7 +1526,6 @@ void SetMousePosition(int x, int y)
{
RGFW_window_moveMouse(platform.window, x, y);
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
}
// Set mouse cursor
@ -1609,9 +1618,12 @@ void PollInputEvents(void)
//-----------------------------------------------------------------------------
mg_event gamepad_event;
while (mg_gamepads_check_event(&platform.minigamepad, &gamepad_event)) {
while (mg_gamepads_check_event(&platform.minigamepad, &gamepad_event))
{
int gamepadIndex = gamepad_event.gamepad->index;
switch (gamepad_event.type) {
switch (gamepad_event.type)
{
case MG_EVENT_BUTTON_PRESS:
{
int button = mg_buttonConvertTable[gamepad_event.button];
@ -1639,10 +1651,12 @@ void PollInputEvents(void)
case GAMEPAD_AXIS_LEFT_Y:
case GAMEPAD_AXIS_RIGHT_X:
case GAMEPAD_AXIS_RIGHT_Y:
{
CORE.Input.Gamepad.axisState[gamepadIndex][axis] = platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value;
break;
} break;
case GAMEPAD_AXIS_LEFT_TRIGGER:
case GAMEPAD_AXIS_RIGHT_TRIGGER:
{
CORE.Input.Gamepad.axisState[gamepadIndex][axis] = platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value;
// Trigger button press when axis is all the way
@ -1652,31 +1666,28 @@ void PollInputEvents(void)
CORE.Input.Gamepad.currentButtonState[gamepadIndex][button] = pressed;
if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
break;
} break;
default: break;
}
} break;
case MG_EVENT_GAMEPAD_CONNECT:
{
CORE.Input.Gamepad.ready[gamepadIndex] = true;
CORE.Input.Gamepad.axisState[gamepadIndex][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
CORE.Input.Gamepad.axisState[gamepadIndex][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
int axisCount = 0;
for (int i = 0; i < MG_AXIS_COUNT; i += 1) {
if (platform.minigamepad.gamepads[gamepadIndex].axes[i].supported)
for (int i = 0; i < MG_AXIS_COUNT; i += 1)
{
axisCount += 1;
}
else
{
break;
}
if (platform.minigamepad.gamepads[gamepadIndex].axes[i].supported) axisCount += 1;
else break;
}
CORE.Input.Gamepad.axisCount[gamepadIndex] = axisCount;
strcpy(CORE.Input.Gamepad.name[gamepadIndex], platform.minigamepad.gamepads[gamepadIndex].name);
break;
case MG_EVENT_GAMEPAD_DISCONNECT:
CORE.Input.Gamepad.ready[gamepadIndex] = false;
break;
snprintf(CORE.Input.Gamepad.name[gamepadIndex], MAX_GAMEPAD_NAME_LENGTH, "%s", platform.minigamepad.gamepads[gamepadIndex].name);
} break;
case MG_EVENT_GAMEPAD_DISCONNECT: CORE.Input.Gamepad.ready[gamepadIndex] = false; break;
default: break;
}
}

View file

@ -863,7 +863,7 @@ void SetWindowMonitor(int monitor)
// ending up positioned partly outside the target display
// NOTE 2: The workaround for that is, previously to moving the window,
// setting the window size to the target display size, so they match
// NOTE 3: It wasn't done here because it can not bee assumed that changing
// NOTE 3: It wasn't done here because it can not be assumed that changing
// the window size automatically is acceptable behavior by the user
SDL_SetWindowPosition(platform.window, usableBounds.x, usableBounds.y);
CORE.Window.position.x = usableBounds.x;
@ -1255,12 +1255,14 @@ Image GetClipboardImage(void)
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, (int)dataSize);
SDL_free(fileData);
if (IsImageValid(image))
{
TRACELOG(LOG_INFO, "Clipboard: Got image from clipboard successfully: %s", imageExtensions[i]);
@ -1341,14 +1343,22 @@ double GetTime(void)
}
// Open URL with default system browser (if available)
// NOTE: This function is only safe to use if the provided URL is safe
// A user could craft a malicious string performing another action
// Avoid calling this function with user input non-validated strings
// REF: https://github.com/raysan5/raylib/issues/686
// WARNING: This function is only safe to use if you control the URL given,
// a user could craft a malicious string to perform and undesired action
// NOTE: Some safety checks have been added to mitigate security issues
void OpenURL(const char *url)
{
// Security check to (partially) avoid malicious code
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
{
// Filter characters: ' and "
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
}
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
{
// Only allow URL starting with "http://" or "https://" protocols
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
}
else SDL_OpenURL(url);
}
@ -1401,7 +1411,6 @@ void SetMousePosition(int x, int y)
SDL_WarpMouseInWindow(platform.window, x, y);
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
}
// Set mouse cursor
@ -1512,9 +1521,9 @@ void PollInputEvents(void)
// Event memory is now managed by SDL, so it should not be freed in SDL_EVENT_DROP_FILE,
// in case data needs to be hold onto the text in SDL_EVENT_TEXT_EDITING and SDL_EVENT_TEXT_INPUT events,
// a copy is required, 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);
snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", event.drop.data);
#else
strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file, MAX_FILEPATH_LENGTH - 1);
snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", event.drop.file);
SDL_free(event.drop.file);
#endif
@ -1525,9 +1534,9 @@ void PollInputEvents(void)
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
#if defined(USING_VERSION_SDL3)
strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data, MAX_FILEPATH_LENGTH - 1);
snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", event.drop.data);
#else
strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file, MAX_FILEPATH_LENGTH - 1);
snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", event.drop.file);
SDL_free(event.drop.file);
#endif
@ -1812,8 +1821,8 @@ void PollInputEvents(void)
CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
memset(CORE.Input.Gamepad.name[nextAvailableSlot], 0, MAX_GAMEPAD_NAME_LENGTH);
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);
if (controllerName != NULL) snprintf(CORE.Input.Gamepad.name[nextAvailableSlot], MAX_GAMEPAD_NAME_LENGTH, "%s", controllerName);
else memcpy(CORE.Input.Gamepad.name[nextAvailableSlot], "noname", 6);
}
else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
}
@ -2164,11 +2173,20 @@ int InitPlatform(void)
platform.gamepadId[i] = -1; // Set all gamepad initial instance ids as invalid to not conflict with instance id zero
}
#if defined(USING_VERSION_SDL3)
int numJoysticks;
SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks);
#else
int numJoysticks = SDL_NumJoysticks();
#endif
for (int i = 0; (i < numJoysticks) && (i < MAX_GAMEPADS); i++)
{
#if defined(USING_VERSION_SDL3)
platform.gamepad[i] = SDL_OpenGamepad(joysticks[i]);
#else
platform.gamepad[i] = SDL_GameControllerOpen(i);
#endif
platform.gamepadId[i] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[i]));
if (platform.gamepad[i])
@ -2177,7 +2195,12 @@ int InitPlatform(void)
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);
#if defined(USING_VERSION_SDL3)
const char *joystickName = SDL_GetJoystickNameForID(joysticks[i]);
#else
const char *joystickName = SDL_GameControllerNameForIndex(i);
#endif
snprintf(CORE.Input.Gamepad.name[i], MAX_GAMEPAD_NAME_LENGTH, "%s", joystickName);
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());

View file

@ -1247,19 +1247,28 @@ double GetTime(void)
}
// Open URL with default system browser (if available)
// NOTE: This function is only safe to use if the provided URL is safe
// A user could craft a malicious string performing another action
// Avoid calling this function with user input non-validated strings
// REF: https://github.com/raysan5/raylib/issues/686
// WARNING: This function is only safe to use if you control the URL given,
// a user could craft a malicious string to perform and undesired action
// NOTE: Some safety checks have been added to mitigate security issues
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");
// Security check to (partially) avoid malicious code
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
{
// Filter characters: ' and "
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
}
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
{
// Only allow URL starting with "http://" or "https://" protocols
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
}
else
{
int len = strlen(url) + 32;
int len = strlen(url) + 16;
char *cmd = (char *)RL_CALLOC(len, sizeof(char));
snprintf(cmd, len, "explorer \"%s\"", url);
int result = system(cmd);
if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
RL_FREE(cmd);
@ -1290,8 +1299,8 @@ void SetMousePosition(int x, int y)
if (!CORE.Input.Mouse.cursorLocked)
{
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
TRACELOG(LOG_WARNING, "SetMousePosition not implemented");
TRACELOG(LOG_WARNING, "SetMousePosition not implemented at platform level");
}
else TRACELOG(LOG_WARNING, "INPUT: MOUSE: Cursor not enabled");
}
@ -2213,7 +2222,7 @@ static unsigned SanitizeFlags(int mode, unsigned flags)
//
// This design takes care of many odd corner cases. For example, in case of restoring
// a window that was previously maximized AND minimized and those two flags need to be removed,
// ShowWindow with SW_RESTORE twice need to bee actually calleed. Another example is
// ShowWindow with SW_RESTORE twice need to be actually calleed. Another example is
// wheen having a maximized window, if the undecorated flag is modified then the window style
// needs to be updated, but updating the style would mean the window size would change
// causing the window to lose its Maximized state which would mean the window size

View file

@ -1014,9 +1014,8 @@ double GetTime(void)
}
// Open URL with default system browser (if available)
// NOTE: This function is only safe to use if the provided URL is safe
// A user could craft a malicious string performing another action
// Avoid calling this function with user input non-validated strings
// WARNING: This function is only safe to use if you control the URL given,
// a user could craft a malicious string to perform and undesired action
void OpenURL(const char *url)
{
TRACELOG(LOG_WARNING, "OpenURL() not implemented on target platform");
@ -1043,7 +1042,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
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
@ -1446,7 +1444,9 @@ int InitPlatform(void)
return -1;
}
if (!eglChooseConfig(platform.device, NULL, NULL, 0, &numConfigs))
// WARNING: Providing framebufferAttribs is not logically necessary,
// but it may prevent segfaults on some nvidia drivers
if (!eglChooseConfig(platform.device, framebufferAttribs, NULL, 0, &numConfigs))
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config count: 0x%x", eglGetError());
return -1;

View file

@ -420,7 +420,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
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

View file

@ -352,14 +352,22 @@ 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
// WARNING: This function is only safe to use if you control the URL given,
// a user could craft a malicious string to perform and undesired action
// NOTE: Some safety checks have been added to mitigate security issues
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");
// Security check to (partially) avoid malicious code
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
{
// Filter characters: ' and "
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
}
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
{
// Only allow URL starting with "http://" or "https://" protocols
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
}
else
{
// TODO: Load url using default browser
@ -387,7 +395,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
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

View file

@ -1047,7 +1047,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
void SetMousePosition(int x, int y)
{
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
if (CORE.Input.Mouse.cursorLocked) CORE.Input.Mouse.lockedPosition = CORE.Input.Mouse.currentPosition;
@ -1579,7 +1578,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));
strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1);
snprintf(CORE.Window.dropFilepaths[i], MAX_FILEPATH_LENGTH, "%s", paths[i]);
}
}
}

View file

@ -968,13 +968,22 @@ double GetTime(void)
}
// Open URL with default system browser (if available)
// NOTE: This function is only safe to use if the provided URL is safe
// A user could craft a malicious string performing another action
// Avoid calling this function with user input non-validated strings
// WARNING: This function is only safe to use if you control the URL given,
// a user could craft a malicious string to perform and undesired action
// NOTE: Some safety checks have been added to mitigate security issues
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");
// Security check to (partially) avoid malicious code
if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL))
{
// Filter characters: ' and "
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters");
}
else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0))
{
// Only allow URL starting with "http://" or "https://" protocols
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols");
}
else emscripten_run_script(TextFormat("window.open('%s', '_blank')", url));
}
@ -1439,7 +1448,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));
strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1);
snprintf(CORE.Window.dropFilepaths[i], MAX_FILEPATH_LENGTH, "%s", paths[i]);
}
}
}
@ -1498,8 +1507,16 @@ static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent
{
switch (eventType)
{
case EMSCRIPTEN_EVENT_MOUSEENTER: CORE.Input.Mouse.cursorOnScreen = true; break;
case EMSCRIPTEN_EVENT_MOUSELEAVE: CORE.Input.Mouse.cursorOnScreen = false; break;
case EMSCRIPTEN_EVENT_MOUSEENTER: {
// NOTE: Mouse position updated by EmscriptenMouseMoveCallback(),
// EmscriptenPointerlockCallback(), and EmscriptenTouchCallback()
CORE.Input.Mouse.cursorOnScreen = true;
} break;
case EMSCRIPTEN_EVENT_MOUSELEAVE:
{
CORE.Input.Mouse.cursorOnScreen = false;
CORE.Input.Mouse.currentPosition = (Vector2){ 0 };
} break;
case EMSCRIPTEN_EVENT_MOUSEDOWN:
{
// NOTE: Emscripten and raylib buttons indices are not aligned

View file

@ -822,7 +822,7 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
wave.sampleRate = wav.sampleRate;
wave.sampleSize = 16;
wave.channels = wav.channels;
wave.data = (short *)RL_MALLOC((size_t)wave.frameCount*wave.channels*sizeof(short));
wave.data = (short *)RL_CALLOC((size_t)wave.frameCount*wave.channels, sizeof(short));
// NOTE: Forcing conversion to 16bit sample size on reading
drwav_read_pcm_frames_s16(&wav, wave.frameCount, (drwav_int16 *)wave.data);
@ -845,7 +845,7 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
wave.sampleSize = 16; // By default, ogg data is 16 bit per sample (short)
wave.channels = info.channels;
wave.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples(oggData); // NOTE: It returns frames!
wave.data = (short *)RL_MALLOC(wave.frameCount*wave.channels*sizeof(short));
wave.data = (short *)RL_CALLOC(wave.frameCount*wave.channels, sizeof(short));
// NOTE: Get the number of samples to process (be careful! asking for number of shorts, not bytes!)
stb_vorbis_get_samples_short_interleaved(oggData, info.channels, (short *)wave.data, wave.frameCount*wave.channels);
@ -1154,7 +1154,7 @@ bool ExportWaveAsCode(Wave wave, const char *fileName)
// Get file name from path and convert variable name to uppercase
char varFileName[256] = { 0 };
strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1);
snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName)); // NOTE: Using function provided by [rcore] module
for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; }
// Add wave information
@ -1258,7 +1258,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
return;
}
void *data = RL_MALLOC(frameCount*channels*(sampleSize/8));
void *data = RL_CALLOC(frameCount*channels*(sampleSize/8), 1);
frameCount = (ma_uint32)ma_convert_frames(data, frameCount, formatOut, channels, sampleRate, wave->data, frameCountIn, formatIn, wave->channels, wave->sampleRate);
if (frameCount == 0)
@ -1772,7 +1772,7 @@ void UnloadMusicStream(Music music)
{
if (false) { }
#if SUPPORT_FILEFORMAT_WAV
else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData);
else if (music.ctxType == MUSIC_AUDIO_WAV) { drwav_uninit((drwav *)music.ctxData); RL_FREE(music.ctxData); }
#endif
#if SUPPORT_FILEFORMAT_OGG
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
@ -2827,7 +2827,7 @@ static const char *GetFileNameWithoutExt(const char *filePath)
static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH] = { 0 };
memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH);
if (filePath != NULL) strncpy(fileName, GetFileName(filePath), MAX_FILENAMEWITHOUTEXT_LENGTH - 1); // Get filename with extension
if (filePath != NULL) snprintf(fileName, MAX_FILENAMEWITHOUTEXT_LENGTH, "%s", GetFileName(filePath));
int fileNameLength = (int)strlen(fileName); // Get size in bytes

View file

@ -409,7 +409,7 @@ typedef struct BoneInfo {
// Skeleton, animation bones hierarchy
typedef struct ModelSkeleton {
int boneCount; // Number of bones
unsigned int boneCount; // Number of bones
BoneInfo *bones; // Bones information (skeleton)
ModelAnimPose bindPose; // Bones base transformation (Transform[])
} ModelSkeleton;
@ -436,7 +436,7 @@ typedef struct Model {
typedef struct ModelAnimation {
char name[32]; // Animation name
int boneCount; // Number of bones (per pose)
unsigned int boneCount; // Number of bones (per pose)
int keyframeCount; // Number of animation key frames
ModelAnimPose *keyframePoses; // Animation sequence keyframe poses [keyframe][pose]
} ModelAnimation;
@ -1154,13 +1154,15 @@ RLAPI long GetFileModTime(const char *fileName); // Get file
RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png')
RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string
RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string)
RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string)
RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string)
RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a provided fileName with path (uses static string)
RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a provided path (uses static string)
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 int ChangeDirectory(const char *dirPath); // Change working directory, returns 0 on success
RLAPI bool IsPathFile(const char *path); // Check if given path is a file or a directory
RLAPI bool IsPathFile(const char *path); // Check if provided path points to a file
RLAPI bool IsPathDirectory(const char *path); // Check if provided path points to a directory
RLAPI bool IsPathAbsolute(const char *path); // Check if provided path is an absolute path
RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS
RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths, files and directories, no subdirs scan
RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*'
@ -1239,7 +1241,7 @@ RLAPI void SetMouseCursor(int cursor); // Set mouse curso
RLAPI int GetTouchX(void); // Get touch position X for touch point 0 (relative to screen size)
RLAPI int GetTouchY(void); // Get touch position Y for touch point 0 (relative to screen size)
RLAPI Vector2 GetTouchPosition(int index); // Get touch position XY for a touch point index (relative to screen size)
RLAPI int GetTouchPointId(int index); // Get touch point identifier for given index
RLAPI int GetTouchPointId(int index); // Get touch point identifier for provided index
RLAPI int GetTouchPointCount(void); // Get number of touch points
//------------------------------------------------------------------------------------
@ -1326,7 +1328,7 @@ RLAPI void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vecto
RLAPI void DrawSplineSegmentBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float thick, Color color); // Draw spline segment: Quadratic Bezier, 2 points, 1 control point
RLAPI void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, Color color); // Draw spline segment: Cubic Bezier, 2 points, 2 control points
// Spline segment point evaluation functions, for a given t [0.0f .. 1.0f]
// Spline segment point evaluation functions, for a provided t [0.0f .. 1.0f]
RLAPI Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t); // Get (evaluate) spline point: Linear
RLAPI Vector2 GetSplinePointBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: B-Spline
RLAPI Vector2 GetSplinePointCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: Catmull-Rom
@ -1416,7 +1418,7 @@ RLAPI Color GetImageColor(Image image, int x, int y);
// Image drawing functions
// NOTE: Image software-rendering functions (CPU)
RLAPI void ImageClearBackground(Image *dst, Color color); // Clear image background with given color
RLAPI void ImageClearBackground(Image *dst, Color color); // Clear image background with provided color
RLAPI void ImageDrawPixel(Image *dst, int posX, int posY, Color color); // Draw pixel within an image
RLAPI void ImageDrawPixelV(Image *dst, Vector2 position, Color color); // Draw pixel within an image (Vector version)
RLAPI void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw line within an image
@ -1431,8 +1433,10 @@ RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCo
RLAPI void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color); // Draw rectangle within an image
RLAPI void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color); // Draw rectangle within an image (Vector version)
RLAPI void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image
RLAPI void ImageDrawRectanglePro(Image *dst, Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters within and image
RLAPI void ImageDrawRectangleLines(Image *dst, int posX, int posY, int width, int height, Color color); // Draw rectangle lines within an image
RLAPI void ImageDrawRectangleLinesEx(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image with line thickness
RLAPI void ImageDrawRectangleGradientEx(Image *dst, Rectangle rec, Color col1, Color col2, Color col3, Color col4); // Draw rectangle with gradient colors within an image, counter-clockwise color order
RLAPI void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color); // Draw a filled circle within an image
RLAPI void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color); // Draw a filled circle within an image (Vector version)
RLAPI void ImageDrawCircleLines(Image *dst, int centerX, int centerY, int radius, Color color); // Draw circle outline within an image
@ -1440,10 +1444,12 @@ RLAPI void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color c
RLAPI void ImageDrawCircleGradient(Image *dst, Vector2 center, float radius, Color inner, Color outer); // Draw a gradient-filled circle within an image
RLAPI void ImageDrawImage(Image *dst, Image src, int posX, int posY, Color tint); // Draw an image within an image
RLAPI void ImageDrawImageEx(Image *dst, Image src, Vector2 position, float rotation, float scale, Color tint); // Draw an image with scaling and rotation within an image
RLAPI void ImageDrawImageRec(Image *dst, Image src, Rectangle srcRec, Vector2 position, Color tint); // Draw a part of an image defined by a rectangle within an image
RLAPI void ImageDrawImagePro(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Vector2 origin, float rotation, Color tint); // Draw a part of an image defined by a rectangle into destination rectangle, with scaling and rotation, within an image
RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination)
RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination)
RLAPI void ImageDrawTextPro(Image *dst, Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); // Draw text using Font and pro parameters (rotation)
// Texture loading functions
// NOTE: These functions require GPU access

View file

@ -108,7 +108,7 @@
#include <stdlib.h> // Required for: srand(), rand(), exit()
#include <stdio.h> // Required for: FILE, fopen(), fseek(), ftell(), fread(), fwrite(), fprintf(), vprintf(), fclose(), sprintf() [Used in OpenURL()]
#include <string.h> // Required for: strlen(), strncpy(), strcmp(), strrchr(), memset(), strcat()
#include <string.h> // Required for: strlen(), strcmp(), strrchr(), memset(), memcpy(), strcat()
#include <stdarg.h> // Required for: va_list, va_start(), va_end() [Used in TraceLog()]
#ifndef PICO_RP2350
@ -1813,7 +1813,6 @@ void UnloadRandomSequence(int *sequence)
}
// Takes a screenshot of current screen
// NOTE: Provided fileName should not contain paths, saving to working directory
void TakeScreenshot(const char *fileName)
{
#if SUPPORT_MODULE_RTEXTURES
@ -1828,7 +1827,8 @@ void TakeScreenshot(const char *fileName)
Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
char path[MAX_FILEPATH_LENGTH] = { 0 };
strncpy(path, TextFormat("%s/%s", CORE.Storage.basePath, fileName), MAX_FILEPATH_LENGTH - 1);
if (!IsPathAbsolute(fileName)) snprintf(path, MAX_FILEPATH_LENGTH, "%s", TextFormat("%s/%s", CORE.Storage.basePath, fileName));
else snprintf(path, MAX_FILEPATH_LENGTH, "%s", fileName);
ExportImage(image, path); // WARNING: Module required: rtextures
RL_FREE(imgData);
@ -1853,8 +1853,6 @@ void SetConfigFlags(unsigned int flags)
FLAG_SET(CORE.Window.flags, flags);
}
// void OpenURL(const char *url); // Defined per platform
//----------------------------------------------------------------------------------
// Module Functions Definition: Logging system
//----------------------------------------------------------------------------------
@ -1894,12 +1892,12 @@ void TraceLog(int logType, const char *text, ...)
switch (logType)
{
case LOG_TRACE: strncpy(buffer, "TRACE: ", 8); break;
case LOG_DEBUG: strncpy(buffer, "DEBUG: ", 8); break;
case LOG_INFO: strncpy(buffer, "INFO: ", 7); break;
case LOG_WARNING: strncpy(buffer, "WARNING: ", 10); break;
case LOG_ERROR: strncpy(buffer, "ERROR: ", 8); break;
case LOG_FATAL: strncpy(buffer, "FATAL: ", 8); break;
case LOG_TRACE: memcpy(buffer, "TRACE: ", 7); break;
case LOG_DEBUG: memcpy(buffer, "DEBUG: ", 7); break;
case LOG_INFO: memcpy(buffer, "INFO: ", 6); break;
case LOG_WARNING: memcpy(buffer, "WARNING: ", 9); break;
case LOG_ERROR: memcpy(buffer, "ERROR: ", 7); break;
case LOG_FATAL: memcpy(buffer, "FATAL: ", 7); break;
default: break;
}
@ -2072,7 +2070,7 @@ bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileN
// Get file name from path
char varFileName[256] = { 0 };
strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1);
snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName));
for (int i = 0; varFileName[i] != '\0'; i++)
{
// Convert variable name to uppercase
@ -2516,7 +2514,7 @@ const char *GetFileNameWithoutExt(const char *filePath)
if (filePath != NULL)
{
strncpy(fileName, GetFileName(filePath), MAX_FILENAME_LENGTH - 1); // Get filename.ext without path
snprintf(fileName, MAX_FILENAME_LENGTH, "%s", GetFileName(filePath)); // Get filename.ext without path
int fileNameLength = (int)strlen(fileName); // Get size in bytes
for (int i = fileNameLength; i > 0; i--) // Reverse search '.'
@ -2533,7 +2531,7 @@ const char *GetFileNameWithoutExt(const char *filePath)
return fileName;
}
// Get directory for a given filePath
// Get directory for a provided filePath
const char *GetDirectoryPath(const char *filePath)
{
/*
@ -2570,7 +2568,6 @@ const char *GetDirectoryPath(const char *filePath)
}
else
{
// NOTE: Be careful, strncpy() is not safe, it does not care about '\0'
char *dirPathPtr = dirPath;
if ((filePath[1] != ':') && (filePath[0] != '\\') && (filePath[0] != '/')) dirPathPtr += 2; // Skip drive letter, "C:"
memcpy(dirPathPtr, filePath, strlen(filePath) - (strlen(lastSlash) - 1));
@ -2581,14 +2578,14 @@ const char *GetDirectoryPath(const char *filePath)
return dirPath;
}
// Get previous directory path for a given path
// Get previous directory path for a provided path
const char *GetPrevDirectoryPath(const char *dirPath)
{
static char prevDirPath[MAX_FILEPATH_LENGTH] = { 0 };
memset(prevDirPath, 0, MAX_FILEPATH_LENGTH);
int dirPathLength = (int)strlen(dirPath);
if (dirPathLength <= 3) strncpy(prevDirPath, dirPath, MAX_FILEPATH_LENGTH - 1);
if (dirPathLength <= 3) snprintf(prevDirPath, MAX_FILEPATH_LENGTH, "%s", dirPath);
for (int i = (dirPathLength - 1); (i >= 0) && (dirPathLength > 3); i--)
{
@ -2597,7 +2594,7 @@ const char *GetPrevDirectoryPath(const char *dirPath)
// Check for root: "C:\" or "/"
if (((i == 2) && (dirPath[1] ==':')) || (i == 0)) i++;
strncpy(prevDirPath, dirPath, i);
memcpy(prevDirPath, dirPath, i);
break;
}
}
@ -2831,13 +2828,49 @@ int ChangeDirectory(const char *dirPath)
return result;
}
// Check if given path point to a file
// Check if provided path point to a file
bool IsPathFile(const char *path)
{
struct stat result = { 0 };
stat(path, &result);
bool result = false;
return S_ISREG(result.st_mode);
struct stat info = { 0 };
stat(path, &info);
if (S_ISREG(info.st_mode)) result = true;
return result;
}
// Check if provided path point to a directory
bool IsPathDirectory(const char *path)
{
bool result = false;
if (!IsPathFile(path)) result = true;
return result;
}
// Check if provided path is an absolute path
bool IsPathAbsolute(const char *path)
{
int result = false;
if ((path != NULL) && (path[0] != '\0'))
{
#if defined(_WIN32)
// UNC path (\\server\share)
if ((path[0] == '\\') && (path[1] == '\\')) result = true;
// Drive letter (e.g. C:\ or D:/)
else if (isalpha((unsigned char)path[0]) && (path[1] == ':') &&
((path[2] == '\\') || (path[2] == '/'))) result = true;
#else
// POSIX: must start with /
if (path[0] == '/') result = true;
#endif
}
return result;
}
// Check if fileName is valid for the platform/OS
@ -3271,7 +3304,7 @@ unsigned int *ComputeMD5(const unsigned char *data, int dataSize)
memcpy(msg + newDataSize, &bitsLen, 4); // Append the len in bits at the end of the buffer
// Process the message in successive 512-bit chunks for each 512-bit chunk of message
for (int offset = 0; offset < newDataSize; offset += (512/8))
for (int offset = 0; offset < newDataSize; offset += 64) // 512/8
{
// Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15
unsigned int *w = (unsigned int *)(msg + offset);
@ -3368,16 +3401,16 @@ unsigned int *ComputeSHA1(const unsigned char *data, int dataSize)
msg[newDataSize - 8] = (unsigned char)(bitsLen >> 56);
// Process the message in successive 512-bit chunks
for (int offset = 0; offset < newDataSize; offset += (512/8))
for (int offset = 0; offset < newDataSize; offset += 64) // 512/8
{
// Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15
unsigned int w[80] = { 0 };
for (int i = 0; i < 16; i++)
{
w[i] = (msg[offset + (i*4) + 0] << 24) |
(msg[offset + (i*4) + 1] << 16) |
(msg[offset + (i*4) + 2] << 8) |
(msg[offset + (i*4) + 3]);
w[i] = ((unsigned int)msg[offset + (i*4) + 0] << 24) |
((unsigned int)msg[offset + (i*4) + 1] << 16) |
((unsigned int)msg[offset + (i*4) + 2] << 8) |
((unsigned int)msg[offset + (i*4) + 3]);
}
// Message schedule: extend the sixteen 32-bit words into eighty 32-bit words:
@ -3599,10 +3632,14 @@ AutomationEventList LoadAutomationEventList(const char *fileName)
case 'c': sscanf(buffer, "c %i", &list.count); break;
case 'e':
{
sscanf(buffer, "e %d %d %d %d %d %d %[^\n]s", &list.events[counter].frame, &list.events[counter].type,
if (counter < list.capacity)
{
sscanf(buffer, "e %d %d %d %d %d %d %63[^\n]s", &list.events[counter].frame, &list.events[counter].type,
&list.events[counter].params[0], &list.events[counter].params[1], &list.events[counter].params[2], &list.events[counter].params[3], eventDesc);
counter++;
}
else TRACELOG(LOG_WARNING, "AUTOMATION: Event goes beyond automated list capacity (MAX: %u): %s", list.capacity, buffer);
} break;
default: break;
}
@ -3935,7 +3972,7 @@ bool IsGamepadAvailable(int gamepad)
{
bool result = false;
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad]) result = true;
if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad]) result = true;
return result;
}
@ -3955,7 +3992,7 @@ bool IsGamepadButtonPressed(int gamepad, int button)
{
bool pressed = false;
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
{
if ((CORE.Input.Gamepad.previousButtonState[gamepad][button] == 0) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1)) pressed = true;
}
@ -3968,7 +4005,7 @@ bool IsGamepadButtonDown(int gamepad, int button)
{
bool down = false;
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
{
if (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1) down = true;
}
@ -3981,7 +4018,7 @@ bool IsGamepadButtonReleased(int gamepad, int button)
{
bool released = false;
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
{
if ((CORE.Input.Gamepad.previousButtonState[gamepad][button] == 1) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0)) released = true;
}
@ -3994,7 +4031,7 @@ bool IsGamepadButtonUp(int gamepad, int button)
{
bool up = false;
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS))
{
if (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0) up = true;
}
@ -4024,7 +4061,7 @@ float GetGamepadAxisMovement(int gamepad, int axis)
{
float value = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f;
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXES))
if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXES))
{
float movement = (value < 0.0f)? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]);
@ -4208,7 +4245,7 @@ Vector2 GetTouchPosition(int index)
return position;
}
// Get touch point identifier for given index
// Get touch point identifier for provided index
int GetTouchPointId(int index)
{
int id = -1;

View file

@ -56,8 +56,8 @@
* #define RL_CULL_DISTANCE_NEAR 0.05 // Default projection matrix near cull distance
* #define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance
*
* When loading a shader, the following vertex attributes and uniform
* location names are tried to be set automatically:
* When loading a shader, the following vertex attributes and uniform location names are tried to be set automatically:
* WARNING: Pre-defined names can not be changed, they are used by default shaders and all raylib examples shaders, they are just listed here for reference
*
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD
@ -67,6 +67,8 @@
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM
*
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
@ -74,6 +76,7 @@
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView)))
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color)
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices
*
* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0)
* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
@ -324,6 +327,7 @@
#define RL_DRAW_FRAMEBUFFER 0x8CA9 // GL_DRAW_FRAMEBUFFER
// Default shader vertex attribute locations
// NOTE: Locations can be redefined by user if required
#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
#endif
@ -906,6 +910,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
#include <stdlib.h> // Required for: calloc(), free()
#include <string.h> // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading]
#include <math.h> // Required for: sqrtf(), sinf(), cosf(), floor(), log()
#include <limits.h> // Required for: INT_MAX
//----------------------------------------------------------------------------------
// Defines and Macros
@ -993,65 +998,28 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
#endif
// Default shader vertex attribute names to set location points
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION
// WARNING: Pre-defined names can not be changed, they are used by default shaders and all raylib examples shaders, they are just listed here for reference
#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL
#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR
#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES
#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS
#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM
#define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM
#endif
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MVP
#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
#endif
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW
#define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
#endif
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION
#define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
#endif
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL
#define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix
#endif
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL
#define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))
#endif
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR
#define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color)
#endif
#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0)
#endif
#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
#endif
#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
#endif
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES
#define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices (required for GPU skinning)
#endif
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0)
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
//----------------------------------------------------------------------------------
// Module Types and Structures Definition
@ -2502,7 +2470,7 @@ void rlLoadExtensions(void *loader)
// NOTE: String duplication rquired because glGetString() returns a const string
int extensionsLength = (int)strlen(extensions); // Get extensions string size in bytes
char *extensionsDup = (char *)RL_CALLOC(extensionsLength + 1, sizeof(char)); // Allocate space for copy with additional EOL byte
strncpy(extensionsDup, extensions, extensionsLength);
snprintf(extensionsDup, extensionsLength, "%s", extensions);
extList[numExt] = extensionsDup;
for (int i = 0; i < extensionsLength; i++)
@ -3022,7 +2990,7 @@ void rlDrawRenderBatch(rlRenderBatch *batch)
// NOTE: glMapBuffer() causes sync issue
// If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job
// To avoid waiting (idle), glBufferData() can bee called first with NULL pointer before glMapBuffer()
// To avoid waiting (idle), glBufferData() can be called first with NULL pointer before glMapBuffer()
// Doing that, the previous data in PBO will be discarded and glMapBuffer() returns a new
// allocated pointer immediately even if GPU is still working with the previous data
@ -3825,6 +3793,10 @@ unsigned char *rlReadScreenPixels(int width, int height)
{
unsigned char *imgData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char));
// NOTE: Buffer retrieved is GL_FRONT in single-buffered configurations
// and GL_BACK in double-buffered configurations, make sure to call it at the end of frame
//glReadBuffer(GL_BACK);
// NOTE: glReadPixels() returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer
// WARNING: Getting alpha channel! Be careful, it can be transparent if not cleared properly!
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, imgData);
@ -5269,7 +5241,9 @@ static int rlGetPixelDataSize(int width, int height, int format)
{
int blockWidth = (width + 3)/4;
int blockHeight = (height + 3)/4;
dataSize = blockWidth*blockHeight*8;
unsigned long long dataSizeBytes = (unsigned long long)blockWidth*blockHeight*8;
if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes;
} break;
case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA:
case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA:
@ -5278,13 +5252,17 @@ static int rlGetPixelDataSize(int width, int height, int format)
{
int blockWidth = (width + 3)/4;
int blockHeight = (height + 3)/4;
dataSize = blockWidth*blockHeight*16;
unsigned long long dataSizeBytes = (unsigned long long)blockWidth*blockHeight*16;
if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes;
} break;
case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: // 4 bytes per each 4x4 block
{
int blockWidth = (width + 3)/4;
int blockHeight = (height + 3)/4;
dataSize = blockWidth*blockHeight*4;
unsigned long long dataSizeBytes = (unsigned long long)blockWidth*blockHeight*4;
if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes;
} break;
default: break;
}
@ -5293,10 +5271,12 @@ static int rlGetPixelDataSize(int width, int height, int format)
if ((format >= RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) &&
(format <= RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16))
{
double bytesPerPixel = (double)bpp/8.0;
dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes
unsigned long long dataSizeBytes = ((unsigned long long)width*height*bpp) >> 3; // Get size in bytes (dividing by 8)
if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes;
}
if (dataSize == 0) TRACELOG(LOG_WARNING, "Requested image size is larger than 2GB, it can not be allocated");
return dataSize;
}

View file

@ -50,9 +50,9 @@
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
#include "raymath.h" // Required for: Vector3, Quaternion and Matrix functionality
#include <stdio.h> // Required for: sprintf()
#include <stdio.h> // Required for: sprintf(), snprintf()
#include <stdlib.h> // Required for: malloc(), calloc(), free()
#include <string.h> // Required for: memcmp(), strlen(), strncpy()
#include <string.h> // Required for: strlen(), memcmp()
#include <math.h> // Required for: sinf(), cosf(), sqrtf(), fabsf()
#if SUPPORT_FILEFORMAT_OBJ || SUPPORT_FILEFORMAT_MTL
@ -2073,7 +2073,7 @@ bool ExportMeshAsCode(Mesh mesh, const char *fileName)
// Get file name from path and convert variable name to uppercase
char varFileName[256] = { 0 };
strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); // NOTE: Using function provided by [rcore] module
snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName)); // NOTE: Using function provided by [rcore] module
for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
// Add image information
@ -2320,7 +2320,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, float frame)
Matrix currentPoseMatrix = { 0 };
// Update all bones and bone matrices of model
for (int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++)
for (unsigned int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++)
{
// Compute interpolated pose between current and next frame
// NOTE: Storing animation frame data in model.currentPose
@ -2390,7 +2390,7 @@ void UpdateModelAnimationEx(Model model, ModelAnimation animA, float frameA, Mod
Matrix bindPoseMatrix = { 0 };
Matrix currentPoseMatrix = { 0 };
for (int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++)
for (unsigned int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++)
{
// Get frame-interpolation for first animation
Vector3 frameATranslation = Vector3Lerp(
@ -4421,7 +4421,7 @@ static Model LoadOBJ(const char *fileName)
}
char currentDir[MAX_FILEPATH_LENGTH] = { 0 };
strncpy(currentDir, GetWorkingDirectory(), MAX_FILEPATH_LENGTH - 1); // Save current working directory
snprintf(currentDir, MAX_FILEPATH_LENGTH, "%s", GetWorkingDirectory()); // Save current working directory
const char *workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness
if (CHDIR(workingDir) != 0) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir);
@ -5013,7 +5013,7 @@ static Model LoadIQM(const char *fileName)
// Initialize runtime animation data: current pose and bone matrices
model.currentPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
model.boneMatrices = (Matrix *)RL_CALLOC(model.skeleton.boneCount, sizeof(Matrix));
for (int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
for (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
UnloadFileData(fileData);
@ -5241,7 +5241,7 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou
// Build frameposes
for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
{
for (int i = 0; i < animations[a].boneCount; i++)
for (unsigned int i = 0; i < animations[a].boneCount; i++)
{
if (bones[i].parent >= 0)
{
@ -5317,7 +5317,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
int base64Size = (int)strlen(cgltfImage->uri + i + 1);
while (cgltfImage->uri[i + base64Size] == '=') base64Size--; // Ignore optional paddings
int numberOfEncodedBits = base64Size*6 - (base64Size*6)%8; // Encoded bits minus extra bits, so it becomes a multiple of 8 bits
int outSize = numberOfEncodedBits/8 ; // Actual encoded bytes
int outSize = numberOfEncodedBits >> 3; // Actual encoded bytes
void *data = NULL;
cgltf_options options = { 0 };
@ -5369,15 +5369,15 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
}
// Load bone info from GLTF skin data
static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount)
static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, unsigned int *boneCount)
{
*boneCount = (int)skin.joints_count;
*boneCount = (unsigned int)skin.joints_count;
BoneInfo *bones = (BoneInfo *)RL_CALLOC(skin.joints_count, sizeof(BoneInfo));
for (unsigned int i = 0; i < skin.joints_count; i++)
{
cgltf_node node = *skin.joints[i];
if (node.name != NULL) strncpy(bones[i].name, node.name, sizeof(bones[i].name) - 1);
if (node.name != NULL) snprintf(bones[i].name, sizeof(bones[i].name), "%s", node.name);
// Find parent bone index by walking up the node tree past any
// non-joint ancestors (intermediate transform nodes used by some
@ -6144,7 +6144,7 @@ static Model LoadGLTF(const char *fileName)
model.skeleton.bones = LoadBoneInfoGLTF(skin, &model.skeleton.boneCount);
model.skeleton.bindPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
for (int i = 0; i < model.skeleton.boneCount; i++)
for (unsigned int i = 0; i < model.skeleton.boneCount; i++)
{
Matrix bindMatrix = { 0 };
cgltf_float inverseBindTransform[16] = { 0 };
@ -6309,7 +6309,7 @@ static Model LoadGLTF(const char *fileName)
if ((data->skins_count > 0) && !hasJoints && (node->parent != NULL) && (node->parent->mesh == NULL))
{
int parentBoneId = -1;
for (int joint = 0; joint < model.skeleton.boneCount; joint++)
for (unsigned int joint = 0; joint < model.skeleton.boneCount; joint++)
{
if (data->skins[0].joints[joint] == node->parent)
{
@ -6347,7 +6347,7 @@ static Model LoadGLTF(const char *fileName)
// Initialize runtime animation data: current pose and bone matrices
model.currentPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
model.boneMatrices = (Matrix *)RL_CALLOC(model.skeleton.boneCount, sizeof(Matrix));
for (int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
for (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
//----------------------------------------------------------------------------------------------------
// Free unused allocated memory in case of no bones defined
@ -6660,7 +6660,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
animDuration = (time > animDuration)? time : animDuration;
}
if (animData.name != NULL) strncpy(animations[a].name, animData.name, sizeof(animations[a].name) - 1);
if (animData.name != NULL) snprintf(animations[a].name, sizeof(animations[a].name), "%s", animData.name);
animations[a].keyframeCount = (int)(animDuration*GLTF_FRAMERATE) + 1;
animations[a].keyframePoses = (Transform **)RL_CALLOC(animations[a].keyframeCount, sizeof(Transform *));
@ -6670,7 +6670,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
animations[a].keyframePoses[j] = (Transform *)RL_CALLOC(animations[a].boneCount, sizeof(Transform));
float time = (float)j / GLTF_FRAMERATE;
for (int k = 0; k < animations[a].boneCount; k++)
for (unsigned int k = 0; k < animations[a].boneCount; k++)
{
Vector3 translation = {skin.joints[k]->translation[0], skin.joints[k]->translation[1], skin.joints[k]->translation[2]};
Quaternion rotation = {skin.joints[k]->rotation[0], skin.joints[k]->rotation[1], skin.joints[k]->rotation[2], skin.joints[k]->rotation[3]};
@ -7150,7 +7150,7 @@ static Model LoadM3D(const char *fileName)
for (i = 0; i < (int)m3d->numbone; i++)
{
model.skeleton.bones[i].parent = m3d->bone[i].parent;
strncpy(model.skeleton.bones[i].name, m3d->bone[i].name, sizeof(model.skeleton.bones[i].name) - 1);
snprintf(model.skeleton.bones[i].name, sizeof(model.skeleton.bones[i].name), "%s", m3d->bone[i].name);
model.skeleton.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x*m3d->scale;
model.skeleton.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y*m3d->scale;
model.skeleton.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z*m3d->scale;
@ -7204,7 +7204,7 @@ static Model LoadM3D(const char *fileName)
// Initialize runtime animation data: current pose and bone matrices
model.currentPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
model.boneMatrices = (Matrix *)RL_CALLOC(model.skeleton.boneCount, sizeof(Matrix));
for (int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
for (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
}
m3d_free(m3d);
@ -7258,14 +7258,14 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou
animations[a].keyframeCount = m3d->action[a].durationmsec/M3D_ANIMDELAY;
animations[a].keyframePoses = (Transform **)RL_CALLOC(animations[a].keyframeCount, sizeof(Transform *));
strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name) - 1);
snprintf(animations[a].name, sizeof(animations[a].name), "%s", m3d->action[a].name);
TRACELOG(LOG_INFO, "MODEL: [%s] Loaded animation: %s | Frames: %d | Duration: %fs", fileName, animations[a].name, animations[a].keyframeCount, m3d->action[a].durationmsec);
for (i = 0; i < (int)m3d->numbone; i++)
{
bones[i].parent = m3d->bone[i].parent;
strncpy(bones[i].name, m3d->bone[i].name, sizeof(bones[i].name) - 1);
snprintf(bones[i].name, sizeof(bones[i].name), "%s", m3d->bone[i].name);
}
// A special, never transformed "no bone" bone, used for boneless vertices

View file

@ -888,14 +888,13 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
// Draw rectangle with rounded edges
void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color)
{
// NOTE: For line thicknes <=1.0f using RL_LINES, otherwise using RL_QUADS/RL_TRIANGLES
DrawRectangleRoundedLinesEx(rec, roundness, segments, 1.0f, color);
}
// Draw rectangle with rounded edges outline with line thickness
void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float thick, Color color)
{
if (thick < 0) thick = 0;
if (thick <= 0) return;
// Not a rounded rectangle
if (roundness <= 0.0f)
@ -966,8 +965,6 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f
const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f };
if (thick > 1)
{
#if SUPPORT_QUADS_DRAW_MODE
rlSetTexture(GetShapesTexture().id);
Rectangle shapeRect = GetShapesTextureRectangle();
@ -1108,35 +1105,6 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f
rlEnd();
#endif
}
else
{
// Use LINES to draw the outline
rlBegin(RL_LINES);
// Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
{
float angle = angles[k];
const Vector2 center = centers[k];
for (int i = 0; i < segments; i++)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius);
rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius);
angle += stepLength;
}
}
// And now the remaining 4 lines
for (int i = 0; i < 8; i += 2)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(point[i].x, point[i].y);
rlVertex2f(point[i + 1].x, point[i + 1].y);
}
rlEnd();
}
}
// Draw a polygon of n sides
void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color)

View file

@ -58,8 +58,8 @@
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 -> Only DrawTextPro()
#include <stdlib.h> // Required for: malloc(), free()
#include <stdio.h> // Required for: vsprintf()
#include <string.h> // Required for: strcmp(), strstr(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()]
#include <stdio.h> // Required for: vsprintf(), snprintf()
#include <string.h> // Required for: strcmp(), strstr(), strncpy(), sscanf() [Used in LoadBMFont()]
#include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
#include <ctype.h> // Required for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
@ -536,7 +536,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
Font font = { 0 };
char fileExtLower[16] = { 0 };
strncpy(fileExtLower, TextToLower(fileType), 16 - 1);
snprintf(fileExtLower, 16, "%s", TextToLower(fileType));
font.baseSize = fontSize;
font.glyphPadding = 0;
@ -1030,7 +1030,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
// Get file name from path
char fileNamePascal[256] = { 0 };
strncpy(fileNamePascal, TextToPascal(GetFileNameWithoutExt(fileName)), 256 - 1);
snprintf(fileNamePascal, 256, "%s", TextToPascal(GetFileNameWithoutExt(fileName)));
// Get font atlas image and size, required to estimate code file size
// NOTE: This mechanism is highly coupled to raylib
@ -1532,7 +1532,7 @@ char **LoadTextLines(const char *text, int *count)
if ((text[i] == '\n') || (text[i] == '\0'))
{
lines[l] = (char *)RL_CALLOC(lineLen + 1, 1);
strncpy(lines[l], &text[i - lineLen], lineLen);
memcpy(lines[l], &text[i - lineLen], lineLen);
lineLen = 0;
l++;
}
@ -1699,7 +1699,7 @@ const char *TextSubtext(const char *text, int position, int length)
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
if (text != NULL)
if ((text != NULL) && (position >= 0) && (length > 0))
{
int textLength = TextLength(text);
@ -1755,8 +1755,8 @@ char *GetTextBetween(const char *text, const char *begin, const char *end)
{
endIndex += (beginIndex + beginLen);
int len = (endIndex - beginIndex - beginLen);
if (len < (MAX_TEXT_BUFFER_LENGTH - 1)) strncpy(buffer, text + beginIndex + beginLen, len);
else strncpy(buffer, text + beginIndex + beginLen, MAX_TEXT_BUFFER_LENGTH - 1);
if (len < (MAX_TEXT_BUFFER_LENGTH - 1)) memcpy(buffer, text + beginIndex + beginLen, len);
else snprintf(buffer, MAX_TEXT_BUFFER_LENGTH, "%s", text + beginIndex + beginLen);
}
}
@ -1764,7 +1764,7 @@ char *GetTextBetween(const char *text, const char *begin, const char *end)
}
// Replace text string
// REQUIRES: strstr(), strncpy()
// REQUIRES: strstr(), memcpy()
// NOTE: Limited text replace functionality, using static string
char *TextReplace(const char *text, const char *search, const char *replacement)
{
@ -1821,7 +1821,7 @@ char *TextReplace(const char *text, const char *search, const char *replacement)
// Copy remaind text part after replacement to result (pointed by moving temp)
// NOTE: Text pointer internal copy has been updated along the process
strncpy(tempPtr, text, TextLength(text));
memcpy(tempPtr, text, TextLength(text));
}
else TRACELOG(LOG_WARNING, "Text with replacement is longer than internal buffer, use TextReplaceAlloc()");
}
@ -1830,7 +1830,7 @@ char *TextReplace(const char *text, const char *search, const char *replacement)
}
// Replace text string
// REQUIRES: strstr(), strncpy()
// REQUIRES: strstr(), memcpy()
// WARNING: Allocated memory must be manually freed
char *TextReplaceAlloc(const char *text, const char *search, const char *replacement)
{
@ -1887,7 +1887,7 @@ char *TextReplaceAlloc(const char *text, const char *search, const char *replace
// Copy remaind text part after replacement to result (pointed by moving temp)
// NOTE: Text pointer internal copy has been updated along the process
strncpy(temp, text, TextLength(text));
memcpy(temp, text, TextLength(text));
}
}
@ -1975,10 +1975,11 @@ char *TextInsert(const char *text, const char *insert, int position)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
if ((text != NULL) && (insert != NULL))
{
int textLen = TextLength(text);
if ((text != NULL) && (insert != NULL) && (position >= 0))
{
if (position > textLen) position = textLen; // End of text string
int insertLen = TextLength(insert);
if ((textLen + insertLen) < (MAX_TEXT_BUFFER_LENGTH - 1))
@ -1987,7 +1988,7 @@ char *TextInsert(const char *text, const char *insert, int position)
for (int i = 0; i < position; i++) buffer[i] = text[i];
for (int i = position; i < insertLen + position; i++) buffer[i] = insert[i - position];
for (int i = (insertLen + position); i < (textLen + insertLen); i++) buffer[i] = text[i];
for (int i = (insertLen + position); i < (textLen + insertLen); i++) buffer[i] = text[i - insertLen];
buffer[textLen + insertLen] = '\0'; // Add EOL
}
@ -2002,17 +2003,18 @@ char *TextInsert(const char *text, const char *insert, int position)
char *TextInsertAlloc(const char *text, const char *insert, int position)
{
char *result = NULL;
if ((text != NULL) && (insert != NULL))
{
int textLen = TextLength(text);
if ((text != NULL) && (insert != NULL) && (position >= 0))
{
if (position > textLen) position = textLen; // End of text string
int insertLen = TextLength(insert);
result = (char *)RL_MALLOC(textLen + insertLen + 1);
for (int i = 0; i < position; i++) result[i] = text[i];
for (int i = position; i < insertLen + position; i++) result[i] = insert[i - position];
for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i];
for (int i = position; i < (insertLen + position); i++) result[i] = insert[i - position];
for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i - insertLen];
result[textLen + insertLen] = '\0'; // Add EOL
}
@ -2036,7 +2038,7 @@ char *TextJoin(char **textList, int count, const char *delimiter)
int textLength = TextLength(textList[i]);
// Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
if ((totalLength + textLength) < MAX_TEXT_BUFFER_LENGTH)
if ((totalLength + textLength + delimiterLen) < MAX_TEXT_BUFFER_LENGTH)
{
memcpy(textPtr, textList[i], textLength);
totalLength += textLength;
@ -2200,18 +2202,43 @@ char *TextToSnake(const char *text)
if (text != NULL)
{
// Check for next separator to upper case another character
for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++, j++)
for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); j++)
{
if ((text[j] >= 'A') && (text[j] <= 'Z'))
if (text[j] == ' ')
{
if (i >= 1)
if ((i > 0) && (buffer[i - 1] != '_'))
{
buffer[i] = '_';
i++;
}
buffer[i] = text[j] + 32;
}
else buffer[i] = text[j];
else if ((text[j] >= 'A') && (text[j] <= 'Z'))
{
if ((i > 0) && (buffer[i - 1] != '_'))
{
char prev = text[j - 1];
char next = text[j + 1];
// Considering multiple cap leters to be on single word (HTTPRequest --> http_request)
if (((prev >= 'a') && (prev <= 'z')) ||
(((prev >= 'A') && (prev <= 'Z')) && ((next >= 'a') && (next <= 'z'))))
{
if (i < MAX_TEXT_BUFFER_LENGTH - 2)
{
buffer[i] = '_';
i++;
}
}
}
buffer[i] = text[j] + 32;
i++;
}
else
{
buffer[i] = text[j];
i++;
}
}
}

View file

@ -12,6 +12,7 @@
* #define SUPPORT_FILEFORMAT_JPG 0
* #define SUPPORT_FILEFORMAT_GIF 1
* #define SUPPORT_FILEFORMAT_QOI 1
* #define SUPPORT_FILEFORMAT_PEP 1
* #define SUPPORT_FILEFORMAT_PSD 0
* #define SUPPORT_FILEFORMAT_HDR 0
* #define SUPPORT_FILEFORMAT_PIC 0
@ -69,6 +70,7 @@
#include <string.h> // Required for: strlen() [Used in ImageTextEx()], strcmp() [Used in LoadImageFromMemory()/LoadImageAnimFromMemory()/ExportImageToMemory()]
#include <math.h> // Required for: fabsf() [Used in DrawTextureRec()]
#include <stdio.h> // Required for: sprintf() [Used in ExportImageAsCode()]
#include <limits.h> // Required for: INT_MAX
// Support only desired texture formats on stb_image
#if !SUPPORT_FILEFORMAT_BMP
@ -188,7 +190,15 @@
#if defined(_MSC_VER)
#pragma warning(pop) // Disable MSVC warning suppression
#endif
#endif
#if SUPPORT_FILEFORMAT_PEP
#define PEP_MALLOC RL_MALLOC
#define PEP_REALLOC RL_REALLOC
#define PEP_FREE RL_FREE
#define PEP_IMPLEMENTATION
#include "external/pep.h"
#endif
#if SUPPORT_IMAGE_EXPORT
@ -510,6 +520,31 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i
}
}
#endif
#if SUPPORT_FILEFORMAT_PEP
else if ((strcmp(fileType, ".pep") == 0) || (strcmp(fileType, ".PEP") == 0))
{
if (fileData != NULL)
{
// Deserialize file data into pep structure
pep p = pep_deserialize(fileData, dataSize);
// Decompress pep data for image struct
// Decompression options:
// - First color transparent, 3rd parameter: 1
// - Premultiply alpha on loading, 4th parameter: 1
unsigned int *pepData = pep_decompress(&p, pep_rgba, 1, 1);
image.data = pepData;
image.width = p.width;
image.height = p.height;
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
image.mipmaps = 1;
PEP_FREE(pepData);
pep_free(&p);
}
}
#endif
#if SUPPORT_FILEFORMAT_DDS
else if ((strcmp(fileType, ".dds") == 0) || (strcmp(fileType, ".DDS") == 0))
{
@ -681,6 +716,25 @@ bool ExportImage(Image image, const char *fileName)
}
}
#endif
#if SUPPORT_FILEFORMAT_PEP
else if (IsFileExtension(fileName, ".pep"))
{
if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
{
// NOTE: Only RGBA 32bit (8bit per channel) image format supported
pep p = pep_compress(image.data, image.width, image.height, pep_rgba, pep_8bit);
unsigned int pepDataSize = 0;
unsigned char *pepData = pep_serialize(&p, &pepDataSize);
result = SaveFileData(fileName, pepData, pepDataSize);
PEP_FREE(pepData);
pep_free(&p);
}
else TRACELOG(LOG_WARNING, "IMAGE: Image can not be exported, .pep requires RGBA 32bit input");
}
#endif
#if SUPPORT_FILEFORMAT_KTX
else if (IsFileExtension(fileName, ".ktx"))
{
@ -760,7 +814,7 @@ bool ExportImageAsCode(Image image, const char *fileName)
// Get file name from path and convert variable name to uppercase
char varFileName[256] = { 0 };
strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); // NOTE: Using function provided by [rcore] module
snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName)); // NOTE: Using function provided by [rcore] module
for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
// Add image information
@ -790,9 +844,10 @@ bool ExportImageAsCode(Image image, const char *fileName)
// Generate image: plain color
Image GenImageColor(int width, int height, Color color)
{
Color *pixels = (Color *)RL_CALLOC(width*height, sizeof(Color));
int dataSize = GetPixelDataSize(width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
Color *pixels = (Color *)RL_CALLOC(dataSize, 1);
for (int i = 0; i < width*height; i++) pixels[i] = color;
for (int i = 0; (pixels != NULL) && (i < width*height); i++) pixels[i] = color;
Image image = {
.data = pixels,
@ -1175,6 +1230,16 @@ Image ImageFromImage(Image image, Rectangle rec)
{
Image result = { 0 };
// Security check to avoid program crash
if ((image.data == NULL) || (image.width == 0) || (image.height == 0)) return result;
if (image.format < PIXELFORMAT_COMPRESSED_DXT1_RGB)
{
// Basic rectangle validation: size smaller than image size
if ((rec.x >= 0) && (rec.y >= 0) && (rec.width > 0) && (rec.height > 0) &&
(((int)rec.x + (int)rec.width) <= image.width) &&
(((int)rec.y + (int)rec.height) <= image.height))
{
int bytesPerPixel = GetPixelDataSize(1, 1, image.format);
result.width = (int)rec.width;
@ -1185,8 +1250,14 @@ Image ImageFromImage(Image image, Rectangle rec)
for (int y = 0; y < (int)rec.height; y++)
{
memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, ((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel, (int)rec.width*bytesPerPixel);
memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel,
((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel,
(int)rec.width*bytesPerPixel);
}
}
else TRACELOG(LOG_WARNING, "IMAGE: ImageToImage(), rectangle provided not valid");
}
else TRACELOG(LOG_WARNING, "IMAGE: Image manipulation not supported for compressed formats");
return result;
}
@ -2631,9 +2702,12 @@ void ImageRotate(Image *image, int degrees)
int width = (int)(fabsf(image->width*cosRadius) + fabsf(image->height*sinRadius));
int height = (int)(fabsf(image->height*cosRadius) + fabsf(image->width*sinRadius));
int dataSize = GetPixelDataSize(width, height, image->format);
int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
unsigned char *rotatedData = (unsigned char *)RL_CALLOC(width*height, bytesPerPixel);
unsigned char *rotatedData = (unsigned char *)RL_CALLOC(dataSize, 1);
if (rotatedData != NULL)
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
@ -2672,6 +2746,7 @@ void ImageRotate(Image *image, int degrees)
image->height = height;
}
}
}
// Rotate image clockwise 90deg
void ImageRotateCW(Image *image)
@ -3865,10 +3940,16 @@ void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color)
}
}
// Draw a color-filled rectangle with pro parameters within and image
void ImageDrawRectanglePro(Image *dst, Rectangle rec, Vector2 origin, float rotation, Color color)
{
// TODO: NEW: Implement ImageDrawRectanglePro()
}
// Draw rectangle lines within an image
void ImageDrawRectangleLines(Image *dst, int posX, int posY, int width, int height, Color color)
{
Rectangle rec = { posX, posY, width, height };
Rectangle rec = { (float)posX, (float)posY, (float)width, (float)height };
ImageDrawRectangleLinesEx(dst, rec, 1, color);
}
@ -3881,6 +3962,12 @@ void ImageDrawRectangleLinesEx(Image *dst, Rectangle rec, int thick, Color color
ImageDrawRectangle(dst, (int)rec.x, (int)(rec.y + rec.height - thick), (int)rec.width, thick, color);
}
// Draw rectangle with gradient colors within an image, counter-clockwise color order
void ImageDrawRectangleGradientEx(Image *dst, Rectangle rec, Color col1, Color col2, Color col3, Color col4)
{
// TODO: NEW: Implement ImageDrawRectangleGradientEx()
}
// Draw circle within an image
void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color)
{
@ -3948,17 +4035,23 @@ void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color color)
// Draw a gradient-filled circle within an image
void ImageDrawCircleGradient(Image *dst, Vector2 center, float radius, Color inner, Color outer)
{
// TODO: Implement gradient circle drawing
// TODO: NEW: Implement ImageDrawCircleGradient()
}
// Draw an image within an image
void ImageDrawImage(Image *dst, Image src, int posX, int posY, Color tint)
{
Rectangle srcRec = { 0, 0, src.width, src.height };
Rectangle dstRec = { posX, posY, srcRec.width, srcRec.height };
Rectangle srcRec = { 0.0f, 0.0f, (float)src.width, (float)src.height };
Rectangle dstRec = { (float)posX, (float)posY, srcRec.width, srcRec.height };
ImageDrawImagePro(dst, src, srcRec, dstRec, (Vector2){ 0 }, 0.0f, tint);
}
// Draw an image with scaling and rotation within an image
void ImageDrawImageEx(Image *dst, Image src, Vector2 position, float rotation, float scale, Color tint)
{
// TODO: NEW: Implement ImageDrawImageEx()
}
// Draw a part of an image defined by a rectangle within an image
void ImageDrawImageRec(Image *dst, Image src, Rectangle srcRec, Vector2 position, Color tint)
{
@ -3967,8 +4060,7 @@ void ImageDrawImageRec(Image *dst, Image src, Rectangle srcRec, Vector2 position
}
// Draw a part of an image defined by a rectangle into destination rectangle, with scaling and rotation, within an image
// NOTE: Color tint is applied to source image
// TODO: WARNING: origin and rotation are not implemented
// TODO: REVIEW: ImageDrawImagePro(), implement origin and rotation for image drawing
void ImageDrawImagePro(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Vector2 origin, float rotation, Color tint)
{
// Security check to avoid program crash
@ -4146,6 +4238,12 @@ void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position,
UnloadImage(imText);
}
// Draw text using Font and pro parameters (rotation)
void ImageDrawTextPro(Image *dst, Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint)
{
// TODO: NEW: Implement ImageDrawTextPro()
}
//------------------------------------------------------------------------------------
// Texture loading functions
//------------------------------------------------------------------------------------
@ -5426,8 +5524,11 @@ int GetPixelDataSize(int width, int height, int format)
default: break;
}
double bytesPerPixel = (double)bpp/8.0;
dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes
unsigned long long dataSizeBytes = ((unsigned long long)width*height*bpp) >> 3; // Get size in bytes (dividing by 8)
if (dataSizeBytes < INT_MAX)
{
dataSize = (int)dataSizeBytes;
// Most compressed formats works on 4x4 blocks,
// if texture is smaller, minimum dataSize is 8 or 16
@ -5436,6 +5537,10 @@ int GetPixelDataSize(int width, int height, int format)
if ((format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8;
else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16;
}
}
// NOTE: In case required image data larger than 2GB, no memory allocated at all (NULL)
if (dataSize == 0) TRACELOG(LOG_WARNING, "Requested image size is larger than 2GB, it can not be allocated");
return dataSize;
}

View file

@ -2331,7 +2331,7 @@ static rlExampleInfo *LoadExampleInfo(const char *exFileName)
// Example found in collection
exInfo = (rlExampleInfo *)RL_CALLOC(1, sizeof(rlExampleInfo));
strncpy(exInfo->name, GetFileNameWithoutExt(exFileName), 128 - 1);
snprintf(exInfo->name, 128, "%s", GetFileNameWithoutExt(exFileName));
strncpy(exInfo->category, exInfo->name, TextFindIndex(exInfo->name, "_"));
char *exText = LoadFileText(exFileName);
@ -2377,7 +2377,7 @@ static rlExampleInfo *LoadExampleInfo(const char *exFileName)
int copyrightIndex = TextFindIndex(exText, "Copyright (c) ");
int yearStartIndex = copyrightIndex + 14;
char yearText[5] = { 0 };
strncpy(yearText, exText + yearStartIndex, 4);
snprintf(yearText, 5, "%s", exText + yearStartIndex);
exInfo->yearCreated = TextToInteger(yearText);
// Check for review year included (or just use creation year)
if (exText[yearStartIndex + 4] == '-') strncpy(yearText, exText + yearStartIndex + 5, 4);
@ -2425,7 +2425,7 @@ static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry)
#define MAX_EXAMPLE_INFO_LINE_LEN 512
char temp[MAX_EXAMPLE_INFO_LINE_LEN] = { 0 };
strncpy(temp, line, MAX_EXAMPLE_INFO_LINE_LEN);
snprintf(temp, MAX_EXAMPLE_INFO_LINE_LEN, "%s", line);
temp[MAX_EXAMPLE_INFO_LINE_LEN - 1] = '\0'; // Ensure null termination
int tokenCount = 0;
@ -2902,7 +2902,7 @@ static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath)
char exTitle[64] = { 0 }; // Example title: fileName without extension, replacing underscores by spaces
// Get example name: replace underscore by spaces
strncpy(exName, GetFileNameWithoutExt(exHtmlPathCopy), 64 - 1);
snprintf(exName, 64, "%s", GetFileNameWithoutExt(exHtmlPathCopy));
strcpy(exTitle, exName);
for (int i = 0; (i < 64) && (exTitle[i] != '\0'); i++) { if (exTitle[i] == '_') exTitle[i] = ' '; }

View file

@ -79,6 +79,7 @@ raylib_api: ../../src/raylib.h rlparser
FORMAT=JSON EXTENSION=json $(MAKE) raylib_api.json
FORMAT=XML EXTENSION=xml $(MAKE) raylib_api.xml
FORMAT=LUA EXTENSION=lua $(MAKE) raylib_api.lua
FORMAT=SEXPR EXTENSION=sexpr $(MAKE) raylib_api.sexpr
# rlparser execution: [raylib.h] parse, generating some output files
raylib_api.$(EXTENSION): ../../src/raylib.h rlparser
@ -112,7 +113,8 @@ all: rlparser
FORMAT=JSON EXTENSION=json $(MAKE) parse
FORMAT=XML EXTENSION=xml $(MAKE) parse
FORMAT=LUA EXTENSION=lua $(MAKE) parse
FORMAT=SEXPR EXTENSION=sexpr $(MAKE) parse
# Clean rlparser and generated output files
clean:
rm -f rlparser *.json *.txt *.xml *.lua
rm -f rlparser *.json *.txt *.xml *.lua *.sexpr

View file

@ -968,7 +968,7 @@
"description": "Skeleton, animation bones hierarchy",
"fields": [
{
"type": "int",
"type": "unsigned int",
"name": "boneCount",
"description": "Number of bones"
},
@ -1045,7 +1045,7 @@
"description": "Animation name"
},
{
"type": "int",
"type": "unsigned int",
"name": "boneCount",
"description": "Number of bones (per pose)"
},
@ -4603,7 +4603,7 @@
},
{
"name": "GetDirectoryPath",
"description": "Get full path for a given fileName with path (uses static string)",
"description": "Get full path for a provided fileName with path (uses static string)",
"returnType": "const char *",
"params": [
{
@ -4614,7 +4614,7 @@
},
{
"name": "GetPrevDirectoryPath",
"description": "Get previous directory path for a given path (uses static string)",
"description": "Get previous directory path for a provided path (uses static string)",
"returnType": "const char *",
"params": [
{
@ -4657,7 +4657,29 @@
},
{
"name": "IsPathFile",
"description": "Check if given path is a file or a directory",
"description": "Check if provided path points to a file",
"returnType": "bool",
"params": [
{
"type": "const char *",
"name": "path"
}
]
},
{
"name": "IsPathDirectory",
"description": "Check if provided path points to a directory",
"returnType": "bool",
"params": [
{
"type": "const char *",
"name": "path"
}
]
},
{
"name": "IsPathAbsolute",
"description": "Check if provided path is an absolute path",
"returnType": "bool",
"params": [
{
@ -5368,7 +5390,7 @@
},
{
"name": "GetTouchPointId",
"description": "Get touch point identifier for given index",
"description": "Get touch point identifier for provided index",
"returnType": "int",
"params": [
{
@ -8088,7 +8110,7 @@
},
{
"name": "ImageClearBackground",
"description": "Clear image background with given color",
"description": "Clear image background with provided color",
"returnType": "void",
"params": [
{
@ -8455,6 +8477,33 @@
}
]
},
{
"name": "ImageDrawRectanglePro",
"description": "Draw a color-filled rectangle with pro parameters within and image",
"returnType": "void",
"params": [
{
"type": "Image *",
"name": "dst"
},
{
"type": "Rectangle",
"name": "rec"
},
{
"type": "Vector2",
"name": "origin"
},
{
"type": "float",
"name": "rotation"
},
{
"type": "Color",
"name": "color"
}
]
},
{
"name": "ImageDrawRectangleLines",
"description": "Draw rectangle lines within an image",
@ -8509,6 +8558,37 @@
}
]
},
{
"name": "ImageDrawRectangleGradientEx",
"description": "Draw rectangle with gradient colors within an image, counter-clockwise color order",
"returnType": "void",
"params": [
{
"type": "Image *",
"name": "dst"
},
{
"type": "Rectangle",
"name": "rec"
},
{
"type": "Color",
"name": "col1"
},
{
"type": "Color",
"name": "col2"
},
{
"type": "Color",
"name": "col3"
},
{
"type": "Color",
"name": "col4"
}
]
},
{
"name": "ImageDrawCircle",
"description": "Draw a filled circle within an image",
@ -8663,6 +8743,37 @@
}
]
},
{
"name": "ImageDrawImageEx",
"description": "Draw an image with scaling and rotation within an image",
"returnType": "void",
"params": [
{
"type": "Image *",
"name": "dst"
},
{
"type": "Image",
"name": "src"
},
{
"type": "Vector2",
"name": "position"
},
{
"type": "float",
"name": "rotation"
},
{
"type": "float",
"name": "scale"
},
{
"type": "Color",
"name": "tint"
}
]
},
{
"name": "ImageDrawImageRec",
"description": "Draw a part of an image defined by a rectangle within an image",
@ -8791,6 +8902,49 @@
}
]
},
{
"name": "ImageDrawTextPro",
"description": "Draw text using Font and pro parameters (rotation)",
"returnType": "void",
"params": [
{
"type": "Image *",
"name": "dst"
},
{
"type": "Font",
"name": "font"
},
{
"type": "const char *",
"name": "text"
},
{
"type": "Vector2",
"name": "position"
},
{
"type": "Vector2",
"name": "origin"
},
{
"type": "float",
"name": "rotation"
},
{
"type": "float",
"name": "fontSize"
},
{
"type": "float",
"name": "spacing"
},
{
"type": "Color",
"name": "tint"
}
]
},
{
"name": "LoadTexture",
"description": "Load texture from file into GPU memory (VRAM)",

View file

@ -968,7 +968,7 @@ return {
description = "Skeleton, animation bones hierarchy",
fields = {
{
type = "int",
type = "unsigned int",
name = "boneCount",
description = "Number of bones"
},
@ -1045,7 +1045,7 @@ return {
description = "Animation name"
},
{
type = "int",
type = "unsigned int",
name = "boneCount",
description = "Number of bones (per pose)"
},
@ -4135,7 +4135,7 @@ return {
},
{
name = "GetDirectoryPath",
description = "Get full path for a given fileName with path (uses static string)",
description = "Get full path for a provided fileName with path (uses static string)",
returnType = "const char *",
params = {
{type = "const char *", name = "filePath"}
@ -4143,7 +4143,7 @@ return {
},
{
name = "GetPrevDirectoryPath",
description = "Get previous directory path for a given path (uses static string)",
description = "Get previous directory path for a provided path (uses static string)",
returnType = "const char *",
params = {
{type = "const char *", name = "dirPath"}
@ -4177,7 +4177,23 @@ return {
},
{
name = "IsPathFile",
description = "Check if given path is a file or a directory",
description = "Check if provided path points to a file",
returnType = "bool",
params = {
{type = "const char *", name = "path"}
}
},
{
name = "IsPathDirectory",
description = "Check if provided path points to a directory",
returnType = "bool",
params = {
{type = "const char *", name = "path"}
}
},
{
name = "IsPathAbsolute",
description = "Check if provided path is an absolute path",
returnType = "bool",
params = {
{type = "const char *", name = "path"}
@ -4663,7 +4679,7 @@ return {
},
{
name = "GetTouchPointId",
description = "Get touch point identifier for given index",
description = "Get touch point identifier for provided index",
returnType = "int",
params = {
{type = "int", name = "index"}
@ -6063,7 +6079,7 @@ return {
},
{
name = "ImageClearBackground",
description = "Clear image background with given color",
description = "Clear image background with provided color",
returnType = "void",
params = {
{type = "Image *", name = "dst"},
@ -6232,6 +6248,18 @@ return {
{type = "Color", name = "color"}
}
},
{
name = "ImageDrawRectanglePro",
description = "Draw a color-filled rectangle with pro parameters within and image",
returnType = "void",
params = {
{type = "Image *", name = "dst"},
{type = "Rectangle", name = "rec"},
{type = "Vector2", name = "origin"},
{type = "float", name = "rotation"},
{type = "Color", name = "color"}
}
},
{
name = "ImageDrawRectangleLines",
description = "Draw rectangle lines within an image",
@ -6256,6 +6284,19 @@ return {
{type = "Color", name = "color"}
}
},
{
name = "ImageDrawRectangleGradientEx",
description = "Draw rectangle with gradient colors within an image, counter-clockwise color order",
returnType = "void",
params = {
{type = "Image *", name = "dst"},
{type = "Rectangle", name = "rec"},
{type = "Color", name = "col1"},
{type = "Color", name = "col2"},
{type = "Color", name = "col3"},
{type = "Color", name = "col4"}
}
},
{
name = "ImageDrawCircle",
description = "Draw a filled circle within an image",
@ -6326,6 +6367,19 @@ return {
{type = "Color", name = "tint"}
}
},
{
name = "ImageDrawImageEx",
description = "Draw an image with scaling and rotation within an image",
returnType = "void",
params = {
{type = "Image *", name = "dst"},
{type = "Image", name = "src"},
{type = "Vector2", name = "position"},
{type = "float", name = "rotation"},
{type = "float", name = "scale"},
{type = "Color", name = "tint"}
}
},
{
name = "ImageDrawImageRec",
description = "Draw a part of an image defined by a rectangle within an image",
@ -6379,6 +6433,22 @@ return {
{type = "Color", name = "tint"}
}
},
{
name = "ImageDrawTextPro",
description = "Draw text using Font and pro parameters (rotation)",
returnType = "void",
params = {
{type = "Image *", name = "dst"},
{type = "Font", name = "font"},
{type = "const char *", name = "text"},
{type = "Vector2", name = "position"},
{type = "Vector2", name = "origin"},
{type = "float", name = "rotation"},
{type = "float", name = "fontSize"},
{type = "float", name = "spacing"},
{type = "Color", name = "tint"}
}
},
{
name = "LoadTexture",
description = "Load texture from file into GPU memory (VRAM)",

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -201,7 +201,7 @@
<Field type="int" name="parent" desc="Bone parent" />
</Struct>
<Struct name="ModelSkeleton" fieldCount="3" desc="Skeleton, animation bones hierarchy">
<Field type="int" name="boneCount" desc="Number of bones" />
<Field type="unsigned int" name="boneCount" desc="Number of bones" />
<Field type="BoneInfo *" name="bones" desc="Bones information (skeleton)" />
<Field type="ModelAnimPose" name="bindPose" desc="Bones base transformation (Transform[])" />
</Struct>
@ -218,7 +218,7 @@
</Struct>
<Struct name="ModelAnimation" fieldCount="4" desc="ModelAnimation, contains a full animation sequence">
<Field type="char[32]" name="name" desc="Animation name" />
<Field type="int" name="boneCount" desc="Number of bones (per pose)" />
<Field type="unsigned int" name="boneCount" desc="Number of bones (per pose)" />
<Field type="int" name="keyframeCount" desc="Number of animation key frames" />
<Field type="ModelAnimPose *" name="keyframePoses" desc="Animation sequence keyframe poses [keyframe][pose]" />
</Struct>
@ -681,7 +681,7 @@
<Param type="unsigned int" name="frames" desc="" />
</Callback>
</Callbacks>
<Functions count="607">
<Functions count="613">
<Function name="InitWindow" retType="void" paramCount="3" desc="Initialize window and OpenGL context">
<Param type="int" name="width" desc="" />
<Param type="int" name="height" desc="" />
@ -1099,10 +1099,10 @@
<Function name="GetFileNameWithoutExt" retType="const char *" paramCount="1" desc="Get filename string without extension (uses static string)">
<Param type="const char *" name="filePath" desc="" />
</Function>
<Function name="GetDirectoryPath" retType="const char *" paramCount="1" desc="Get full path for a given fileName with path (uses static string)">
<Function name="GetDirectoryPath" retType="const char *" paramCount="1" desc="Get full path for a provided fileName with path (uses static string)">
<Param type="const char *" name="filePath" desc="" />
</Function>
<Function name="GetPrevDirectoryPath" retType="const char *" paramCount="1" desc="Get previous directory path for a given path (uses static string)">
<Function name="GetPrevDirectoryPath" retType="const char *" paramCount="1" desc="Get previous directory path for a provided path (uses static string)">
<Param type="const char *" name="dirPath" desc="" />
</Function>
<Function name="GetWorkingDirectory" retType="const char *" paramCount="0" desc="Get current working directory (uses static string)">
@ -1115,7 +1115,13 @@
<Function name="ChangeDirectory" retType="int" paramCount="1" desc="Change working directory, returns 0 on success">
<Param type="const char *" name="dirPath" desc="" />
</Function>
<Function name="IsPathFile" retType="bool" paramCount="1" desc="Check if given path is a file or a directory">
<Function name="IsPathFile" retType="bool" paramCount="1" desc="Check if provided path points to a file">
<Param type="const char *" name="path" desc="" />
</Function>
<Function name="IsPathDirectory" retType="bool" paramCount="1" desc="Check if provided path points to a directory">
<Param type="const char *" name="path" desc="" />
</Function>
<Function name="IsPathAbsolute" retType="bool" paramCount="1" desc="Check if provided path is an absolute path">
<Param type="const char *" name="path" desc="" />
</Function>
<Function name="IsFileNameValid" retType="bool" paramCount="1" desc="Check if fileName is valid for the platform/OS">
@ -1316,7 +1322,7 @@
<Function name="GetTouchPosition" retType="Vector2" paramCount="1" desc="Get touch position XY for a touch point index (relative to screen size)">
<Param type="int" name="index" desc="" />
</Function>
<Function name="GetTouchPointId" retType="int" paramCount="1" desc="Get touch point identifier for given index">
<Function name="GetTouchPointId" retType="int" paramCount="1" desc="Get touch point identifier for provided index">
<Param type="int" name="index" desc="" />
</Function>
<Function name="GetTouchPointCount" retType="int" paramCount="0" desc="Get number of touch points">
@ -2036,7 +2042,7 @@
<Param type="int" name="x" desc="" />
<Param type="int" name="y" desc="" />
</Function>
<Function name="ImageClearBackground" retType="void" paramCount="2" desc="Clear image background with given color">
<Function name="ImageClearBackground" retType="void" paramCount="2" desc="Clear image background with provided color">
<Param type="Image *" name="dst" desc="" />
<Param type="Color" name="color" desc="" />
</Function>
@ -2132,6 +2138,13 @@
<Param type="Rectangle" name="rec" desc="" />
<Param type="Color" name="color" desc="" />
</Function>
<Function name="ImageDrawRectanglePro" retType="void" paramCount="5" desc="Draw a color-filled rectangle with pro parameters within and image">
<Param type="Image *" name="dst" desc="" />
<Param type="Rectangle" name="rec" desc="" />
<Param type="Vector2" name="origin" desc="" />
<Param type="float" name="rotation" desc="" />
<Param type="Color" name="color" desc="" />
</Function>
<Function name="ImageDrawRectangleLines" retType="void" paramCount="6" desc="Draw rectangle lines within an image">
<Param type="Image *" name="dst" desc="" />
<Param type="int" name="posX" desc="" />
@ -2146,6 +2159,14 @@
<Param type="int" name="thick" desc="" />
<Param type="Color" name="color" desc="" />
</Function>
<Function name="ImageDrawRectangleGradientEx" retType="void" paramCount="6" desc="Draw rectangle with gradient colors within an image, counter-clockwise color order">
<Param type="Image *" name="dst" desc="" />
<Param type="Rectangle" name="rec" desc="" />
<Param type="Color" name="col1" desc="" />
<Param type="Color" name="col2" desc="" />
<Param type="Color" name="col3" desc="" />
<Param type="Color" name="col4" desc="" />
</Function>
<Function name="ImageDrawCircle" retType="void" paramCount="5" desc="Draw a filled circle within an image">
<Param type="Image *" name="dst" desc="" />
<Param type="int" name="centerX" desc="" />
@ -2186,6 +2207,14 @@
<Param type="int" name="posY" desc="" />
<Param type="Color" name="tint" desc="" />
</Function>
<Function name="ImageDrawImageEx" retType="void" paramCount="6" desc="Draw an image with scaling and rotation within an image">
<Param type="Image *" name="dst" desc="" />
<Param type="Image" name="src" desc="" />
<Param type="Vector2" name="position" desc="" />
<Param type="float" name="rotation" desc="" />
<Param type="float" name="scale" desc="" />
<Param type="Color" name="tint" desc="" />
</Function>
<Function name="ImageDrawImageRec" retType="void" paramCount="5" desc="Draw a part of an image defined by a rectangle within an image">
<Param type="Image *" name="dst" desc="" />
<Param type="Image" name="src" desc="" />
@ -2219,6 +2248,17 @@
<Param type="float" name="spacing" desc="" />
<Param type="Color" name="tint" desc="" />
</Function>
<Function name="ImageDrawTextPro" retType="void" paramCount="9" desc="Draw text using Font and pro parameters (rotation)">
<Param type="Image *" name="dst" desc="" />
<Param type="Font" name="font" desc="" />
<Param type="const char *" name="text" desc="" />
<Param type="Vector2" name="position" desc="" />
<Param type="Vector2" name="origin" desc="" />
<Param type="float" name="rotation" desc="" />
<Param type="float" name="fontSize" desc="" />
<Param type="float" name="spacing" desc="" />
<Param type="Color" name="tint" desc="" />
</Function>
<Function name="LoadTexture" retType="Texture2D" paramCount="1" desc="Load texture from file into GPU memory (VRAM)">
<Param type="const char *" name="fileName" desc="" />
</Function>

View file

@ -146,7 +146,7 @@ typedef struct FunctionInfo {
} FunctionInfo;
// Output format for parsed data
typedef enum { DEFAULT = 0, JSON, XML, LUA, CODE } OutputFormat;
typedef enum { DEFAULT = 0, JSON, XML, LUA, SEXPR, CODE } OutputFormat;
//----------------------------------------------------------------------------------
// Global Variables Definition
@ -1062,6 +1062,7 @@ int main(int argc, char *argv[])
else if (outputFormat == JSON) printf("\nOutput format: JSON\n\n");
else if (outputFormat == XML) printf("\nOutput format: XML\n\n");
else if (outputFormat == LUA) printf("\nOutput format: LUA\n\n");
else if (outputFormat == SEXPR) printf("\nOutput format: SEXPR\n\n");
else if (outputFormat == CODE) printf("\nOutput format: CODE\n\n");
ExportParsedData(outFileName, outputFormat);
@ -1098,10 +1099,10 @@ static void ShowCommandLineInfo(void)
printf(" -i, --input <filename.h> : Define input header file to parse.\n");
printf(" NOTE: If not specified, defaults to: raylib.h\n\n");
printf(" -o, --output <filename.ext> : Define output file and format.\n");
printf(" Supported extensions: .txt, .json, .xml, .lua, .h\n");
printf(" Supported extensions: .txt, .json, .xml, .lua, .sexpr, .h\n");
printf(" NOTE: If not specified, defaults to: raylib_api.txt\n\n");
printf(" -f, --format <type> : Define output format for parser data.\n");
printf(" Supported types: DEFAULT, JSON, XML, LUA, CODE\n\n");
printf(" Supported types: DEFAULT, JSON, XML, LUA, SEXPR, CODE\n\n");
printf(" -d, --define <DEF> : Define functions specifiers (i.e. RLAPI for raylib.h, RMAPI for raymath.h, etc.)\n");
printf(" NOTE: If no specifier defined, defaults to: RLAPI\n\n");
printf(" -t, --truncate <after> : Define string to truncate input after (i.e. \"RLGL IMPLEMENTATION\" for rlgl.h)\n");
@ -1154,6 +1155,7 @@ static void ProcessCommandLine(int argc, char *argv[])
else if (IsTextEqual(argv[i + 1], "JSON\0", 5)) outputFormat = JSON;
else if (IsTextEqual(argv[i + 1], "XML\0", 4)) outputFormat = XML;
else if (IsTextEqual(argv[i + 1], "LUA\0", 4)) outputFormat = LUA;
else if (IsTextEqual(argv[i + 1], "SEXPR\0", 4)) outputFormat = SEXPR;
else if (IsTextEqual(argv[i + 1], "CODE\0", 5)) outputFormat = CODE;
}
else printf("WARNING: No format parameters provided\n");
@ -2007,6 +2009,131 @@ static void ExportParsedData(const char *fileName, int format)
fprintf(outFile, " }\n");
fprintf(outFile, "}\n");
} break;
case SEXPR:
{
fprintf(outFile, "(");
// Print defines info
fprintf(outFile, "(defines\n");
for (int i = 0; i < defineCount; i++)
{
if(i != 0) fprintf(outFile, "\n");
fprintf(outFile, " ((name \"%s\")\n", defines[i].name);
fprintf(outFile, " (type \"%s\")\n", StrDefineType(defines[i].type));
if ((defines[i].type == INT) ||
(defines[i].type == LONG) ||
(defines[i].type == FLOAT) ||
(defines[i].type == DOUBLE) ||
(defines[i].type == STRING))
{
fprintf(outFile, " (value %s)\n", defines[i].value);
}
else
{
fprintf(outFile, " (value \"%s\")\n", defines[i].value);
}
fprintf(outFile, " (description \"%s\"))", defines[i].desc);
}
fprintf(outFile, ")\n\n");
// Print structs info
fprintf(outFile, " (structs\n");
for (int i = 0; i < structCount; i++)
{
if(i != 0) fprintf(outFile, "\n\n");
fprintf(outFile, " ((name \"%s\")\n", structs[i].name);
fprintf(outFile, " (description \"%s\")\n", EscapeBackslashes(structs[i].desc));
fprintf(outFile, " (fields ");
for (int f = 0; f < structs[i].fieldCount; f++)
{
fprintf(outFile, "\n ((type \"%s\")\n", structs[i].fieldType[f]);
fprintf(outFile, " (name \"%s\")\n", structs[i].fieldName[f]);
fprintf(outFile, " (description \"%s\"))", EscapeBackslashes(structs[i].fieldDesc[f]));
}
fprintf(outFile, "))");
}
fprintf(outFile, ")\n\n");
// Print aliases info
fprintf(outFile, " (aliases\n");
for (int i = 0; i < aliasCount; i++)
{
if(i != 0) fprintf(outFile, "\n\n");
fprintf(outFile, " ((type \"%s\")\n", aliases[i].type);
fprintf(outFile, " (name \"%s\")\n", aliases[i].name);
fprintf(outFile, " (description \"%s\"))", aliases[i].desc);
}
fprintf(outFile, ")\n\n");
// Print enums info
fprintf(outFile, " (enums\n");
for (int i = 0; i < enumCount; i++)
{
if(i != 0) fprintf(outFile, "\n\n");
fprintf(outFile, " ((name \"%s\")\n", enums[i].name);
fprintf(outFile, " (description \"%s\")\n", EscapeBackslashes(enums[i].desc));
fprintf(outFile, " (values\n");
for (int e = 0; e < enums[i].valueCount; e++)
{
if(e != 0) fprintf(outFile, "\n\n");
fprintf(outFile, " ((name \"%s\")\n", enums[i].valueName[e]);
fprintf(outFile, " (value %i)\n", enums[i].valueInteger[e]);
fprintf(outFile, " (description \"%s\"))", EscapeBackslashes(enums[i].valueDesc[e]));
}
fprintf(outFile, "))");
}
fprintf(outFile, ")\n\n");
// Print callbacks info
fprintf(outFile, " (callbacks\n");
for (int i = 0; i < callbackCount; i++)
{
if(i != 0) fprintf(outFile, "\n\n");
fprintf(outFile, " ((name \"%s\")\n", callbacks[i].name);
fprintf(outFile, " (description \"%s\")\n", EscapeBackslashes(callbacks[i].desc));
fprintf(outFile, " (return-type \"%s\")", callbacks[i].retType);
if (callbacks[i].paramCount == 0) fprintf(outFile, "\n");
else
{
fprintf(outFile, "\n (params\n");
for (int p = 0; p < callbacks[i].paramCount; p++)
{
if(p != 0) fprintf(outFile, "\n");
fprintf(outFile, " ((type \"%s\") (name \"%s\"))", callbacks[i].paramType[p], callbacks[i].paramName[p]);
}
fprintf(outFile, ")");
}
fprintf(outFile, ")");
}
fprintf(outFile, ")\n\n");
// Print functions info
fprintf(outFile, " (functions\n");
for (int i = 0; i < funcCount; i++)
{
if(i != 0) fprintf(outFile, "\n\n");
fprintf(outFile, " ((name \"%s\")\n", funcs[i].name);
fprintf(outFile, " (description \"%s\")\n", EscapeBackslashes(funcs[i].desc));
fprintf(outFile, " (return-type \"%s\")", funcs[i].retType);
if (funcs[i].paramCount == 0) fprintf(outFile, "");
else
{
fprintf(outFile, "\n (params\n");
for (int p = 0; p < funcs[i].paramCount; p++)
{
if(p != 0) fprintf(outFile, "\n");
fprintf(outFile, " ((type \"%s\") (name \"%s\"))", funcs[i].paramType[p], funcs[i].paramName[p]);
}
fprintf(outFile, ")");
}
fprintf(outFile, ")");
}
fprintf(outFile, ")");
fprintf(outFile, ")\n");
} break;
case CODE:
default: break;
}