Merge pull request #465 from raysan5/develop

Integrate develop branch into master
This commit is contained in:
Ray 2018-02-12 11:27:26 +01:00 committed by GitHub
commit dd8f0765b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1170 additions and 616 deletions

View file

@ -24,29 +24,59 @@
.PHONY: all clean .PHONY: all clean
# Define required raylib variables # Define required raylib variables
# WARNING: To compile to HTML5, code must be redesigned to use emscripten.h and emscripten_set_main_loop() PROJECT_NAME ?= raylib_examples
PLATFORM ?= PLATFORM_DESKTOP RAYLIB_VERSION ?= 1.9.4
RAYLIB_PATH ?= .. RAYLIB_API_VERSION ?= 1
PROJECT_NAME ?= raylib_example RAYLIB_PATH ?= ..
# Define default options
# One of PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
PLATFORM ?= PLATFORM_DESKTOP
# Default path for raylib on Raspberry Pi, if installed in different path, update it! # Default path for raylib on Raspberry Pi, if installed in different path, update it!
ifeq ($(PLATFORM),PLATFORM_RPI) ifeq ($(PLATFORM),PLATFORM_RPI)
RAYLIB_PATH ?= /home/pi/raylib RAYLIB_PATH ?= /home/pi/raylib
endif endif
# RAYLIB_RELEASE_PATH points to provided binaries or your immediate build of libraylib.
# See below for additions.
RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/release/libs
# 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 runtime linking to libraylib.so, run sudo ldconfig $(RAYLIB_INSTALL_PATH).
# ldconfig is not necessary if using RAYLIB_RUNTIME_PATH below.
RAYLIB_INSTALL_PATH ?= /usr/local/lib/raysan5
RAYLIB_H_INSTALL_PATH ?= /usr/local/include/raysan5
# Set runtime path to custom location of shared library if desired, avoiding sudo ldconfig.
# If you have compiled the examples but cannot run them, examine both RAYLIB_INSTALL_PATH and
# RAYLIB_RUNTIME_PATH. To see which libraries a built example is using, ldd core/core_basic_window;
# Look for libraylib.so.1 => $(RAYLIB_INSTALL_PATH)/libraylib.so.1
# or libraylib.so.1 => $(RAYLIB_RUNTIME_PATH)/libraylib.so.1 or similar listing.
# Implemented for LINUX below with CFLAGS += -Wl,-rpath,$(RAYLIB_RUNTIME_PATH)
# This should be a fully qualified path. RAYLIB_RELEASE_PATH doesn't work here
# because it's a relative path. You must spell it out if needed.
# To see the result, run readelf -d core/core_basic_window, looking at the RPATH attribute.
RAYLIB_RUNTIME_PATH ?= $(RAYLIB_INSTALL_PATH)
# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) # Library type used for raylib: STATIC (.a) or SHARED (.so/.dll)
RAYLIB_LIBTYPE ?= STATIC RAYLIB_LIBTYPE ?= STATIC
# Build mode for project: DEBUG or RELEASE
RAYLIB_BUILD_MODE ?= RELEASE
# Use external GLFW library instead of rglfw module # Use external GLFW library instead of rglfw module
USE_EXTERNAL_GLFW ?= FALSE USE_EXTERNAL_GLFW ?= FALSE
# Use Wayland display server protocol on Linux desktop # Use Wayland display server protocol on Linux desktop
# by default it uses X11 windowing system # by default it uses X11 windowing system
USE_WAYLAND_DISPLAY ?= FALSE USE_WAYLAND_DISPLAY ?= FALSE
# NOTE: On PLATFORM_WEB OpenAL Soft backend is used by default (check raylib/src/Makefile) # NOTE: On PLATFORM_WEB OpenAL Soft backend is used by default (check raylib/src/Makefile)
# Determine PLATFORM_OS in case PLATFORM_DESKTOP selected # Determine PLATFORM_OS in case PLATFORM_DESKTOP selected
ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM),PLATFORM_DESKTOP)
# No uname.exe on MinGW!, but OS=Windows_NT on Windows! # No uname.exe on MinGW!, but OS=Windows_NT on Windows!
@ -84,8 +114,6 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
EMSCRIPTEN=$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION) EMSCRIPTEN=$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION)
endif endif
RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/release/libs
# Define raylib release directory for compiled library # Define raylib release directory for compiled library
ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM),PLATFORM_DESKTOP)
ifeq ($(PLATFORM_OS),WINDOWS) ifeq ($(PLATFORM_OS),WINDOWS)
@ -130,6 +158,7 @@ ifeq ($(PLATFORM),PLATFORM_RPI)
endif endif
endif endif
ifeq ($(PLATFORM),PLATFORM_WEB) ifeq ($(PLATFORM),PLATFORM_WEB)
# WARNING: To compile to HTML5, code must be redesigned to use emscripten.h and emscripten_set_main_loop()
# HTML5 emscripten compiler # HTML5 emscripten compiler
CC = emcc CC = emcc
endif endif
@ -164,7 +193,13 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
CFLAGS += $(RAYLIB_PATH)/src/resources -Wl,--subsystem,windows CFLAGS += $(RAYLIB_PATH)/src/resources -Wl,--subsystem,windows
endif endif
ifeq ($(PLATFORM_OS),LINUX) ifeq ($(PLATFORM_OS),LINUX)
ifeq ($(RAYLIB_LIBTYPE),STATIC)
CFLAGS += -no-pie -D_DEFAULT_SOURCE CFLAGS += -no-pie -D_DEFAULT_SOURCE
endif
ifeq ($(RAYLIB_LIBTYPE),SHARED)
# Explicitly enable runtime link to libraylib
CFLAGS += -Wl,-rpath,$(RAYLIB_RUNTIME_PATH)
endif
endif endif
endif endif
ifeq ($(PLATFORM),PLATFORM_RPI) ifeq ($(PLATFORM),PLATFORM_RPI)
@ -185,19 +220,21 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
EXT = .html EXT = .html
endif endif
# Define include paths for required headers # Define include paths for required headers.
# Precedence: immediately local, raysan5 provided sources
# NOTE: Several external required libraries (stb and others) # NOTE: Several external required libraries (stb and others)
INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/release/include -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/release/include -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external
# Define additional directories containing required header files # Define additional directories containing required header files
ifeq ($(PLATFORM),PLATFORM_RPI) ifeq ($(PLATFORM),PLATFORM_RPI)
# RPI requried libraries # RPI required libraries
INCLUDE_PATHS += -I/opt/vc/include INCLUDE_PATHS += -I/opt/vc/include
INCLUDE_PATHS += -I/opt/vc/include/interface/vmcs_host/linux INCLUDE_PATHS += -I/opt/vc/include/interface/vmcs_host/linux
INCLUDE_PATHS += -I/opt/vc/include/interface/vcos/pthreads INCLUDE_PATHS += -I/opt/vc/include/interface/vcos/pthreads
endif endif
# Define library paths containing required libs # Define library paths containing required libs.
# Precedence: immediately local, then raysan5 provided libs
LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src
ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM),PLATFORM_DESKTOP)
@ -205,6 +242,12 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
INCLUDE_PATHS += -I/usr/local/include INCLUDE_PATHS += -I/usr/local/include
LDFLAGS += -L. -Lsrc -L/usr/local/lib LDFLAGS += -L. -Lsrc -L/usr/local/lib
endif endif
ifeq ($(PLATFORM_OS),LINUX)
# Reset everything.
# Precedence: immediately local, installed version, raysan5 provided libs
INCLUDE_PATHS = -I. -I$(RAYLIB_H_INSTALL_PATH) -I$(RAYLIB_PATH)/release/include -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external
LDFLAGS = -L. -L$(RAYLIB_INSTALL_PATH) -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src
endif
endif endif
ifeq ($(PLATFORM),PLATFORM_RPI) ifeq ($(PLATFORM),PLATFORM_RPI)
@ -235,6 +278,11 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
ifeq ($(USE_WAYLAND_DISPLAY),TRUE) ifeq ($(USE_WAYLAND_DISPLAY),TRUE)
LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon
endif endif
# Explicit link to libc
ifeq ($(RAYLIB_LIBTYPE),SHARED)
LDLIBS += -lc
endif
endif endif
ifeq ($(PLATFORM_OS),OSX) ifeq ($(PLATFORM_OS),OSX)
# Libraries for OSX 10.9 desktop compiling # Libraries for OSX 10.9 desktop compiling
@ -360,7 +408,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
del *.o *.exe /s del *.o *.exe /s
endif endif
ifeq ($(PLATFORM_OS),LINUX) 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 -f 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 endif
ifeq ($(PLATFORM_OS),OSX) ifeq ($(PLATFORM_OS),OSX)
find . -type f -perm +ugo+x -delete find . -type f -perm +ugo+x -delete
@ -369,7 +417,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
endif endif
ifeq ($(PLATFORM),PLATFORM_RPI) ifeq ($(PLATFORM),PLATFORM_RPI)
find . -type f -executable -delete find . -type f -executable -delete
rm -f *.o rm -fv *.o
endif endif
ifeq ($(PLATFORM),PLATFORM_WEB) ifeq ($(PLATFORM),PLATFORM_WEB)
del *.o *.html *.js del *.o *.html *.js

View file

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 293 B

After

Width:  |  Height:  |  Size: 293 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 383 B

After

Width:  |  Height:  |  Size: 383 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 552 B

After

Width:  |  Height:  |  Size: 552 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 922 B

After

Width:  |  Height:  |  Size: 922 B

Before After
Before After

BIN
logo/raylib_512x512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before After
Before After

BIN
logo/raylib_96x96.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -8,6 +8,6 @@ Description: Simple and easy-to-use library to learn videogames programming
URL: http://github.com/raysan5/raylib URL: http://github.com/raysan5/raylib
Version: @PROJECT_VERSION@ Version: @PROJECT_VERSION@
Libs: -L${libdir} -lraylib Libs: -L${libdir} -lraylib
Libs.private:@PKG_CONFIG_LIBS_PRIVATE@ Libs.private: @PKG_CONFIG_LIBS_PRIVATE@
Requires.private: Requires.private:
Cflags: -I${includedir} Cflags: -I${includedir}

View file

@ -137,6 +137,8 @@ if(${PLATFORM} MATCHES "PLATFORM_DESKTOP")
PUBLIC ${GRAPHICS} PUBLIC ${GRAPHICS}
) )
set(PKG_CONFIG_LIBS_PRIVATE ${__PKG_CONFIG_LIBS_PRIVATE})
if (WITH_PIC) if (WITH_PIC)
set_property(TARGET ${RAYLIB} PROPERTY POSITION_INDEPENDENT_CODE ON) set_property(TARGET ${RAYLIB} PROPERTY POSITION_INDEPENDENT_CODE ON)
endif() endif()

View file

@ -42,34 +42,48 @@
.PHONY: all clean install uninstall .PHONY: all clean install uninstall
# Define required raylib variables # Define required raylib variables
PLATFORM ?= PLATFORM_DESKTOP
RAYLIB_PATH = ..
RAYLIB_VERSION = 1.9.4 RAYLIB_VERSION = 1.9.4
RAYLIB_API_VERSION = 1 RAYLIB_API_VERSION = 1
RAYLIB_PATH = ..
# Define default options
# RAYLIB_RELEASE_PATH points to provided binaries and your immediate build of raylib.
# It is further modified below by PLATFORM below.
RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/release/libs
# See install target for *_INSTALL_PATH locations.
# One of PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
PLATFORM ?= PLATFORM_DESKTOP
# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) # Library type used for raylib: STATIC (.a) or SHARED (.so/.dll)
RAYLIB_LIBTYPE ?= STATIC RAYLIB_LIBTYPE ?= STATIC
# Build mode for library: DEBUG or RELEASE # Build mode for library: DEBUG or RELEASE
RAYLIB_BUILD_MODE ?= RELEASE RAYLIB_BUILD_MODE ?= RELEASE
# Included raylib audio module on compilation # Included raylib audio module on compilation
# NOTE: Some programs like tools could not require audio support # NOTE: Some programs like tools could not require audio support
INCLUDE_AUDIO_MODULE ?= TRUE INCLUDE_AUDIO_MODULE ?= TRUE
# Use OpenAL Soft backend for audio # Use OpenAL Soft backend for audio
USE_OPENAL_BACKEND ?= FALSE USE_OPENAL_BACKEND ?= FALSE
# Use external GLFW library instead of rglfw module
USE_EXTERNAL_GLFW ?= FALSE
# Use Wayland display server protocol on Linux desktop
# by default it uses X11 windowing system
USE_WAYLAND_DISPLAY ?= FALSE
# OpenAL Soft audio backend forced on HTML5 and OSX (see below) # OpenAL Soft audio backend forced on HTML5 and OSX (see below)
ifeq ($(PLATFORM),PLATFORM_WEB) ifeq ($(PLATFORM),PLATFORM_WEB)
USE_OPENAL_BACKEND = TRUE USE_OPENAL_BACKEND = TRUE
endif endif
# Use external GLFW library instead of rglfw module
USE_EXTERNAL_GLFW ?= FALSE
# Use Wayland display server protocol on Linux desktop
# by default it uses X11 windowing system
USE_WAYLAND_DISPLAY ?= FALSE
# See below for more GRAPHICS options.
# Use cross-compiler for PLATFORM_RPI # Use cross-compiler for PLATFORM_RPI
ifeq ($(PLATFORM),PLATFORM_RPI) ifeq ($(PLATFORM),PLATFORM_RPI)
USE_RPI_CROSS_COMPILER ?= FALSE USE_RPI_CROSS_COMPILER ?= FALSE
@ -138,8 +152,6 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID)
ANDROID_ARCH ?= ARM ANDROID_ARCH ?= ARM
endif endif
RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/release/libs
# Define output directory for compiled library # Define output directory for compiled library
ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM),PLATFORM_DESKTOP)
ifeq ($(PLATFORM_OS),WINDOWS) ifeq ($(PLATFORM_OS),WINDOWS)
@ -262,15 +274,20 @@ endif
# -Wno-missing-braces ignore invalid warning (GCC bug 53119) # -Wno-missing-braces ignore invalid warning (GCC bug 53119)
# -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec # -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec
# -Werror=pointer-arith catch unportable code that does direct arithmetic on void pointers # -Werror=pointer-arith catch unportable code that does direct arithmetic on void pointers
# -Werror=implicit-function-declaration catch function calls without prior declaration CFLAGS += -O1 -Wall -std=c99 -D_DEFAULT_SOURCE -fgnu89-inline -Wno-missing-braces -Werror=pointer-arith
CFLAGS += -O1 -Wall -std=c99 -D_DEFAULT_SOURCE -fgnu89-inline -Wno-missing-braces -Werror=pointer-arith -Werror=implicit-function-declaration
ifeq ($(RAYLIB_BUILD_MODE), DEBUG) ifeq ($(RAYLIB_BUILD_MODE), DEBUG)
CFLAGS += -g CFLAGS += -g
endif endif
# Additional flags for compiler (if desired) # Additional flags for compiler (if desired)
#CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes # -Wextra enables some extra warning flags that are not enabled by -Wall
# -Wmissing-prototypes warn if a global function is defined without a previous prototype declaration
# -Wstrict-prototypes warn if a function is declared or defined without specifying the argument types
# -Werror=implicit-function-declaration catch function calls without prior declaration
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
CFLAGS += -Werror=implicit-function-declaration
endif
ifeq ($(PLATFORM),PLATFORM_WEB) ifeq ($(PLATFORM),PLATFORM_WEB)
# -O2 # if used, also set --memory-init-file 0 # -O2 # if used, also set --memory-init-file 0
# --memory-init-file 0 # to avoid an external memory initialization code file (.mem) # --memory-init-file 0 # to avoid an external memory initialization code file (.mem)
@ -285,7 +302,8 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID)
# Compilation functions attributes options # Compilation functions attributes options
CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC
# Compiler options for the linker # Compiler options for the linker
CFLAGS += -Wa,--noexecstack -Wformat -Werror=format-security -no-canonical-prefixes # -Werror=format-security
CFLAGS += -Wa,--noexecstack -Wformat -no-canonical-prefixes
# Preprocessor macro definitions # Preprocessor macro definitions
CFLAGS += -DANDROID -DPLATFORM_ANDROID -D__ANDROID_API__=16 CFLAGS += -DANDROID -DPLATFORM_ANDROID -D__ANDROID_API__=16
endif endif
@ -293,7 +311,7 @@ endif
# Define required compilation flags for raylib SHARED lib # Define required compilation flags for raylib SHARED lib
ifeq ($(RAYLIB_LIBTYPE),SHARED) ifeq ($(RAYLIB_LIBTYPE),SHARED)
# make sure code is compiled as position independent # make sure code is compiled as position independent
# BE CAREFUL: It seems that for gcc -fpic si not the same as -fPIC # BE CAREFUL: It seems that for gcc -fpic is not the same as -fPIC
# MinGW32 just doesn't need -fPIC, it shows warnings # MinGW32 just doesn't need -fPIC, it shows warnings
CFLAGS += -fPIC -DBUILD_LIBTYPE_SHARED CFLAGS += -fPIC -DBUILD_LIBTYPE_SHARED
endif endif
@ -413,10 +431,10 @@ else
ifeq ($(PLATFORM_OS),LINUX) ifeq ($(PLATFORM_OS),LINUX)
# Compile raylib to shared library version for GNU/Linux. # Compile raylib to shared library version for GNU/Linux.
# WARNING: you should type "make clean" before doing this target # WARNING: you should type "make clean" before doing this target
$(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_VERSION).so $(OBJS) -Wl,-soname,libraylib.$(RAYLIB_API_VERSION).so -lGL -lm -lpthread -ldl -lrt $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/libraylib.so.$(RAYLIB_VERSION) $(OBJS) -shared -Wl,-soname,libraylib.so.$(RAYLIB_API_VERSION) -lGL -lc -lm -lpthread -ldl -lrt
@echo "raylib shared library generated (libraylib.$(RAYLIB_VERSION).so)!" @echo "raylib shared library generated (libraylib.so.$(RAYLIB_VERSION))!"
cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(RAYLIB_VERSION).so libraylib.$(RAYLIB_API_VERSION).so cd $(RAYLIB_RELEASE_PATH) && ln -fsv libraylib.so.$(RAYLIB_VERSION) libraylib.so.$(RAYLIB_API_VERSION)
cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(RAYLIB_VERSION).so libraylib.so cd $(RAYLIB_RELEASE_PATH) && ln -fsv libraylib.so.$(RAYLIB_API_VERSION) libraylib.so
endif endif
ifeq ($(PLATFORM_OS),OSX) ifeq ($(PLATFORM_OS),OSX)
$(CC) -dynamiclib -o $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_VERSION).dylib $(OBJS) -compatibility_version $(RAYLIB_API_VERSION) -current_version $(RAYLIB_VERSION) -framework OpenGL -framework OpenAL -framework IOKit -framework CoreVideo -framework Cocoa $(CC) -dynamiclib -o $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_VERSION).dylib $(OBJS) -compatibility_version $(RAYLIB_API_VERSION) -current_version $(RAYLIB_VERSION) -framework OpenGL -framework OpenAL -framework IOKit -framework CoreVideo -framework Cocoa
@ -493,49 +511,77 @@ utils.o : utils.c utils.h
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM)
# Install generated and needed files to required directories # Install generated and needed files to required directories
# TODO: add other platforms. # TODO: Add other platforms. Remove sudo requirement, i.e. add USER mode.
# On GNU/Linux and BSDs, there are some standard directories that contain extra
# libraries and header files. These directories (often /usr/local/lib and
# /usr/local/include) are for libraries that are installed manually
# (without a package manager). We'll use /usr/local/lib/raysan5 and /usr/local/include/raysan5
# for our -L and -I specification to simplify management of the raylib source package.
# Customize these locations if you like but don't forget to pass them to make
# for compilation and enable runtime linking with -rpath, LD_LIBRARY_PATH, or ldconfig.
# Hint: add -L$(RAYLIB_INSTALL_PATH) -I$(RAYLIB_H_INSTALL_PATH) to your own makefiles.
# See below and ../examples/Makefile for more information.
# RAYLIB_INSTALL_PATH should be the desired full path to libraylib. No relative paths.
RAYLIB_INSTALL_PATH ?= /usr/local/lib/raysan5
# RAYLIB_H_INSTALL_PATH locates the installed raylib header and associated source files.
RAYLIB_H_INSTALL_PATH ?= /usr/local/include/raysan5
install : install :
ifeq ($(ROOT),root) ifeq ($(ROOT),root)
# Attention! You are root. Consult this Makefile for more information.
ifeq ($(PLATFORM_OS),LINUX) ifeq ($(PLATFORM_OS),LINUX)
# On GNU/Linux there are some standard directories that contain # Prepare the environment as needed.
# libraries and header files. These directory (/usr/local/lib and mkdir --parents --verbose $(RAYLIB_INSTALL_PATH)
# /usr/local/include/) are for libraries that are installed mkdir --parents --verbose $(RAYLIB_H_INSTALL_PATH)
# manually (without a package manager). ifeq ($(RAYLIB_LIBTYPE),SHARED)
ifeq ($(RAYLIB_LIBTYPE),SHARED) # Installing the shared library.
cp --update $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_VERSION).so /usr/local/lib/libraylib.$(RAYLIB_VERSION).so cp --update --verbose $(RAYLIB_RELEASE_PATH)/libraylib.so.$(RAYLIB_VERSION) $(RAYLIB_INSTALL_PATH)/libraylib.so.$(RAYLIB_VERSION)
cp --update $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_API_VERSION).so /usr/local/lib/libraylib.$(RAYLIB_API_VERSION).so cd $(RAYLIB_INSTALL_PATH); ln -fsv libraylib.so.$(RAYLIB_VERSION) libraylib.so.$(RAYLIB_API_VERSION)
cp --update $(RAYLIB_RELEASE_PATH)/libraylib.so /usr/local/lib/libraylib.so cd $(RAYLIB_INSTALL_PATH); ln -fsv libraylib.so.$(RAYLIB_API_VERSION) libraylib.so
else # Uncomment to update the runtime linker cache with RAYLIB_INSTALL_PATH.
cp --update raylib.h /usr/local/include/raylib.h # Not necessary if later embedding RPATH in your executable. See examples/Makefile.
cp --update $(RAYLIB_RELEASE_PATH)/libraylib.a /usr/local/lib/libraylib.a ldconfig $(RAYLIB_INSTALL_PATH)
endif else
# Installing the static library.
cp --update --verbose $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_INSTALL_PATH)/libraylib.a
endif
# Let's have all the source.
cp --update --recursive $(RAYLIB_PATH)/src/*.h $(RAYLIB_H_INSTALL_PATH)/
cp --update --recursive $(RAYLIB_PATH)/src/*.c $(RAYLIB_H_INSTALL_PATH)/
cp --update --recursive $(RAYLIB_PATH)/src/external $(RAYLIB_H_INSTALL_PATH)/
cp --update --recursive $(RAYLIB_PATH)/release/include/AL $(RAYLIB_H_INSTALL_PATH)/external
@echo "raylib dev files installed/updated!" @echo "raylib dev files installed/updated!"
else else
@echo "This function works only on GNU/Linux systems" @echo "This function currently works on GNU/Linux systems. Add yours today (^;"
endif endif
else else
@echo "Error: no root permissions" @echo "Error: Root permissions needed for installation. Try sudo make install"
endif endif
# Remove raylib dev files installed on the system # Remove raylib dev files installed on the system
# TODO: see 'install' target. # TODO: see 'install' target.
uninstall : uninstall :
ifeq ($(ROOT),root) ifeq ($(ROOT),root)
# Warning! You are root. Please confirm that there is nothing here to keep.
# Proceeding will remove everything under the specified locations!
ifeq ($(PLATFORM_OS),LINUX) ifeq ($(PLATFORM_OS),LINUX)
rm --force /usr/local/include/raylib.h
ifeq ($(RAYLIB_LIBTYPE),SHARED) ifeq ($(RAYLIB_LIBTYPE),SHARED)
rm --force /usr/local/lib/libraylib.so rm --force --interactive --verbose $(RAYLIB_INSTALL_PATH)/libraylib.so
rm --force /usr/local/lib/libraylib.$(RAYLIB_API_VERSION).so rm --force --interactive --verbose $(RAYLIB_INSTALL_PATH)/libraylib.so.$(RAYLIB_API_VERSION)
rm --force /usr/local/lib/libraylib.$(RAYLIB_VERSION).so rm --force --interactive --verbose $(RAYLIB_INSTALL_PATH)/libraylib.so.$(RAYLIB_VERSION)
# Uncomment to clean up the runtime linker cache. See install target.
ldconfig
else else
rm --force /usr/local/lib/libraylib.a rm --force --interactive --verbose $(RAYLIB_INSTALL_PATH)/libraylib.a
endif endif
@echo "raylib development files removed!" rm --force --interactive=once --recursive $(RAYLIB_H_INSTALL_PATH)/*
@echo "raylib development files removed!"
else else
@echo "This function works only on GNU/Linux systems" @echo "This function works only on GNU/Linux systems"
endif endif
else else
@echo "Error: no root permissions" @echo "Error: Root permissions needed for uninstallation. Try sudo make uninstall"
endif endif
# Clean everything # Clean everything
@ -543,7 +589,7 @@ clean:
ifeq ($(PLATFORM_OS),WINDOWS) ifeq ($(PLATFORM_OS),WINDOWS)
del *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so external/stb_vorbis.o del *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so external/stb_vorbis.o
else else
rm -f *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_API_VERSION).so $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_VERSION).so external/stb_vorbis.o rm -fv *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so* external/stb_vorbis.o
endif endif
ifeq ($(PLATFORM),PLATFORM_ANDROID) ifeq ($(PLATFORM),PLATFORM_ANDROID)
rm -rf $(ANDROID_TOOLCHAIN) rm -rf $(ANDROID_TOOLCHAIN)

View file

@ -225,9 +225,10 @@ void TraceLog(int msgType, const char *text, ...); // Show trace lo
#endif #endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition - Audio Device initialization and Closing // mini_al AudioBuffer Functionality
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if USE_MINI_AL #if USE_MINI_AL
#define DEVICE_FORMAT mal_format_f32 #define DEVICE_FORMAT mal_format_f32
#define DEVICE_CHANNELS 2 #define DEVICE_CHANNELS 2
#define DEVICE_SAMPLE_RATE 44100 #define DEVICE_SAMPLE_RATE 44100
@ -235,15 +236,16 @@ void TraceLog(int msgType, const char *text, ...); // Show trace lo
typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM } AudioBufferUsage; typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM } AudioBufferUsage;
// Audio buffer structure // Audio buffer structure
// NOTE: Slightly different logic is used when feeding data to the playback device depending on whether or not data is streamed
typedef struct AudioBuffer AudioBuffer; typedef struct AudioBuffer AudioBuffer;
struct AudioBuffer { struct AudioBuffer {
mal_dsp dsp; // For format conversion. mal_dsp dsp; // Required for format conversion
float volume; float volume;
float pitch; float pitch;
bool playing; bool playing;
bool paused; bool paused;
bool looping; // Always true for AudioStreams. bool looping; // Always true for AudioStreams
AudioBufferUsage usage; // Slightly different logic is used when feeding data to the playback device depending on whether or not data is streamed. int usage; // AudioBufferUsage type
bool isSubBufferProcessed[2]; bool isSubBufferProcessed[2];
unsigned int frameCursorPos; unsigned int frameCursorPos;
unsigned int bufferSizeInFrames; unsigned int bufferSizeInFrames;
@ -252,76 +254,48 @@ struct AudioBuffer {
unsigned char buffer[1]; unsigned char buffer[1];
}; };
void StopAudioBuffer(AudioBuffer *audioBuffer); // mini_al global variables
static mal_context context; static mal_context context;
static mal_device device; static mal_device device;
static mal_bool32 isAudioInitialized = MAL_FALSE;
static float masterVolume = 1;
static mal_mutex audioLock; static mal_mutex audioLock;
static AudioBuffer *firstAudioBuffer = NULL; // Audio buffers are tracked in a linked list. static bool isAudioInitialized = MAL_FALSE;
static float masterVolume = 1.0f;
// Audio buffers are tracked in a linked list
static AudioBuffer *firstAudioBuffer = NULL;
static AudioBuffer *lastAudioBuffer = NULL; static AudioBuffer *lastAudioBuffer = NULL;
static void TrackAudioBuffer(AudioBuffer* audioBuffer) // mini_al functions declaration
{ static void OnLog(mal_context *pContext, mal_device *pDevice, const char *message);
mal_mutex_lock(&audioLock); static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameCount, void *pFramesOut);
static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, void *pFramesOut, void *pUserData);
static void MixAudioFrames(float *framesOut, const float *framesIn, mal_uint32 frameCount, float localVolume);
{ // AudioBuffer management functions declaration
if (firstAudioBuffer == NULL) firstAudioBuffer = audioBuffer; // NOTE: Those functions are not exposed by raylib... for the moment
else AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_uint32 bufferSizeInFrames, AudioBufferUsage usage);
{ void DeleteAudioBuffer(AudioBuffer *audioBuffer);
lastAudioBuffer->next = audioBuffer; bool IsAudioBufferPlaying(AudioBuffer *audioBuffer);
audioBuffer->prev = lastAudioBuffer; void PlayAudioBuffer(AudioBuffer *audioBuffer);
} void StopAudioBuffer(AudioBuffer *audioBuffer);
void PauseAudioBuffer(AudioBuffer *audioBuffer);
void ResumeAudioBuffer(AudioBuffer *audioBuffer);
void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume);
void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch);
void TrackAudioBuffer(AudioBuffer *audioBuffer);
void UntrackAudioBuffer(AudioBuffer *audioBuffer);
lastAudioBuffer = audioBuffer;
}
mal_mutex_unlock(&audioLock); // Log callback function
} static void OnLog(mal_context *pContext, mal_device *pDevice, const char *message)
static void UntrackAudioBuffer(AudioBuffer* audioBuffer)
{
mal_mutex_lock(&audioLock);
{
if (audioBuffer->prev == NULL) firstAudioBuffer = audioBuffer->next;
else audioBuffer->prev->next = audioBuffer->next;
if (audioBuffer->next == NULL) lastAudioBuffer = audioBuffer->prev;
else audioBuffer->next->prev = audioBuffer->prev;
audioBuffer->prev = NULL;
audioBuffer->next = NULL;
}
mal_mutex_unlock(&audioLock);
}
static void OnLog_MAL(mal_context *pContext, mal_device *pDevice, const char *message)
{ {
(void)pContext; (void)pContext;
(void)pDevice; (void)pDevice;
TraceLog(LOG_ERROR, message); // All log messages from mini_al are errors.
} TraceLog(LOG_ERROR, message); // All log messages from mini_al are errors
// This is the main mixing function. Mixing is pretty simple in this project - it's just an accumulation.
//
// framesOut is both an input and an output. It will be initially filled with zeros outside of this function.
static void MixFrames(float* framesOut, const float* framesIn, mal_uint32 frameCount, float localVolume)
{
for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame)
{
for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel)
{
float *frameOut = framesOut + (iFrame*device.channels);
const float *frameIn = framesIn + (iFrame*device.channels);
frameOut[iChannel] += frameIn[iChannel]*masterVolume*localVolume;
}
}
} }
// Sending audio data to device callback function
static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameCount, void *pFramesOut) static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameCount, void *pFramesOut)
{ {
// This is where all of the mixing takes place. // This is where all of the mixing takes place.
@ -334,7 +308,7 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameC
// want to consider how you might want to avoid this. // want to consider how you might want to avoid this.
mal_mutex_lock(&audioLock); mal_mutex_lock(&audioLock);
{ {
for (AudioBuffer* audioBuffer = firstAudioBuffer; audioBuffer != NULL; audioBuffer = audioBuffer->next) for (AudioBuffer *audioBuffer = firstAudioBuffer; audioBuffer != NULL; audioBuffer = audioBuffer->next)
{ {
// Ignore stopped or paused sounds. // Ignore stopped or paused sounds.
if (!audioBuffer->playing || audioBuffer->paused) continue; if (!audioBuffer->playing || audioBuffer->paused) continue;
@ -364,14 +338,14 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameC
// If we're not looping, we need to make sure we flush the internal buffers of the DSP pipeline to ensure we get the // If we're not looping, we need to make sure we flush the internal buffers of the DSP pipeline to ensure we get the
// last few samples. // last few samples.
mal_bool32 flushDSP = !audioBuffer->looping; bool flushDSP = !audioBuffer->looping;
mal_uint32 framesJustRead = mal_dsp_read_frames_ex(&audioBuffer->dsp, framesToReadRightNow, tempBuffer, flushDSP); mal_uint32 framesJustRead = mal_dsp_read_frames_ex(&audioBuffer->dsp, framesToReadRightNow, tempBuffer, flushDSP);
if (framesJustRead > 0) if (framesJustRead > 0)
{ {
float *framesOut = (float *)pFramesOut + (framesRead*device.channels); float *framesOut = (float *)pFramesOut + (framesRead*device.channels);
float *framesIn = tempBuffer; float *framesIn = tempBuffer;
MixFrames(framesOut, framesIn, framesJustRead, audioBuffer->volume); MixAudioFrames(framesOut, framesIn, framesJustRead, audioBuffer->volume);
framesToRead -= framesJustRead; framesToRead -= framesJustRead;
framesRead += framesJustRead; framesRead += framesJustRead;
@ -387,15 +361,16 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameC
} }
else else
{ {
// Should never get here, but just for safety, move the cursor position back to the start and continue the loop. // Should never get here, but just for safety,
// move the cursor position back to the start and continue the loop.
audioBuffer->frameCursorPos = 0; audioBuffer->frameCursorPos = 0;
continue; continue;
} }
} }
} }
// If for some reason we weren't able to read every frame we'll need to break from the loop. Not doing this could // If for some reason we weren't able to read every frame we'll need to break from the loop.
// theoretically put us into an infinite loop. // Not doing this could theoretically put us into an infinite loop.
if (framesToRead > 0) break; if (framesToRead > 0) break;
} }
} }
@ -405,14 +380,122 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameC
return frameCount; // We always output the same number of frames that were originally requested. return frameCount; // We always output the same number of frames that were originally requested.
} }
// DSP read from audio buffer callback function
static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, void *pFramesOut, void *pUserData)
{
AudioBuffer *audioBuffer = (AudioBuffer *)pUserData;
mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2;
mal_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames;
if (currentSubBufferIndex > 1)
{
TraceLog(LOG_DEBUG, "Frame cursor position moved too far forward in audio stream");
return 0;
}
// Another thread can update the processed state of buffers so we just take a copy here to try and avoid potential synchronization problems.
bool isSubBufferProcessed[2];
isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0];
isSubBufferProcessed[1] = audioBuffer->isSubBufferProcessed[1];
mal_uint32 frameSizeInBytes = mal_get_sample_size_in_bytes(audioBuffer->dsp.config.formatIn)*audioBuffer->dsp.config.channelsIn;
// Fill out every frame until we find a buffer that's marked as processed. Then fill the remainder with 0.
mal_uint32 framesRead = 0;
for (;;)
{
// We break from this loop differently depending on the buffer's usage. For static buffers, we simply fill as much data as we can. For
// streaming buffers we only fill the halves of the buffer that are processed. Unprocessed halves must keep their audio data in-tact.
if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC)
{
if (framesRead >= frameCount) break;
}
else
{
if (isSubBufferProcessed[currentSubBufferIndex]) break;
}
mal_uint32 totalFramesRemaining = (frameCount - framesRead);
if (totalFramesRemaining == 0) break;
mal_uint32 framesRemainingInOutputBuffer;
if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC)
{
framesRemainingInOutputBuffer = audioBuffer->bufferSizeInFrames - audioBuffer->frameCursorPos;
}
else
{
mal_uint32 firstFrameIndexOfThisSubBuffer = subBufferSizeInFrames * currentSubBufferIndex;
framesRemainingInOutputBuffer = subBufferSizeInFrames - (audioBuffer->frameCursorPos - firstFrameIndexOfThisSubBuffer);
}
mal_uint32 framesToRead = totalFramesRemaining;
if (framesToRead > framesRemainingInOutputBuffer) framesToRead = framesRemainingInOutputBuffer;
memcpy((unsigned char *)pFramesOut + (framesRead*frameSizeInBytes), audioBuffer->buffer + (audioBuffer->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes);
audioBuffer->frameCursorPos = (audioBuffer->frameCursorPos + framesToRead) % audioBuffer->bufferSizeInFrames;
framesRead += framesToRead;
// If we've read to the end of the buffer, mark it as processed.
if (framesToRead == framesRemainingInOutputBuffer)
{
audioBuffer->isSubBufferProcessed[currentSubBufferIndex] = true;
isSubBufferProcessed[currentSubBufferIndex] = true;
currentSubBufferIndex = (currentSubBufferIndex + 1)%2;
// We need to break from this loop if we're not looping.
if (!audioBuffer->looping)
{
StopAudioBuffer(audioBuffer);
break;
}
}
}
// Zero-fill excess.
mal_uint32 totalFramesRemaining = (frameCount - framesRead);
if (totalFramesRemaining > 0)
{
memset((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes);
// For static buffers we can fill the remaining frames with silence for safety, but we don't want
// to report those frames as "read". The reason for this is that the caller uses the return value
// to know whether or not a non-looping sound has finished playback.
if (audioBuffer->usage != AUDIO_BUFFER_USAGE_STATIC) framesRead += totalFramesRemaining;
}
return framesRead;
}
// This is the main mixing function. Mixing is pretty simple in this project - it's just an accumulation.
// NOTE: framesOut is both an input and an output. It will be initially filled with zeros outside of this function.
static void MixAudioFrames(float *framesOut, const float *framesIn, mal_uint32 frameCount, float localVolume)
{
for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame)
{
for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel)
{
float *frameOut = framesOut + (iFrame*device.channels);
const float *frameIn = framesIn + (iFrame*device.channels);
frameOut[iChannel] += frameIn[iChannel]*masterVolume*localVolume;
}
}
}
#endif #endif
//----------------------------------------------------------------------------------
// Module Functions Definition - Audio Device initialization and Closing
//----------------------------------------------------------------------------------
// Initialize audio device // Initialize audio device
void InitAudioDevice(void) void InitAudioDevice(void)
{ {
#if USE_MINI_AL #if USE_MINI_AL
// Context. // Context.
mal_context_config contextConfig = mal_context_config_init(OnLog_MAL); mal_context_config contextConfig = mal_context_config_init(OnLog);
mal_result result = mal_context_init(NULL, 0, &contextConfig, &context); mal_result result = mal_context_init(NULL, 0, &contextConfig, &context);
if (result != MAL_SUCCESS) if (result != MAL_SUCCESS)
{ {
@ -550,106 +633,17 @@ void SetMasterVolume(float volume)
else if (volume > 1.0f) volume = 1.0f; else if (volume > 1.0f) volume = 1.0f;
#if USE_MINI_AL #if USE_MINI_AL
masterVolume = 1; masterVolume = volume;
#else #else
alListenerf(AL_GAIN, volume); alListenerf(AL_GAIN, volume);
#endif #endif
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Audio Buffer // Module Functions Definition - Audio Buffer management
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if USE_MINI_AL #if USE_MINI_AL
static mal_uint32 AudioBuffer_OnDSPRead(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) // Create a new audio buffer. Initially filled with silence
{
AudioBuffer *audioBuffer = (AudioBuffer *)pUserData;
mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2;
mal_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames;
if (currentSubBufferIndex > 1)
{
TraceLog(LOG_DEBUG, "Frame cursor position moved too far forward in audio stream");
return 0;
}
// Another thread can update the processed state of buffers so we just take a copy here to try and avoid potential synchronization problems.
bool isSubBufferProcessed[2];
isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0];
isSubBufferProcessed[1] = audioBuffer->isSubBufferProcessed[1];
mal_uint32 frameSizeInBytes = mal_get_sample_size_in_bytes(audioBuffer->dsp.config.formatIn)*audioBuffer->dsp.config.channelsIn;
// Fill out every frame until we find a buffer that's marked as processed. Then fill the remainder with 0.
mal_uint32 framesRead = 0;
for (;;)
{
// We break from this loop differently depending on the buffer's usage. For static buffers, we simply fill as much data as we can. For
// streaming buffers we only fill the halves of the buffer that are processed. Unprocessed halves must keep their audio data in-tact.
if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC)
{
if (framesRead >= frameCount) break;
}
else
{
if (isSubBufferProcessed[currentSubBufferIndex]) break;
}
mal_uint32 totalFramesRemaining = (frameCount - framesRead);
if (totalFramesRemaining == 0) break;
mal_uint32 framesRemainingInOutputBuffer;
if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC)
{
framesRemainingInOutputBuffer = audioBuffer->bufferSizeInFrames - audioBuffer->frameCursorPos;
}
else
{
mal_uint32 firstFrameIndexOfThisSubBuffer = subBufferSizeInFrames * currentSubBufferIndex;
framesRemainingInOutputBuffer = subBufferSizeInFrames - (audioBuffer->frameCursorPos - firstFrameIndexOfThisSubBuffer);
}
mal_uint32 framesToRead = totalFramesRemaining;
if (framesToRead > framesRemainingInOutputBuffer) framesToRead = framesRemainingInOutputBuffer;
memcpy((unsigned char *)pFramesOut + (framesRead*frameSizeInBytes), audioBuffer->buffer + (audioBuffer->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes);
audioBuffer->frameCursorPos = (audioBuffer->frameCursorPos + framesToRead) % audioBuffer->bufferSizeInFrames;
framesRead += framesToRead;
// If we've read to the end of the buffer, mark it as processed.
if (framesToRead == framesRemainingInOutputBuffer)
{
audioBuffer->isSubBufferProcessed[currentSubBufferIndex] = true;
isSubBufferProcessed[currentSubBufferIndex] = true;
currentSubBufferIndex = (currentSubBufferIndex + 1) % 2;
// We need to break from this loop if we're not looping.
if (!audioBuffer->looping)
{
StopAudioBuffer(audioBuffer);
break;
}
}
}
// Zero-fill excess.
mal_uint32 totalFramesRemaining = (frameCount - framesRead);
if (totalFramesRemaining > 0)
{
memset((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes);
// For static buffers we can fill the remaining frames with silence for safety, but we don't want
// to report those frames as "read". The reason for this is that the caller uses the return value
// to know whether or not a non-looping sound has finished playback.
if (audioBuffer->usage != AUDIO_BUFFER_USAGE_STATIC) framesRead += totalFramesRemaining;
}
return framesRead;
}
// Create a new audio buffer. Initially filled with silence.
AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_uint32 bufferSizeInFrames, AudioBufferUsage usage) AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_uint32 bufferSizeInFrames, AudioBufferUsage usage)
{ {
AudioBuffer *audioBuffer = (AudioBuffer *)calloc(sizeof(*audioBuffer) + (bufferSizeInFrames*channels*mal_get_sample_size_in_bytes(format)), 1); AudioBuffer *audioBuffer = (AudioBuffer *)calloc(sizeof(*audioBuffer) + (bufferSizeInFrames*channels*mal_get_sample_size_in_bytes(format)), 1);
@ -668,7 +662,7 @@ AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint3
dspConfig.channelsOut = DEVICE_CHANNELS; dspConfig.channelsOut = DEVICE_CHANNELS;
dspConfig.sampleRateIn = sampleRate; dspConfig.sampleRateIn = sampleRate;
dspConfig.sampleRateOut = DEVICE_SAMPLE_RATE; dspConfig.sampleRateOut = DEVICE_SAMPLE_RATE;
mal_result resultMAL = mal_dsp_init(&dspConfig, AudioBuffer_OnDSPRead, audioBuffer, &audioBuffer->dsp); mal_result resultMAL = mal_dsp_init(&dspConfig, OnAudioBufferDSPRead, audioBuffer, &audioBuffer->dsp);
if (resultMAL != MAL_SUCCESS) if (resultMAL != MAL_SUCCESS)
{ {
TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create data conversion pipeline"); TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create data conversion pipeline");
@ -694,7 +688,7 @@ AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint3
return audioBuffer; return audioBuffer;
} }
// Delete an audio buffer. // Delete an audio buffer
void DeleteAudioBuffer(AudioBuffer *audioBuffer) void DeleteAudioBuffer(AudioBuffer *audioBuffer)
{ {
if (audioBuffer == NULL) if (audioBuffer == NULL)
@ -707,7 +701,7 @@ void DeleteAudioBuffer(AudioBuffer *audioBuffer)
free(audioBuffer); free(audioBuffer);
} }
// Check if an audio buffer is playing. // Check if an audio buffer is playing
bool IsAudioBufferPlaying(AudioBuffer *audioBuffer) bool IsAudioBufferPlaying(AudioBuffer *audioBuffer)
{ {
if (audioBuffer == NULL) if (audioBuffer == NULL)
@ -719,10 +713,9 @@ bool IsAudioBufferPlaying(AudioBuffer *audioBuffer)
return audioBuffer->playing && !audioBuffer->paused; return audioBuffer->playing && !audioBuffer->paused;
} }
// Play an audio buffer. // Play an audio buffer
// // NOTE: Buffer is restarted to the start.
// This will restart the buffer from the start. Use PauseAudioBuffer() and ResumeAudioBuffer() if the playback position // Use PauseAudioBuffer() and ResumeAudioBuffer() if the playback position should be maintained.
// should be maintained.
void PlayAudioBuffer(AudioBuffer *audioBuffer) void PlayAudioBuffer(AudioBuffer *audioBuffer)
{ {
if (audioBuffer == NULL) if (audioBuffer == NULL)
@ -736,7 +729,7 @@ void PlayAudioBuffer(AudioBuffer *audioBuffer)
audioBuffer->frameCursorPos = 0; audioBuffer->frameCursorPos = 0;
} }
// Stop an audio buffer. // Stop an audio buffer
void StopAudioBuffer(AudioBuffer *audioBuffer) void StopAudioBuffer(AudioBuffer *audioBuffer)
{ {
if (audioBuffer == NULL) if (audioBuffer == NULL)
@ -755,7 +748,7 @@ void StopAudioBuffer(AudioBuffer *audioBuffer)
audioBuffer->isSubBufferProcessed[1] = true; audioBuffer->isSubBufferProcessed[1] = true;
} }
// Pause an audio buffer. // Pause an audio buffer
void PauseAudioBuffer(AudioBuffer *audioBuffer) void PauseAudioBuffer(AudioBuffer *audioBuffer)
{ {
if (audioBuffer == NULL) if (audioBuffer == NULL)
@ -767,7 +760,7 @@ void PauseAudioBuffer(AudioBuffer *audioBuffer)
audioBuffer->paused = true; audioBuffer->paused = true;
} }
// Resume an audio buffer. // Resume an audio buffer
void ResumeAudioBuffer(AudioBuffer *audioBuffer) void ResumeAudioBuffer(AudioBuffer *audioBuffer)
{ {
if (audioBuffer == NULL) if (audioBuffer == NULL)
@ -779,7 +772,7 @@ void ResumeAudioBuffer(AudioBuffer *audioBuffer)
audioBuffer->paused = false; audioBuffer->paused = false;
} }
// Set volume for an audio buffer. // Set volume for an audio buffer
void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume) void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume)
{ {
if (audioBuffer == NULL) if (audioBuffer == NULL)
@ -791,7 +784,7 @@ void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume)
audioBuffer->volume = volume; audioBuffer->volume = volume;
} }
// Set pitch for an audio buffer. // Set pitch for an audio buffer
void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch) void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch)
{ {
if (audioBuffer == NULL) if (audioBuffer == NULL)
@ -807,6 +800,44 @@ void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch)
mal_uint32 newOutputSampleRate = (mal_uint32)((((float)audioBuffer->dsp.config.sampleRateOut / (float)audioBuffer->dsp.config.sampleRateIn) / pitch) * audioBuffer->dsp.config.sampleRateIn); mal_uint32 newOutputSampleRate = (mal_uint32)((((float)audioBuffer->dsp.config.sampleRateOut / (float)audioBuffer->dsp.config.sampleRateIn) / pitch) * audioBuffer->dsp.config.sampleRateIn);
mal_dsp_set_output_sample_rate(&audioBuffer->dsp, newOutputSampleRate); mal_dsp_set_output_sample_rate(&audioBuffer->dsp, newOutputSampleRate);
} }
// Track audio buffer to linked list next position
void TrackAudioBuffer(AudioBuffer *audioBuffer)
{
mal_mutex_lock(&audioLock);
{
if (firstAudioBuffer == NULL) firstAudioBuffer = audioBuffer;
else
{
lastAudioBuffer->next = audioBuffer;
audioBuffer->prev = lastAudioBuffer;
}
lastAudioBuffer = audioBuffer;
}
mal_mutex_unlock(&audioLock);
}
// Untrack audio buffer from linked list
void UntrackAudioBuffer(AudioBuffer *audioBuffer)
{
mal_mutex_lock(&audioLock);
{
if (audioBuffer->prev == NULL) firstAudioBuffer = audioBuffer->next;
else audioBuffer->prev->next = audioBuffer->next;
if (audioBuffer->next == NULL) lastAudioBuffer = audioBuffer->prev;
else audioBuffer->next->prev = audioBuffer->prev;
audioBuffer->prev = NULL;
audioBuffer->next = NULL;
}
mal_mutex_unlock(&audioLock);
}
#endif #endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -883,13 +914,13 @@ Sound LoadSoundFromWave(Wave wave)
mal_uint32 frameCountIn = wave.sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so. mal_uint32 frameCountIn = wave.sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so.
mal_uint32 frameCount = mal_convert_frames(NULL, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, formatIn, wave.channels, wave.sampleRate, frameCountIn); mal_uint32 frameCount = mal_convert_frames(NULL, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, formatIn, wave.channels, wave.sampleRate, frameCountIn);
if (frameCount == 0) TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to get frame count for format conversion"); if (frameCount == 0) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Failed to get frame count for format conversion");
AudioBuffer* audioBuffer = CreateAudioBuffer(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, frameCount, AUDIO_BUFFER_USAGE_STATIC); AudioBuffer* audioBuffer = CreateAudioBuffer(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, frameCount, AUDIO_BUFFER_USAGE_STATIC);
if (audioBuffer == NULL) TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create audio buffer"); if (audioBuffer == NULL) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Failed to create audio buffer");
frameCount = mal_convert_frames(audioBuffer->buffer, audioBuffer->dsp.config.formatIn, audioBuffer->dsp.config.channelsIn, audioBuffer->dsp.config.sampleRateIn, wave.data, formatIn, wave.channels, wave.sampleRate, frameCountIn); frameCount = mal_convert_frames(audioBuffer->buffer, audioBuffer->dsp.config.formatIn, audioBuffer->dsp.config.channelsIn, audioBuffer->dsp.config.sampleRateIn, wave.data, formatIn, wave.channels, wave.sampleRate, frameCountIn);
if (frameCount == 0) TraceLog(LOG_ERROR, "LoadSoundFromWave() : Format conversion failed"); if (frameCount == 0) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Format conversion failed");
sound.audioBuffer = audioBuffer; sound.audioBuffer = audioBuffer;
#else #else
@ -1853,7 +1884,7 @@ void CloseAudioStream(AudioStream stream)
void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
{ {
#if USE_MINI_AL #if USE_MINI_AL
AudioBuffer* audioBuffer = (AudioBuffer*)stream.audioBuffer; AudioBuffer *audioBuffer = (AudioBuffer *)stream.audioBuffer;
if (audioBuffer == NULL) if (audioBuffer == NULL)
{ {
TraceLog(LOG_ERROR, "UpdateAudioStream() : No audio buffer"); TraceLog(LOG_ERROR, "UpdateAudioStream() : No audio buffer");

View file

@ -294,11 +294,11 @@ static int renderOffsetX = 0; // Offset X from render area (must b
static int renderOffsetY = 0; // Offset Y from render area (must be divided by 2) static int renderOffsetY = 0; // Offset Y from render area (must be divided by 2)
static bool fullscreen = false; // Fullscreen mode (useful only for PLATFORM_DESKTOP) static bool fullscreen = false; // Fullscreen mode (useful only for PLATFORM_DESKTOP)
static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size) static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size)
static bool cursorHidden = false; // Track if cursor is hidden
static bool cursorOnScreen = false; // Tracks if cursor is inside client area
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
static const char *windowTitle = NULL; // Window text title... static const char *windowTitle = NULL; // Window text title...
static bool cursorHidden = false; // Track if cursor is hidden
static bool cursorOnScreen = false; // Tracks if cursor is inside client area
static int screenshotCounter = 0; // Screenshots counter static int screenshotCounter = 0; // Screenshots counter
// Register mouse states // Register mouse states
@ -441,12 +441,13 @@ void InitWindow(int width, int height, void *data)
uwpWindow = (EGLNativeWindowType)data; uwpWindow = (EGLNativeWindowType)data;
#endif #endif
// Init hi-res timer
InitTimer();
// Init graphics device (display device and OpenGL context) // Init graphics device (display device and OpenGL context)
// NOTE: returns true if window and graphic device has been initialized successfully // NOTE: returns true if window and graphic device has been initialized successfully
windowReady = InitGraphicsDevice(width, height); windowReady = InitGraphicsDevice(width, height);
if (!windowReady) return;
// Init hi-res timer
InitTimer();
#if defined(SUPPORT_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
// Load default font // Load default font
@ -1733,7 +1734,13 @@ static bool InitGraphicsDevice(int width, int height)
// NOTE: Getting video modes is not implemented in emscripten GLFW3 version // NOTE: Getting video modes is not implemented in emscripten GLFW3 version
#if defined(PLATFORM_DESKTOP) #if defined(PLATFORM_DESKTOP)
// Find monitor resolution // Find monitor resolution
const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); GLFWmonitor *monitor = glfwGetPrimaryMonitor();
if (!monitor)
{
TraceLog(LOG_WARNING, "Failed to get monitor");
return false;
}
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
displayWidth = mode->width; displayWidth = mode->width;
displayHeight = mode->height; displayHeight = mode->height;

View file

@ -1,5 +1,5 @@
// Audio playback and capture library. Public domain. See "unlicense" statement at the end of this file. // Audio playback and capture library. Public domain. See "unlicense" statement at the end of this file.
// mini_al - v0.x - xxxx-xx-xx // mini_al - v0.6b - 2018-02-03
// //
// David Reid - davidreidsoftware@gmail.com // David Reid - davidreidsoftware@gmail.com
@ -59,7 +59,7 @@
// //
// Building (BSD) // Building (BSD)
// -------------- // --------------
// The BSD build uses OSS and should Just Work without any linking nor include path configuration. // BSD build uses OSS. Requires linking to -lossaudio on {Open,Net}BSD, but not FreeBSD.
// //
// Building (Emscripten) // Building (Emscripten)
// --------------------- // ---------------------
@ -1774,7 +1774,10 @@ typedef HWND (WINAPI * MAL_PFN_GetDesktopWindow)();
#define mal_buffer_frame_capacity(buffer, channels, format) (sizeof(buffer) / mal_get_sample_size_in_bytes(format) / (channels)) #define mal_buffer_frame_capacity(buffer, channels, format) (sizeof(buffer) / mal_get_sample_size_in_bytes(format) / (channels))
// Some of these string utility functions are unused on some platforms. // Some of these string utility functions are unused on some platforms.
#if defined(__GNUC__) #if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4505)
#elif defined(__GNUC__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-function"
#endif #endif
@ -1972,7 +1975,9 @@ static int mal_strcmp(const char* str1, const char* str2)
return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0]; return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0];
} }
#if defined(__GNUC__) #if defined(_MSC_VER)
#pragma warning(pop)
#elif defined(__GNUC__)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
@ -6707,6 +6712,10 @@ static mal_result mal_device__main_loop__alsa(mal_device* pDevice)
#include <fcntl.h> #include <fcntl.h>
#include <sys/soundcard.h> #include <sys/soundcard.h>
#ifndef SNDCTL_DSP_HALT
#define SNDCTL_DSP_HALT SNDCTL_DSP_RESET
#endif
int mal_open_temp_device__oss() int mal_open_temp_device__oss()
{ {
// The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. // The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same.
@ -8843,6 +8852,8 @@ mal_result mal_device_init__sdl(mal_context* pContext, mal_device_type type, mal
mal_assert(pConfig != NULL); mal_assert(pConfig != NULL);
mal_assert(pDevice != NULL); mal_assert(pDevice != NULL);
(void)pContext;
// SDL wants the buffer size to be a power of 2. The SDL_AudioSpec property for this is only a Uint16, so we need // SDL wants the buffer size to be a power of 2. The SDL_AudioSpec property for this is only a Uint16, so we need
// to explicitly clamp this because it will be easy to overflow. // to explicitly clamp this because it will be easy to overflow.
mal_uint32 bufferSize = pConfig->bufferSizeInFrames; mal_uint32 bufferSize = pConfig->bufferSizeInFrames;
@ -10760,7 +10771,7 @@ static void mal_dsp_mix_channels__inc(float* pFramesOut, mal_uint32 channelsOut,
(void)channelMapOut; (void)channelMapOut;
(void)channelMapIn; (void)channelMapIn;
if (mode == mal_channel_mix_mode_basic) {\ if (mode == mal_channel_mix_mode_basic) {
// Basic mode is where we just zero out extra channels. // Basic mode is where we just zero out extra channels.
for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) {
switch (channelsIn) { switch (channelsIn) {
@ -10785,23 +10796,23 @@ static void mal_dsp_mix_channels__inc(float* pFramesOut, mal_uint32 channelsOut,
// Zero out extra channels. // Zero out extra channels.
switch (channelsOut - channelsIn) { switch (channelsOut - channelsIn) {
case 17: pFramesOut[iFrame*channelsOut+16] = 0; case 17: pFramesOut[iFrame*channelsOut+16 + channelsIn] = 0;
case 16: pFramesOut[iFrame*channelsOut+15] = 0; case 16: pFramesOut[iFrame*channelsOut+15 + channelsIn] = 0;
case 15: pFramesOut[iFrame*channelsOut+14] = 0; case 15: pFramesOut[iFrame*channelsOut+14 + channelsIn] = 0;
case 14: pFramesOut[iFrame*channelsOut+13] = 0; case 14: pFramesOut[iFrame*channelsOut+13 + channelsIn] = 0;
case 13: pFramesOut[iFrame*channelsOut+12] = 0; case 13: pFramesOut[iFrame*channelsOut+12 + channelsIn] = 0;
case 12: pFramesOut[iFrame*channelsOut+11] = 0; case 12: pFramesOut[iFrame*channelsOut+11 + channelsIn] = 0;
case 11: pFramesOut[iFrame*channelsOut+10] = 0; case 11: pFramesOut[iFrame*channelsOut+10 + channelsIn] = 0;
case 10: pFramesOut[iFrame*channelsOut+ 9] = 0; case 10: pFramesOut[iFrame*channelsOut+ 9 + channelsIn] = 0;
case 9: pFramesOut[iFrame*channelsOut+ 8] = 0; case 9: pFramesOut[iFrame*channelsOut+ 8 + channelsIn] = 0;
case 8: pFramesOut[iFrame*channelsOut+ 7] = 0; case 8: pFramesOut[iFrame*channelsOut+ 7 + channelsIn] = 0;
case 7: pFramesOut[iFrame*channelsOut+ 6] = 0; case 7: pFramesOut[iFrame*channelsOut+ 6 + channelsIn] = 0;
case 6: pFramesOut[iFrame*channelsOut+ 5] = 0; case 6: pFramesOut[iFrame*channelsOut+ 5 + channelsIn] = 0;
case 5: pFramesOut[iFrame*channelsOut+ 4] = 0; case 5: pFramesOut[iFrame*channelsOut+ 4 + channelsIn] = 0;
case 4: pFramesOut[iFrame*channelsOut+ 3] = 0; case 4: pFramesOut[iFrame*channelsOut+ 3 + channelsIn] = 0;
case 3: pFramesOut[iFrame*channelsOut+ 2] = 0; case 3: pFramesOut[iFrame*channelsOut+ 2 + channelsIn] = 0;
case 2: pFramesOut[iFrame*channelsOut+ 1] = 0; case 2: pFramesOut[iFrame*channelsOut+ 1 + channelsIn] = 0;
case 1: pFramesOut[iFrame*channelsOut+ 0] = 0; case 1: pFramesOut[iFrame*channelsOut+ 0 + channelsIn] = 0;
} }
} }
} else { } else {
@ -10832,10 +10843,10 @@ static void mal_dsp_mix_channels__inc(float* pFramesOut, mal_uint32 channelsOut,
} }
} else if (channelsIn == 2) { } else if (channelsIn == 2) {
// TODO: Implement an optimized stereo conversion. // TODO: Implement an optimized stereo conversion.
mal_dsp_mix_channels__dec(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic); mal_dsp_mix_channels__inc(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic);
} else { } else {
// Fall back to basic mixing mode. // Fall back to basic mixing mode.
mal_dsp_mix_channels__dec(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic); mal_dsp_mix_channels__inc(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic);
} }
} }
} }
@ -11494,7 +11505,11 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count)
// REVISION HISTORY // REVISION HISTORY
// ================ // ================
// //
// v0.x - xxxx-xx-xx // v0.6b - 2018-02-03
// - Fix some warnings when compiling with Visual C++.
//
// v0.6a - 2018-01-26
// - Fix errors with channel mixing when increasing the channel count.
// - Improvements to the build system for the OpenAL backend. // - Improvements to the build system for the OpenAL backend.
// - Documentation fixes. // - Documentation fixes.
// //

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
/* stb_image_write - v1.07 - public domain - http://nothings.org/stb/stb_image_write.h /* stb_image_write - v1.08 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk no warranty implied; use at your own risk
@ -10,34 +10,47 @@
Will probably not work correctly with strict-aliasing optimizations. Will probably not work correctly with strict-aliasing optimizations.
If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause
compilation warnings or even errors. To avoid this, also before #including,
#define STBI_MSC_SECURE_CRT
ABOUT: ABOUT:
This header file is a library for writing images to C stdio. It could be This header file is a library for writing images to C stdio. It could be
adapted to write to memory or a general streaming interface; let me know. adapted to write to memory or a general streaming interface; let me know.
The PNG output is not optimal; it is 20-50% larger than the file The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation. This library is designed written by a decent optimizing implementation; though providing a custom
for source code compactness and simplicity, not optimal image file size zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.
or run-time performance. This library is designed for source code compactness and simplicity,
not optimal image file size or run-time performance.
BUILDING: BUILDING:
You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
malloc,realloc,free. malloc,realloc,free.
You can define STBIW_MEMMOVE() to replace memmove() You can #define STBIW_MEMMOVE() to replace memmove()
You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function
for PNG compression (instead of the builtin one), it must have the following signature:
unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);
The returned data will be freed with STBIW_FREE() (free() by default),
so it must be heap allocated with STBIW_MALLOC() (malloc() by default),
USAGE: USAGE:
There are four functions, one for each image file format: There are five functions, one for each image file format:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
int stbi_write_jpg(char const *filename, int w, int h, int comp, const float *data); int stbi_write_jpg(char const *filename, int w, int h, int comp, const float *data, int quality);
There are also four equivalent functions that use an arbitrary write function. You are void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically
There are also five equivalent functions that use an arbitrary write function. You are
expected to open/close your file-equivalent before and after calling these: expected to open/close your file-equivalent before and after calling these:
int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
@ -49,6 +62,12 @@ USAGE:
where the callback is: where the callback is:
void stbi_write_func(void *context, void *data, int size); void stbi_write_func(void *context, void *data, int size);
You can configure it with these global variables:
int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE
int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression
int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode
You can define STBI_WRITE_NO_STDIO to disable the file variant of these You can define STBI_WRITE_NO_STDIO to disable the file variant of these
functions, so the library will not use stdio.h at all. However, this will functions, so the library will not use stdio.h at all. However, this will
also disable HDR writing, because it requires stdio for formatted output. also disable HDR writing, because it requires stdio for formatted output.
@ -75,6 +94,9 @@ USAGE:
writer, both because it is in BGR order and because it may have padding writer, both because it is in BGR order and because it may have padding
at the end of the line.) at the end of the line.)
PNG allows you to set the deflate compression level by setting the global
variable 'stbi_write_png_level' (it defaults to 8).
HDR expects linear float data. Since the format is always 32-bit rgb(e) HDR expects linear float data. Since the format is always 32-bit rgb(e)
data, alpha (if provided) is discarded, and for monochrome data it is data, alpha (if provided) is discarded, and for monochrome data it is
replicated across all three channels. replicated across all three channels.
@ -88,21 +110,17 @@ USAGE:
CREDITS: CREDITS:
PNG/BMP/TGA
Sean Barrett Sean Barrett - PNG/BMP/TGA
HDR Baldur Karlsson - HDR
Baldur Karlsson Jean-Sebastien Guay - TGA monochrome
TGA monochrome: Tim Kelsey - misc enhancements
Jean-Sebastien Guay Alan Hickman - TGA RLE
misc enhancements: Emmanuel Julien - initial file IO callback implementation
Tim Kelsey Jon Olick - original jo_jpeg.cpp code
TGA RLE Daniel Gibson - integrate JPEG, allow external zlib
Alan Hickman Aarni Koskela - allow choosing PNG filter
initial file IO callback implementation
Emmanuel Julien
JPEG
Jon Olick (original jo_jpeg.cpp code)
Daniel Gibson
bugfixes: bugfixes:
github:Chribba github:Chribba
Guillaume Chereau Guillaume Chereau
@ -114,6 +132,7 @@ CREDITS:
Thatcher Ulrich Thatcher Ulrich
github:poppolopoppo github:poppolopoppo
Patrick Boettcher Patrick Boettcher
github:xeekworx
LICENSE LICENSE
@ -132,9 +151,12 @@ extern "C" {
#define STBIWDEF static #define STBIWDEF static
#else #else
#define STBIWDEF extern #define STBIWDEF extern
extern int stbi_write_tga_with_rle;
#endif #endif
STBIWDEF int stbi_write_tga_with_rle;
STBIWDEF int stbi_write_png_comperssion_level;
STBIWDEF int stbi_write_force_png_filter;
#ifndef STBI_WRITE_NO_STDIO #ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
@ -151,6 +173,8 @@ STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w,
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@ -208,6 +232,23 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x,
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
#ifdef STB_IMAGE_WRITE_STATIC
static stbi__flip_vertically_on_write=0;
static int stbi_write_png_compression level = 8;
static int stbi_write_tga_with_rle = 1;
static int stbi_write_force_png_filter = -1;
#else
int stbi_write_png_compression_level = 8;
int stbi__flip_vertically_on_write=0;
int stbi_write_tga_with_rle = 1;
int stbi_write_force_png_filter = -1;
#endif
STBIWDEF void stbi_flip_vertically_on_write(int flag)
{
stbi__flip_vertically_on_write = flag;
}
typedef struct typedef struct
{ {
stbi_write_func *func; stbi_write_func *func;
@ -230,7 +271,13 @@ static void stbi__stdio_write(void *context, void *data, int size)
static int stbi__start_write_file(stbi__write_context *s, const char *filename) static int stbi__start_write_file(stbi__write_context *s, const char *filename)
{ {
FILE *f = fopen(filename, "wb"); FILE *f;
#ifdef STBI_MSC_SECURE_CRT
if (fopen_s(&f, filename, "wb"))
f = NULL;
#else
f = fopen(filename, "wb");
#endif
stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
return f != NULL; return f != NULL;
} }
@ -245,12 +292,6 @@ static void stbi__end_write_file(stbi__write_context *s)
typedef unsigned int stbiw_uint32; typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
#ifdef STB_IMAGE_WRITE_STATIC
static int stbi_write_tga_with_rle = 1;
#else
int stbi_write_tga_with_rle = 1;
#endif
static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
{ {
while (*fmt) { while (*fmt) {
@ -341,6 +382,9 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i
if (y <= 0) if (y <= 0)
return; return;
if (stbi__flip_vertically_on_write)
vdir *= -1;
if (vdir < 0) if (vdir < 0)
j_end = -1, j = y-1; j_end = -1, j = y-1;
else else
@ -412,11 +456,21 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v
"111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
} else { } else {
int i,j,k; int i,j,k;
int jend, jdir;
stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);
for (j = y - 1; j >= 0; --j) { if (stbi__flip_vertically_on_write) {
unsigned char *row = (unsigned char *) data + j * x * comp; j = 0;
jend = y;
jdir = 1;
} else {
j = y-1;
jend = -1;
jdir = -1;
}
for (; j != jend; j += jdir) {
unsigned char *row = (unsigned char *) data + j * x * comp;
int len; int len;
for (i = 0; i < x; i += len) { for (i = 0; i < x; i += len) {
@ -626,11 +680,15 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
s->func(s->context, header, sizeof(header)-1); s->func(s->context, header, sizeof(header)-1);
#ifdef STBI_MSC_SECURE_CRT
len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#else
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#endif
s->func(s->context, buffer, len); s->func(s->context, buffer, len);
for(i=0; i < y; i++) for(i=0; i < y; i++)
stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x); stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)*x);
STBIW_FREE(scratch); STBIW_FREE(scratch);
return 1; return 1;
} }
@ -662,6 +720,7 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const
// PNG writer // PNG writer
// //
#ifndef STBIW_ZLIB_COMPRESS
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2) #define stbiw__sbraw(a) ((int *) (a) - 2)
#define stbiw__sbm(a) stbiw__sbraw(a)[0] #define stbiw__sbm(a) stbiw__sbraw(a)[0]
@ -742,8 +801,14 @@ static unsigned int stbiw__zhash(unsigned char *data)
#define stbiw__ZHASH 16384 #define stbiw__ZHASH 16384
#endif // STBIW_ZLIB_COMPRESS
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{ {
#ifdef STBIW_ZLIB_COMPRESS
// user provided a zlib compress implementation, use that
return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);
#else // use builtin
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
@ -752,6 +817,8 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
int i,j, bitcount=0; int i,j, bitcount=0;
unsigned char *out = NULL; unsigned char *out = NULL;
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
if (hash_table == NULL)
return NULL;
if (quality < 5) quality = 5; if (quality < 5) quality = 5;
stbiw__sbpush(out, 0x78); // DEFLATE 32K window stbiw__sbpush(out, 0x78); // DEFLATE 32K window
@ -845,6 +912,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
// make returned pointer freeable // make returned pointer freeable
STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
return (unsigned char *) stbiw__sbraw(out); return (unsigned char *) stbiw__sbraw(out);
#endif // STBIW_ZLIB_COMPRESS
} }
static unsigned int stbiw__crc32(unsigned char *buffer, int len) static unsigned int stbiw__crc32(unsigned char *buffer, int len)
@ -911,61 +979,87 @@ static unsigned char stbiw__paeth(int a, int b, int c)
} }
// @OPTIMIZE: provide an option that always forces left-predict or paeth predict // @OPTIMIZE: provide an option that always forces left-predict or paeth predict
static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer)
{
static int mapping[] = { 0,1,2,3,4 };
static int firstmap[] = { 0,1,0,5,6 };
int *mymap = (y != 0) ? mapping : firstmap;
int i;
int type = mymap[filter_type];
unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);
for (i = 0; i < n; ++i) {
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
case 5: line_buffer[i] = z[i]; break;
case 6: line_buffer[i] = z[i]; break;
}
}
for (i=n; i < width*n; ++i) {
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i] - z[i-n]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
}
}
}
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
{ {
int force_filter = stbi_write_force_png_filter;
int ctype[5] = { -1, 0, 4, 2, 6 }; int ctype[5] = { -1, 0, 4, 2, 6 };
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
unsigned char *out,*o, *filt, *zlib; unsigned char *out,*o, *filt, *zlib;
signed char *line_buffer; signed char *line_buffer;
int i,j,k,p,zlen; int j,zlen;
if (stride_bytes == 0) if (stride_bytes == 0)
stride_bytes = x * n; stride_bytes = x * n;
if (force_filter >= 5) {
force_filter = -1;
}
filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
for (j=0; j < y; ++j) { for (j=0; j < y; ++j) {
static int mapping[] = { 0,1,2,3,4 }; int filter_type;
static int firstmap[] = { 0,1,0,5,6 }; if (force_filter > -1) {
int *mymap = (j != 0) ? mapping : firstmap; filter_type = force_filter;
int best = 0, bestval = 0x7fffffff; stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, force_filter, line_buffer);
for (p=0; p < 2; ++p) { } else { // Estimate the best filter by running through all of them:
for (k= p?best:0; k < 5; ++k) { // @TODO: clarity: rewrite this to go 0..5, and 'continue' the unwanted ones during 2nd pass int best_filter = 0, best_filter_val = 0x7fffffff, est, i;
int type = mymap[k],est=0; for (filter_type = 0; filter_type < 5; filter_type++) {
unsigned char *z = pixels + stride_bytes*j; stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, filter_type, line_buffer);
for (i=0; i < n; ++i)
switch (type) { // Estimate the entropy of the line using this filter; the less, the better.
case 0: line_buffer[i] = z[i]; break; est = 0;
case 1: line_buffer[i] = z[i]; break; for (i = 0; i < x*n; ++i) {
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
case 5: line_buffer[i] = z[i]; break;
case 6: line_buffer[i] = z[i]; break;
}
for (i=n; i < x*n; ++i) {
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i] - z[i-n]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
}
}
if (p) break;
for (i=0; i < x*n; ++i)
est += abs((signed char) line_buffer[i]); est += abs((signed char) line_buffer[i]);
if (est < bestval) { bestval = est; best = k; } }
if (est < best_filter_val) {
best_filter_val = est;
best_filter = filter_type;
}
}
if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it
stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, best_filter, line_buffer);
filter_type = best_filter;
} }
} }
// when we get here, best contains the filter type, and line_buffer contains the data // when we get here, filter_type contains the filter type, and line_buffer contains the data
filt[j*(x*n+1)] = (unsigned char) best; filt[j*(x*n+1)] = (unsigned char) filter_type;
STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
} }
STBIW_FREE(line_buffer); STBIW_FREE(line_buffer);
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level);
STBIW_FREE(filt); STBIW_FREE(filt);
if (!zlib) return 0; if (!zlib) return 0;
@ -1010,7 +1104,12 @@ STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const
int len; int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (png == NULL) return 0; if (png == NULL) return 0;
#ifdef STBI_MSC_SECURE_CRT
if (fopen_s(&f, filename, "wb"))
f = NULL;
#else
f = fopen(filename, "wb"); f = fopen(filename, "wb");
#endif
if (!f) { STBIW_FREE(png); return 0; } if (!f) { STBIW_FREE(png); return 0; }
fwrite(png, 1, len, f); fwrite(png, 1, len, f);
fclose(f); fclose(f);
@ -1318,7 +1417,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
float YDU[64], UDU[64], VDU[64]; float YDU[64], UDU[64], VDU[64];
for(row = y, pos = 0; row < y+8; ++row) { for(row = y, pos = 0; row < y+8; ++row) {
for(col = x; col < x+8; ++col, ++pos) { for(col = x; col < x+8; ++col, ++pos) {
int p = row*width*comp + col*comp; int p = (stbi__flip_vertically_on_write ? height-1-row : row)*width*comp + col*comp;
float r, g, b; float r, g, b;
if(row >= height) { if(row >= height) {
p -= width*comp*(row+1 - height); p -= width*comp*(row+1 - height);
@ -1377,6 +1476,8 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
#endif // STB_IMAGE_WRITE_IMPLEMENTATION #endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history /* Revision history
1.08 (2018-01-29)
add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter
1.07 (2017-07-24) 1.07 (2017-07-24)
doc fix doc fix
1.06 (2017-07-23) 1.06 (2017-07-23)

View file

@ -1,4 +1,4 @@
// stb_truetype.h - v1.17 - public domain // stb_truetype.h - v1.18 - public domain
// authored from 2009-2016 by Sean Barrett / RAD Game Tools // authored from 2009-2016 by Sean Barrett / RAD Game Tools
// //
// This library processes TrueType files: // This library processes TrueType files:
@ -30,33 +30,24 @@
// Imanol Celaya // Imanol Celaya
// //
// Bug/warning reports/fixes: // Bug/warning reports/fixes:
// "Zer" on mollyrocket // "Zer" on mollyrocket Fabian "ryg" Giesen
// Cass Everitt // Cass Everitt Martins Mozeiko
// stoiko (Haemimont Games) // stoiko (Haemimont Games) Cap Petschulat
// Brian Hook // Brian Hook Omar Cornut
// Walter van Niftrik // Walter van Niftrik github:aloucks
// David Gow // David Gow Peter LaValle
// David Given // David Given Sergey Popov
// Ivan-Assen Ivanov // Ivan-Assen Ivanov Giumo X. Clanjor
// Anthony Pesch // Anthony Pesch Higor Euripedes
// Johan Duparc // Johan Duparc Thomas Fields
// Hou Qiming // Hou Qiming Derek Vinyard
// Fabian "ryg" Giesen // Rob Loach Cort Stratton
// Martins Mozeiko // Kenney Phillis Jr. github:oyvindjam
// Cap Petschulat // Brian Costabile github:vassvik
// Omar Cornut
// github:aloucks
// Peter LaValle
// Sergey Popov
// Giumo X. Clanjor
// Higor Euripedes
// Thomas Fields
// Derek Vinyard
// Cort Stratton
// github:oyvindjam
// //
// VERSION HISTORY // VERSION HISTORY
// //
// 1.18 (2018-01-29) add missing function
// 1.17 (2017-07-23) make more arguments const; doc fix // 1.17 (2017-07-23) make more arguments const; doc fix
// 1.16 (2017-07-12) SDF support // 1.16 (2017-07-12) SDF support
// 1.15 (2017-03-03) make more arguments const // 1.15 (2017-03-03) make more arguments const
@ -171,7 +162,7 @@
// measurement for describing font size, defined as 72 points per inch. // measurement for describing font size, defined as 72 points per inch.
// stb_truetype provides a point API for compatibility. However, true // stb_truetype provides a point API for compatibility. However, true
// "per inch" conventions don't make much sense on computer displays // "per inch" conventions don't make much sense on computer displays
// since they different monitors have different number of pixels per // since different monitors have different number of pixels per
// inch. For example, Windows traditionally uses a convention that // inch. For example, Windows traditionally uses a convention that
// there are 96 pixels per inch, thus making 'inch' measurements have // there are 96 pixels per inch, thus making 'inch' measurements have
// nothing to do with inches, and thus effectively defining a point to // nothing to do with inches, and thus effectively defining a point to
@ -181,6 +172,39 @@
// for non-commercial fonts, thus making fonts scaled in points // for non-commercial fonts, thus making fonts scaled in points
// according to the TrueType spec incoherently sized in practice. // according to the TrueType spec incoherently sized in practice.
// //
// DETAILED USAGE:
//
// Scale:
// Select how high you want the font to be, in points or pixels.
// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute
// a scale factor SF that will be used by all other functions.
//
// Baseline:
// You need to select a y-coordinate that is the baseline of where
// your text will appear. Call GetFontBoundingBox to get the baseline-relative
// bounding box for all characters. SF*-y0 will be the distance in pixels
// that the worst-case character could extend above the baseline, so if
// you want the top edge of characters to appear at the top of the
// screen where y=0, then you would set the baseline to SF*-y0.
//
// Current point:
// Set the current point where the first character will appear. The
// first character could extend left of the current point; this is font
// dependent. You can either choose a current point that is the leftmost
// point and hope, or add some padding, or check the bounding box or
// left-side-bearing of the first character to be displayed and set
// the current point based on that.
//
// Displaying a character:
// Compute the bounding box of the character. It will contain signed values
// relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1,
// then the character should be displayed in the rectangle from
// <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1).
//
// Advancing for the next character:
// Call GlyphHMetrics, and compute 'current_point += SF * advance'.
//
//
// ADVANCED USAGE // ADVANCED USAGE
// //
// Quality: // Quality:
@ -427,11 +451,6 @@ int main(int arg, char **argv)
#define STBTT_fabs(x) fabs(x) #define STBTT_fabs(x) fabs(x)
#endif #endif
#ifndef STBTT_fabs
#include <math.h>
#define STBTT_fabs(x) fabs(x)
#endif
// #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
#ifndef STBTT_malloc #ifndef STBTT_malloc
#include <stdlib.h> #include <stdlib.h>
@ -2172,7 +2191,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
// push immediate // push immediate
if (b0 == 255) { if (b0 == 255) {
f = (float)stbtt__buf_get32(&b) / 0x10000; f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
} else { } else {
stbtt__buf_skip(&b, -1); stbtt__buf_skip(&b, -1);
f = (float)(stbtt_int16)stbtt__cff_int(&b); f = (float)(stbtt_int16)stbtt__cff_int(&b);
@ -2210,12 +2229,10 @@ static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, in
{ {
stbtt__csctx c = STBTT__CSCTX_INIT(1); stbtt__csctx c = STBTT__CSCTX_INIT(1);
int r = stbtt__run_charstring(info, glyph_index, &c); int r = stbtt__run_charstring(info, glyph_index, &c);
if (x0) { if (x0) *x0 = r ? c.min_x : 0;
*x0 = r ? c.min_x : 0; if (y0) *y0 = r ? c.min_y : 0;
*y0 = r ? c.min_y : 0; if (x1) *x1 = r ? c.max_x : 0;
*x1 = r ? c.max_x : 0; if (y1) *y1 = r ? c.max_y : 0;
*y1 = r ? c.max_y : 0;
}
return r ? c.num_vertices : 0; return r ? c.num_vertices : 0;
} }
@ -2395,7 +2412,7 @@ static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)
hh->num_remaining_in_head_chunk = count; hh->num_remaining_in_head_chunk = count;
} }
--hh->num_remaining_in_head_chunk; --hh->num_remaining_in_head_chunk;
return (char *) (hh->head) + size * hh->num_remaining_in_head_chunk; return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;
} }
} }
@ -3229,8 +3246,9 @@ error:
STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
{ {
float scale = scale_x > scale_y ? scale_y : scale_x; float scale = scale_x > scale_y ? scale_y : scale_x;
int winding_count, *winding_lengths; int winding_count = 0;
int *winding_lengths = NULL;
stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
if (windings) { if (windings) {
stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
@ -3318,6 +3336,11 @@ STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *
return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
} }
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)
{
stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));
}
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)
{ {
stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));

View file

@ -1658,6 +1658,8 @@ static int residue_decode(vorb *f, Codebook *book, float *target, int offset, in
return TRUE; return TRUE;
} }
// n is 1/2 of the blocksize --
// specification: "Correct per-vector decode length is [n]/2"
static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode) static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode)
{ {
int i,j,pass; int i,j,pass;
@ -1665,7 +1667,10 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int rtype = f->residue_types[rn]; int rtype = f->residue_types[rn];
int c = r->classbook; int c = r->classbook;
int classwords = f->codebooks[c].dimensions; int classwords = f->codebooks[c].dimensions;
int n_read = r->end - r->begin; unsigned int actual_size = rtype == 2 ? n*2 : n;
unsigned int limit_r_begin = (r->begin < actual_size ? r->begin : actual_size);
unsigned int limit_r_end = (r->end < actual_size ? r->end : actual_size);
int n_read = limit_r_end - limit_r_begin;
int part_read = n_read / r->part_size; int part_read = n_read / r->part_size;
int temp_alloc_point = temp_alloc_save(f); int temp_alloc_point = temp_alloc_save(f);
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
@ -3007,7 +3012,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
if (f->last_seg_which == f->end_seg_with_known_loc) { if (f->last_seg_which == f->end_seg_with_known_loc) {
// if we have a valid current loc, and this is final: // if we have a valid current loc, and this is final:
if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) { if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) {
uint32 current_end = f->known_loc_for_packet - (n-right_end); uint32 current_end = f->known_loc_for_packet;
// then let's infer the size of the (probably) short final frame // then let's infer the size of the (probably) short final frame
if (current_end < f->current_loc + (right_end-left_start)) { if (current_end < f->current_loc + (right_end-left_start)) {
if (current_end < f->current_loc) { if (current_end < f->current_loc) {
@ -3016,7 +3021,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
} else { } else {
*len = current_end - f->current_loc; *len = current_end - f->current_loc;
} }
*len += left_start; *len += left_start; // this doesn't seem right, but has no ill effect on my test files
if (*len > right_end) *len = right_end; // this should never happen if (*len > right_end) *len = right_end; // this should never happen
f->current_loc += *len; f->current_loc += *len;
return TRUE; return TRUE;
@ -3693,7 +3698,10 @@ static int start_decoder(vorb *f)
int i,max_part_read=0; int i,max_part_read=0;
for (i=0; i < f->residue_count; ++i) { for (i=0; i < f->residue_count; ++i) {
Residue *r = f->residue_config + i; Residue *r = f->residue_config + i;
int n_read = r->end - r->begin; unsigned int actual_size = f->blocksize_1 / 2;
unsigned int limit_r_begin = r->begin < actual_size ? r->begin : actual_size;
unsigned int limit_r_end = r->end < actual_size ? r->end : actual_size;
int n_read = limit_r_end - limit_r_begin;
int part_read = n_read / r->part_size; int part_read = n_read / r->part_size;
if (part_read > max_part_read) if (part_read > max_part_read)
max_part_read = part_read; max_part_read = part_read;
@ -3704,6 +3712,8 @@ static int start_decoder(vorb *f)
classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *)); classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *));
#endif #endif
// maximum reasonable partition size is f->blocksize_1
f->temp_memory_required = classify_mem; f->temp_memory_required = classify_mem;
if (imdct_mem > f->temp_memory_required) if (imdct_mem > f->temp_memory_required)
f->temp_memory_required = imdct_mem; f->temp_memory_required = imdct_mem;
@ -4967,6 +4977,8 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in
#endif // STB_VORBIS_NO_PULLDATA_API #endif // STB_VORBIS_NO_PULLDATA_API
/* Version history /* Version history
1.12 - 2017/11/21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
1.11 - 2017/07/23 - fix MinGW compilation
1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory 1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory
1.09 - 2016/04/04 - back out 'avoid discarding last frame' fix from previous version 1.09 - 2016/04/04 - back out 'avoid discarding last frame' fix from previous version
1.08 - 2016/04/02 - fixed multiple warnings; fix setup memory leaks; 1.08 - 2016/04/02 - fixed multiple warnings; fix setup memory leaks;

View file

@ -1,11 +1,11 @@
// Ogg Vorbis audio decoder - v1.11 - public domain // Ogg Vorbis audio decoder - v1.13b - public domain
// http://nothings.org/stb_vorbis/ // http://nothings.org/stb_vorbis/
// //
// Original version written by Sean Barrett in 2007. // Original version written by Sean Barrett in 2007.
// //
// Originally sponsored by RAD Game Tools. Seeking sponsored // Originally sponsored by RAD Game Tools. Seeking implementation
// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software, // sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker,
// Aras Pranckevicius, and Sean Barrett. // Elias Software, Aras Pranckevicius, and Sean Barrett.
// //
// LICENSE // LICENSE
// //
@ -32,6 +32,8 @@
// manxorist@github saga musix github:infatum // manxorist@github saga musix github:infatum
// //
// Partial history: // Partial history:
// 1.13 - 2018/01/29 - fix truncation of last frame (hopefully)
// 1.12 - 2017/11/21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
// 1.11 - 2017/07/23 - fix MinGW compilation // 1.11 - 2017/07/23 - fix MinGW compilation
// 1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory // 1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory
// 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version // 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version

View file

@ -1044,7 +1044,8 @@ RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight);
// Shader loading/unloading functions // Shader loading/unloading functions
RLAPI char *LoadText(const char *fileName); // Load chars array from text file RLAPI char *LoadText(const char *fileName); // Load chars array from text file
RLAPI Shader LoadShader(char *vsFileName, char *fsFileName); // Load shader from files and bind default locations RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations
RLAPI Shader LoadShaderCode(char *vsCode, char *fsCode); // Load shader from code strings and bind default locations
RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM)
RLAPI Shader GetShaderDefault(void); // Get default shader RLAPI Shader GetShaderDefault(void); // Get default shader

View file

@ -2324,7 +2324,27 @@ char *LoadText(const char *fileName)
// Load shader from files and bind default locations // Load shader from files and bind default locations
// NOTE: If shader string is NULL, using default vertex/fragment shaders // NOTE: If shader string is NULL, using default vertex/fragment shaders
Shader LoadShader(char *vsFileName, char *fsFileName) Shader LoadShader(const char *vsFileName, const char *fsFileName)
{
Shader shader = { 0 };
char *vShaderStr = NULL;
char *fShaderStr = NULL;
if (vsFileName != NULL) vShaderStr = LoadText(vsFileName);
if (fsFileName != NULL) fShaderStr = LoadText(fsFileName);
shader = LoadShaderCode(vShaderStr, fShaderStr);
if (vShaderStr != NULL) free(vShaderStr);
if (fShaderStr != NULL) free(fShaderStr);
return shader;
}
// Load shader from code strings
// NOTE: If shader string is NULL, using default vertex/fragment shaders
Shader LoadShaderCode(char *vsCode, char *fsCode)
{ {
Shader shader = { 0 }; Shader shader = { 0 };
@ -2335,27 +2355,8 @@ Shader LoadShader(char *vsFileName, char *fsFileName)
unsigned int vertexShaderId = defaultVShaderId; unsigned int vertexShaderId = defaultVShaderId;
unsigned int fragmentShaderId = defaultFShaderId; unsigned int fragmentShaderId = defaultFShaderId;
if (vsFileName != NULL) if (vsCode != NULL) vertexShaderId = CompileShader(vsCode, GL_VERTEX_SHADER);
{ if (fsCode != NULL) fragmentShaderId = CompileShader(fsCode, GL_FRAGMENT_SHADER);
char *vShaderStr = LoadText(vsFileName);
if (vShaderStr != NULL)
{
vertexShaderId = CompileShader(vShaderStr, GL_VERTEX_SHADER);
free(vShaderStr);
}
}
if (fsFileName != NULL)
{
char* fShaderStr = LoadText(fsFileName);
if (fShaderStr != NULL)
{
fragmentShaderId = CompileShader(fShaderStr, GL_FRAGMENT_SHADER);
free(fShaderStr);
}
}
if ((vertexShaderId == defaultVShaderId) && (fragmentShaderId == defaultFShaderId)) shader = defaultShader; if ((vertexShaderId == defaultVShaderId) && (fragmentShaderId == defaultFShaderId)) shader = defaultShader;
else else

View file

@ -418,11 +418,14 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
} }
else index = GetCharIndex(spriteFont, (unsigned char)text[i]); else index = GetCharIndex(spriteFont, (unsigned char)text[i]);
DrawTexturePro(spriteFont.texture, spriteFont.chars[index].rec, if ((unsigned char)text[i] != ' ')
{
DrawTexturePro(spriteFont.texture, spriteFont.chars[index].rec,
(Rectangle){ position.x + textOffsetX + spriteFont.chars[index].offsetX*scaleFactor, (Rectangle){ position.x + textOffsetX + spriteFont.chars[index].offsetX*scaleFactor,
position.y + textOffsetY + spriteFont.chars[index].offsetY*scaleFactor, position.y + textOffsetY + spriteFont.chars[index].offsetY*scaleFactor,
spriteFont.chars[index].rec.width*scaleFactor, spriteFont.chars[index].rec.width*scaleFactor,
spriteFont.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint); spriteFont.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint);
}
if (spriteFont.chars[index].advanceX == 0) textOffsetX += (int)(spriteFont.chars[index].rec.width*scaleFactor + spacing); if (spriteFont.chars[index].advanceX == 0) textOffsetX += (int)(spriteFont.chars[index].rec.width*scaleFactor + spacing);
else textOffsetX += (int)(spriteFont.chars[index].advanceX*scaleFactor + spacing); else textOffsetX += (int)(spriteFont.chars[index].advanceX*scaleFactor + spacing);

View file

@ -53,26 +53,21 @@ APP_COMPANY_NAME ?= raylib
APP_PRODUCT_NAME ?= rgame APP_PRODUCT_NAME ?= rgame
APP_VERSION_CODE ?= 1 APP_VERSION_CODE ?= 1
APP_VERSION_NAME ?= 1.0 APP_VERSION_NAME ?= 1.0
APP_ICON_LDPI ?= $(RAYLIB_PATH)\logo\logo36x36.png APP_ICON_LDPI ?= $(RAYLIB_PATH)\logo\raylib_36x36.png
APP_ICON_MDPI ?= $(RAYLIB_PATH)\logo\logo48x48.png APP_ICON_MDPI ?= $(RAYLIB_PATH)\logo\raylib_48x48.png
APP_ICON_HDPI ?= $(RAYLIB_PATH)\logo\logo72x72.png APP_ICON_HDPI ?= $(RAYLIB_PATH)\logo\raylib_72x72.png
APP_SCREEN_ORIENTATION ?= landscape APP_SCREEN_ORIENTATION ?= landscape
APP_KEYSTORE_PASS ?= raylib APP_KEYSTORE_PASS ?= raylib
# Library type used for raylib and OpenAL Soft: STATIC (.a) or SHARED (.so/.dll) # Library type used for raylib: STATIC (.a) or SHARED (.so/.dll)
RAYLIB_LIBTYPE ?= STATIC RAYLIB_LIBTYPE ?= STATIC
OPENAL_LIBTYPE ?= STATIC
RAYLIB_LIB_PATH = $(RAYLIB_PATH)\release\libs\android\armeabi-v7a RAYLIB_LIB_PATH = $(RAYLIB_PATH)\release\libs\android\armeabi-v7a
OPENAL_LIB_PATH = $(RAYLIB_PATH)\release\libs\android\armeabi-v7a
# Shared libs must be added to APK if required # Shared libs must be added to APK if required
# NOTE: Generated NativeLoader.java automatically load those libraries # NOTE: Generated NativeLoader.java automatically load those libraries
ifeq ($(RAYLIB_LIBTYPE),SHARED) ifeq ($(RAYLIB_LIBTYPE),SHARED)
PROJECT_SHARED_LIBS = lib/armeabi-v7a/libraylib.so PROJECT_SHARED_LIBS = lib/armeabi-v7a/libraylib.so
endif endif
ifeq ($(OPENAL_LIBTYPE),SHARED)
PROJECT_SHARED_LIBS += lib/armeabi-v7a/libopenal.so
endif
# Compiler and archiver # Compiler and archiver
# NOTE: GCC is being deprectated in Android NDK r16 # NOTE: GCC is being deprectated in Android NDK r16
@ -154,15 +149,9 @@ copy_project_required_libs:
ifeq ($(RAYLIB_LIBTYPE),SHARED) ifeq ($(RAYLIB_LIBTYPE),SHARED)
copy /Y $(RAYLIB_LIB_PATH)\libraylib.so $(PROJECT_BUILD_PATH)\lib\armeabi-v7a\libraylib.so copy /Y $(RAYLIB_LIB_PATH)\libraylib.so $(PROJECT_BUILD_PATH)\lib\armeabi-v7a\libraylib.so
endif endif
ifeq ($(OPENAL_LIBTYPE),SHARED)
copy /Y $(OPENAL_LIB_PATH)\libopenal.so $(PROJECT_BUILD_PATH)\lib\armeabi-v7a\libopenal.so
endif
ifeq ($(RAYLIB_LIBTYPE),STATIC) ifeq ($(RAYLIB_LIBTYPE),STATIC)
copy /Y $(RAYLIB_LIB_PATH)\libraylib.a $(PROJECT_BUILD_PATH)\lib\armeabi-v7a\libraylib.a copy /Y $(RAYLIB_LIB_PATH)\libraylib.a $(PROJECT_BUILD_PATH)\lib\armeabi-v7a\libraylib.a
endif endif
ifeq ($(OPENAL_LIBTYPE),STATIC)
copy /Y $(OPENAL_LIB_PATH)\libopenal.a $(PROJECT_BUILD_PATH)\lib\armeabi-v7a\libopenal.a
endif
# Copy project required resources: strings.xml, icon.png, assets # Copy project required resources: strings.xml, icon.png, assets
# NOTE: Required strings.xml is generated and game resources are copied to assets folder # NOTE: Required strings.xml is generated and game resources are copied to assets folder
@ -182,9 +171,6 @@ generate_loader_script:
@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
@echo public class NativeLoader extends android.app.NativeActivity { >> $(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 @echo static { >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
ifeq ($(OPENAL_LIBTYPE),SHARED)
@echo System.loadLibrary("openal"); >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
endif
ifeq ($(RAYLIB_LIBTYPE),SHARED) ifeq ($(RAYLIB_LIBTYPE),SHARED)
@echo System.loadLibrary("raylib"); >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java @echo System.loadLibrary("raylib"); >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
endif endif

View file

@ -32,7 +32,11 @@ else()
find_library(XCURSOR_LIBRARY Xcursor) find_library(XCURSOR_LIBRARY Xcursor)
include_directories(${OPENGL_INCLUDE_DIR}) include_directories(${OPENGL_INCLUDE_DIR})
set(LIBS_PRIVATE m ${pthread} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${XRANDR_LIBRARY} ${XINERAMA_LIBRARY} ${XI_LIBRARY} ${XXF86VM_LIBRARY} ${XCURSOR_LIBRARY}) if ("${CMAKE_SYSTEM_NAME}" MATCHES "(Net|Open)BSD")
find_library(OSS_LIBRARY ossaudio)
endif()
set(LIBS_PRIVATE m ${pthread} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${XRANDR_LIBRARY} ${XINERAMA_LIBRARY} ${XI_LIBRARY} ${XXF86VM_LIBRARY} ${XCURSOR_LIBRARY} ${OSS_LIBRARY})
endif() endif()
endif() endif()
@ -70,8 +74,8 @@ foreach(L ${LIBS_PRIVATE})
set(LASTDIR ${DIR}) set(LASTDIR ${DIR})
set(PKG_CONFIG_LIBS_PRIVATE ${PKG_CONFIG_LIBS_PRIVATE} ${DIR_OPT} ${FILE_OPT}) set(__PKG_CONFIG_LIBS_PRIVATE ${__PKG_CONFIG_LIBS_PRIVATE} ${DIR_OPT} ${FILE_OPT})
string (REPLACE ";" " " PKG_CONFIG_LIBS_PRIVATE "${PKG_CONFIG_LIBS_PRIVATE}") string (REPLACE ";" " " __PKG_CONFIG_LIBS_PRIVATE "${__PKG_CONFIG_LIBS_PRIVATE}")
endforeach(L) endforeach(L)
@ -82,7 +86,7 @@ function(link_libraries_to_executable executable)
if (TARGET raylib_shared) if (TARGET raylib_shared)
target_link_libraries(${executable} raylib_shared) target_link_libraries(${executable} raylib_shared)
else() else()
target_link_libraries(${executable} raylib ${PKG_CONFIG_LIBS_PRIVATE}) target_link_libraries(${executable} raylib ${__PKG_CONFIG_LIBS_PRIVATE})
endif() endif()
endfunction() endfunction()