Merge pull request #465 from raysan5/develop
Integrate develop branch into master
@ -24,19 +24,50 @@
|
||||
.PHONY: all clean
|
||||
|
||||
# Define required raylib variables
|
||||
# WARNING: To compile to HTML5, code must be redesigned to use emscripten.h and emscripten_set_main_loop()
|
||||
PLATFORM ?= PLATFORM_DESKTOP
|
||||
PROJECT_NAME ?= raylib_examples
|
||||
RAYLIB_VERSION ?= 1.9.4
|
||||
RAYLIB_API_VERSION ?= 1
|
||||
RAYLIB_PATH ?= ..
|
||||
PROJECT_NAME ?= raylib_example
|
||||
|
||||
# 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!
|
||||
ifeq ($(PLATFORM),PLATFORM_RPI)
|
||||
RAYLIB_PATH ?= /home/pi/raylib
|
||||
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)
|
||||
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 ?= FALSE
|
||||
|
||||
@ -46,7 +77,6 @@ USE_WAYLAND_DISPLAY ?= FALSE
|
||||
|
||||
# NOTE: On PLATFORM_WEB OpenAL Soft backend is used by default (check raylib/src/Makefile)
|
||||
|
||||
|
||||
# Determine PLATFORM_OS in case PLATFORM_DESKTOP selected
|
||||
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
|
||||
# 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)
|
||||
endif
|
||||
|
||||
RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/release/libs
|
||||
|
||||
# Define raylib release directory for compiled library
|
||||
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
|
||||
ifeq ($(PLATFORM_OS),WINDOWS)
|
||||
@ -130,6 +158,7 @@ ifeq ($(PLATFORM),PLATFORM_RPI)
|
||||
endif
|
||||
endif
|
||||
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
|
||||
CC = emcc
|
||||
endif
|
||||
@ -164,8 +193,14 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
|
||||
CFLAGS += $(RAYLIB_PATH)/src/resources -Wl,--subsystem,windows
|
||||
endif
|
||||
ifeq ($(PLATFORM_OS),LINUX)
|
||||
ifeq ($(RAYLIB_LIBTYPE),STATIC)
|
||||
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
|
||||
ifeq ($(PLATFORM),PLATFORM_RPI)
|
||||
CFLAGS += -std=gnu99
|
||||
@ -185,19 +220,21 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
|
||||
EXT = .html
|
||||
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)
|
||||
INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/release/include -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external
|
||||
|
||||
# Define additional directories containing required header files
|
||||
ifeq ($(PLATFORM),PLATFORM_RPI)
|
||||
# RPI requried libraries
|
||||
# RPI required libraries
|
||||
INCLUDE_PATHS += -I/opt/vc/include
|
||||
INCLUDE_PATHS += -I/opt/vc/include/interface/vmcs_host/linux
|
||||
INCLUDE_PATHS += -I/opt/vc/include/interface/vcos/pthreads
|
||||
endif
|
||||
|
||||
# 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
|
||||
|
||||
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
|
||||
@ -205,6 +242,12 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
|
||||
INCLUDE_PATHS += -I/usr/local/include
|
||||
LDFLAGS += -L. -Lsrc -L/usr/local/lib
|
||||
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
|
||||
|
||||
ifeq ($(PLATFORM),PLATFORM_RPI)
|
||||
@ -235,6 +278,11 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
|
||||
ifeq ($(USE_WAYLAND_DISPLAY),TRUE)
|
||||
LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon
|
||||
endif
|
||||
|
||||
# Explicit link to libc
|
||||
ifeq ($(RAYLIB_LIBTYPE),SHARED)
|
||||
LDLIBS += -lc
|
||||
endif
|
||||
endif
|
||||
ifeq ($(PLATFORM_OS),OSX)
|
||||
# Libraries for OSX 10.9 desktop compiling
|
||||
@ -360,7 +408,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
|
||||
del *.o *.exe /s
|
||||
endif
|
||||
ifeq ($(PLATFORM_OS),LINUX)
|
||||
find -type f -executable | xargs file -i | grep -E 'x-object|x-archive|x-sharedlib|x-executable' | rev | cut -d ':' -f 2- | rev | xargs rm -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
|
||||
ifeq ($(PLATFORM_OS),OSX)
|
||||
find . -type f -perm +ugo+x -delete
|
||||
@ -369,7 +417,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
|
||||
endif
|
||||
ifeq ($(PLATFORM),PLATFORM_RPI)
|
||||
find . -type f -executable -delete
|
||||
rm -f *.o
|
||||
rm -fv *.o
|
||||
endif
|
||||
ifeq ($(PLATFORM),PLATFORM_WEB)
|
||||
del *.o *.html *.js
|
||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 293 B After Width: | Height: | Size: 293 B |
Before Width: | Height: | Size: 383 B After Width: | Height: | Size: 383 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 552 B After Width: | Height: | Size: 552 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 922 B After Width: | Height: | Size: 922 B |
BIN
logo/raylib_512x512.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
logo/raylib_96x96.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
@ -8,6 +8,6 @@ Description: Simple and easy-to-use library to learn videogames programming
|
||||
URL: http://github.com/raysan5/raylib
|
||||
Version: @PROJECT_VERSION@
|
||||
Libs: -L${libdir} -lraylib
|
||||
Libs.private:@PKG_CONFIG_LIBS_PRIVATE@
|
||||
Libs.private: @PKG_CONFIG_LIBS_PRIVATE@
|
||||
Requires.private:
|
||||
Cflags: -I${includedir}
|
||||
|
@ -137,6 +137,8 @@ if(${PLATFORM} MATCHES "PLATFORM_DESKTOP")
|
||||
PUBLIC ${GRAPHICS}
|
||||
)
|
||||
|
||||
set(PKG_CONFIG_LIBS_PRIVATE ${__PKG_CONFIG_LIBS_PRIVATE})
|
||||
|
||||
if (WITH_PIC)
|
||||
set_property(TARGET ${RAYLIB} PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
118
src/Makefile
@ -42,12 +42,24 @@
|
||||
.PHONY: all clean install uninstall
|
||||
|
||||
# Define required raylib variables
|
||||
PLATFORM ?= PLATFORM_DESKTOP
|
||||
RAYLIB_PATH = ..
|
||||
RAYLIB_VERSION = 1.9.4
|
||||
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)
|
||||
RAYLIB_LIBTYPE ?= STATIC
|
||||
|
||||
# Build mode for library: DEBUG or RELEASE
|
||||
RAYLIB_BUILD_MODE ?= RELEASE
|
||||
|
||||
@ -58,6 +70,11 @@ INCLUDE_AUDIO_MODULE ?= TRUE
|
||||
# Use OpenAL Soft backend for audio
|
||||
USE_OPENAL_BACKEND ?= FALSE
|
||||
|
||||
# OpenAL Soft audio backend forced on HTML5 and OSX (see below)
|
||||
ifeq ($(PLATFORM),PLATFORM_WEB)
|
||||
USE_OPENAL_BACKEND = TRUE
|
||||
endif
|
||||
|
||||
# Use external GLFW library instead of rglfw module
|
||||
USE_EXTERNAL_GLFW ?= FALSE
|
||||
|
||||
@ -65,10 +82,7 @@ USE_EXTERNAL_GLFW ?= FALSE
|
||||
# by default it uses X11 windowing system
|
||||
USE_WAYLAND_DISPLAY ?= FALSE
|
||||
|
||||
# OpenAL Soft audio backend forced on HTML5 and OSX (see below)
|
||||
ifeq ($(PLATFORM),PLATFORM_WEB)
|
||||
USE_OPENAL_BACKEND = TRUE
|
||||
endif
|
||||
# See below for more GRAPHICS options.
|
||||
|
||||
# Use cross-compiler for PLATFORM_RPI
|
||||
ifeq ($(PLATFORM),PLATFORM_RPI)
|
||||
@ -138,8 +152,6 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID)
|
||||
ANDROID_ARCH ?= ARM
|
||||
endif
|
||||
|
||||
RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/release/libs
|
||||
|
||||
# Define output directory for compiled library
|
||||
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
|
||||
ifeq ($(PLATFORM_OS),WINDOWS)
|
||||
@ -262,15 +274,20 @@ endif
|
||||
# -Wno-missing-braces ignore invalid warning (GCC bug 53119)
|
||||
# -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=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 -Werror=implicit-function-declaration
|
||||
CFLAGS += -O1 -Wall -std=c99 -D_DEFAULT_SOURCE -fgnu89-inline -Wno-missing-braces -Werror=pointer-arith
|
||||
|
||||
ifeq ($(RAYLIB_BUILD_MODE), DEBUG)
|
||||
CFLAGS += -g
|
||||
endif
|
||||
|
||||
# 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)
|
||||
# -O2 # if used, also set --memory-init-file 0
|
||||
# --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
|
||||
CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC
|
||||
# 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
|
||||
CFLAGS += -DANDROID -DPLATFORM_ANDROID -D__ANDROID_API__=16
|
||||
endif
|
||||
@ -293,7 +311,7 @@ endif
|
||||
# Define required compilation flags for raylib SHARED lib
|
||||
ifeq ($(RAYLIB_LIBTYPE),SHARED)
|
||||
# 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
|
||||
CFLAGS += -fPIC -DBUILD_LIBTYPE_SHARED
|
||||
endif
|
||||
@ -413,10 +431,10 @@ else
|
||||
ifeq ($(PLATFORM_OS),LINUX)
|
||||
# Compile raylib to shared library version for GNU/Linux.
|
||||
# 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
|
||||
@echo "raylib shared library generated (libraylib.$(RAYLIB_VERSION).so)!"
|
||||
cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(RAYLIB_VERSION).so libraylib.$(RAYLIB_API_VERSION).so
|
||||
cd $(RAYLIB_RELEASE_PATH) && ln -fs libraylib.$(RAYLIB_VERSION).so libraylib.so
|
||||
$(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.so.$(RAYLIB_VERSION))!"
|
||||
cd $(RAYLIB_RELEASE_PATH) && ln -fsv libraylib.so.$(RAYLIB_VERSION) libraylib.so.$(RAYLIB_API_VERSION)
|
||||
cd $(RAYLIB_RELEASE_PATH) && ln -fsv libraylib.so.$(RAYLIB_API_VERSION) libraylib.so
|
||||
endif
|
||||
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
|
||||
@ -493,49 +511,77 @@ utils.o : utils.c utils.h
|
||||
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM)
|
||||
|
||||
# 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 :
|
||||
ifeq ($(ROOT),root)
|
||||
# Attention! You are root. Consult this Makefile for more information.
|
||||
ifeq ($(PLATFORM_OS),LINUX)
|
||||
# On GNU/Linux there are some standard directories that contain
|
||||
# libraries and header files. These directory (/usr/local/lib and
|
||||
# /usr/local/include/) are for libraries that are installed
|
||||
# manually (without a package manager).
|
||||
# Prepare the environment as needed.
|
||||
mkdir --parents --verbose $(RAYLIB_INSTALL_PATH)
|
||||
mkdir --parents --verbose $(RAYLIB_H_INSTALL_PATH)
|
||||
ifeq ($(RAYLIB_LIBTYPE),SHARED)
|
||||
cp --update $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_VERSION).so /usr/local/lib/libraylib.$(RAYLIB_VERSION).so
|
||||
cp --update $(RAYLIB_RELEASE_PATH)/libraylib.$(RAYLIB_API_VERSION).so /usr/local/lib/libraylib.$(RAYLIB_API_VERSION).so
|
||||
cp --update $(RAYLIB_RELEASE_PATH)/libraylib.so /usr/local/lib/libraylib.so
|
||||
# Installing the shared library.
|
||||
cp --update --verbose $(RAYLIB_RELEASE_PATH)/libraylib.so.$(RAYLIB_VERSION) $(RAYLIB_INSTALL_PATH)/libraylib.so.$(RAYLIB_VERSION)
|
||||
cd $(RAYLIB_INSTALL_PATH); ln -fsv libraylib.so.$(RAYLIB_VERSION) libraylib.so.$(RAYLIB_API_VERSION)
|
||||
cd $(RAYLIB_INSTALL_PATH); ln -fsv libraylib.so.$(RAYLIB_API_VERSION) libraylib.so
|
||||
# Uncomment to update the runtime linker cache with RAYLIB_INSTALL_PATH.
|
||||
# Not necessary if later embedding RPATH in your executable. See examples/Makefile.
|
||||
ldconfig $(RAYLIB_INSTALL_PATH)
|
||||
else
|
||||
cp --update raylib.h /usr/local/include/raylib.h
|
||||
cp --update $(RAYLIB_RELEASE_PATH)/libraylib.a /usr/local/lib/libraylib.a
|
||||
# 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!"
|
||||
else
|
||||
@echo "This function works only on GNU/Linux systems"
|
||||
@echo "This function currently works on GNU/Linux systems. Add yours today (^;"
|
||||
endif
|
||||
else
|
||||
@echo "Error: no root permissions"
|
||||
@echo "Error: Root permissions needed for installation. Try sudo make install"
|
||||
endif
|
||||
|
||||
# Remove raylib dev files installed on the system
|
||||
# TODO: see 'install' target.
|
||||
uninstall :
|
||||
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)
|
||||
rm --force /usr/local/include/raylib.h
|
||||
ifeq ($(RAYLIB_LIBTYPE),SHARED)
|
||||
rm --force /usr/local/lib/libraylib.so
|
||||
rm --force /usr/local/lib/libraylib.$(RAYLIB_API_VERSION).so
|
||||
rm --force /usr/local/lib/libraylib.$(RAYLIB_VERSION).so
|
||||
rm --force --interactive --verbose $(RAYLIB_INSTALL_PATH)/libraylib.so
|
||||
rm --force --interactive --verbose $(RAYLIB_INSTALL_PATH)/libraylib.so.$(RAYLIB_API_VERSION)
|
||||
rm --force --interactive --verbose $(RAYLIB_INSTALL_PATH)/libraylib.so.$(RAYLIB_VERSION)
|
||||
# Uncomment to clean up the runtime linker cache. See install target.
|
||||
ldconfig
|
||||
else
|
||||
rm --force /usr/local/lib/libraylib.a
|
||||
rm --force --interactive --verbose $(RAYLIB_INSTALL_PATH)/libraylib.a
|
||||
endif
|
||||
rm --force --interactive=once --recursive $(RAYLIB_H_INSTALL_PATH)/*
|
||||
@echo "raylib development files removed!"
|
||||
else
|
||||
@echo "This function works only on GNU/Linux systems"
|
||||
endif
|
||||
else
|
||||
@echo "Error: no root permissions"
|
||||
@echo "Error: Root permissions needed for uninstallation. Try sudo make uninstall"
|
||||
endif
|
||||
|
||||
# Clean everything
|
||||
@ -543,7 +589,7 @@ clean:
|
||||
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
|
||||
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
|
||||
ifeq ($(PLATFORM),PLATFORM_ANDROID)
|
||||
rm -rf $(ANDROID_TOOLCHAIN)
|
||||
|
383
src/audio.c
@ -225,9 +225,10 @@ void TraceLog(int msgType, const char *text, ...); // Show trace lo
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition - Audio Device initialization and Closing
|
||||
// mini_al AudioBuffer Functionality
|
||||
//----------------------------------------------------------------------------------
|
||||
#if USE_MINI_AL
|
||||
|
||||
#define DEVICE_FORMAT mal_format_f32
|
||||
#define DEVICE_CHANNELS 2
|
||||
#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;
|
||||
|
||||
// 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;
|
||||
struct AudioBuffer {
|
||||
mal_dsp dsp; // For format conversion.
|
||||
mal_dsp dsp; // Required for format conversion
|
||||
float volume;
|
||||
float pitch;
|
||||
bool playing;
|
||||
bool paused;
|
||||
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.
|
||||
bool looping; // Always true for AudioStreams
|
||||
int usage; // AudioBufferUsage type
|
||||
bool isSubBufferProcessed[2];
|
||||
unsigned int frameCursorPos;
|
||||
unsigned int bufferSizeInFrames;
|
||||
@ -252,76 +254,48 @@ struct AudioBuffer {
|
||||
unsigned char buffer[1];
|
||||
};
|
||||
|
||||
void StopAudioBuffer(AudioBuffer *audioBuffer);
|
||||
|
||||
// mini_al global variables
|
||||
static mal_context context;
|
||||
static mal_device device;
|
||||
static mal_bool32 isAudioInitialized = MAL_FALSE;
|
||||
static float masterVolume = 1;
|
||||
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 void TrackAudioBuffer(AudioBuffer* audioBuffer)
|
||||
{
|
||||
mal_mutex_lock(&audioLock);
|
||||
// mini_al functions declaration
|
||||
static void OnLog(mal_context *pContext, mal_device *pDevice, const char *message);
|
||||
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);
|
||||
|
||||
{
|
||||
if (firstAudioBuffer == NULL) firstAudioBuffer = audioBuffer;
|
||||
else
|
||||
{
|
||||
lastAudioBuffer->next = audioBuffer;
|
||||
audioBuffer->prev = lastAudioBuffer;
|
||||
}
|
||||
// AudioBuffer management functions declaration
|
||||
// NOTE: Those functions are not exposed by raylib... for the moment
|
||||
AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_uint32 bufferSizeInFrames, AudioBufferUsage usage);
|
||||
void DeleteAudioBuffer(AudioBuffer *audioBuffer);
|
||||
bool IsAudioBufferPlaying(AudioBuffer *audioBuffer);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
// Log callback function
|
||||
static void OnLog(mal_context *pContext, mal_device *pDevice, const char *message)
|
||||
{
|
||||
(void)pContext;
|
||||
(void)pDevice;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
TraceLog(LOG_ERROR, message); // All log messages from mini_al are errors
|
||||
}
|
||||
|
||||
// Sending audio data to device callback function
|
||||
static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameCount, void *pFramesOut)
|
||||
{
|
||||
// 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.
|
||||
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.
|
||||
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
|
||||
// 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);
|
||||
if (framesJustRead > 0)
|
||||
{
|
||||
float *framesOut = (float *)pFramesOut + (framesRead*device.channels);
|
||||
float *framesIn = tempBuffer;
|
||||
MixFrames(framesOut, framesIn, framesJustRead, audioBuffer->volume);
|
||||
MixAudioFrames(framesOut, framesIn, framesJustRead, audioBuffer->volume);
|
||||
|
||||
framesToRead -= framesJustRead;
|
||||
framesRead += framesJustRead;
|
||||
@ -387,15 +361,16 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameC
|
||||
}
|
||||
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;
|
||||
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
|
||||
// theoretically put us into an infinite loop.
|
||||
// If for some reason we weren't able to read every frame we'll need to break from the loop.
|
||||
// Not doing this could theoretically put us into an infinite loop.
|
||||
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.
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition - Audio Device initialization and Closing
|
||||
//----------------------------------------------------------------------------------
|
||||
// Initialize audio device
|
||||
void InitAudioDevice(void)
|
||||
{
|
||||
#if USE_MINI_AL
|
||||
// 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);
|
||||
if (result != MAL_SUCCESS)
|
||||
{
|
||||
@ -550,106 +633,17 @@ void SetMasterVolume(float volume)
|
||||
else if (volume > 1.0f) volume = 1.0f;
|
||||
|
||||
#if USE_MINI_AL
|
||||
masterVolume = 1;
|
||||
masterVolume = volume;
|
||||
#else
|
||||
alListenerf(AL_GAIN, volume);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Audio Buffer
|
||||
// Module Functions Definition - Audio Buffer management
|
||||
//----------------------------------------------------------------------------------
|
||||
#if USE_MINI_AL
|
||||
static mal_uint32 AudioBuffer_OnDSPRead(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;
|
||||
}
|
||||
|
||||
// Create a new audio buffer. Initially filled with silence.
|
||||
// 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 *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.sampleRateIn = sampleRate;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// Delete an audio buffer.
|
||||
// Delete an audio buffer
|
||||
void DeleteAudioBuffer(AudioBuffer *audioBuffer)
|
||||
{
|
||||
if (audioBuffer == NULL)
|
||||
@ -707,7 +701,7 @@ void DeleteAudioBuffer(AudioBuffer *audioBuffer)
|
||||
free(audioBuffer);
|
||||
}
|
||||
|
||||
// Check if an audio buffer is playing.
|
||||
// Check if an audio buffer is playing
|
||||
bool IsAudioBufferPlaying(AudioBuffer *audioBuffer)
|
||||
{
|
||||
if (audioBuffer == NULL)
|
||||
@ -719,10 +713,9 @@ bool IsAudioBufferPlaying(AudioBuffer *audioBuffer)
|
||||
return audioBuffer->playing && !audioBuffer->paused;
|
||||
}
|
||||
|
||||
// Play an audio buffer.
|
||||
//
|
||||
// This will restart the buffer from the start. Use PauseAudioBuffer() and ResumeAudioBuffer() if the playback position
|
||||
// should be maintained.
|
||||
// Play an audio buffer
|
||||
// NOTE: Buffer is restarted to the start.
|
||||
// Use PauseAudioBuffer() and ResumeAudioBuffer() if the playback position should be maintained.
|
||||
void PlayAudioBuffer(AudioBuffer *audioBuffer)
|
||||
{
|
||||
if (audioBuffer == NULL)
|
||||
@ -736,7 +729,7 @@ void PlayAudioBuffer(AudioBuffer *audioBuffer)
|
||||
audioBuffer->frameCursorPos = 0;
|
||||
}
|
||||
|
||||
// Stop an audio buffer.
|
||||
// Stop an audio buffer
|
||||
void StopAudioBuffer(AudioBuffer *audioBuffer)
|
||||
{
|
||||
if (audioBuffer == NULL)
|
||||
@ -755,7 +748,7 @@ void StopAudioBuffer(AudioBuffer *audioBuffer)
|
||||
audioBuffer->isSubBufferProcessed[1] = true;
|
||||
}
|
||||
|
||||
// Pause an audio buffer.
|
||||
// Pause an audio buffer
|
||||
void PauseAudioBuffer(AudioBuffer *audioBuffer)
|
||||
{
|
||||
if (audioBuffer == NULL)
|
||||
@ -767,7 +760,7 @@ void PauseAudioBuffer(AudioBuffer *audioBuffer)
|
||||
audioBuffer->paused = true;
|
||||
}
|
||||
|
||||
// Resume an audio buffer.
|
||||
// Resume an audio buffer
|
||||
void ResumeAudioBuffer(AudioBuffer *audioBuffer)
|
||||
{
|
||||
if (audioBuffer == NULL)
|
||||
@ -779,7 +772,7 @@ void ResumeAudioBuffer(AudioBuffer *audioBuffer)
|
||||
audioBuffer->paused = false;
|
||||
}
|
||||
|
||||
// Set volume for an audio buffer.
|
||||
// Set volume for an audio buffer
|
||||
void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume)
|
||||
{
|
||||
if (audioBuffer == NULL)
|
||||
@ -791,7 +784,7 @@ void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume)
|
||||
audioBuffer->volume = volume;
|
||||
}
|
||||
|
||||
// Set pitch for an audio buffer.
|
||||
// Set pitch for an audio buffer
|
||||
void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch)
|
||||
{
|
||||
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_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
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -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 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);
|
||||
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);
|
||||
if (frameCount == 0) TraceLog(LOG_ERROR, "LoadSoundFromWave() : Format conversion failed");
|
||||
if (frameCount == 0) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Format conversion failed");
|
||||
|
||||
sound.audioBuffer = audioBuffer;
|
||||
#else
|
||||
@ -1853,7 +1884,7 @@ void CloseAudioStream(AudioStream stream)
|
||||
void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
|
||||
{
|
||||
#if USE_MINI_AL
|
||||
AudioBuffer* audioBuffer = (AudioBuffer*)stream.audioBuffer;
|
||||
AudioBuffer *audioBuffer = (AudioBuffer *)stream.audioBuffer;
|
||||
if (audioBuffer == NULL)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "UpdateAudioStream() : No audio buffer");
|
||||
|
19
src/core.c
@ -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 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 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)
|
||||
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
|
||||
|
||||
// Register mouse states
|
||||
@ -441,12 +441,13 @@ void InitWindow(int width, int height, void *data)
|
||||
uwpWindow = (EGLNativeWindowType)data;
|
||||
#endif
|
||||
|
||||
// Init hi-res timer
|
||||
InitTimer();
|
||||
|
||||
// Init graphics device (display device and OpenGL context)
|
||||
// NOTE: returns true if window and graphic device has been initialized successfully
|
||||
windowReady = InitGraphicsDevice(width, height);
|
||||
|
||||
// Init hi-res timer
|
||||
InitTimer();
|
||||
if (!windowReady) return;
|
||||
|
||||
#if defined(SUPPORT_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
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
// 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;
|
||||
displayHeight = mode->height;
|
||||
|
65
src/external/mini_al.h
vendored
@ -1,5 +1,5 @@
|
||||
// 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
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
//
|
||||
// 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)
|
||||
// ---------------------
|
||||
@ -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))
|
||||
|
||||
// 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 ignored "-Wunused-function"
|
||||
#endif
|
||||
@ -1972,7 +1975,9 @@ static int mal_strcmp(const char* str1, const char* str2)
|
||||
|
||||
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
|
||||
#endif
|
||||
|
||||
@ -6707,6 +6712,10 @@ static mal_result mal_device__main_loop__alsa(mal_device* pDevice)
|
||||
#include <fcntl.h>
|
||||
#include <sys/soundcard.h>
|
||||
|
||||
#ifndef SNDCTL_DSP_HALT
|
||||
#define SNDCTL_DSP_HALT SNDCTL_DSP_RESET
|
||||
#endif
|
||||
|
||||
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.
|
||||
@ -8843,6 +8852,8 @@ mal_result mal_device_init__sdl(mal_context* pContext, mal_device_type type, mal
|
||||
mal_assert(pConfig != 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
|
||||
// to explicitly clamp this because it will be easy to overflow.
|
||||
mal_uint32 bufferSize = pConfig->bufferSizeInFrames;
|
||||
@ -10760,7 +10771,7 @@ static void mal_dsp_mix_channels__inc(float* pFramesOut, mal_uint32 channelsOut,
|
||||
(void)channelMapOut;
|
||||
(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.
|
||||
for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) {
|
||||
switch (channelsIn) {
|
||||
@ -10785,23 +10796,23 @@ static void mal_dsp_mix_channels__inc(float* pFramesOut, mal_uint32 channelsOut,
|
||||
|
||||
// Zero out extra channels.
|
||||
switch (channelsOut - channelsIn) {
|
||||
case 17: pFramesOut[iFrame*channelsOut+16] = 0;
|
||||
case 16: pFramesOut[iFrame*channelsOut+15] = 0;
|
||||
case 15: pFramesOut[iFrame*channelsOut+14] = 0;
|
||||
case 14: pFramesOut[iFrame*channelsOut+13] = 0;
|
||||
case 13: pFramesOut[iFrame*channelsOut+12] = 0;
|
||||
case 12: pFramesOut[iFrame*channelsOut+11] = 0;
|
||||
case 11: pFramesOut[iFrame*channelsOut+10] = 0;
|
||||
case 10: pFramesOut[iFrame*channelsOut+ 9] = 0;
|
||||
case 9: pFramesOut[iFrame*channelsOut+ 8] = 0;
|
||||
case 8: pFramesOut[iFrame*channelsOut+ 7] = 0;
|
||||
case 7: pFramesOut[iFrame*channelsOut+ 6] = 0;
|
||||
case 6: pFramesOut[iFrame*channelsOut+ 5] = 0;
|
||||
case 5: pFramesOut[iFrame*channelsOut+ 4] = 0;
|
||||
case 4: pFramesOut[iFrame*channelsOut+ 3] = 0;
|
||||
case 3: pFramesOut[iFrame*channelsOut+ 2] = 0;
|
||||
case 2: pFramesOut[iFrame*channelsOut+ 1] = 0;
|
||||
case 1: pFramesOut[iFrame*channelsOut+ 0] = 0;
|
||||
case 17: pFramesOut[iFrame*channelsOut+16 + channelsIn] = 0;
|
||||
case 16: pFramesOut[iFrame*channelsOut+15 + channelsIn] = 0;
|
||||
case 15: pFramesOut[iFrame*channelsOut+14 + channelsIn] = 0;
|
||||
case 14: pFramesOut[iFrame*channelsOut+13 + channelsIn] = 0;
|
||||
case 13: pFramesOut[iFrame*channelsOut+12 + channelsIn] = 0;
|
||||
case 12: pFramesOut[iFrame*channelsOut+11 + channelsIn] = 0;
|
||||
case 11: pFramesOut[iFrame*channelsOut+10 + channelsIn] = 0;
|
||||
case 10: pFramesOut[iFrame*channelsOut+ 9 + channelsIn] = 0;
|
||||
case 9: pFramesOut[iFrame*channelsOut+ 8 + channelsIn] = 0;
|
||||
case 8: pFramesOut[iFrame*channelsOut+ 7 + channelsIn] = 0;
|
||||
case 7: pFramesOut[iFrame*channelsOut+ 6 + channelsIn] = 0;
|
||||
case 6: pFramesOut[iFrame*channelsOut+ 5 + channelsIn] = 0;
|
||||
case 5: pFramesOut[iFrame*channelsOut+ 4 + channelsIn] = 0;
|
||||
case 4: pFramesOut[iFrame*channelsOut+ 3 + channelsIn] = 0;
|
||||
case 3: pFramesOut[iFrame*channelsOut+ 2 + channelsIn] = 0;
|
||||
case 2: pFramesOut[iFrame*channelsOut+ 1 + channelsIn] = 0;
|
||||
case 1: pFramesOut[iFrame*channelsOut+ 0 + channelsIn] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -10832,10 +10843,10 @@ static void mal_dsp_mix_channels__inc(float* pFramesOut, mal_uint32 channelsOut,
|
||||
}
|
||||
} else if (channelsIn == 2) {
|
||||
// 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 {
|
||||
// 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
|
||||
// ================
|
||||
//
|
||||
// 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.
|
||||
// - Documentation fixes.
|
||||
//
|
||||
|
542
src/external/stb_image.h
vendored
@ -1,4 +1,4 @@
|
||||
/* stb_image - v2.16 - public domain image loader - http://nothings.org/stb_image.h
|
||||
/* stb_image - v2.18 - public domain image loader - http://nothings.org/stb
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
Do this:
|
||||
@ -48,6 +48,8 @@ LICENSE
|
||||
|
||||
RECENT REVISION HISTORY:
|
||||
|
||||
2.18 (2018-01-30) fix warnings
|
||||
2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
|
||||
2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
|
||||
2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
|
||||
2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
|
||||
@ -74,11 +76,11 @@ RECENT REVISION HISTORY:
|
||||
Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
|
||||
Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
|
||||
github:urraka (animated gif) Junggon Kim (PNM comments)
|
||||
Daniel Gibson (16-bit TGA)
|
||||
Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA)
|
||||
socks-the-fox (16-bit PNG)
|
||||
Jeremy Sawicki (handle all ImageNet JPGs)
|
||||
Optimizations & bugfixes
|
||||
Fabian "ryg" Giesen
|
||||
Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
|
||||
Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query)
|
||||
Arseny Kapoulkine
|
||||
John-Mark Allen
|
||||
|
||||
@ -87,16 +89,17 @@ RECENT REVISION HISTORY:
|
||||
Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan
|
||||
Dave Moore Roy Eltham Hayaki Saito Nathan Reed
|
||||
Won Chun Luke Graham Johan Duparc Nick Verigakis
|
||||
the Horde3D community Thomas Ruf Ronny Chevalier Baldur Karlsson
|
||||
Janez Zemva John Bartholomew Michal Cichon github:rlyeh
|
||||
Jonathan Blow Ken Hamada Tero Hanninen github:romigrou
|
||||
Laurent Gomila Cort Stratton Sergio Gonzalez github:svdijk
|
||||
Aruelien Pocheville Thibault Reuille Cass Everitt github:snagar
|
||||
Ryamond Barbiero Paul Du Bois Engin Manap github:Zelex
|
||||
Michaelangel007@github Philipp Wiesemann Dale Weiler github:grim210
|
||||
Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:sammyhw
|
||||
Blazej Dariusz Roszkowski Gregory Mullen github:phprus
|
||||
Christian Floisand Kevin Schmidt github:poppolopoppo
|
||||
the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh
|
||||
Janez Zemva John Bartholomew Michal Cichon github:romigrou
|
||||
Jonathan Blow Ken Hamada Tero Hanninen github:svdijk
|
||||
Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar
|
||||
Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex
|
||||
Ryamond Barbiero Paul Du Bois Engin Manap github:grim210
|
||||
Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw
|
||||
Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus
|
||||
Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo
|
||||
Christian Floisand Kevin Schmidt github:darealshinji
|
||||
Blazej Dariusz Roszkowski github:Michaelangel007
|
||||
*/
|
||||
|
||||
#ifndef STBI_INCLUDE_STB_IMAGE_H
|
||||
@ -105,10 +108,8 @@ RECENT REVISION HISTORY:
|
||||
// DOCUMENTATION
|
||||
//
|
||||
// Limitations:
|
||||
// - no 16-bit-per-channel PNG
|
||||
// - no 12-bit-per-channel JPEG
|
||||
// - no JPEGs with arithmetic coding
|
||||
// - no 1-bit BMP
|
||||
// - GIF always returns *comp=4
|
||||
//
|
||||
// Basic usage (see HDR discussion below for HDR usage):
|
||||
@ -353,6 +354,10 @@ typedef struct
|
||||
|
||||
STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
#ifndef STBI_NO_GIF
|
||||
STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
@ -416,11 +421,14 @@ STBIDEF void stbi_image_free (void *retval_from_stbi_load);
|
||||
// get image dimensions & components without fully decoding
|
||||
STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
|
||||
STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
|
||||
STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
|
||||
STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp);
|
||||
STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
|
||||
|
||||
STBIDEF int stbi_is_16_bit (char const *filename);
|
||||
STBIDEF int stbi_is_16_bit_from_file(FILE *f);
|
||||
#endif
|
||||
|
||||
|
||||
@ -504,7 +512,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
|
||||
#include <limits.h>
|
||||
|
||||
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
|
||||
#include <math.h> // ldexp
|
||||
#include <math.h> // ldexp, pow
|
||||
#endif
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
@ -784,6 +792,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
|
||||
static int stbi__png_test(stbi__context *s);
|
||||
static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
|
||||
static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
|
||||
static int stbi__png_is16(stbi__context *s);
|
||||
#endif
|
||||
|
||||
#ifndef STBI_NO_BMP
|
||||
@ -802,6 +811,7 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
|
||||
static int stbi__psd_test(stbi__context *s);
|
||||
static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);
|
||||
static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
|
||||
static int stbi__psd_is16(stbi__context *s);
|
||||
#endif
|
||||
|
||||
#ifndef STBI_NO_HDR
|
||||
@ -819,6 +829,7 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
|
||||
#ifndef STBI_NO_GIF
|
||||
static int stbi__gif_test(stbi__context *s);
|
||||
static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
|
||||
static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
|
||||
static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
|
||||
#endif
|
||||
|
||||
@ -893,11 +904,13 @@ static int stbi__mad3sizes_valid(int a, int b, int c, int add)
|
||||
}
|
||||
|
||||
// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow
|
||||
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
|
||||
static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
|
||||
{
|
||||
return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
|
||||
stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);
|
||||
}
|
||||
#endif
|
||||
|
||||
// mallocs with size overflow checking
|
||||
static void *stbi__malloc_mad2(int a, int b, int add)
|
||||
@ -912,11 +925,13 @@ static void *stbi__malloc_mad3(int a, int b, int c, int add)
|
||||
return stbi__malloc(a*b*c + add);
|
||||
}
|
||||
|
||||
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
|
||||
static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
|
||||
{
|
||||
if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;
|
||||
return stbi__malloc(a*b*c*d + add);
|
||||
}
|
||||
#endif
|
||||
|
||||
// stbi__err - error
|
||||
// stbi__errpf - error returning pointer to float
|
||||
@ -1054,6 +1069,18 @@ static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
|
||||
}
|
||||
}
|
||||
|
||||
static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel)
|
||||
{
|
||||
int slice;
|
||||
int slice_size = w * h * bytes_per_pixel;
|
||||
|
||||
stbi_uc *bytes = (stbi_uc *)image;
|
||||
for (slice = 0; slice < z; ++slice) {
|
||||
stbi__vertical_flip(bytes, w, h, bytes_per_pixel);
|
||||
bytes += slice_size;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
||||
{
|
||||
stbi__result_info ri;
|
||||
@ -1103,7 +1130,7 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x,
|
||||
return (stbi__uint16 *) result;
|
||||
}
|
||||
|
||||
#ifndef STBI_NO_HDR
|
||||
#if !defined(STBI_NO_HDR) || !defined(STBI_NO_LINEAR)
|
||||
static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
|
||||
{
|
||||
if (stbi__vertically_flip_on_load && result != NULL) {
|
||||
@ -1205,6 +1232,22 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u
|
||||
return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
|
||||
}
|
||||
|
||||
#ifndef STBI_NO_GIF
|
||||
STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
|
||||
{
|
||||
unsigned char *result;
|
||||
stbi__context s;
|
||||
stbi__start_mem(&s,buffer,len);
|
||||
|
||||
result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);
|
||||
if (stbi__vertically_flip_on_load) {
|
||||
stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef STBI_NO_LINEAR
|
||||
static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
||||
{
|
||||
@ -1291,9 +1334,13 @@ STBIDEF int stbi_is_hdr (char const *filename)
|
||||
STBIDEF int stbi_is_hdr_from_file(FILE *f)
|
||||
{
|
||||
#ifndef STBI_NO_HDR
|
||||
long pos = ftell(f);
|
||||
int res;
|
||||
stbi__context s;
|
||||
stbi__start_file(&s,f);
|
||||
return stbi__hdr_test(&s);
|
||||
res = stbi__hdr_test(&s);
|
||||
fseek(f, pos, SEEK_SET);
|
||||
return res;
|
||||
#else
|
||||
STBI_NOTUSED(f);
|
||||
return 0;
|
||||
@ -1705,7 +1752,8 @@ typedef struct
|
||||
|
||||
static int stbi__build_huffman(stbi__huffman *h, int *count)
|
||||
{
|
||||
int i,j,k=0,code;
|
||||
int i,j,k=0;
|
||||
unsigned int code;
|
||||
// build size list for each symbol (from JPEG spec)
|
||||
for (i=0; i < 16; ++i)
|
||||
for (j=0; j < count[i]; ++j)
|
||||
@ -1721,7 +1769,7 @@ static int stbi__build_huffman(stbi__huffman *h, int *count)
|
||||
if (h->size[k] == j) {
|
||||
while (h->size[k] == j)
|
||||
h->code[k++] = (stbi__uint16) (code++);
|
||||
if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG");
|
||||
if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG");
|
||||
}
|
||||
// compute largest code + 1 for this size, preshifted as needed later
|
||||
h->maxcode[j] = code << (16-j);
|
||||
@ -1765,7 +1813,7 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
|
||||
if (k < m) k += (~0U << magbits) + 1;
|
||||
// if the result is small enough, we can fit it in fast_ac table
|
||||
if (k >= -128 && k <= 127)
|
||||
fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits));
|
||||
fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1774,7 +1822,7 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
|
||||
static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
|
||||
{
|
||||
do {
|
||||
int b = j->nomore ? 0 : stbi__get8(j->s);
|
||||
unsigned int b = j->nomore ? 0 : stbi__get8(j->s);
|
||||
if (b == 0xff) {
|
||||
int c = stbi__get8(j->s);
|
||||
while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes
|
||||
@ -1790,7 +1838,7 @@ static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
|
||||
}
|
||||
|
||||
// (1 << n) - 1
|
||||
static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
|
||||
static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
|
||||
|
||||
// decode a jpeg huffman value from the bitstream
|
||||
stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
|
||||
@ -1843,7 +1891,7 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
|
||||
}
|
||||
|
||||
// bias[n] = (-1<<n) + 1
|
||||
static int const stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
|
||||
static const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
|
||||
|
||||
// combined JPEG 'receive' and JPEG 'extend', since baseline
|
||||
// always extends everything it receives.
|
||||
@ -1886,7 +1934,7 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
|
||||
|
||||
// given a value that's at position X in the zigzag stream,
|
||||
// where does it appear in the 8x8 matrix coded as row-major?
|
||||
static stbi_uc stbi__jpeg_dezigzag[64+15] =
|
||||
static const stbi_uc stbi__jpeg_dezigzag[64+15] =
|
||||
{
|
||||
0, 1, 8, 16, 9, 2, 3, 10,
|
||||
17, 24, 32, 25, 18, 11, 4, 5,
|
||||
@ -2112,7 +2160,7 @@ stbi_inline static stbi_uc stbi__clamp(int x)
|
||||
}
|
||||
|
||||
#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5)))
|
||||
#define stbi__fsh(x) ((x) << 12)
|
||||
#define stbi__fsh(x) ((x) * 4096)
|
||||
|
||||
// derived from jidctint -- DCT_ISLOW
|
||||
#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
|
||||
@ -2167,7 +2215,7 @@ static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
|
||||
// (1|2|3|4|5|6|7)==0 0 seconds
|
||||
// all separate -0.047 seconds
|
||||
// 1 && 2|3 && 4|5 && 6|7: -0.047 seconds
|
||||
int dcterm = d[0] << 2;
|
||||
int dcterm = d[0]*4;
|
||||
v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
|
||||
} else {
|
||||
STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])
|
||||
@ -2968,7 +3016,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
|
||||
|
||||
z->rgb = 0;
|
||||
for (i=0; i < s->img_n; ++i) {
|
||||
static unsigned char rgb[3] = { 'R', 'G', 'B' };
|
||||
static const unsigned char rgb[3] = { 'R', 'G', 'B' };
|
||||
z->img_comp[i].id = stbi__get8(s);
|
||||
if (s->img_n == 3 && z->img_comp[i].id == rgb[i])
|
||||
++z->rgb;
|
||||
@ -3093,8 +3141,8 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j)
|
||||
} else if (stbi__DNL(m)) {
|
||||
int Ld = stbi__get16be(j->s);
|
||||
stbi__uint32 NL = stbi__get16be(j->s);
|
||||
if (Ld != 4) stbi__err("bad DNL len", "Corrupt JPEG");
|
||||
if (NL != j->s->img_y) stbi__err("bad DNL height", "Corrupt JPEG");
|
||||
if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG");
|
||||
if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG");
|
||||
} else {
|
||||
if (!stbi__process_marker(j, m)) return 0;
|
||||
}
|
||||
@ -3912,18 +3960,18 @@ static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int stbi__zlength_base[31] = {
|
||||
static const int stbi__zlength_base[31] = {
|
||||
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,0,0 };
|
||||
|
||||
static int stbi__zlength_extra[31]=
|
||||
static const int stbi__zlength_extra[31]=
|
||||
{ 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,0,0 };
|
||||
|
||||
static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
|
||||
static const int stbi__zdist_base[32] = { 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,0,0};
|
||||
|
||||
static int stbi__zdist_extra[32] =
|
||||
static const int stbi__zdist_extra[32] =
|
||||
{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
|
||||
|
||||
static int stbi__parse_huffman_block(stbi__zbuf *a)
|
||||
@ -3970,7 +4018,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
|
||||
|
||||
static int stbi__compute_huffman_codes(stbi__zbuf *a)
|
||||
{
|
||||
static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
|
||||
static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
|
||||
stbi__zhuffman z_codelength;
|
||||
stbi_uc lencodes[286+32+137];//padding for maximum single op
|
||||
stbi_uc codelength_sizes[19];
|
||||
@ -4229,7 +4277,7 @@ static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
|
||||
|
||||
static int stbi__check_png_header(stbi__context *s)
|
||||
{
|
||||
static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
|
||||
static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
|
||||
int i;
|
||||
for (i=0; i < 8; ++i)
|
||||
if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
|
||||
@ -4275,7 +4323,7 @@ static int stbi__paeth(int a, int b, int c)
|
||||
return c;
|
||||
}
|
||||
|
||||
static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
|
||||
static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
|
||||
|
||||
// create the png data from post-deflated data
|
||||
static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
|
||||
@ -4295,8 +4343,10 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
|
||||
a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
|
||||
if (!a->out) return stbi__err("outofmem", "Out of memory");
|
||||
|
||||
if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
|
||||
img_width_bytes = (((img_n * x * depth) + 7) >> 3);
|
||||
img_len = (img_width_bytes + 1) * y;
|
||||
|
||||
// we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
|
||||
// but issue #276 reported a PNG in the wild that had extra data at the end (all zeros),
|
||||
// so just check for raw_len < img_len always.
|
||||
@ -4675,7 +4725,7 @@ static void stbi__de_iphone(stbi__png *z)
|
||||
}
|
||||
}
|
||||
|
||||
#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
|
||||
#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))
|
||||
|
||||
static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
|
||||
{
|
||||
@ -4912,6 +4962,19 @@ static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
|
||||
p.s = s;
|
||||
return stbi__png_info_raw(&p, x, y, comp);
|
||||
}
|
||||
|
||||
static int stbi__png_is16(stbi__context *s)
|
||||
{
|
||||
stbi__png p;
|
||||
p.s = s;
|
||||
if (!stbi__png_info_raw(&p, NULL, NULL, NULL))
|
||||
return 0;
|
||||
if (p.depth != 16) {
|
||||
stbi__rewind(p.s);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Microsoft/Windows BMP image
|
||||
@ -4963,21 +5026,27 @@ static int stbi__bitcount(unsigned int a)
|
||||
return a & 0xff;
|
||||
}
|
||||
|
||||
// extract an arbitrarily-aligned N-bit value (N=bits)
|
||||
// from v, and then make it 8-bits long and fractionally
|
||||
// extend it to full full range.
|
||||
static int stbi__shiftsigned(int v, int shift, int bits)
|
||||
{
|
||||
int result;
|
||||
int z=0;
|
||||
|
||||
if (shift < 0) v <<= -shift;
|
||||
else v >>= shift;
|
||||
result = v;
|
||||
|
||||
z = bits;
|
||||
while (z < 8) {
|
||||
result += v >> z;
|
||||
z += bits;
|
||||
}
|
||||
return result;
|
||||
static unsigned int mul_table[9] = {
|
||||
0,
|
||||
0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/,
|
||||
0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/,
|
||||
};
|
||||
static unsigned int shift_table[9] = {
|
||||
0, 0,0,1,0,2,4,6,0,
|
||||
};
|
||||
if (shift < 0)
|
||||
v <<= -shift;
|
||||
else
|
||||
v >>= shift;
|
||||
STBI_ASSERT(v >= 0 && v < 256);
|
||||
v >>= (8-bits);
|
||||
STBI_ASSERT(bits >= 0 && bits <= 8);
|
||||
return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits];
|
||||
}
|
||||
|
||||
typedef struct
|
||||
@ -5007,7 +5076,6 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
|
||||
}
|
||||
if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
|
||||
info->bpp = stbi__get16le(s);
|
||||
if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
|
||||
if (hsz != 12) {
|
||||
int compress = stbi__get32le(s);
|
||||
if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
|
||||
@ -5125,10 +5193,27 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
|
||||
pal[i][3] = 255;
|
||||
}
|
||||
stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
|
||||
if (info.bpp == 4) width = (s->img_x + 1) >> 1;
|
||||
if (info.bpp == 1) width = (s->img_x + 7) >> 3;
|
||||
else if (info.bpp == 4) width = (s->img_x + 1) >> 1;
|
||||
else if (info.bpp == 8) width = s->img_x;
|
||||
else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
|
||||
pad = (-width)&3;
|
||||
if (info.bpp == 1) {
|
||||
for (j=0; j < (int) s->img_y; ++j) {
|
||||
int bit_offset = 7, v = stbi__get8(s);
|
||||
for (i=0; i < (int) s->img_x; ++i) {
|
||||
int color = (v>>bit_offset)&0x1;
|
||||
out[z++] = pal[color][0];
|
||||
out[z++] = pal[color][1];
|
||||
out[z++] = pal[color][2];
|
||||
if((--bit_offset) < 0) {
|
||||
bit_offset = 7;
|
||||
v = stbi__get8(s);
|
||||
}
|
||||
}
|
||||
stbi__skip(s, pad);
|
||||
}
|
||||
} else {
|
||||
for (j=0; j < (int) s->img_y; ++j) {
|
||||
for (i=0; i < (int) s->img_x; i += 2) {
|
||||
int v=stbi__get8(s),v2=0;
|
||||
@ -5149,6 +5234,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
|
||||
}
|
||||
stbi__skip(s, pad);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
|
||||
int z = 0;
|
||||
@ -5188,7 +5274,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
|
||||
int bpp = info.bpp;
|
||||
for (i=0; i < (int) s->img_x; ++i) {
|
||||
stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
|
||||
int a;
|
||||
unsigned int a;
|
||||
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
|
||||
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
|
||||
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));
|
||||
@ -5236,14 +5322,14 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
|
||||
static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
|
||||
{
|
||||
// only RGB or RGBA (incl. 16bit) or grey allowed
|
||||
if(is_rgb16) *is_rgb16 = 0;
|
||||
if (is_rgb16) *is_rgb16 = 0;
|
||||
switch(bits_per_pixel) {
|
||||
case 8: return STBI_grey;
|
||||
case 16: if(is_grey) return STBI_grey_alpha;
|
||||
// else: fall-through
|
||||
// fallthrough
|
||||
case 15: if(is_rgb16) *is_rgb16 = 1;
|
||||
return STBI_rgb;
|
||||
case 24: // fall-through
|
||||
case 24: // fallthrough
|
||||
case 32: return bits_per_pixel/8;
|
||||
default: return 0;
|
||||
}
|
||||
@ -6038,11 +6124,13 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
int w,h;
|
||||
stbi_uc *out, *old_out; // output buffer (always 4 components)
|
||||
int flags, bgindex, ratio, transparent, eflags, delay;
|
||||
stbi_uc *out; // output buffer (always 4 components)
|
||||
stbi_uc *background; // The current "background" as far as a gif is concerned
|
||||
stbi_uc *history;
|
||||
int flags, bgindex, ratio, transparent, eflags;
|
||||
stbi_uc pal[256][4];
|
||||
stbi_uc lpal[256][4];
|
||||
stbi__gif_lzw codes[4096];
|
||||
stbi__gif_lzw codes[8192];
|
||||
stbi_uc *color_table;
|
||||
int parse, step;
|
||||
int lflags;
|
||||
@ -6050,6 +6138,7 @@ typedef struct
|
||||
int max_x, max_y;
|
||||
int cur_x, cur_y;
|
||||
int line_size;
|
||||
int delay;
|
||||
} stbi__gif;
|
||||
|
||||
static int stbi__gif_test_raw(stbi__context *s)
|
||||
@ -6125,6 +6214,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
|
||||
static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
|
||||
{
|
||||
stbi_uc *p, *c;
|
||||
int idx;
|
||||
|
||||
// recurse to decode the prefixes, since the linked-list is backwards,
|
||||
// and working backwards through an interleaved image would be nasty
|
||||
@ -6133,10 +6223,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
|
||||
|
||||
if (g->cur_y >= g->max_y) return;
|
||||
|
||||
p = &g->out[g->cur_x + g->cur_y];
|
||||
c = &g->color_table[g->codes[code].suffix * 4];
|
||||
idx = g->cur_x + g->cur_y;
|
||||
p = &g->out[idx];
|
||||
g->history[idx / 4] = 1;
|
||||
|
||||
if (c[3] >= 128) {
|
||||
c = &g->color_table[g->codes[code].suffix * 4];
|
||||
if (c[3] > 128) { // don't render transparent pixels;
|
||||
p[0] = c[2];
|
||||
p[1] = c[1];
|
||||
p[2] = c[0];
|
||||
@ -6210,11 +6302,16 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
|
||||
stbi__skip(s,len);
|
||||
return g->out;
|
||||
} else if (code <= avail) {
|
||||
if (first) return stbi__errpuc("no clear code", "Corrupt GIF");
|
||||
if (first) {
|
||||
return stbi__errpuc("no clear code", "Corrupt GIF");
|
||||
}
|
||||
|
||||
if (oldcode >= 0) {
|
||||
p = &g->codes[avail++];
|
||||
if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF");
|
||||
if (avail > 8192) {
|
||||
return stbi__errpuc("too many codes", "Corrupt GIF");
|
||||
}
|
||||
|
||||
p->prefix = (stbi__int16) oldcode;
|
||||
p->first = g->codes[oldcode].first;
|
||||
p->suffix = (code == avail) ? p->first : g->codes[code].first;
|
||||
@ -6236,62 +6333,72 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
|
||||
}
|
||||
}
|
||||
|
||||
static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1)
|
||||
{
|
||||
int x, y;
|
||||
stbi_uc *c = g->pal[g->bgindex];
|
||||
for (y = y0; y < y1; y += 4 * g->w) {
|
||||
for (x = x0; x < x1; x += 4) {
|
||||
stbi_uc *p = &g->out[y + x];
|
||||
p[0] = c[2];
|
||||
p[1] = c[1];
|
||||
p[2] = c[0];
|
||||
p[3] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this function is designed to support animated gifs, although stb_image doesn't support it
|
||||
static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp)
|
||||
// two back is the image from two frames ago, used for a very specific disposal format
|
||||
static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)
|
||||
{
|
||||
int i;
|
||||
stbi_uc *prev_out = 0;
|
||||
int dispose;
|
||||
int first_frame;
|
||||
int pi;
|
||||
int pcount;
|
||||
|
||||
if (g->out == 0 && !stbi__gif_header(s, g, comp,0))
|
||||
return 0; // stbi__g_failure_reason set by stbi__gif_header
|
||||
|
||||
if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0))
|
||||
return stbi__errpuc("too large", "GIF too large");
|
||||
|
||||
prev_out = g->out;
|
||||
g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0);
|
||||
// on first frame, any non-written pixels get the background colour (non-transparent)
|
||||
first_frame = 0;
|
||||
if (g->out == 0) {
|
||||
if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header
|
||||
g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
|
||||
g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
|
||||
g->history = (stbi_uc *) stbi__malloc(g->w * g->h);
|
||||
if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory");
|
||||
|
||||
switch ((g->eflags & 0x1C) >> 2) {
|
||||
case 0: // unspecified (also always used on 1st frame)
|
||||
stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h);
|
||||
break;
|
||||
case 1: // do not dispose
|
||||
if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
|
||||
g->old_out = prev_out;
|
||||
break;
|
||||
case 2: // dispose to background
|
||||
if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
|
||||
stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y);
|
||||
break;
|
||||
case 3: // dispose to previous
|
||||
if (g->old_out) {
|
||||
for (i = g->start_y; i < g->max_y; i += 4 * g->w)
|
||||
memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x);
|
||||
}
|
||||
break;
|
||||
// image is treated as "tranparent" at the start - ie, nothing overwrites the current background;
|
||||
// background colour is only used for pixels that are not rendered first frame, after that "background"
|
||||
// color refers to teh color that was there the previous frame.
|
||||
memset( g->out, 0x00, 4 * g->w * g->h );
|
||||
memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent)
|
||||
memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame
|
||||
first_frame = 1;
|
||||
} else {
|
||||
// second frame - how do we dispoase of the previous one?
|
||||
dispose = (g->eflags & 0x1C) >> 2;
|
||||
pcount = g->w * g->h;
|
||||
|
||||
if ((dispose == 3) && (two_back == 0)) {
|
||||
dispose = 2; // if I don't have an image to revert back to, default to the old background
|
||||
}
|
||||
|
||||
if (dispose == 3) { // use previous graphic
|
||||
for (pi = 0; pi < pcount; ++pi) {
|
||||
if (g->history[pi]) {
|
||||
memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );
|
||||
}
|
||||
}
|
||||
} else if (dispose == 2) {
|
||||
// restore what was changed last frame to background before that frame;
|
||||
for (pi = 0; pi < pcount; ++pi) {
|
||||
if (g->history[pi]) {
|
||||
memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// This is a non-disposal case eithe way, so just
|
||||
// leave the pixels as is, and they will become the new background
|
||||
// 1: do not dispose
|
||||
// 0: not specified.
|
||||
}
|
||||
|
||||
// background is what out is after the undoing of the previou frame;
|
||||
memcpy( g->background, g->out, 4 * g->w * g->h );
|
||||
}
|
||||
|
||||
// clear my history;
|
||||
memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame
|
||||
|
||||
for (;;) {
|
||||
switch (stbi__get8(s)) {
|
||||
int tag = stbi__get8(s);
|
||||
switch (tag) {
|
||||
case 0x2C: /* Image Descriptor */
|
||||
{
|
||||
int prev_trans = -1;
|
||||
stbi__int32 x, y, w, h;
|
||||
stbi_uc *o;
|
||||
|
||||
@ -6324,10 +6431,6 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
|
||||
stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
|
||||
g->color_table = (stbi_uc *) g->lpal;
|
||||
} else if (g->flags & 0x80) {
|
||||
if (g->transparent >= 0 && (g->eflags & 0x01)) {
|
||||
prev_trans = g->pal[g->transparent][3];
|
||||
g->pal[g->transparent][3] = 0;
|
||||
}
|
||||
g->color_table = (stbi_uc *) g->pal;
|
||||
} else
|
||||
return stbi__errpuc("missing color table", "Corrupt GIF");
|
||||
@ -6335,8 +6438,17 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
|
||||
o = stbi__process_gif_raster(s, g);
|
||||
if (o == NULL) return NULL;
|
||||
|
||||
if (prev_trans != -1)
|
||||
g->pal[g->transparent][3] = (stbi_uc) prev_trans;
|
||||
// if this was the first frame,
|
||||
pcount = g->w * g->h;
|
||||
if (first_frame && (g->bgindex > 0)) {
|
||||
// if first frame, any pixel not drawn to gets the background color
|
||||
for (pi = 0; pi < pcount; ++pi) {
|
||||
if (g->history[pi] == 0) {
|
||||
g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;
|
||||
memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
@ -6344,19 +6456,35 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
|
||||
case 0x21: // Comment Extension.
|
||||
{
|
||||
int len;
|
||||
if (stbi__get8(s) == 0xF9) { // Graphic Control Extension.
|
||||
int ext = stbi__get8(s);
|
||||
if (ext == 0xF9) { // Graphic Control Extension.
|
||||
len = stbi__get8(s);
|
||||
if (len == 4) {
|
||||
g->eflags = stbi__get8(s);
|
||||
g->delay = stbi__get16le(s);
|
||||
g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths.
|
||||
|
||||
// unset old transparent
|
||||
if (g->transparent >= 0) {
|
||||
g->pal[g->transparent][3] = 255;
|
||||
}
|
||||
if (g->eflags & 0x01) {
|
||||
g->transparent = stbi__get8(s);
|
||||
if (g->transparent >= 0) {
|
||||
g->pal[g->transparent][3] = 0;
|
||||
}
|
||||
} else {
|
||||
// don't need transparent
|
||||
stbi__skip(s, 1);
|
||||
g->transparent = -1;
|
||||
}
|
||||
} else {
|
||||
stbi__skip(s, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while ((len = stbi__get8(s)) != 0)
|
||||
while ((len = stbi__get8(s)) != 0) {
|
||||
stbi__skip(s, len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -6367,28 +6495,92 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
|
||||
return stbi__errpuc("unknown code", "Corrupt GIF");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STBI_NOTUSED(req_comp);
|
||||
static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
|
||||
{
|
||||
if (stbi__gif_test(s)) {
|
||||
int layers = 0;
|
||||
stbi_uc *u = 0;
|
||||
stbi_uc *out = 0;
|
||||
stbi_uc *two_back = 0;
|
||||
stbi__gif g;
|
||||
int stride;
|
||||
memset(&g, 0, sizeof(g));
|
||||
if (delays) {
|
||||
*delays = 0;
|
||||
}
|
||||
|
||||
do {
|
||||
u = stbi__gif_load_next(s, &g, comp, req_comp, two_back);
|
||||
if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
|
||||
|
||||
if (u) {
|
||||
*x = g.w;
|
||||
*y = g.h;
|
||||
++layers;
|
||||
stride = g.w * g.h * 4;
|
||||
|
||||
if (out) {
|
||||
out = (stbi_uc*) STBI_REALLOC( out, layers * stride );
|
||||
if (delays) {
|
||||
*delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers );
|
||||
}
|
||||
} else {
|
||||
out = (stbi_uc*)stbi__malloc( layers * stride );
|
||||
if (delays) {
|
||||
*delays = (int*) stbi__malloc( layers * sizeof(int) );
|
||||
}
|
||||
}
|
||||
memcpy( out + ((layers - 1) * stride), u, stride );
|
||||
if (layers >= 2) {
|
||||
two_back = out - 2 * stride;
|
||||
}
|
||||
|
||||
if (delays) {
|
||||
(*delays)[layers - 1U] = g.delay;
|
||||
}
|
||||
}
|
||||
} while (u != 0);
|
||||
|
||||
// free temp buffer;
|
||||
STBI_FREE(g.out);
|
||||
STBI_FREE(g.history);
|
||||
STBI_FREE(g.background);
|
||||
|
||||
// do the final conversion after loading everything;
|
||||
if (req_comp && req_comp != 4)
|
||||
out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);
|
||||
|
||||
*z = layers;
|
||||
return out;
|
||||
} else {
|
||||
return stbi__errpuc("not GIF", "Image was not as a gif type.");
|
||||
}
|
||||
}
|
||||
|
||||
static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
|
||||
{
|
||||
stbi_uc *u = 0;
|
||||
stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
|
||||
memset(g, 0, sizeof(*g));
|
||||
STBI_NOTUSED(ri);
|
||||
stbi__gif g;
|
||||
memset(&g, 0, sizeof(g));
|
||||
|
||||
u = stbi__gif_load_next(s, g, comp, req_comp);
|
||||
u = stbi__gif_load_next(s, &g, comp, req_comp, 0);
|
||||
if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
|
||||
if (u) {
|
||||
*x = g->w;
|
||||
*y = g->h;
|
||||
*x = g.w;
|
||||
*y = g.h;
|
||||
|
||||
// moved conversion to after successful load so that the same
|
||||
// can be done for multiple frames.
|
||||
if (req_comp && req_comp != 4)
|
||||
u = stbi__convert_format(u, 4, req_comp, g->w, g->h);
|
||||
u = stbi__convert_format(u, 4, req_comp, g.w, g.h);
|
||||
}
|
||||
else if (g->out)
|
||||
STBI_FREE(g->out);
|
||||
STBI_FREE(g);
|
||||
|
||||
// free buffers needed for multiple frame loading;
|
||||
STBI_FREE(g.history);
|
||||
STBI_FREE(g.background);
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
@ -6667,7 +6859,7 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
|
||||
#ifndef STBI_NO_PSD
|
||||
static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
|
||||
{
|
||||
int channelCount, dummy;
|
||||
int channelCount, dummy, depth;
|
||||
if (!x) x = &dummy;
|
||||
if (!y) y = &dummy;
|
||||
if (!comp) comp = &dummy;
|
||||
@ -6687,7 +6879,8 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
|
||||
}
|
||||
*y = stbi__get32be(s);
|
||||
*x = stbi__get32be(s);
|
||||
if (stbi__get16be(s) != 8) {
|
||||
depth = stbi__get16be(s);
|
||||
if (depth != 8 && depth != 16) {
|
||||
stbi__rewind( s );
|
||||
return 0;
|
||||
}
|
||||
@ -6698,6 +6891,33 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
|
||||
*comp = 4;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int stbi__psd_is16(stbi__context *s)
|
||||
{
|
||||
int channelCount, dummy, depth;
|
||||
if (stbi__get32be(s) != 0x38425053) {
|
||||
stbi__rewind( s );
|
||||
return 0;
|
||||
}
|
||||
if (stbi__get16be(s) != 1) {
|
||||
stbi__rewind( s );
|
||||
return 0;
|
||||
}
|
||||
stbi__skip(s, 6);
|
||||
channelCount = stbi__get16be(s);
|
||||
if (channelCount < 0 || channelCount > 16) {
|
||||
stbi__rewind( s );
|
||||
return 0;
|
||||
}
|
||||
dummy = stbi__get32be(s);
|
||||
dummy = stbi__get32be(s);
|
||||
depth = stbi__get16be(s);
|
||||
if (depth != 16) {
|
||||
stbi__rewind( s );
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef STBI_NO_PIC
|
||||
@ -6928,6 +7148,19 @@ static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
|
||||
return stbi__err("unknown image type", "Image not of any known type, or corrupt");
|
||||
}
|
||||
|
||||
static int stbi__is_16_main(stbi__context *s)
|
||||
{
|
||||
#ifndef STBI_NO_PNG
|
||||
if (stbi__png_is16(s)) return 1;
|
||||
#endif
|
||||
|
||||
#ifndef STBI_NO_PSD
|
||||
if (stbi__psd_is16(s)) return 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)
|
||||
{
|
||||
@ -6949,6 +7182,27 @@ STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
|
||||
fseek(f,pos,SEEK_SET);
|
||||
return r;
|
||||
}
|
||||
|
||||
STBIDEF int stbi_is_16_bit(char const *filename)
|
||||
{
|
||||
FILE *f = stbi__fopen(filename, "rb");
|
||||
int result;
|
||||
if (!f) return stbi__err("can't fopen", "Unable to open file");
|
||||
result = stbi_is_16_bit_from_file(f);
|
||||
fclose(f);
|
||||
return result;
|
||||
}
|
||||
|
||||
STBIDEF int stbi_is_16_bit_from_file(FILE *f)
|
||||
{
|
||||
int r;
|
||||
stbi__context s;
|
||||
long pos = ftell(f);
|
||||
stbi__start_file(&s, f);
|
||||
r = stbi__is_16_main(&s);
|
||||
fseek(f,pos,SEEK_SET);
|
||||
return r;
|
||||
}
|
||||
#endif // !STBI_NO_STDIO
|
||||
|
||||
STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
|
||||
@ -6965,10 +7219,28 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
|
||||
return stbi__info_main(&s,x,y,comp);
|
||||
}
|
||||
|
||||
STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len)
|
||||
{
|
||||
stbi__context s;
|
||||
stbi__start_mem(&s,buffer,len);
|
||||
return stbi__is_16_main(&s);
|
||||
}
|
||||
|
||||
STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user)
|
||||
{
|
||||
stbi__context s;
|
||||
stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
|
||||
return stbi__is_16_main(&s);
|
||||
}
|
||||
|
||||
#endif // STB_IMAGE_IMPLEMENTATION
|
||||
|
||||
/*
|
||||
revision history:
|
||||
2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug
|
||||
1-bit BMP
|
||||
*_is_16_bit api
|
||||
avoid warnings
|
||||
2.16 (2017-07-23) all functions have 16-bit variants;
|
||||
STBI_NO_STDIO works again;
|
||||
compilation fixes;
|
||||
|
223
src/external/stb_image_write.h
vendored
@ -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
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
@ -10,34 +10,47 @@
|
||||
|
||||
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:
|
||||
|
||||
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.
|
||||
|
||||
The PNG output is not optimal; it is 20-50% larger than the file
|
||||
written by a decent optimizing implementation. This library is designed
|
||||
for source code compactness and simplicity, not optimal image file size
|
||||
or run-time performance.
|
||||
written by a decent optimizing implementation; though providing a custom
|
||||
zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.
|
||||
This library is designed for source code compactness and simplicity,
|
||||
not optimal image file size or run-time performance.
|
||||
|
||||
BUILDING:
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
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_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_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:
|
||||
|
||||
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:
|
||||
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
|
||||
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.
|
||||
@ -75,6 +94,9 @@ USAGE:
|
||||
writer, both because it is in BGR order and because it may have padding
|
||||
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)
|
||||
data, alpha (if provided) is discarded, and for monochrome data it is
|
||||
replicated across all three channels.
|
||||
@ -88,21 +110,17 @@ USAGE:
|
||||
|
||||
CREDITS:
|
||||
|
||||
PNG/BMP/TGA
|
||||
Sean Barrett
|
||||
HDR
|
||||
Baldur Karlsson
|
||||
TGA monochrome:
|
||||
Jean-Sebastien Guay
|
||||
misc enhancements:
|
||||
Tim Kelsey
|
||||
TGA RLE
|
||||
Alan Hickman
|
||||
initial file IO callback implementation
|
||||
Emmanuel Julien
|
||||
JPEG
|
||||
Jon Olick (original jo_jpeg.cpp code)
|
||||
Daniel Gibson
|
||||
|
||||
Sean Barrett - PNG/BMP/TGA
|
||||
Baldur Karlsson - HDR
|
||||
Jean-Sebastien Guay - TGA monochrome
|
||||
Tim Kelsey - misc enhancements
|
||||
Alan Hickman - TGA RLE
|
||||
Emmanuel Julien - initial file IO callback implementation
|
||||
Jon Olick - original jo_jpeg.cpp code
|
||||
Daniel Gibson - integrate JPEG, allow external zlib
|
||||
Aarni Koskela - allow choosing PNG filter
|
||||
|
||||
bugfixes:
|
||||
github:Chribba
|
||||
Guillaume Chereau
|
||||
@ -114,6 +132,7 @@ CREDITS:
|
||||
Thatcher Ulrich
|
||||
github:poppolopoppo
|
||||
Patrick Boettcher
|
||||
github:xeekworx
|
||||
|
||||
LICENSE
|
||||
|
||||
@ -132,9 +151,12 @@ extern "C" {
|
||||
#define STBIWDEF static
|
||||
#else
|
||||
#define STBIWDEF extern
|
||||
extern int stbi_write_tga_with_rle;
|
||||
#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
|
||||
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);
|
||||
@ -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_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
|
||||
}
|
||||
#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)
|
||||
|
||||
#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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return f != NULL;
|
||||
}
|
||||
@ -245,12 +292,6 @@ static void stbi__end_write_file(stbi__write_context *s)
|
||||
typedef unsigned int stbiw_uint32;
|
||||
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)
|
||||
{
|
||||
while (*fmt) {
|
||||
@ -341,6 +382,9 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i
|
||||
if (y <= 0)
|
||||
return;
|
||||
|
||||
if (stbi__flip_vertically_on_write)
|
||||
vdir *= -1;
|
||||
|
||||
if (vdir < 0)
|
||||
j_end = -1, j = y-1;
|
||||
else
|
||||
@ -412,10 +456,20 @@ 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);
|
||||
} else {
|
||||
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);
|
||||
|
||||
for (j = y - 1; j >= 0; --j) {
|
||||
if (stbi__flip_vertically_on_write) {
|
||||
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;
|
||||
|
||||
@ -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";
|
||||
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);
|
||||
#endif
|
||||
s->func(s->context, buffer, len);
|
||||
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
@ -662,6 +720,7 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const
|
||||
// PNG writer
|
||||
//
|
||||
|
||||
#ifndef STBIW_ZLIB_COMPRESS
|
||||
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
|
||||
#define stbiw__sbraw(a) ((int *) (a) - 2)
|
||||
#define stbiw__sbm(a) stbiw__sbraw(a)[0]
|
||||
@ -742,8 +801,14 @@ static unsigned int stbiw__zhash(unsigned char *data)
|
||||
|
||||
#define stbiw__ZHASH 16384
|
||||
|
||||
#endif // STBIW_ZLIB_COMPRESS
|
||||
|
||||
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 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 };
|
||||
@ -752,6 +817,8 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
||||
int i,j, bitcount=0;
|
||||
unsigned char *out = NULL;
|
||||
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
|
||||
if (hash_table == NULL)
|
||||
return NULL;
|
||||
if (quality < 5) quality = 5;
|
||||
|
||||
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
|
||||
STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
|
||||
return (unsigned char *) stbiw__sbraw(out);
|
||||
#endif // STBIW_ZLIB_COMPRESS
|
||||
}
|
||||
|
||||
static unsigned int stbiw__crc32(unsigned char *buffer, int len)
|
||||
@ -911,29 +979,15 @@ static unsigned char stbiw__paeth(int a, int b, int c)
|
||||
}
|
||||
|
||||
// @OPTIMIZE: provide an option that always forces left-predict or paeth predict
|
||||
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
|
||||
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)
|
||||
{
|
||||
int ctype[5] = { -1, 0, 4, 2, 6 };
|
||||
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
|
||||
unsigned char *out,*o, *filt, *zlib;
|
||||
signed char *line_buffer;
|
||||
int i,j,k,p,zlen;
|
||||
|
||||
if (stride_bytes == 0)
|
||||
stride_bytes = x * n;
|
||||
|
||||
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; }
|
||||
for (j=0; j < y; ++j) {
|
||||
static int mapping[] = { 0,1,2,3,4 };
|
||||
static int firstmap[] = { 0,1,0,5,6 };
|
||||
int *mymap = (j != 0) ? mapping : firstmap;
|
||||
int best = 0, bestval = 0x7fffffff;
|
||||
for (p=0; p < 2; ++p) {
|
||||
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 type = mymap[k],est=0;
|
||||
unsigned char *z = pixels + stride_bytes*j;
|
||||
for (i=0; i < n; ++i)
|
||||
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;
|
||||
@ -943,7 +997,8 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
||||
case 5: line_buffer[i] = z[i]; break;
|
||||
case 6: line_buffer[i] = z[i]; break;
|
||||
}
|
||||
for (i=n; i < x*n; ++i) {
|
||||
}
|
||||
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;
|
||||
@ -954,18 +1009,57 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
||||
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)
|
||||
}
|
||||
|
||||
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 };
|
||||
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
|
||||
unsigned char *out,*o, *filt, *zlib;
|
||||
signed char *line_buffer;
|
||||
int j,zlen;
|
||||
|
||||
if (stride_bytes == 0)
|
||||
stride_bytes = x * n;
|
||||
|
||||
if (force_filter >= 5) {
|
||||
force_filter = -1;
|
||||
}
|
||||
|
||||
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; }
|
||||
for (j=0; j < y; ++j) {
|
||||
int filter_type;
|
||||
if (force_filter > -1) {
|
||||
filter_type = force_filter;
|
||||
stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, force_filter, line_buffer);
|
||||
} else { // Estimate the best filter by running through all of them:
|
||||
int best_filter = 0, best_filter_val = 0x7fffffff, est, i;
|
||||
for (filter_type = 0; filter_type < 5; filter_type++) {
|
||||
stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, filter_type, line_buffer);
|
||||
|
||||
// Estimate the entropy of the line using this filter; the less, the better.
|
||||
est = 0;
|
||||
for (i = 0; i < x*n; ++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;
|
||||
}
|
||||
}
|
||||
// when we get here, best contains the filter type, and line_buffer contains the data
|
||||
filt[j*(x*n+1)] = (unsigned char) best;
|
||||
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, filter_type contains the filter type, and line_buffer contains the data
|
||||
filt[j*(x*n+1)] = (unsigned char) filter_type;
|
||||
STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
|
||||
}
|
||||
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);
|
||||
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;
|
||||
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
|
||||
if (png == NULL) return 0;
|
||||
#ifdef STBI_MSC_SECURE_CRT
|
||||
if (fopen_s(&f, filename, "wb"))
|
||||
f = NULL;
|
||||
#else
|
||||
f = fopen(filename, "wb");
|
||||
#endif
|
||||
if (!f) { STBIW_FREE(png); return 0; }
|
||||
fwrite(png, 1, len, 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];
|
||||
for(row = y, pos = 0; row < y+8; ++row) {
|
||||
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;
|
||||
if(row >= 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
|
||||
|
||||
/* 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)
|
||||
doc fix
|
||||
1.06 (2017-07-23)
|
||||
|
103
src/external/stb_truetype.h
vendored
@ -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
|
||||
//
|
||||
// This library processes TrueType files:
|
||||
@ -30,33 +30,24 @@
|
||||
// Imanol Celaya
|
||||
//
|
||||
// Bug/warning reports/fixes:
|
||||
// "Zer" on mollyrocket
|
||||
// Cass Everitt
|
||||
// stoiko (Haemimont Games)
|
||||
// Brian Hook
|
||||
// Walter van Niftrik
|
||||
// David Gow
|
||||
// David Given
|
||||
// Ivan-Assen Ivanov
|
||||
// Anthony Pesch
|
||||
// Johan Duparc
|
||||
// Hou Qiming
|
||||
// Fabian "ryg" Giesen
|
||||
// Martins Mozeiko
|
||||
// Cap Petschulat
|
||||
// Omar Cornut
|
||||
// github:aloucks
|
||||
// Peter LaValle
|
||||
// Sergey Popov
|
||||
// Giumo X. Clanjor
|
||||
// Higor Euripedes
|
||||
// Thomas Fields
|
||||
// Derek Vinyard
|
||||
// Cort Stratton
|
||||
// github:oyvindjam
|
||||
// "Zer" on mollyrocket Fabian "ryg" Giesen
|
||||
// Cass Everitt Martins Mozeiko
|
||||
// stoiko (Haemimont Games) Cap Petschulat
|
||||
// Brian Hook Omar Cornut
|
||||
// Walter van Niftrik github:aloucks
|
||||
// David Gow Peter LaValle
|
||||
// David Given Sergey Popov
|
||||
// Ivan-Assen Ivanov Giumo X. Clanjor
|
||||
// Anthony Pesch Higor Euripedes
|
||||
// Johan Duparc Thomas Fields
|
||||
// Hou Qiming Derek Vinyard
|
||||
// Rob Loach Cort Stratton
|
||||
// Kenney Phillis Jr. github:oyvindjam
|
||||
// Brian Costabile github:vassvik
|
||||
//
|
||||
// VERSION HISTORY
|
||||
//
|
||||
// 1.18 (2018-01-29) add missing function
|
||||
// 1.17 (2017-07-23) make more arguments const; doc fix
|
||||
// 1.16 (2017-07-12) SDF support
|
||||
// 1.15 (2017-03-03) make more arguments const
|
||||
@ -171,7 +162,7 @@
|
||||
// measurement for describing font size, defined as 72 points per inch.
|
||||
// stb_truetype provides a point API for compatibility. However, true
|
||||
// "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
|
||||
// there are 96 pixels per inch, thus making 'inch' measurements have
|
||||
// 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
|
||||
// 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
|
||||
//
|
||||
// Quality:
|
||||
@ -427,11 +451,6 @@ int main(int arg, char **argv)
|
||||
#define STBTT_fabs(x) fabs(x)
|
||||
#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
|
||||
#ifndef STBTT_malloc
|
||||
#include <stdlib.h>
|
||||
@ -2172,7 +2191,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
|
||||
|
||||
// push immediate
|
||||
if (b0 == 255) {
|
||||
f = (float)stbtt__buf_get32(&b) / 0x10000;
|
||||
f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
|
||||
} else {
|
||||
stbtt__buf_skip(&b, -1);
|
||||
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);
|
||||
int r = stbtt__run_charstring(info, glyph_index, &c);
|
||||
if (x0) {
|
||||
*x0 = r ? c.min_x : 0;
|
||||
*y0 = r ? c.min_y : 0;
|
||||
*x1 = r ? c.max_x : 0;
|
||||
*y1 = r ? c.max_y : 0;
|
||||
}
|
||||
if (x0) *x0 = r ? c.min_x : 0;
|
||||
if (y0) *y0 = r ? c.min_y : 0;
|
||||
if (x1) *x1 = r ? c.max_x : 0;
|
||||
if (y1) *y1 = r ? c.max_y : 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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3230,7 +3247,8 @@ 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)
|
||||
{
|
||||
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);
|
||||
if (windings) {
|
||||
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);
|
||||
}
|
||||
|
||||
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_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
|
||||
|
20
src/external/stb_vorbis.c
vendored
@ -1658,6 +1658,8 @@ static int residue_decode(vorb *f, Codebook *book, float *target, int offset, in
|
||||
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)
|
||||
{
|
||||
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 c = r->classbook;
|
||||
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 temp_alloc_point = temp_alloc_save(f);
|
||||
#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 we have a valid current loc, and this is final:
|
||||
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
|
||||
if (current_end < f->current_loc + (right_end-left_start)) {
|
||||
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 {
|
||||
*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
|
||||
f->current_loc += *len;
|
||||
return TRUE;
|
||||
@ -3693,7 +3698,10 @@ static int start_decoder(vorb *f)
|
||||
int i,max_part_read=0;
|
||||
for (i=0; i < f->residue_count; ++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;
|
||||
if (part_read > max_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 *));
|
||||
#endif
|
||||
|
||||
// maximum reasonable partition size is f->blocksize_1
|
||||
|
||||
f->temp_memory_required = classify_mem;
|
||||
if (imdct_mem > f->temp_memory_required)
|
||||
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
|
||||
|
||||
/* 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.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;
|
||||
|
10
src/external/stb_vorbis.h
vendored
@ -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/
|
||||
//
|
||||
// Original version written by Sean Barrett in 2007.
|
||||
//
|
||||
// Originally sponsored by RAD Game Tools. Seeking sponsored
|
||||
// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software,
|
||||
// Aras Pranckevicius, and Sean Barrett.
|
||||
// Originally sponsored by RAD Game Tools. Seeking implementation
|
||||
// sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker,
|
||||
// Elias Software, Aras Pranckevicius, and Sean Barrett.
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
@ -32,6 +32,8 @@
|
||||
// manxorist@github saga musix github:infatum
|
||||
//
|
||||
// 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.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
|
||||
|
@ -1044,7 +1044,8 @@ RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight);
|
||||
|
||||
// Shader loading/unloading functions
|
||||
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 Shader GetShaderDefault(void); // Get default shader
|
||||
|
45
src/rlgl.c
@ -2324,7 +2324,27 @@ char *LoadText(const char *fileName)
|
||||
|
||||
// Load shader from files and bind default locations
|
||||
// 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 };
|
||||
|
||||
@ -2335,27 +2355,8 @@ Shader LoadShader(char *vsFileName, char *fsFileName)
|
||||
unsigned int vertexShaderId = defaultVShaderId;
|
||||
unsigned int fragmentShaderId = defaultFShaderId;
|
||||
|
||||
if (vsFileName != NULL)
|
||||
{
|
||||
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 (vsCode != NULL) vertexShaderId = CompileShader(vsCode, GL_VERTEX_SHADER);
|
||||
if (fsCode != NULL) fragmentShaderId = CompileShader(fsCode, GL_FRAGMENT_SHADER);
|
||||
|
||||
if ((vertexShaderId == defaultVShaderId) && (fragmentShaderId == defaultFShaderId)) shader = defaultShader;
|
||||
else
|
||||
|
@ -418,11 +418,14 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
|
||||
}
|
||||
else index = GetCharIndex(spriteFont, (unsigned char)text[i]);
|
||||
|
||||
if ((unsigned char)text[i] != ' ')
|
||||
{
|
||||
DrawTexturePro(spriteFont.texture, spriteFont.chars[index].rec,
|
||||
(Rectangle){ position.x + textOffsetX + spriteFont.chars[index].offsetX*scaleFactor,
|
||||
position.y + textOffsetY + spriteFont.chars[index].offsetY*scaleFactor,
|
||||
spriteFont.chars[index].rec.width*scaleFactor,
|
||||
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);
|
||||
else textOffsetX += (int)(spriteFont.chars[index].advanceX*scaleFactor + spacing);
|
||||
|
@ -53,26 +53,21 @@ APP_COMPANY_NAME ?= raylib
|
||||
APP_PRODUCT_NAME ?= rgame
|
||||
APP_VERSION_CODE ?= 1
|
||||
APP_VERSION_NAME ?= 1.0
|
||||
APP_ICON_LDPI ?= $(RAYLIB_PATH)\logo\logo36x36.png
|
||||
APP_ICON_MDPI ?= $(RAYLIB_PATH)\logo\logo48x48.png
|
||||
APP_ICON_HDPI ?= $(RAYLIB_PATH)\logo\logo72x72.png
|
||||
APP_ICON_LDPI ?= $(RAYLIB_PATH)\logo\raylib_36x36.png
|
||||
APP_ICON_MDPI ?= $(RAYLIB_PATH)\logo\raylib_48x48.png
|
||||
APP_ICON_HDPI ?= $(RAYLIB_PATH)\logo\raylib_72x72.png
|
||||
APP_SCREEN_ORIENTATION ?= landscape
|
||||
APP_KEYSTORE_PASS ?= raylib
|
||||
|
||||
# Library type used for raylib and OpenAL Soft: STATIC (.a) or SHARED (.so/.dll)
|
||||
# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll)
|
||||
RAYLIB_LIBTYPE ?= STATIC
|
||||
OPENAL_LIBTYPE ?= STATIC
|
||||
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
|
||||
# NOTE: Generated NativeLoader.java automatically load those libraries
|
||||
ifeq ($(RAYLIB_LIBTYPE),SHARED)
|
||||
PROJECT_SHARED_LIBS = lib/armeabi-v7a/libraylib.so
|
||||
endif
|
||||
ifeq ($(OPENAL_LIBTYPE),SHARED)
|
||||
PROJECT_SHARED_LIBS += lib/armeabi-v7a/libopenal.so
|
||||
endif
|
||||
|
||||
# Compiler and archiver
|
||||
# NOTE: GCC is being deprectated in Android NDK r16
|
||||
@ -154,15 +149,9 @@ copy_project_required_libs:
|
||||
ifeq ($(RAYLIB_LIBTYPE),SHARED)
|
||||
copy /Y $(RAYLIB_LIB_PATH)\libraylib.so $(PROJECT_BUILD_PATH)\lib\armeabi-v7a\libraylib.so
|
||||
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)
|
||||
copy /Y $(RAYLIB_LIB_PATH)\libraylib.a $(PROJECT_BUILD_PATH)\lib\armeabi-v7a\libraylib.a
|
||||
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
|
||||
# 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 public class NativeLoader extends android.app.NativeActivity { >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
|
||||
@echo static { >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
|
||||
ifeq ($(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)
|
||||
@echo System.loadLibrary("raylib"); >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java
|
||||
endif
|
||||
|
12
utils.cmake
@ -32,7 +32,11 @@ else()
|
||||
find_library(XCURSOR_LIBRARY Xcursor)
|
||||
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()
|
||||
|
||||
@ -70,8 +74,8 @@ foreach(L ${LIBS_PRIVATE})
|
||||
|
||||
set(LASTDIR ${DIR})
|
||||
|
||||
set(PKG_CONFIG_LIBS_PRIVATE ${PKG_CONFIG_LIBS_PRIVATE} ${DIR_OPT} ${FILE_OPT})
|
||||
string (REPLACE ";" " " PKG_CONFIG_LIBS_PRIVATE "${PKG_CONFIG_LIBS_PRIVATE}")
|
||||
set(__PKG_CONFIG_LIBS_PRIVATE ${__PKG_CONFIG_LIBS_PRIVATE} ${DIR_OPT} ${FILE_OPT})
|
||||
string (REPLACE ";" " " __PKG_CONFIG_LIBS_PRIVATE "${__PKG_CONFIG_LIBS_PRIVATE}")
|
||||
endforeach(L)
|
||||
|
||||
|
||||
@ -82,7 +86,7 @@ function(link_libraries_to_executable executable)
|
||||
if (TARGET raylib_shared)
|
||||
target_link_libraries(${executable} raylib_shared)
|
||||
else()
|
||||
target_link_libraries(${executable} raylib ${PKG_CONFIG_LIBS_PRIVATE})
|
||||
target_link_libraries(${executable} raylib ${__PKG_CONFIG_LIBS_PRIVATE})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|