diff --git a/BINDINGS.md b/BINDINGS.md index b415065d7..ac79a1fa9 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -36,7 +36,7 @@ Some people ported raylib to other languages in form of bindings or wrappers to | raylib_odin_bindings | 4.0-dev | [Odin](https://odin-lang.org/) | MIT | https://github.com/Deathbat2190/raylib_odin_bindings | | raylib-odin | **4.0** | [Odin](https://odin-lang.org/) | BSD-3Clause | https://github.com/odin-lang/Odin/tree/master/vendor/raylib | | raylib.v | **4.0** | [V](https://vlang.io/) | Zlib | https://github.com/irishgreencitrus/raylib.v | -| raylib-ocaml | 3.7 | [OCaml](https://ocaml.org/) | MIT | https://github.com/tjammer/raylib-ocaml | +| raylib-ocaml | **4.0** | [OCaml](https://ocaml.org/) | MIT | https://github.com/tjammer/raylib-ocaml | | raylib-swift | 3.7 | [Swift](https://swift.org/) | MIT | https://github.com/STREGAsGate/Raylib | | hb-raylib | 3.5 | [Harbour](https://harbour.github.io) | MIT | https://github.com/MarcosLeonardoMendezGerencir/hb-raylib | | Relib | 3.5 | [ReCT](https://github.com/RedCubeDev-ByteSpace/ReCT) | ? | https://github.com/RedCubeDev-ByteSpace/Relib | diff --git a/cmake/CompileDefinitions.cmake b/cmake/CompileDefinitions.cmake index 36062b309..7fbbef99e 100644 --- a/cmake/CompileDefinitions.cmake +++ b/cmake/CompileDefinitions.cmake @@ -4,26 +4,35 @@ target_compile_definitions("raylib" PUBLIC "${GRAPHICS}") function(define_if target variable) if (${${variable}}) + message(STATUS "${variable}=${${variable}}") target_compile_definitions(${target} PUBLIC "${variable}") endif () endfunction() if (${CUSTOMIZE_BUILD}) target_compile_definitions("raylib" PUBLIC EXTERNAL_CONFIG_FLAGS) + define_if("raylib" USE_AUDIO) + define_if("raylib" SUPPORT_MODULE_RSHAPES) + define_if("raylib" SUPPORT_MODULE_RTEXTURES) + define_if("raylib" SUPPORT_MODULE_RTEXT) + define_if("raylib" SUPPORT_MODULE_RMODELS) + define_if("raylib" SUPPORT_MODULE_RAUDIO) define_if("raylib" SUPPORT_CAMERA_SYSTEM) define_if("raylib" SUPPORT_GESTURES_SYSTEM) define_if("raylib" SUPPORT_MOUSE_GESTURES) define_if("raylib" SUPPORT_SSH_KEYBOARD_RPI) - define_if("raylib" SUPPORT_BUSY_WAIT_LOOP) - define_if("raylib" SUPPORT_EVENTS_WAITING) + define_if("raylib" SUPPORT_DEFAULT_FONT) define_if("raylib" SUPPORT_SCREEN_CAPTURE) define_if("raylib" SUPPORT_GIF_RECORDING) - define_if("raylib" SUPPORT_HIGH_DPI) - define_if("raylib" SUPPORT_COMPRESSION_API) + define_if("raylib" SUPPORT_BUSY_WAIT_LOOP) + define_if("raylib" SUPPORT_EVENTS_WAITING) + define_if("raylib" SUPPORT_WINMM_HIGHRES_TIMER) define_if("raylib" SUPPORT_DATA_STORAGE) - define_if("raylib" SUPPORT_VR_SIMULATOR) - define_if("raylib" SUPPORT_FONT_TEXTURE) + define_if("raylib" SUPPORT_COMPRESSION_API) define_if("raylib" SUPPORT_QUADS_DRAW_MODE) + define_if("raylib" SUPPORT_IMAGE_EXPORT) + define_if("raylib" SUPPORT_IMAGE_GENERATION) + define_if("raylib" SUPPORT_IMAGE_MANIPULATION) define_if("raylib" SUPPORT_FILEFORMAT_PNG) define_if("raylib" SUPPORT_FILEFORMAT_DDS) define_if("raylib" SUPPORT_FILEFORMAT_HDR) @@ -33,32 +42,28 @@ if (${CUSTOMIZE_BUILD}) define_if("raylib" SUPPORT_FILEFORMAT_TGA) define_if("raylib" SUPPORT_FILEFORMAT_JPG) define_if("raylib" SUPPORT_FILEFORMAT_GIF) + define_if("raylib" SUPPORT_FILEFORMAT_QOI) define_if("raylib" SUPPORT_FILEFORMAT_PSD) define_if("raylib" SUPPORT_FILEFORMAT_PKM) define_if("raylib" SUPPORT_FILEFORMAT_PVR) - define_if("raylib" ORT_IMAGE_EXPORT) - define_if("raylib" SUPPORT_IMAGE_MANIPULATION) - define_if("raylib" SUPPORT_IMAGE_GENERATION) - define_if("raylib" SUPPORT_DEFAULT_FONT) define_if("raylib" SUPPORT_FILEFORMAT_FNT) define_if("raylib" SUPPORT_FILEFORMAT_TTF) define_if("raylib" SUPPORT_TEXT_MANIPULATION) + define_if("raylib" SUPPORT_MESH_GENERATION) define_if("raylib" SUPPORT_FILEFORMAT_OBJ) define_if("raylib" SUPPORT_FILEFORMAT_MTL) define_if("raylib" SUPPORT_FILEFORMAT_IQM) define_if("raylib" SUPPORT_FILEFORMAT_GLTF) - define_if("raylib" SUPPORT_MESH_GENERATION) + define_if("raylib" SUPPORT_FILEFORMAT_VOX) define_if("raylib" SUPPORT_FILEFORMAT_WAV) define_if("raylib" SUPPORT_FILEFORMAT_OGG) define_if("raylib" SUPPORT_FILEFORMAT_XM) define_if("raylib" SUPPORT_FILEFORMAT_MOD) - define_if("raylib" SUPPORT_FILEFORMAT_FLAC) define_if("raylib" SUPPORT_FILEFORMAT_MP3) + define_if("raylib" SUPPORT_FILEFORMAT_FLAC) define_if("raylib" SUPPORT_STANDARD_FILEIO) define_if("raylib" SUPPORT_TRACELOG) - define_if("raylib" SUPPORT_COMPRESSION_API) - - + if (UNIX AND NOT APPLE) target_compile_definitions("raylib" PUBLIC "MAX_FILEPATH_LENGTH=4096") else () diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake index c156d6b35..b7874888f 100644 --- a/cmake/LibraryConfigurations.cmake +++ b/cmake/LibraryConfigurations.cmake @@ -40,10 +40,10 @@ elseif (${PLATFORM} MATCHES "Android") set(PLATFORM_CPP "PLATFORM_ANDROID") set(GRAPHICS "GRAPHICS_API_OPENGL_ES2") set(CMAKE_POSITION_INDEPENDENT_CODE ON) - + set(raylib_sources "${raylib_sources} ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c") add_definitions(-DANDROID -D__ANDROID_API__=21) - include_directories(external/android/native_app_glue) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -uANativeActivity_onCreate") + include_directories(${ANDROID_NDK}/sources/android/native_app_glue) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -u ANativeActivity_onCreate -Wl,-undefined,dynamic_lookup") find_library(OPENGL_LIBRARY OpenGL) set(LIBS_PRIVATE m log android EGL GLESv2 OpenSLES atomic c) diff --git a/examples/Makefile b/examples/Makefile index f0bb6404f..50a12e5c1 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -23,42 +23,32 @@ .PHONY: all clean +# Define required environment variables +#------------------------------------------------------------------------------------------------ +# Define target platform: PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_DRM, PLATFORM_ANDROID, PLATFORM_WEB +PLATFORM ?= PLATFORM_DESKTOP + # Define required raylib variables -PROJECT_NAME ?= raylib_examples -RAYLIB_VERSION ?= 4.0.0 -RAYLIB_PATH ?= .. +PROJECT_NAME ?= raylib_examples +RAYLIB_VERSION ?= 4.0.0 +RAYLIB_PATH ?= .. -# Define default options +# Locations of raylib.h and libraylib.a/libraylib.so +# NOTE: Those variables are only used for PLATFORM_OS: LINUX, BSD +RAYLIB_INCLUDE_PATH ?= /usr/local/include +RAYLIB_LIB_PATH ?= /usr/local/lib -# One of PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB -PLATFORM ?= PLATFORM_DESKTOP - -# Locations of your newly installed library and associated headers. See ../src/Makefile -# On Linux, if you have installed raylib but cannot compile the examples, check that -# the *_INSTALL_PATH values here are the same as those in src/Makefile or point to known locations. -# To enable system-wide compile-time and runtime linking to libraylib.so, run ../src/$ sudo make install RAYLIB_LIBTYPE_SHARED. -# To enable compile-time linking to a special version of libraylib.so, change these variables here. -# To enable runtime linking to a special version of libraylib.so, see EXAMPLE_RUNTIME_PATH below. -# If there is a libraylib in both EXAMPLE_RUNTIME_PATH and RAYLIB_INSTALL_PATH, at runtime, -# the library at EXAMPLE_RUNTIME_PATH, if present, will take precedence over the one at RAYLIB_INSTALL_PATH. -# RAYLIB_INSTALL_PATH should be the desired full path to libraylib. No relative paths. -DESTDIR ?= /usr/local -RAYLIB_INSTALL_PATH ?= $(DESTDIR)/lib -# RAYLIB_H_INSTALL_PATH locates the installed raylib header and associated source files. -RAYLIB_H_INSTALL_PATH ?= $(DESTDIR)/include - -# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) +# Library type compilation: STATIC (.a) or SHARED (.so/.dll) RAYLIB_LIBTYPE ?= STATIC # Build mode for project: DEBUG or RELEASE BUILD_MODE ?= RELEASE # Use external GLFW library instead of rglfw module -# TODO: Review usage on Linux. Target version of choice. Switch on -lglfw or -lglfw3 USE_EXTERNAL_GLFW ?= FALSE -# Use Wayland display server protocol on Linux desktop -# by default it uses X11 windowing system +# Use Wayland display server protocol on Linux desktop (by default it uses X11 windowing system) +# NOTE: This variable is only used for PLATFORM_OS: LINUX USE_WAYLAND_DISPLAY ?= FALSE # Use cross-compiler for PLATFORM_RPI @@ -75,54 +65,52 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) # No uname.exe on MinGW!, but OS=Windows_NT on Windows! # ifeq ($(UNAME),Msys) -> Windows ifeq ($(OS),Windows_NT) - PLATFORM_OS=WINDOWS + PLATFORM_OS = WINDOWS else - UNAMEOS=$(shell uname) + UNAMEOS = $(shell uname) ifeq ($(UNAMEOS),Linux) - PLATFORM_OS=LINUX + PLATFORM_OS = LINUX endif ifeq ($(UNAMEOS),FreeBSD) - PLATFORM_OS=BSD + PLATFORM_OS = BSD endif ifeq ($(UNAMEOS),OpenBSD) - PLATFORM_OS=BSD + PLATFORM_OS = BSD endif ifeq ($(UNAMEOS),NetBSD) - PLATFORM_OS=BSD + PLATFORM_OS = BSD endif ifeq ($(UNAMEOS),DragonFly) - PLATFORM_OS=BSD + PLATFORM_OS = BSD endif ifeq ($(UNAMEOS),Darwin) - PLATFORM_OS=OSX + PLATFORM_OS = OSX endif endif endif ifeq ($(PLATFORM),PLATFORM_RPI) - UNAMEOS=$(shell uname) + UNAMEOS = $(shell uname) ifeq ($(UNAMEOS),Linux) - PLATFORM_OS=LINUX + PLATFORM_OS = LINUX endif endif ifeq ($(PLATFORM),PLATFORM_DRM) - UNAMEOS=$(shell uname) + UNAMEOS = $(shell uname) ifeq ($(UNAMEOS),Linux) - PLATFORM_OS=LINUX + PLATFORM_OS = LINUX endif endif -# RAYLIB_PATH adjustment for different platforms. -# If using GNU make, we can get the full path to the top of the tree. Windows? BSD? -# Required for ldconfig or other tools that do not perform path expansion. +# RAYLIB_PATH adjustment for LINUX platform +# TODO: Do we really need this? ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),LINUX) - RAYLIB_PREFIX ?= .. - RAYLIB_PATH = $(realpath $(RAYLIB_PREFIX)) + RAYLIB_PREFIX ?= .. + RAYLIB_PATH = $(realpath $(RAYLIB_PREFIX)) endif endif -# Default path for raylib on Raspberry Pi, if installed in different path, update it! -# This is not currently used by src/Makefile. Not sure of its origin or usage. Refer to wiki. -# TODO: update install: target in src/Makefile for RPI, consider relation to LINUX. + +# Default path for raylib on Raspberry Pi ifeq ($(PLATFORM),PLATFORM_RPI) RAYLIB_PATH ?= /home/pi/raylib endif @@ -130,6 +118,9 @@ ifeq ($(PLATFORM),PLATFORM_DRM) RAYLIB_PATH ?= /home/pi/raylib endif +# Define raylib release directory for compiled library +RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/src + ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables EMSDK_PATH ?= C:/emsdk @@ -137,29 +128,11 @@ ifeq ($(PLATFORM),PLATFORM_WEB) CLANG_PATH = $(EMSDK_PATH)/upstream/bin PYTHON_PATH = $(EMSDK_PATH)/python/3.9.2-1_64bit NODE_PATH = $(EMSDK_PATH)/node/14.15.5_64bit/bin - export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH);C:\raylib\MinGW\bin:$$(PATH) + export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH):$$(PATH) endif -# Define raylib release directory for compiled library. -# RAYLIB_RELEASE_PATH points to provided binaries or your freshly built version -RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/src - -# EXAMPLE_RUNTIME_PATH embeds a custom runtime location of libraylib.so or other desired libraries -# into each example binary compiled with RAYLIB_LIBTYPE=SHARED. It defaults to RAYLIB_RELEASE_PATH -# so that these examples link at runtime with your version of libraylib.so in ../release/libs/linux -# without formal installation from ../src/Makefile. It aids portability and is useful if you have -# multiple versions of raylib, have raylib installed to a non-standard location, or want to -# bundle libraylib.so with your game. Change it to your liking. -# NOTE: If, at runtime, there is a libraylib.so at both EXAMPLE_RUNTIME_PATH and RAYLIB_INSTALL_PATH, -# The library at EXAMPLE_RUNTIME_PATH, if present, will take precedence over RAYLIB_INSTALL_PATH, -# Implemented for LINUX below with CFLAGS += -Wl,-rpath,$(EXAMPLE_RUNTIME_PATH) -# To see the result, run readelf -d core/core_basic_window; looking at the RPATH or RUNPATH attribute. -# To see which libraries a built example is linking to, ldd core/core_basic_window; -# Look for libraylib.so.1 => $(RAYLIB_INSTALL_PATH)/libraylib.so.1 or similar listing. -EXAMPLE_RUNTIME_PATH ?= $(RAYLIB_RELEASE_PATH) - -# Define default C compiler: gcc -# NOTE: define g++ compiler if using C++ +# Define default C compiler: CC +#------------------------------------------------------------------------------------------------ CC = gcc ifeq ($(PLATFORM),PLATFORM_DESKTOP) @@ -186,7 +159,8 @@ ifeq ($(PLATFORM),PLATFORM_WEB) CC = emcc endif -# Define default make program +# Define default make program: MAKE +#------------------------------------------------------------------------------------------------ MAKE ?= make ifeq ($(PLATFORM),PLATFORM_DESKTOP) @@ -201,7 +175,8 @@ ifeq ($(PLATFORM),PLATFORM_WEB) MAKE = mingw32-make endif -# Define compiler flags: +# Define compiler flags: CFLAGS +#------------------------------------------------------------------------------------------------ # -O1 defines optimization level # -g include debug information on compilation # -s strip unnecessary data from build @@ -209,6 +184,7 @@ endif # -std=c99 defines C language mode (standard C from 1999 revision) # -std=gnu99 defines C language mode (GNU C from 1999 revision) # -Wno-missing-braces ignore invalid warning (GCC bug 53119) +# -Wno-unused-value ignore unused return values of some functions (i.e. fread()) # -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec CFLAGS = -Wall -std=c99 -D_DEFAULT_SOURCE -Wno-missing-braces -Wunused-result @@ -226,6 +202,10 @@ else endif # Additional flags for compiler (if desired) +# -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 #CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),LINUX) @@ -234,7 +214,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) endif ifeq ($(RAYLIB_LIBTYPE),SHARED) # Explicitly enable runtime link to libraylib.so - CFLAGS += -Wl,-rpath,$(EXAMPLE_RUNTIME_PATH) + CFLAGS += -Wl,-rpath,$(RAYLIB_RELEASE_PATH) endif endif endif @@ -245,51 +225,47 @@ ifeq ($(PLATFORM),PLATFORM_DRM) CFLAGS += -std=gnu99 -DEGL_NO_X11 endif -# Define include paths for required headers +# Define include paths for required headers: INCLUDE_PATHS # NOTE: Some external/extras libraries could be required (stb, physac, easings...) +#------------------------------------------------------------------------------------------------ INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external -I$(RAYLIB_PATH)/src/extras # Define additional directories containing required header files +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),BSD) + INCLUDE_PATHS += -I$(RAYLIB_INCLUDE_PATH) + endif + ifeq ($(PLATFORM_OS),LINUX) + INCLUDE_PATHS += -I$(RAYLIB_INCLUDE_PATH) + endif +endif ifeq ($(PLATFORM),PLATFORM_RPI) - # RPI required libraries INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include/interface/vmcs_host/linux INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include/interface/vcos/pthreads endif ifeq ($(PLATFORM),PLATFORM_DRM) - # DRM required libraries INCLUDE_PATHS += -I/usr/include/libdrm endif -ifeq ($(PLATFORM),PLATFORM_DESKTOP) - ifeq ($(PLATFORM_OS),BSD) - # Consider -L$(RAYLIB_H_INSTALL_PATH) - INCLUDE_PATHS += -I/usr/local/include - endif - ifeq ($(PLATFORM_OS),LINUX) - INCLUDE_PATHS += -I$(RAYLIB_H_INSTALL_PATH) - endif -endif -# Define library paths containing required libs. +# Define library paths containing required libs: LDFLAGS +#------------------------------------------------------------------------------------------------ LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) - # resource file contains windows executable icon and properties + # NOTE: The resource .rc file contains windows executable icon and properties LDFLAGS += $(RAYLIB_PATH)/src/raylib.rc.data # -Wl,--subsystem,windows hides the console window ifeq ($(BUILD_MODE), RELEASE) LDFLAGS += -Wl,--subsystem,windows endif endif - ifeq ($(PLATFORM_OS),BSD) - # Consider -L$(RAYLIB_INSTALL_PATH) - LDFLAGS += -Lsrc -L/usr/local/lib - endif ifeq ($(PLATFORM_OS),LINUX) - # Reset everything. - # Precedence: immediately local, installed version, raysan5 provided libs - LDFLAGS += -L$(RAYLIB_INSTALL_PATH) + LDFLAGS += -L$(RAYLIB_LIB_PATH) + endif + ifeq ($(PLATFORM_OS),BSD) + LDFLAGS += -Lsrc -L$(RAYLIB_LIB_PATH) endif endif ifeq ($(PLATFORM),PLATFORM_WEB) @@ -322,8 +298,9 @@ ifeq ($(PLATFORM),PLATFORM_RPI) LDFLAGS += -L$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/lib endif -# Define any libraries required on linking -# if you want to link libraries (libname.so or libname.a), use the -lname +# Define libraries required on linking: LDLIBS +# NOTE: To link libraries (lib.so or lib.a), use -l +#------------------------------------------------------------------------------------------------ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) # Libraries for Windows desktop compilation @@ -387,7 +364,8 @@ ifeq ($(PLATFORM),PLATFORM_WEB) LDLIBS = $(RAYLIB_RELEASE_PATH)/libraylib.a endif -# Define all object files required +# Define source code object files required +#------------------------------------------------------------------------------------------------ CORE = \ core/core_basic_window \ core/core_basic_screen_manager \ @@ -433,7 +411,7 @@ SHAPES = \ shapes/shapes_easings_rectangle_array \ shapes/shapes_draw_ring \ shapes/shapes_draw_circle_sector \ - shapes/shapes_draw_rectangle_rounded + shapes/shapes_top_down_lights TEXTURES = \ textures/textures_logo_raylib \ @@ -526,6 +504,8 @@ PHYSICS = \ CURRENT_MAKEFILE = $(lastword $(MAKEFILE_LIST)) +# Define processes to execute +#------------------------------------------------------------------------------------------------ # Default target entry all: $(CORE) $(SHAPES) $(TEXT) $(TEXTURES) $(MODELS) $(SHADERS) $(AUDIO) $(PHYSICS) diff --git a/examples/audio/audio_raw_stream.c b/examples/audio/audio_raw_stream.c index c9ec7a9df..9b2d10227 100644 --- a/examples/audio/audio_raw_stream.c +++ b/examples/audio/audio_raw_stream.c @@ -77,6 +77,9 @@ int main(void) { float fp = (float)(mousePosition.y); frequency = 40.0f + (float)(fp); + + float pan = (float)(mousePosition.x) / (float)screenWidth; + SetAudioStreamPan(stream, pan); } // Rewrite the sine wave. @@ -137,7 +140,7 @@ int main(void) ClearBackground(RAYWHITE); DrawText(TextFormat("sine frequency: %i",(int)frequency), GetScreenWidth() - 220, 10, 20, RED); - DrawText("click mouse button to change frequency", 10, 10, 20, DARKGRAY); + DrawText("click mouse button to change frequency or pan", 10, 10, 20, DARKGRAY); // Draw the current buffer state proportionate to the screen for (int i = 0; i < screenWidth; i++) diff --git a/examples/shaders/shaders_spotlight.c b/examples/shaders/shaders_spotlight.c index bdc2a0aaf..e0a9ac5b9 100644 --- a/examples/shaders/shaders_spotlight.c +++ b/examples/shaders/shaders_spotlight.c @@ -12,7 +12,7 @@ * ******************************************************************************************** * -* The shader makes alpha holes in the forground to give the apearance of a top +* The shader makes alpha holes in the forground to give the appearance of a top * down look at a spotlight casting a pool of light... * * The right hand side of the screen there is just enough light to see whats diff --git a/examples/shapes/shapes_top_down_lights.c b/examples/shapes/shapes_top_down_lights.c new file mode 100644 index 000000000..5234c28c0 --- /dev/null +++ b/examples/shapes/shapes_top_down_lights.c @@ -0,0 +1,350 @@ +/******************************************************************************************* +* +* raylib [shapes] example - top down lights +* +* This example has been created using raylib 4.0 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5) +* +* Copyright (c) 2022 Jeffery Myers (@JeffM2501) +* +********************************************************************************************/ + +#include "raylib.h" +#include "raymath.h" +#include "rlgl.h" + +// Custom Blend Modes +#define RLGL_SRC_ALPHA 0x0302 +#define RLGL_MIN 0x8007 +#define RLGL_MAX 0x8008 + +#define MAX_BOXES 20 +#define MAX_SHADOWS MAX_BOXES*3 // MAX_BOXES *3. Each box can cast up to two shadow volumes for the edges it is away from, and one for the box itself +#define MAX_LIGHTS 16 + +// Shadow geometry type +typedef struct ShadowGeometry { + Vector2 vertices[4]; +} ShadowGeometry; + +// Light info type +typedef struct LightInfo { + bool active; // Is this light slot active? + bool dirty; // Does this light need to be updated? + bool valid; // Is this light in a valid position? + + Vector2 position; // Light position + RenderTexture mask; // Alpha mask for the light + float outerRadius; // The distance the light touches + Rectangle bounds; // A cached rectangle of the light bounds to help with culling + + ShadowGeometry shadows[MAX_SHADOWS]; + int shadowCount; +} LightInfo; + + +LightInfo lights[MAX_LIGHTS] = { 0 }; + +// Move a light and mark it as dirty so that we update it's mask next frame +void MoveLight(int slot, float x, float y) +{ + lights[slot].dirty = true; + lights[slot].position.x = x; + lights[slot].position.y = y; + + // update the cached bounds + lights[slot].bounds.x = x - lights[slot].outerRadius; + lights[slot].bounds.y = y - lights[slot].outerRadius; +} + +// Compute a shadow volume for the edge +// It takes the edge and projects it back by the light radius and turns it into a quad +void ComputeShadowVolumeForEdge(int slot, Vector2 sp, Vector2 ep) +{ + if (lights[slot].shadowCount >= MAX_SHADOWS) return; + + float extension = lights[slot].outerRadius*2; + + Vector2 spVector = Vector2Normalize(Vector2Subtract(sp, lights[slot].position)); + Vector2 spProjection = Vector2Add(sp, Vector2Scale(spVector, extension)); + + Vector2 epVector = Vector2Normalize(Vector2Subtract(ep, lights[slot].position)); + Vector2 epProjection = Vector2Add(ep, Vector2Scale(epVector, extension)); + + lights[slot].shadows[lights[slot].shadowCount].vertices[0] = sp; + lights[slot].shadows[lights[slot].shadowCount].vertices[1] = ep; + lights[slot].shadows[lights[slot].shadowCount].vertices[2] = epProjection; + lights[slot].shadows[lights[slot].shadowCount].vertices[3] = spProjection; + + lights[slot].shadowCount++; +} + +// Draw the light and shadows to the mask for a light +void DrawLightMask(int slot) +{ + // Use the light mask + BeginTextureMode(lights[slot].mask); + + ClearBackground(WHITE); + + // Force the blend mode to only set the alpha of the destination + rlSetBlendFactors(RLGL_SRC_ALPHA, RLGL_SRC_ALPHA, RLGL_MIN); + rlSetBlendMode(BLEND_CUSTOM); + + // If we are valid, then draw the light radius to the alpha mask + if (lights[slot].valid) DrawCircleGradient((int)lights[slot].position.x, (int)lights[slot].position.y, lights[slot].outerRadius, ColorAlpha(WHITE, 0), WHITE); + + rlDrawRenderBatchActive(); + + // Cut out the shadows from the light radius by forcing the alpha to maximum + rlSetBlendMode(BLEND_ALPHA); + rlSetBlendFactors(RLGL_SRC_ALPHA, RLGL_SRC_ALPHA, RLGL_MAX); + rlSetBlendMode(BLEND_CUSTOM); + + // Draw the shadows to the alpha mask + for (int i = 0; i < lights[slot].shadowCount; i++) + { + DrawTriangleFan(lights[slot].shadows[i].vertices, 4, WHITE); + } + + rlDrawRenderBatchActive(); + + // Go back to normal blend mode + rlSetBlendMode(BLEND_ALPHA); + + EndTextureMode(); +} + +// Setup a light +void SetupLight(int slot, float x, float y, float radius) +{ + lights[slot].active = true; + lights[slot].valid = false; // The light must prove it is valid + lights[slot].mask = LoadRenderTexture(GetScreenWidth(), GetScreenHeight()); + lights[slot].outerRadius = radius; + + lights[slot].bounds.width = radius * 2; + lights[slot].bounds.height = radius * 2; + + MoveLight(slot, x, y); + + // Force the render texture to have something in it + DrawLightMask(slot); +} + +// See if a light needs to update it's mask +bool UpdateLight(int slot, Rectangle* boxes, int count) +{ + if (!lights[slot].active || !lights[slot].dirty) return false; + + lights[slot].dirty = false; + lights[slot].shadowCount = 0; + lights[slot].valid = false; + + for (int i = 0; i < count; i++) + { + // Are we in a box? if so we are not valid + if (CheckCollisionPointRec(lights[slot].position, boxes[i])) return false; + + // If this box is outside our bounds, we can skip it + if (!CheckCollisionRecs(lights[slot].bounds, boxes[i])) continue; + + // Check the edges that are on the same side we are, and cast shadow volumes out from them + + // Top + Vector2 sp = (Vector2){ boxes[i].x, boxes[i].y }; + Vector2 ep = (Vector2){ boxes[i].x + boxes[i].width, boxes[i].y }; + + if (lights[slot].position.y > ep.y) ComputeShadowVolumeForEdge(slot, sp, ep); + + // Right + sp = ep; + ep.y += boxes[i].height; + if (lights[slot].position.x < ep.x) ComputeShadowVolumeForEdge(slot, sp, ep); + + // Bottom + sp = ep; + ep.x -= boxes[i].width; + if (lights[slot].position.y < ep.y) ComputeShadowVolumeForEdge(slot, sp, ep); + + // Left + sp = ep; + ep.y -= boxes[i].height; + if (lights[slot].position.x > ep.x) ComputeShadowVolumeForEdge(slot, sp, ep); + + // The box itself + lights[slot].shadows[lights[slot].shadowCount].vertices[0] = (Vector2){ boxes[i].x, boxes[i].y }; + lights[slot].shadows[lights[slot].shadowCount].vertices[1] = (Vector2){ boxes[i].x, boxes[i].y + boxes[i].height }; + lights[slot].shadows[lights[slot].shadowCount].vertices[2] = (Vector2){ boxes[i].x + boxes[i].width, boxes[i].y + boxes[i].height }; + lights[slot].shadows[lights[slot].shadowCount].vertices[3] = (Vector2){ boxes[i].x + boxes[i].width, boxes[i].y }; + lights[slot].shadowCount++; + } + + lights[slot].valid = true; + + DrawLightMask(slot); + + return true; +} + +// Set up some boxes +void SetupBoxes(Rectangle *boxes, int *count) +{ + boxes[0] = (Rectangle){ 150,80, 40, 40 }; + boxes[1] = (Rectangle){ 1200, 700, 40, 40 }; + boxes[2] = (Rectangle){ 200, 600, 40, 40 }; + boxes[3] = (Rectangle){ 1000, 50, 40, 40 }; + boxes[4] = (Rectangle){ 500, 350, 40, 40 }; + + for (int i = 5; i < MAX_BOXES; i++) + { + boxes[i] = (Rectangle){(float)GetRandomValue(0,GetScreenWidth()), (float)GetRandomValue(0,GetScreenHeight()), (float)GetRandomValue(10,100), (float)GetRandomValue(10,100) }; + } + + *count = MAX_BOXES; +} + +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - top down lights"); + + // Initialize our 'world' of boxes + int boxCount = 0; + Rectangle boxes[MAX_BOXES] = { 0 }; + SetupBoxes(boxes, &boxCount); + + // Create a checkerboard ground texture + Image img = GenImageChecked(64, 64, 32, 32, DARKBROWN, DARKGRAY); + Texture2D backgroundTexture = LoadTextureFromImage(img); + UnloadImage(img); + + // Create a global light mask to hold all the blended lights + RenderTexture lightMask = LoadRenderTexture(GetScreenWidth(), GetScreenHeight()); + + // Setup initial light + SetupLight(0, 600, 400, 300); + int nextLight = 1; + + bool showLines = false; + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + // Drag light 0 + if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) MoveLight(0, GetMousePosition().x, GetMousePosition().y); + + // Make a new light + if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) && (nextLight < MAX_LIGHTS)) + { + SetupLight(nextLight, GetMousePosition().x, GetMousePosition().y, 200); + nextLight++; + } + + // Toggle debug info + if (IsKeyPressed(KEY_F1)) showLines = !showLines; + + // Update the lights and keep track if any were dirty so we know if we need to update the master light mask + bool dirtyLights = false; + for (int i = 0; i < MAX_LIGHTS; i++) + { + if (UpdateLight(i, boxes, boxCount)) dirtyLights = true; + } + + // Update the light mask + if (dirtyLights) + { + // Build up the light mask + BeginTextureMode(lightMask); + + ClearBackground(BLACK); + + // Force the blend mode to only set the alpha of the destination + rlSetBlendFactors(RLGL_SRC_ALPHA, RLGL_SRC_ALPHA, RLGL_MIN); + rlSetBlendMode(BLEND_CUSTOM); + + // Merge in all the light masks + for (int i = 0; i < MAX_LIGHTS; i++) + { + if (lights[i].active) DrawTextureRec(lights[i].mask.texture, (Rectangle){ 0, 0, (float)GetScreenWidth(), -(float)GetScreenHeight() }, Vector2Zero(), WHITE); + } + + rlDrawRenderBatchActive(); + + // Go back to normal blend + rlSetBlendMode(BLEND_ALPHA); + EndTextureMode(); + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(BLACK); + + // Draw the tile background + DrawTextureRec(backgroundTexture, (Rectangle){ 0, 0, (float)GetScreenWidth(), (float)GetScreenHeight() }, Vector2Zero(), WHITE); + + // Overlay the shadows from all the lights + DrawTextureRec(lightMask.texture, (Rectangle){ 0, 0, (float)GetScreenWidth(), -(float)GetScreenHeight() }, Vector2Zero(), ColorAlpha(WHITE, showLines? 0.75f : 1.0f)); + + // Draw the lights + for (int i = 0; i < MAX_LIGHTS; i++) + { + if (lights[i].active) DrawCircle((int)lights[i].position.x, (int)lights[i].position.y, 10, (i == 0)? YELLOW : WHITE); + } + + if (showLines) + { + for (int s = 0; s < lights[0].shadowCount; s++) + { + DrawTriangleFan(lights[0].shadows[s].vertices, 4, DARKPURPLE); + } + + for (int b = 0; b < boxCount; b++) + { + if (CheckCollisionRecs(boxes[b],lights[0].bounds)) DrawRectangleRec(boxes[b], PURPLE); + + DrawRectangleLines((int)boxes[b].x, (int)boxes[b].y, (int)boxes[b].width, (int)boxes[b].height, DARKBLUE); + } + + DrawText("(F1) Hide Shadow Volumes", 10, 50, 10, GREEN); + } + else + { + DrawText("(F1) Show Shadow Volumes", 10, 50, 10, GREEN); + } + + DrawFPS(screenWidth - 80, 10); + DrawText("Drag to move light #1", 10, 10, 10, DARKGREEN); + DrawText("Right click to add new light", 10, 30, 10, DARKGREEN); + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadTexture(backgroundTexture); + UnloadRenderTexture(lightMask); + for (int i = 0; i < MAX_LIGHTS; i++) + { + if (lights[i].active) UnloadRenderTexture(lights[i].mask); + } + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/shapes/shapes_top_down_lights.png b/examples/shapes/shapes_top_down_lights.png new file mode 100644 index 000000000..e14bb5494 Binary files /dev/null and b/examples/shapes/shapes_top_down_lights.png differ diff --git a/projects/CMake/CMakeLists.txt b/projects/CMake/CMakeLists.txt index 0876f0d55..580ecfed2 100644 --- a/projects/CMake/CMakeLists.txt +++ b/projects/CMake/CMakeLists.txt @@ -1,44 +1,38 @@ cmake_minimum_required(VERSION 3.11) # FetchContent is available in 3.11+ project(example) -# Set this to the minimal version you want to support -find_package(raylib 3.0 QUIET) # Let CMake search for a raylib-config.cmake - -# You could change the QUIET above to REQUIRED and remove this if() clause -# This part downloads raylib and builds it if it's not installed on your system +# Dependencies +find_package(raylib 4.0.0 QUIET) # QUIET or REQUIRED if (NOT raylib_FOUND) # If there's none, fetch and build raylib include(FetchContent) - FetchContent_Declare( raylib - URL https://github.com/raysan5/raylib/archive/master.tar.gz + URL https://github.com/raysan5/raylib/archive/refs/tags/4.0.0.tar.gz ) - FetchContent_GetProperties(raylib) if (NOT raylib_POPULATED) # Have we downloaded raylib yet? set(FETCHCONTENT_QUIET NO) FetchContent_Populate(raylib) - set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) # don't build the supplied examples - - # build raylib add_subdirectory(${raylib_SOURCE_DIR} ${raylib_BINARY_DIR}) - endif() - endif() -# This is the main part: +# Our Project add_executable(${PROJECT_NAME} core_basic_window.c) #set(raylib_VERBOSE 1) target_link_libraries(${PROJECT_NAME} raylib) +# Web Configurations +if (${PLATFORM} STREQUAL "Web") + # Tell Emscripten to build an example.html file. + set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".html") +endif() + # Checks if OSX and links appropriate frameworks (Only required on MacOS) if (APPLE) target_link_libraries(${PROJECT_NAME} "-framework IOKit") target_link_libraries(${PROJECT_NAME} "-framework Cocoa") target_link_libraries(${PROJECT_NAME} "-framework OpenGL") -endif() - -# That's it! You should have an example executable that you can run. Have fun! +endif() \ No newline at end of file diff --git a/projects/CMake/README.md b/projects/CMake/README.md new file mode 100644 index 000000000..402d3170c --- /dev/null +++ b/projects/CMake/README.md @@ -0,0 +1,29 @@ +# raylib CMake Project + +This provides a base project template which builds with [CMake](https://cmake.org). + +## Usage + +To compile the example, use one of the following dependending on your build target... + +### Desktop + +Use the following to build for desktop: + +``` bash +mkdir build +cd build +cmake .. +make +``` + +### Web + +Compiling for the web requires the [Emscripten SDK](https://emscripten.org/docs/getting_started/downloads.html): + +``` bash +mkdir build +cd build +emcmake cmake .. -DPLATFORM=Web -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXE_LINKER_FLAGS="-s USE_GLFW=3" -DCMAKE_EXECUTABLE_SUFFIX=".html" +emmake make +``` \ No newline at end of file diff --git a/projects/CMake/core_basic_window.c b/projects/CMake/core_basic_window.c index 176f46c91..4357ae598 100644 --- a/projects/CMake/core_basic_window.c +++ b/projects/CMake/core_basic_window.c @@ -1,57 +1,56 @@ /******************************************************************************************* * -* raylib [core] example - Basic window +* raylib [core] example - Basic window (adapted for HTML5 platform) * -* Welcome to raylib! +* This example is prepared to compile for PLATFORM_WEB, PLATFORM_DESKTOP and PLATFORM_RPI +* As you will notice, code structure is slightly diferent to the other examples... +* To compile it for PLATFORM_WEB just uncomment #define PLATFORM_WEB at beginning * -* To test examples, just press F6 and execute raylib_compile_execute script -* Note that compiled executable is placed in the same folder as .c file -* -* You can find all basic examples on C:\raylib\raylib\examples folder or -* raylib official webpage: www.raylib.com -* -* Enjoy using raylib. :) -* -* This example has been created using raylib 1.0 (www.raylib.com) +* This example has been created using raylib 1.3 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2013-2016 Ramon Santamaria (@raysan5) +* Copyright (c) 2015 Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +int screenWidth = 800; +int screenHeight = 450; + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +void UpdateDrawFrame(void); // Update and Draw one frame + +//---------------------------------------------------------------------------------- +// Main Enry Point +//---------------------------------------------------------------------------------- int main() { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); - SetTargetFPS(60); +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key { - // Update - //---------------------------------------------------------------------------------- - // TODO: Update your variables here - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); - - EndDrawing(); - //---------------------------------------------------------------------------------- + UpdateDrawFrame(); } +#endif // De-Initialization //-------------------------------------------------------------------------------------- @@ -60,3 +59,25 @@ int main() return 0; } + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +void UpdateDrawFrame(void) +{ + // Update + //---------------------------------------------------------------------------------- + // TODO: Update your variables here + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/projects/README.md b/projects/README.md index acf8ec743..af24f1547 100644 --- a/projects/README.md +++ b/projects/README.md @@ -6,7 +6,7 @@ IDE | Platform(s) | Source | Example(s) ----| ------------| :-------: | :-----: [4coder](http://4coder.net/) | Windows | ❌ | ✔️ [Builder](https://wiki.gnome.org/Apps/Builder) | Linux | ❌ | ✔️ -[CMake](https://cmake.org/) | Windows, Linux, macOS | ✔️ | ✔️ +[CMake](https://cmake.org/) | Windows, Linux, macOS, Web | ✔️ | ✔️ [CodeBlocks](http://www.codeblocks.org/) | Windows, Linux, macOS | ❌ | ✔️ [Geany](https://www.geany.org/) | Windows, Linux | ✔️ | ✔️ [Notepad++](https://notepad-plus-plus.org/) | Windows | ✔️ | ✔️ diff --git a/projects/VS2019/examples/shapes_top_down_lights.vcxproj b/projects/VS2019/examples/shapes_top_down_lights.vcxproj new file mode 100644 index 000000000..65f4ea896 --- /dev/null +++ b/projects/VS2019/examples/shapes_top_down_lights.vcxproj @@ -0,0 +1,387 @@ + + + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + Win32 + + + Release + x64 + + + + {67A9CF3B-A5E8-442E-A437-ED74A08CA312} + Win32Proj + shapes_top_down_lights + 10.0 + shapes_top_down_lights + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\effects + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\effects + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\effects + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\effects + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\effects + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\effects + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\effects + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\effects + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file diff --git a/projects/VS2019/raylib.sln b/projects/VS2019/raylib.sln index aa92a456c..82f5fff21 100644 --- a/projects/VS2019/raylib.sln +++ b/projects/VS2019/raylib.sln @@ -199,6 +199,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_easings_box_anim", " EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_easings_rectangle_array", "examples\shapes_easings_rectangle_array.vcxproj", "{1EDD4BCF-345C-4065-8CBD-7285224293C3}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "top_down_lights", "examples\shapes_top_down_lights.vcxproj", "{67A9CF3B-A5E8-442E-A437-ED74A08CA312}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "physics_demo", "examples\physics_demo.vcxproj", "{581F89BD-FBB9-4699-B8DB-EB38E6DEE097}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "physics_friction", "examples\physics_friction.vcxproj", "{A6260ED4-5361-4B61-B6B9-8D8119457BA4}" @@ -1675,6 +1677,22 @@ Global {1EDD4BCF-345C-4065-8CBD-7285224293C3}.Release|x64.Build.0 = Release|x64 {1EDD4BCF-345C-4065-8CBD-7285224293C3}.Release|x86.ActiveCfg = Release|Win32 {1EDD4BCF-345C-4065-8CBD-7285224293C3}.Release|x86.Build.0 = Release|Win32 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Debug|x64.ActiveCfg = Debug|x64 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Debug|x64.Build.0 = Debug|x64 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Debug|x86.ActiveCfg = Debug|Win32 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Debug|x86.Build.0 = Debug|Win32 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Release|x64.ActiveCfg = Release|x64 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Release|x64.Build.0 = Release|x64 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Release|x86.ActiveCfg = Release|Win32 + {67A9CF3B-A5E8-442E-A437-ED74A08CA312}.Release|x86.Build.0 = Release|Win32 {581F89BD-FBB9-4699-B8DB-EB38E6DEE097}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 {581F89BD-FBB9-4699-B8DB-EB38E6DEE097}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 {581F89BD-FBB9-4699-B8DB-EB38E6DEE097}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 @@ -2238,6 +2256,7 @@ Global {1C49E35A-2838-49D9-9D5F-4B8134960EF6} = {278D8859-20B1-428F-8448-064F46E1F021} {F91142E2-A999-47F0-9E74-38C1E2930EBE} = {278D8859-20B1-428F-8448-064F46E1F021} {1EDD4BCF-345C-4065-8CBD-7285224293C3} = {278D8859-20B1-428F-8448-064F46E1F021} + {67A9CF3B-A5E8-442E-A437-ED74A08CA312} = {278D8859-20B1-428F-8448-064F46E1F021} {581F89BD-FBB9-4699-B8DB-EB38E6DEE097} = {D6B669E2-68D0-4E62-83D1-E14DDD6A356F} {A6260ED4-5361-4B61-B6B9-8D8119457BA4} = {D6B669E2-68D0-4E62-83D1-E14DDD6A356F} {29817904-E3D3-4C28-BD8D-A3A09DD199D2} = {D6B669E2-68D0-4E62-83D1-E14DDD6A356F} diff --git a/projects/VSCode/Makefile b/projects/VSCode/Makefile index d89a80ffe..9907c036d 100644 --- a/projects/VSCode/Makefile +++ b/projects/VSCode/Makefile @@ -117,13 +117,12 @@ endif ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables - EMSDK_PATH ?= C:/emsdk - EMSCRIPTEN_VERSION ?= 1.38.31 - CLANG_VERSION = e$(EMSCRIPTEN_VERSION)_64bit - PYTHON_VERSION = 2.7.13.1_64bit\python-2.7.13.amd64 - NODE_VERSION = 8.9.1_64bit - export PATH = $(EMSDK_PATH);$(EMSDK_PATH)\clang\$(CLANG_VERSION);$(EMSDK_PATH)\node\$(NODE_VERSION)\bin;$(EMSDK_PATH)\python\$(PYTHON_VERSION);$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION);C:\raylib\MinGW\bin:$$(PATH) - EMSCRIPTEN = $(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION) + EMSDK_PATH ?= C:/emsdk + EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten + CLANG_PATH = $(EMSDK_PATH)/upstream/bin + PYTHON_PATH = $(EMSDK_PATH)/python/3.9.2-1_64bit + NODE_PATH = $(EMSDK_PATH)/node/14.18.2_64bit/bin + export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH):$$(PATH) endif # Define raylib release directory for compiled library. @@ -344,7 +343,7 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif ifeq ($(PLATFORM),PLATFORM_WEB) # Libraries for web (HTML5) compiling - LDLIBS = $(RAYLIB_RELEASE_PATH)/libraylib.bc + LDLIBS = $(RAYLIB_RELEASE_PATH)/libraylib.a endif # Define a recursive wildcard function diff --git a/projects/VSCode/main.c b/projects/VSCode/main.c index 835b4b08f..2d7b121f9 100644 --- a/projects/VSCode/main.c +++ b/projects/VSCode/main.c @@ -15,12 +15,30 @@ * This example has been created using raylib 1.0 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2013-2020 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Local Variables Definition (local to this module) +//---------------------------------------------------------------------------------- +Camera camera = { 0 }; +Vector3 cubePosition = { 0 }; + +//---------------------------------------------------------------------------------- +// Local Functions Declaration +//---------------------------------------------------------------------------------- +static void UpdateDrawFrame(void); // Update and draw one frame + +//---------------------------------------------------------------------------------- +// Main entry point +//---------------------------------------------------------------------------------- int main() { // Initialization @@ -30,7 +48,6 @@ int main() InitWindow(screenWidth, screenHeight, "raylib"); - Camera camera = { 0 }; camera.position = (Vector3){ 10.0f, 10.0f, 8.0f }; camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; @@ -39,45 +56,55 @@ int main() SetCameraMode(camera, CAMERA_ORBITAL); - Vector3 cubePosition = { 0 }; + //-------------------------------------------------------------------------------------- +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 60, 1); +#else SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key { - // Update - //---------------------------------------------------------------------------------- - UpdateCamera(&camera); - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - BeginMode3D(camera); - - DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); - DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON); - DrawGrid(10, 1.0f); - - EndMode3D(); - - DrawText("This is a raylib example", 10, 40, 20, DARKGRAY); - - DrawFPS(10, 10); - - EndDrawing(); - //---------------------------------------------------------------------------------- + UpdateDrawFrame(); } +#endif // De-Initialization //-------------------------------------------------------------------------------------- - CloseWindow(); // Close window and OpenGL context + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; +} + +// Update and draw game frame +static void UpdateDrawFrame(void) +{ + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); + DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON); + DrawGrid(10, 1.0f); + + EndMode3D(); + + DrawText("This is a raylib example", 10, 40, 20, DARKGRAY); + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- } \ No newline at end of file diff --git a/projects/VSCode/resources/LICENSE b/projects/VSCode/resources/LICENSE new file mode 100644 index 000000000..ebde2c573 --- /dev/null +++ b/projects/VSCode/resources/LICENSE @@ -0,0 +1 @@ +Assets license. diff --git a/src/Makefile b/src/Makefile index 4ecad6f8b..ddac896cb 100644 --- a/src/Makefile +++ b/src/Makefile @@ -15,33 +15,35 @@ # Many thanks to Milan Nikolic (@gen2brain) for implementing Android platform pipeline. # Many thanks to Emanuele Petriglia for his contribution on GNU/Linux pipeline. # -# Copyright (c) 2014-2022 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2022 Ramon Santamaria (@raysan5) # -# This software is provided "as-is", without any express or implied warranty. -# In no event will the authors be held liable for any damages arising from -# the use of this software. +# This software is provided "as-is", without any express or implied warranty. In no event +# will the authors be held liable for any damages arising from the use of this software. # -# Permission is granted to anyone to use this software for any purpose, -# including commercial applications, and to alter it and redistribute it -# freely, subject to the following restrictions: +# Permission is granted to anyone to use this software for any purpose, including commercial +# applications, and to alter it and redistribute it freely, subject to the following restrictions: # -# 1. The origin of this software must not be misrepresented; you must not -# claim that you wrote the original software. If you use this software in a -# product, an acknowledgment in the product documentation would be -# appreciated but is not required. +# 1. The origin of this software must not be misrepresented; you must not claim that you +# wrote the original software. If you use this software in a product, an acknowledgment +# in the product documentation would be appreciated but is not required. # -# 2. Altered source versions must be plainly marked as such, and must not -# be misrepresented as being the original software. +# 2. Altered source versions must be plainly marked as such, and must not be misrepresented +# as being the original software. # -# 3. This notice may not be removed or altered from any source distribution. +# 3. This notice may not be removed or altered from any source distribution. # -#****************************************************************************** +#************************************************************************************************** -# Please read the wiki to know how to compile raylib, because there are different methods. +# NOTE: Highly recommended to read the raylib Wiki to know how to compile raylib for different platforms # https://github.com/raysan5/raylib/wiki .PHONY: all clean install uninstall +# Define required environment variables +#------------------------------------------------------------------------------------------------ +# Define target platform: PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_DRM, PLATFORM_ANDROID, PLATFORM_WEB +PLATFORM ?= PLATFORM_DESKTOP + # Define required raylib variables RAYLIB_VERSION = 4.0.0 RAYLIB_API_VERSION = 400 @@ -70,10 +72,6 @@ RAYLIB_RES_FILE ?= ./raylib.dll.rc.data # if NONE, default config.h flags are used RAYLIB_CONFIG_FLAGS ?= NONE -# Define raylib platform -# Options: PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB -PLATFORM ?= PLATFORM_DESKTOP - # To define additional cflags: Use make CUSTOM_CFLAGS="" # Include raylib modules on compilation @@ -87,11 +85,11 @@ RAYLIB_MODULE_RAYGUI_PATH ?= $(RAYLIB_SRC_PATH)/extras RAYLIB_MODULE_PHYSAC_PATH ?= $(RAYLIB_SRC_PATH)/extras # Use external GLFW library instead of rglfw module -USE_EXTERNAL_GLFW ?= FALSE +USE_EXTERNAL_GLFW ?= FALSE -# Use Wayland display server protocol on Linux desktop -# by default it uses X11 windowing system -USE_WAYLAND_DISPLAY ?= FALSE +# Use Wayland display server protocol on Linux desktop (by default it uses X11 windowing system) +# NOTE: This variable is only used for PLATFORM_OS: LINUX +USE_WAYLAND_DISPLAY ?= FALSE # Use cross-compiler for PLATFORM_RPI ifeq ($(PLATFORM),PLATFORM_RPI) @@ -102,9 +100,8 @@ ifeq ($(PLATFORM),PLATFORM_RPI) endif endif -# Determine if the file has root access (only for installing raylib) -# "whoami" prints the name of the user that calls him (so, if it is the root -# user, "whoami" prints "root"). +# Determine if the file has root access (only required to install raylib) +# "whoami" prints the name of the user that calls him (so, if it is the root user, "whoami" prints "root") ROOT = $(shell whoami) # By default we suppose we are working on Windows @@ -220,7 +217,8 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID) GRAPHICS = GRAPHICS_API_OPENGL_ES2 endif -# Define default C compiler and archiver to pack library +# Define default C compiler and archiver to pack library: CC, AR +#------------------------------------------------------------------------------------------------ CC = gcc AR = ar @@ -266,7 +264,8 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID) AR = $(ANDROID_TOOLCHAIN)/bin/llvm-ar endif -# Define compiler flags: +# Define compiler flags: CFLAGS +#------------------------------------------------------------------------------------------------ # -O1 defines optimization level # -g include debug information on compilation # -s strip unnecessary data from build @@ -274,6 +273,7 @@ endif # -std=c99 defines C language mode (standard C from 1999 revision) # -std=gnu99 defines C language mode (GNU C from 1999 revision) # -Wno-missing-braces ignore invalid warning (GCC bug 53119) +# -Wno-unused-value ignore unused return values of some functions (i.e. fread()) # -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 # -fno-strict-aliasing jar_xm.h does shady stuff (breaks strict aliasing) @@ -377,8 +377,9 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) endif endif -# Define include paths for required headers +# Define include paths for required headers: INCLUDE_PATHS # NOTE: Several external required libraries (stb and others) +#------------------------------------------------------------------------------------------------ INCLUDE_PATHS = -I. -Iexternal/glfw/include -Iexternal/glfw/deps/mingw # Define additional directories containing required header files @@ -388,13 +389,11 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) endif endif ifeq ($(PLATFORM),PLATFORM_RPI) - # RPI required libraries INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include/interface/vmcs_host/linux INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include/interface/vcos/pthreads endif ifeq ($(PLATFORM),PLATFORM_DRM) - # DRM required libraries INCLUDE_PATHS += -I/usr/include/libdrm endif ifeq ($(PLATFORM),PLATFORM_ANDROID) @@ -418,7 +417,9 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID) endif endif -# Define linker flags (required for dynamic library generation) +# Define library paths containing required libs: LDFLAGS +# NOTE: This is only required for dynamic library generation +#------------------------------------------------------------------------------------------------ LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) ifeq ($(PLATFORM),PLATFORM_DESKTOP) @@ -452,7 +453,9 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID) LDFLAGS += -Wl,-undefined,dynamic_lookup endif -# Define linker libraries (required for dynamic library generation) +# Define libraries required on linking: LDLIBS +# NOTE: This is only required for dynamic library generation +#------------------------------------------------------------------------------------------------ ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) LDLIBS = -static-libgcc -lopengl32 -lgdi32 -lwinmm @@ -485,13 +488,8 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID) LDLIBS = -llog -landroid -lEGL -lGLESv2 -lOpenSLES -lc -lm endif -# Define all object files required with a wildcard -# The wildcard takes all files that finish with ".c", -# and replaces extentions with ".o", that are the object files -# NOTE: Some objects depend on the PLATFORM to be added or not! -# OBJS = $(patsubst %.c, %.o, $(wildcard *.c)) - -# Define object required on compilation +# Define source code object files required +#------------------------------------------------------------------------------------------------ OBJS = rcore.o \ rshapes.o \ rtextures.o \ @@ -520,6 +518,8 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID) OBJS += android_native_app_glue.o endif +# Define processes to execute +#------------------------------------------------------------------------------------------------ # Default target entry all: raylib diff --git a/src/build.zig b/src/build.zig index 76d4a6611..915d33a83 100644 --- a/src/build.zig +++ b/src/build.zig @@ -1,5 +1,77 @@ const std = @import("std"); +pub fn Pkg(srcdir: []const u8) type { + return struct { + pub fn addRaylib(b: *std.build.Builder, target: std.zig.CrossTarget) *std.build.LibExeObjStep { + // Standard release options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. + const mode = b.standardReleaseOptions(); + + const raylib_flags = &[_][]const u8{ + "-std=gnu99", + "-DPLATFORM_DESKTOP", + "-DGL_SILENCE_DEPRECATION=199309L", + "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/1891 + }; + + const raylib = b.addStaticLibrary("raylib", srcdir ++ "/raylib.h"); + raylib.setTarget(target); + raylib.setBuildMode(mode); + raylib.linkLibC(); + + raylib.addIncludeDir(srcdir ++ "/external/glfw/include"); + + raylib.addCSourceFiles(&.{ + srcdir ++ "/raudio.c", + srcdir ++ "/rcore.c", + srcdir ++ "/rmodels.c", + srcdir ++ "/rshapes.c", + srcdir ++ "/rtext.c", + srcdir ++ "/rtextures.c", + srcdir ++ "/utils.c", + }, raylib_flags); + + switch (raylib.target.toTarget().os.tag) { + .windows => { + raylib.addCSourceFiles(&.{srcdir ++ "/rglfw.c"}, raylib_flags); + raylib.linkSystemLibrary("winmm"); + raylib.linkSystemLibrary("gdi32"); + raylib.linkSystemLibrary("opengl32"); + raylib.addIncludeDir("external/glfw/deps/mingw"); + }, + .linux => { + raylib.addCSourceFiles(&.{srcdir ++ "/rglfw.c"}, raylib_flags); + raylib.linkSystemLibrary("GL"); + raylib.linkSystemLibrary("rt"); + raylib.linkSystemLibrary("dl"); + raylib.linkSystemLibrary("m"); + raylib.linkSystemLibrary("X11"); + }, + .macos => { + // On macos rglfw.c include Objective-C files. + const raylib_flags_extra_macos = &[_][]const u8{ + "-ObjC", + }; + raylib.addCSourceFiles( + &.{srcdir ++ "/rglfw.c"}, + raylib_flags ++ raylib_flags_extra_macos, + ); + raylib.linkFramework("Foundation"); + }, + else => { + @panic("Unsupported OS"); + }, + } + + raylib.setOutputDir("./"); + raylib.install(); + return raylib; + } + }; +} + +const lib = Pkg("."); + pub fn build(b: *std.build.Builder) void { // Standard target options allows the person running `zig build` to choose // what target to build for. Here we do not override the defaults, which @@ -7,66 +79,5 @@ pub fn build(b: *std.build.Builder) void { // for restricting supported target set are available. const target = b.standardTargetOptions(.{}); - // Standard release options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const mode = b.standardReleaseOptions(); - - const raylib_flags = &[_][]const u8{ - "-std=gnu99", - "-DPLATFORM_DESKTOP", - "-DGL_SILENCE_DEPRECATION", - "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/1891 - }; - - const raylib = b.addStaticLibrary("raylib", "raylib.h"); - raylib.setTarget(target); - raylib.setBuildMode(mode); - raylib.linkLibC(); - - raylib.addIncludeDir("external/glfw/include"); - - raylib.addCSourceFiles(&.{ - "raudio.c", - "rcore.c", - "rmodels.c", - "rshapes.c", - "rtext.c", - "rtextures.c", - "utils.c", - }, raylib_flags); - - switch (raylib.target.toTarget().os.tag) { - .windows => { - raylib.addCSourceFiles(&.{"rglfw.c"}, raylib_flags); - raylib.linkSystemLibrary("winmm"); - raylib.linkSystemLibrary("gdi32"); - raylib.linkSystemLibrary("opengl32"); - raylib.addIncludeDir("external/glfw/deps/mingw"); - }, - .linux => { - raylib.addCSourceFiles(&.{"rglfw.c"}, raylib_flags); - raylib.linkSystemLibrary("GL"); - raylib.linkSystemLibrary("rt"); - raylib.linkSystemLibrary("dl"); - raylib.linkSystemLibrary("m"); - raylib.linkSystemLibrary("X11"); - }, - .macos => { - // On macos rglfw.c include Objective-C files. - const raylib_flags_extra_macos = &[_][]const u8{ - "-ObjC", - }; - raylib.addCSourceFiles( - &.{"rglfw.c"}, - raylib_flags ++ raylib_flags_extra_macos, - ); - raylib.linkFramework("Foundation"); - }, - else => { - @panic("Unsupported OS"); - }, - } - - raylib.setOutputDir("./"); - raylib.install(); + _ = lib.addRaylib(b, target); } diff --git a/src/external/cgltf.h b/src/external/cgltf.h index 565003801..796eb86c1 100644 --- a/src/external/cgltf.h +++ b/src/external/cgltf.h @@ -948,7 +948,11 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m fseek(file, 0, SEEK_END); #ifdef _WIN32 - __int64 length = _ftelli64(file); + #ifdef __TINYC__ + __int64 length = ftell(file); + #else + __int64 length = _ftelli64(file); + #endif #else long length = ftell(file); #endif diff --git a/src/external/qoi.h b/src/external/qoi.h index 5e31076bf..988f9edcb 100644 --- a/src/external/qoi.h +++ b/src/external/qoi.h @@ -28,8 +28,8 @@ SOFTWARE. -- About -QOI encodes and decodes images in a lossless format. Compared to stb_image and -stb_image_write QOI offers 20x-50x faster encoding, 3x-4x faster decoding and +QOI encodes and decodes images in a lossless format. Compared to stb_image and +stb_image_write QOI offers 20x-50x faster encoding, 3x-4x faster decoding and 20% better compression. @@ -45,7 +45,7 @@ stb_image_write QOI offers 20x-50x faster encoding, 3x-4x faster decoding and // the input pixel data. qoi_write("image_new.qoi", rgba_pixels, &(qoi_desc){ .width = 1920, - .height = 1080, + .height = 1080, .channels = 4, .colorspace = QOI_SRGB }); @@ -74,7 +74,7 @@ QOI_NO_STDIO before including this library. This library uses malloc() and free(). To supply your own malloc implementation you can define QOI_MALLOC and QOI_FREE before including this library. -This library uses memset() to zero-initialize the index. To supply your own +This library uses memset() to zero-initialize the index. To supply your own implementation you can define QOI_ZEROARR before including this library. @@ -91,9 +91,9 @@ struct qoi_header_t { uint8_t colorspace; // 0 = sRGB with linear alpha, 1 = all channels linear }; -Images are encoded from top to bottom, left to right. The decoder and encoder -start with {r: 0, g: 0, b: 0, a: 255} as the previous pixel value. An image is -complete when all pixels specified by width * height have been covered. +Images are encoded row by row, left to right, top to bottom. The decoder and +encoder start with {r: 0, g: 0, b: 0, a: 255} as the previous pixel value. An +image is complete when all pixels specified by width * height have been covered. Pixels are encoded as - a run of the previous pixel @@ -101,20 +101,20 @@ Pixels are encoded as - a difference to the previous pixel value in r,g,b - full r,g,b or r,g,b,a values -The color channels are assumed to not be premultiplied with the alpha channel +The color channels are assumed to not be premultiplied with the alpha channel ("un-premultiplied alpha"). -A running array[64] (zero-initialized) of previously seen pixel values is +A running array[64] (zero-initialized) of previously seen pixel values is maintained by the encoder and decoder. Each pixel that is seen by the encoder and decoder is put into this array at the position formed by a hash function of the color value. In the encoder, if the pixel value at the index matches the -current pixel, this index position is written to the stream as QOI_OP_INDEX. +current pixel, this index position is written to the stream as QOI_OP_INDEX. The hash function for the index is: index_position = (r * 3 + g * 5 + b * 7 + a * 11) % 64 -Each chunk starts with a 2- or 8-bit tag, followed by a number of data bits. The -bit length of chunks is divisible by 8 - i.e. all chunks are byte aligned. All +Each chunk starts with a 2- or 8-bit tag, followed by a number of data bits. The +bit length of chunks is divisible by 8 - i.e. all chunks are byte aligned. All values encoded in these data bits have the most significant bit on the left. The 8-bit tags have precedence over the 2-bit tags. A decoder must check for the @@ -135,11 +135,11 @@ The possible chunks are: 2-bit tag b00 6-bit index into the color index array: 0..63 -A valid encoder must not issue 7 or more consecutive QOI_OP_INDEX chunks to the -index 0, to avoid confusion with the 8 byte end marker. +A valid encoder must not issue 2 or more consecutive QOI_OP_INDEX chunks to the +same index. QOI_OP_RUN should be used instead. -.- QOI_OP_DIFF -----------. +.- QOI_OP_DIFF -----------. | Byte[0] | | 7 6 5 4 3 2 1 0 | |-------+-----+-----+-----| @@ -150,14 +150,16 @@ index 0, to avoid confusion with the 8 byte end marker. 2-bit green channel difference from the previous pixel between -2..1 2-bit blue channel difference from the previous pixel between -2..1 -The difference to the current channel values are using a wraparound operation, +The difference to the current channel values are using a wraparound operation, so "1 - 2" will result in 255, while "255 + 1" will result in 0. -Values are stored as unsigned integers with a bias of 2. E.g. -2 is stored as +Values are stored as unsigned integers with a bias of 2. E.g. -2 is stored as 0 (b00). 1 is stored as 3 (b11). +The alpha value remains unchanged from the previous pixel. -.- QOI_OP_LUMA -------------------------------------. + +.- QOI_OP_LUMA -------------------------------------. | Byte[0] | Byte[1] | | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | |-------+-----------------+-------------+-----------| @@ -168,18 +170,20 @@ Values are stored as unsigned integers with a bias of 2. E.g. -2 is stored as 4-bit red channel difference minus green channel difference -8..7 4-bit blue channel difference minus green channel difference -8..7 -The green channel is used to indicate the general direction of change and is +The green channel is used to indicate the general direction of change and is encoded in 6 bits. The red and blue channels (dr and db) base their diffs off of the green channel difference and are encoded in 4 bits. I.e.: - dr_dg = (last_px.r - cur_px.r) - (last_px.g - cur_px.g) - db_dg = (last_px.b - cur_px.b) - (last_px.g - cur_px.g) + dr_dg = (cur_px.r - prev_px.r) - (cur_px.g - prev_px.g) + db_dg = (cur_px.b - prev_px.b) - (cur_px.g - prev_px.g) -The difference to the current channel values are using a wraparound operation, +The difference to the current channel values are using a wraparound operation, so "10 - 13" will result in 253, while "250 + 7" will result in 1. -Values are stored as unsigned integers with a bias of 32 for the green channel +Values are stored as unsigned integers with a bias of 32 for the green channel and a bias of 8 for the red and blue channel. +The alpha value remains unchanged from the previous pixel. + .- QOI_OP_RUN ------------. | Byte[0] | @@ -190,8 +194,8 @@ and a bias of 8 for the red and blue channel. 2-bit tag b11 6-bit run-length repeating the previous pixel: 1..62 -The run-length is stored with a bias of -1. Note that the run-lengths 63 and 64 -(b111110 and b111111) are illegal as they are occupied by the QOI_OP_RGB and +The run-length is stored with a bias of -1. Note that the run-lengths 63 and 64 +(b111110 and b111111) are illegal as they are occupied by the QOI_OP_RGB and QOI_OP_RGBA tags. @@ -206,6 +210,8 @@ QOI_OP_RGBA tags. 8-bit green channel value 8-bit blue channel value +The alpha value remains unchanged from the previous pixel. + .- QOI_OP_RGBA ---------------------------------------------------. | Byte[0] | Byte[1] | Byte[2] | Byte[3] | Byte[4] | @@ -232,17 +238,17 @@ Header - Public functions */ extern "C" { #endif -/* A pointer to a qoi_desc struct has to be supplied to all of qoi's functions. -It describes either the input format (for qoi_write and qoi_encode), or is +/* A pointer to a qoi_desc struct has to be supplied to all of qoi's functions. +It describes either the input format (for qoi_write and qoi_encode), or is filled with the description read from the file header (for qoi_read and qoi_decode). -The colorspace in this qoi_desc is an enum where +The colorspace in this qoi_desc is an enum where 0 = sRGB, i.e. gamma scaled RGB channels and a linear alpha channel 1 = all channels are linear -You may use the constants QOI_SRGB or QOI_LINEAR. The colorspace is purely +You may use the constants QOI_SRGB or QOI_LINEAR. The colorspace is purely informative. It will be saved to the file header, but does not affect -en-/decoding in any way. */ +how chunks are en-/decoded. */ #define QOI_SRGB 0 #define QOI_LINEAR 1 @@ -256,11 +262,11 @@ typedef struct { #ifndef QOI_NO_STDIO -/* Encode raw RGB or RGBA pixels into a QOI image and write it to the file -system. The qoi_desc struct must be filled with the image width, height, -number of channels (3 = RGB, 4 = RGBA) and the colorspace. +/* Encode raw RGB or RGBA pixels into a QOI image and write it to the file +system. The qoi_desc struct must be filled with the image width, height, +number of channels (3 = RGB, 4 = RGBA) and the colorspace. -The function returns 0 on failure (invalid parameters, or fopen or malloc +The function returns 0 on failure (invalid parameters, or fopen or malloc failed) or the number of bytes written on success. */ int qoi_write(const char *filename, const void *data, const qoi_desc *desc); @@ -271,7 +277,7 @@ number of channels from the file header is used. If channels is 3 or 4 the output format will be forced into this number of channels. The function either returns NULL on failure (invalid data, or malloc or fopen -failed) or a pointer to the decoded pixels. On success, the qoi_desc struct +failed) or a pointer to the decoded pixels. On success, the qoi_desc struct will be filled with the description from the file header. The returned pixel data should be free()d after use. */ @@ -283,8 +289,8 @@ void *qoi_read(const char *filename, qoi_desc *desc, int channels); /* Encode raw RGB or RGBA pixels into a QOI image in memory. -The function either returns NULL on failure (invalid parameters or malloc -failed) or a pointer to the encoded data on success. On success the out_len +The function either returns NULL on failure (invalid parameters or malloc +failed) or a pointer to the encoded data on success. On success the out_len is set to the size in bytes of the encoded data. The returned qoi data should be free()d after use. */ @@ -294,8 +300,8 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len); /* Decode a QOI image from memory. -The function either returns NULL on failure (invalid parameters or malloc -failed) or a pointer to the decoded pixels. On success, the qoi_desc struct +The function either returns NULL on failure (invalid parameters or malloc +failed) or a pointer to the decoded pixels. On success, the qoi_desc struct is filled with the description from the file header. The returned pixel data should be free()d after use. */ @@ -340,8 +346,8 @@ Implementation */ #define QOI_HEADER_SIZE 14 /* 2GB is the max file size that this implementation can safely handle. We guard -against anything larger than that, assuming the worst case with 5 bytes per -pixel, rounded down to a nice clean value. 400 million pixels ought to be +against anything larger than that, assuming the worst case with 5 bytes per +pixel, rounded down to a nice clean value. 400 million pixels ought to be enough for anybody. */ #define QOI_PIXELS_MAX ((unsigned int)400000000) @@ -352,14 +358,14 @@ typedef union { static const unsigned char qoi_padding[8] = {0,0,0,0,0,0,0,1}; -void qoi_write_32(unsigned char *bytes, int *p, unsigned int v) { +static void qoi_write_32(unsigned char *bytes, int *p, unsigned int v) { bytes[(*p)++] = (0xff000000 & v) >> 24; bytes[(*p)++] = (0x00ff0000 & v) >> 16; bytes[(*p)++] = (0x0000ff00 & v) >> 8; bytes[(*p)++] = (0x000000ff & v); } -unsigned int qoi_read_32(const unsigned char *bytes, int *p) { +static unsigned int qoi_read_32(const unsigned char *bytes, int *p) { unsigned int a = bytes[(*p)++]; unsigned int b = bytes[(*p)++]; unsigned int c = bytes[(*p)++]; @@ -385,8 +391,8 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) { return NULL; } - max_size = - desc->width * desc->height * (desc->channels + 1) + + max_size = + desc->width * desc->height * (desc->channels + 1) + QOI_HEADER_SIZE + sizeof(qoi_padding); p = 0; @@ -412,7 +418,7 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) { px_prev.rgba.b = 0; px_prev.rgba.a = 255; px = px_prev; - + px_len = desc->width * desc->height * desc->channels; px_end = px_len - desc->channels; channels = desc->channels; @@ -460,14 +466,14 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) { if ( vr > -3 && vr < 2 && - vg > -3 && vg < 2 && + vg > -3 && vg < 2 && vb > -3 && vb < 2 ) { bytes[p++] = QOI_OP_DIFF | (vr + 2) << 4 | (vg + 2) << 2 | (vb + 2); } else if ( - vg_r > -9 && vg_r < 8 && - vg > -33 && vg < 32 && + vg_r > -9 && vg_r < 8 && + vg > -33 && vg < 32 && vg_b > -9 && vg_b < 8 ) { bytes[p++] = QOI_OP_LUMA | (vg + 32); @@ -526,7 +532,7 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) { desc->colorspace = bytes[p++]; if ( - desc->width == 0 || desc->height == 0 || + desc->width == 0 || desc->height == 0 || desc->channels < 3 || desc->channels > 4 || desc->colorspace > 1 || header_magic != QOI_MAGIC || @@ -592,7 +598,7 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) { index[QOI_COLOR_HASH(px) % 64] = px; } - if (channels == 4) { + if (channels == 4) { *(qoi_rgba_t*)(pixels + px_pos) = px; } else { @@ -621,11 +627,11 @@ int qoi_write(const char *filename, const void *data, const qoi_desc *desc) { if (!encoded) { fclose(f); return 0; - } - + } + fwrite(encoded, 1, size, f); fclose(f); - + QOI_FREE(encoded); return size; } diff --git a/src/extras/physac.h b/src/extras/physac.h index aadc76988..3ab427acd 100644 --- a/src/extras/physac.h +++ b/src/extras/physac.h @@ -5,7 +5,7 @@ * DESCRIPTION: * * Physac is a small 2D physics engine written in pure C. The engine uses a fixed time-step thread loop -* to simluate physics. A physics step contains the following phases: get collision information, +* to simulate physics. A physics step contains the following phases: get collision information, * apply dynamics, collision solving and position correction. It uses a very simple struct for physic * bodies with a position vector to be used in any 3D rendering API. * diff --git a/src/minshell.html b/src/minshell.html new file mode 100644 index 000000000..c34637f99 --- /dev/null +++ b/src/minshell.html @@ -0,0 +1,82 @@ + + + + + + + raylib web game + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + {{{ SCRIPT }}} + + diff --git a/src/raudio.c b/src/raudio.c index 67510dc22..5abb1d05c 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -317,6 +317,7 @@ struct rAudioBuffer { float volume; // Audio buffer volume float pitch; // Audio buffer pitch + float pan; // Audio buffer pan (0.0f to 1.0f) bool playing; // Audio buffer state: AUDIO_PLAYING bool paused; // Audio buffer state: AUDIO_PAUSED @@ -373,7 +374,7 @@ static AudioData AUDIO = { // Global AUDIO context //---------------------------------------------------------------------------------- static void OnLog(ma_context *pContext, ma_device *pDevice, ma_uint32 logLevel, const char *message); static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const void *pFramesInput, ma_uint32 frameCount); -static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, float localVolume); +static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, AudioBuffer *buffer); #if defined(RAUDIO_STANDALONE) static bool IsFileExtension(const char *fileName, const char *ext); // Check file extension @@ -398,6 +399,7 @@ void PauseAudioBuffer(AudioBuffer *buffer); void ResumeAudioBuffer(AudioBuffer *buffer); void SetAudioBufferVolume(AudioBuffer *buffer, float volume); void SetAudioBufferPitch(AudioBuffer *buffer, float pitch); +void SetAudioBufferPan(AudioBuffer *buffer, float pan); void TrackAudioBuffer(AudioBuffer *buffer); void UntrackAudioBuffer(AudioBuffer *buffer); @@ -553,6 +555,8 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam // Init audio buffer values audioBuffer->volume = 1.0f; audioBuffer->pitch = 1.0f; + audioBuffer->pan = 0.5f; + audioBuffer->playing = false; audioBuffer->paused = false; audioBuffer->looping = false; @@ -657,6 +661,15 @@ void SetAudioBufferPitch(AudioBuffer *buffer, float pitch) } } +// Set pan for an audio buffer +void SetAudioBufferPan(AudioBuffer *buffer, float pan) +{ + if (pan < 0.0f) pan = 0.0f; + else if (pan > 1.0f) pan = 1.0f; + + if (buffer != NULL) buffer->pan = pan; +} + // Track audio buffer to linked list next position void TrackAudioBuffer(AudioBuffer *buffer) { @@ -1048,6 +1061,8 @@ void PlaySoundMulti(Sound sound) SetAudioBufferVolume(AUDIO.MultiChannel.pool[index], sound.stream.buffer->volume); SetAudioBufferPitch(AUDIO.MultiChannel.pool[index], sound.stream.buffer->pitch); + SetAudioBufferPan(AUDIO.MultiChannel.pool[index], sound.stream.buffer->pan); + AUDIO.MultiChannel.pool[index]->looping = sound.stream.buffer->looping; AUDIO.MultiChannel.pool[index]->usage = sound.stream.buffer->usage; AUDIO.MultiChannel.pool[index]->isSubBufferProcessed[0] = false; @@ -1113,6 +1128,12 @@ void SetSoundPitch(Sound sound, float pitch) SetAudioBufferPitch(sound.stream.buffer, pitch); } +// Set pan for a sound +void SetSoundPan(Sound sound, float pan) +{ + SetAudioBufferPan(sound.stream.buffer, pan); +} + // Convert wave data to desired format void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) { @@ -1809,6 +1830,12 @@ void SetMusicPitch(Music music, float pitch) SetAudioBufferPitch(music.stream.buffer, pitch); } +// Set pan for a music +void SetMusicPan(Music music, float pan) +{ + SetAudioBufferPan(music.stream.buffer, pan); +} + // Get music time length (in seconds) float GetMusicTimeLength(Music music) { @@ -1989,6 +2016,12 @@ void SetAudioStreamPitch(AudioStream stream, float pitch) SetAudioBufferPitch(stream.buffer, pitch); } +// Set pan for audio stream +void SetAudioStreamPan(AudioStream stream, float pan) +{ + SetAudioBufferPan(stream.buffer, pan); +} + // Default size for new audio streams void SetAudioStreamBufferSizeDefault(int size) { @@ -2184,7 +2217,7 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const float *framesOut = (float *)pFramesOut + (framesRead*AUDIO.System.device.playback.channels); float *framesIn = tempBuffer; - MixAudioFrames(framesOut, framesIn, framesJustRead, audioBuffer->volume); + MixAudioFrames(framesOut, framesIn, framesJustRead, audioBuffer); framesToRead -= framesJustRead; framesRead += framesJustRead; @@ -2226,16 +2259,40 @@ static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const // 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, ma_uint32 frameCount, float localVolume) +static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, AudioBuffer *buffer) { - for (ma_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) - { - for (ma_uint32 iChannel = 0; iChannel < AUDIO.System.device.playback.channels; ++iChannel) - { - float *frameOut = framesOut + (iFrame*AUDIO.System.device.playback.channels); - const float *frameIn = framesIn + (iFrame*AUDIO.System.device.playback.channels); + const float localVolume = buffer->volume; - frameOut[iChannel] += (frameIn[iChannel]*localVolume); + const ma_uint32 nChannels = AUDIO.System.device.playback.channels; + if (nChannels == 2) + { + const float left = buffer->pan; + const float right = 1.0f - left; + + // fast sine approximation in [0..1] for pan law: y = 0.5f * x * (3 - x * x); + const float levels[2] = { localVolume*0.5f*left*(3.0f-left*left), localVolume*0.5f*right*(3.0f-right*right) }; + + float *frameOut = framesOut; + const float *frameIn = framesIn; + for (ma_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) + { + frameOut[0] += (frameIn[0]*levels[0]); + frameOut[1] += (frameIn[1]*levels[1]); + frameOut += 2; + frameIn += 2; + } + } + else // pan is kinda meaningless + { + for (ma_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) + { + for (ma_uint32 iChannel = 0; iChannel < nChannels; ++iChannel) + { + float *frameOut = framesOut + (iFrame * nChannels); + const float *frameIn = framesIn + (iFrame * nChannels); + + frameOut[iChannel] += (frameIn[iChannel] * localVolume); + } } } } diff --git a/src/raudio.h b/src/raudio.h index dbcfbd699..35c850bd3 100644 --- a/src/raudio.h +++ b/src/raudio.h @@ -155,6 +155,7 @@ int GetSoundsPlaying(void); // Get number of bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) +void SetSoundPan(Sound sound, float pan); // Set pan for a sound (0.0 to 1.0, 0.5=center) void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format Wave WaveCopy(Wave wave); // Copy a wave to a new wave void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range @@ -173,6 +174,7 @@ void PauseMusicStream(Music music); // Pause music p void ResumeMusicStream(Music music); // Resume playing paused music void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds) void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) +void SetMusicPan(Music sound, float pan); // Set pan for a music (0.0 to 1.0, 0.5=center) void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) float GetMusicTimeLength(Music music); // Get music time length (in seconds) float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) @@ -189,6 +191,7 @@ bool IsAudioStreamPlaying(AudioStream stream); // Check if audi void StopAudioStream(AudioStream stream); // Stop audio stream void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) +void SetAudioStreamPan(AudioStream strean, float pan); // Set pan for audio stream (0.0 to 1.0, 0.5=center) void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams #ifdef __cplusplus diff --git a/src/raylib.h b/src/raylib.h index 3805ba349..70384e281 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -839,7 +839,7 @@ typedef enum { BLEND_MULTIPLIED, // Blend textures multiplying colors BLEND_ADD_COLORS, // Blend textures adding colors (alternative) BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative) - BLEND_CUSTOM // Belnd textures using custom src/dst factors (use rlSetBlendMode()) + BLEND_CUSTOM // Blend textures using custom src/dst factors (use rlSetBlendMode()) } BlendMode; // Gesture @@ -1041,12 +1041,14 @@ RLAPI bool SaveFileText(const char *fileName, char *text); // Save text d RLAPI bool FileExists(const char *fileName); // Check if file exists RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists RLAPI bool IsFileExtension(const char *fileName, const char *ext); // Check file extension (including point: .png, .wav) +RLAPI int GetFileLength(const char *fileName); // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h) RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png') RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string) RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string) RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string) RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) +RLAPI const char *GetApplicationDirectory(void); // Get the directory if the running application (uses static string) RLAPI char **GetDirectoryFiles(const char *dirPath, int *count); // Get filenames in a directory path (memory should be freed) RLAPI void ClearDirectoryFiles(void); // Clear directory files paths buffers (free memory) RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success @@ -1335,6 +1337,7 @@ RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color co RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters RLAPI void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); // Draw text using Font and pro parameters (rotation) RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint) +RLAPI void DrawTextCodepoints(Font font, int *codepoints, int count, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple character (codepoint) // Text font info functions RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font @@ -1498,10 +1501,11 @@ RLAPI int GetSoundsPlaying(void); // Get num RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) -RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format +RLAPI void SetSoundPan(Sound sound, float pan); // Set pan for a sound (0.5 is center) RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave RLAPI void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range -RLAPI float *LoadWaveSamples(Wave wave); // Load samples data from wave as a floats array +RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format +RLAPI float *LoadWaveSamples(Wave wave); // Load samples data from wave as a 32bit float data array RLAPI void UnloadWaveSamples(float *samples); // Unload samples data loaded with LoadWaveSamples() // Music management functions @@ -1517,6 +1521,7 @@ RLAPI void ResumeMusicStream(Music music); // Resume RLAPI void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds) RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) +RLAPI void SetMusicPan(Music music, float pan); // Set pan for a music (0.5 is center) RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds) RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) @@ -1532,6 +1537,7 @@ RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check i RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) +RLAPI void SetAudioStreamPan(AudioStream stream, float pan); // Set pan for audio stream (0.5 is centered) RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams #if defined(__cplusplus) diff --git a/src/raymath.h b/src/raymath.h index 9b86b2936..51dc2abc1 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -282,7 +282,7 @@ RMAPI float Vector2Distance(Vector2 v1, Vector2 v2) RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) { float result = atan2f(v2.y, v2.x) - atan2f(v1.y, v1.x); - + return result; } @@ -334,6 +334,21 @@ RMAPI Vector2 Vector2Normalize(Vector2 v) return result; } +// Transforms a Vector2 by a given Matrix +RMAPI Vector2 Vector2Transform(Vector2 v, Matrix mat) +{ + Vector2 result = { 0 }; + + float x = v.x; + float y = v.y; + float z = 0; + + result.x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12; + result.y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13; + + return result; +} + // Calculate linear interpolation between two vectors RMAPI Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount) { @@ -534,12 +549,12 @@ RMAPI float Vector3Distance(Vector3 v1, Vector3 v2) RMAPI float Vector3Angle(Vector3 v1, Vector3 v2) { float result = 0.0f; - + Vector3 cross = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x }; float len = sqrtf(cross.x*cross.x + cross.y*cross.y + cross.z*cross.z); float dot = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); result = atan2f(len, dot); - + return result; } @@ -1475,8 +1490,7 @@ RMAPI Quaternion QuaternionInvert(Quaternion q) { Quaternion result = q; - float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); - float lengthSq = length*length; + float lengthSq = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w; if (lengthSq != 0.0) { diff --git a/src/rcore.c b/src/rcore.c index 7752a7cc8..f0652d3bb 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -160,6 +160,23 @@ #define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without gnu ext. #endif +// Platform specific defines to handle GetApplicationDirectory() +#if defined (PLATFORM_DESKTOP) + #if defined(_WIN32) + #ifndef MAX_PATH + #define MAX_PATH 1025 + #endif + __declspec(dllimport) unsigned long __stdcall GetModuleFileNameA(void *hModule, void *lpFilename, unsigned long nSize); + __declspec(dllimport) unsigned long __stdcall GetModuleFileNameW(void *hModule, void *lpFilename, unsigned long nSize); + __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, void *widestr, int cchwide, void *str, int cbmb, void *defchar, int *used_default); + #elif defined(__linux__) + #include + #elif defined(__APPLE__) + #include + #include + #endif // OSs +#endif // PLATFORM_DESKTOP + #include // Required for: srand(), rand(), atexit() #include // Required for: sprintf() [Used in OpenURL()] #include // Required for: strrchr(), strcmp(), strlen() @@ -2834,6 +2851,24 @@ bool DirectoryExists(const char *dirPath) return result; } +// Get file length in bytes +// NOTE: GetFileSize() conflicts with windows.h +int GetFileLength(const char *fileName) +{ + int size = 0; + + FILE *file = fopen(fileName, "rb"); + + if (file != NULL) + { + fseek(file, 0L, SEEK_END); + size = (int)ftell(file); + fclose(file); + } + + return size; +} + // Get pointer to extension for a filename string (includes the dot: .png) const char *GetFileExtension(const char *fileName) { @@ -2969,6 +3004,82 @@ const char *GetWorkingDirectory(void) return path; } +const char *GetApplicationDirectory(void) +{ + static char appDir[MAX_FILEPATH_LENGTH] = { 0 }; + memset(appDir, 0, MAX_FILEPATH_LENGTH); + +#if defined(_WIN32) + int len = 0; +#if defined (UNICODE) + unsigned short widePath[MAX_PATH]; + len = GetModuleFileNameW(NULL, widePath, MAX_PATH); + len = WideCharToMultiByte(0, 0, widePath, len, appDir, MAX_PATH, NULL, NULL); +#else + len = GetModuleFileNameA(NULL, appDir, MAX_PATH); +#endif + if (len > 0) + { + for (int i = len; i >= 0; --i) + { + if (appDir[i] == '\\') + { + appDir[i + 1] = '\0'; + break; + } + } + } + else + { + appDir[0] = '.'; + appDir[1] = '\\'; + } + +#elif defined(__linux__) + unsigned int size = sizeof(appDir); + ssize_t len = readlink("/proc/self/exe", appDir, size); + + if (len > 0) + { + for (int i = len; i >= 0; --i) + { + if (appDir[i] == '/') + { + appDir[i + 1] = '\0'; + break; + } + } + } + else + { + appDir[0] = '.'; + appDir[1] = '/'; + } +#elif defined(__APPLE__) + uint32_t size = sizeof(appDir); + + if (_NSGetExecutablePath(appDir, &size) == 0) + { + int len = strlen(appDir); + for (int i = len; i >= 0; --i) + { + if (appDir[i] == '/') + { + appDir[i + 1] = '\0'; + break; + } + } + } + else + { + appDir[0] = '.'; + appDir[1] = '/'; + } +#endif + + return appDir; +} + // Get filenames in a directory path // NOTE: Files count is returned by parameters pointer char **GetDirectoryFiles(const char *dirPath, int *fileCount) @@ -3142,7 +3253,7 @@ char *EncodeDataBase64(const unsigned char *data, int dataLength, int *outputLen encodedData[j++] = base64encodeTable[(triple >> 0*6) & 0x3F]; } - for (int i = 0; i < modTable[dataLength%3]; i++) encodedData[*outputLength - 1 - i] = '='; + for (int i = 0; i < modTable[dataLength%3]; i++) encodedData[*outputLength - 1 - i] = '='; // Padding character return encodedData; } diff --git a/src/rlgl.h b/src/rlgl.h index fc5857b83..fa096ca6b 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1778,7 +1778,11 @@ void rlSetBlendMode(int mode) case RL_BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); break; case RL_BLEND_ADD_COLORS: glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); break; case RL_BLEND_SUBTRACT_COLORS: glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_SUBTRACT); break; - case RL_BLEND_CUSTOM: glBlendFunc(RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor); glBlendEquation(RLGL.State.glBlendEquation); break; + case RL_BLEND_CUSTOM: + { + // NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactors() + glBlendFunc(RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor); glBlendEquation(RLGL.State.glBlendEquation); + } break; default: break; } @@ -3541,56 +3545,69 @@ unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode) unsigned int id = 0; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - unsigned int vertexShaderId = RLGL.State.defaultVShaderId; - unsigned int fragmentShaderId = RLGL.State.defaultFShaderId; + unsigned int vertexShaderId = 0; + unsigned int fragmentShaderId = 0; + // Compile vertex shader (if provided) if (vsCode != NULL) vertexShaderId = rlCompileShader(vsCode, GL_VERTEX_SHADER); - if (fsCode != NULL) fragmentShaderId = rlCompileShader(fsCode, GL_FRAGMENT_SHADER); + // In case no vertex shader was provided or compilation failed, we use default vertex shader + if (vertexShaderId == 0) vertexShaderId = RLGL.State.defaultVShaderId; + // Compile fragment shader (if provided) + if (fsCode != NULL) fragmentShaderId = rlCompileShader(fsCode, GL_FRAGMENT_SHADER); + // In case no fragment shader was provided or compilation failed, we use default fragment shader + if (fragmentShaderId == 0) fragmentShaderId = RLGL.State.defaultFShaderId; + + // In case vertex and fragment shader are the default ones, no need to recompile, we can just assign the default shader program id if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) id = RLGL.State.defaultShaderId; else { + // One of or both shader are new, we need to compile a new shader program id = rlLoadShaderProgram(vertexShaderId, fragmentShaderId); + // We can detach and delete vertex/fragment shaders (if not default ones) + // NOTE: We detach shader before deletion to make sure memory is freed if (vertexShaderId != RLGL.State.defaultVShaderId) { - // Detach shader before deletion to make sure memory is freed glDetachShader(id, vertexShaderId); glDeleteShader(vertexShaderId); } if (fragmentShaderId != RLGL.State.defaultFShaderId) { - // Detach shader before deletion to make sure memory is freed glDetachShader(id, fragmentShaderId); glDeleteShader(fragmentShaderId); } + // In case shader program loading failed, we assign default shader if (id == 0) { - TRACELOG(RL_LOG_WARNING, "SHADER: Failed to load custom shader code"); + // In case shader loading fails, we return the default shader + TRACELOG(RL_LOG_WARNING, "SHADER: Failed to load custom shader code, using default shader"); id = RLGL.State.defaultShaderId; } - } + /* + else + { + // Get available shader uniforms + // NOTE: This information is useful for debug... + int uniformCount = -1; + glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount); - // Get available shader uniforms - // NOTE: This information is useful for debug... - int uniformCount = -1; + for (int i = 0; i < uniformCount; i++) + { + int namelen = -1; + int num = -1; + char name[256] = { 0 }; // Assume no variable names longer than 256 + GLenum type = GL_ZERO; - glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount); + // Get the name of the uniforms + glGetActiveUniform(id, i, sizeof(name) - 1, &namelen, &num, &type, name); - for (int i = 0; i < uniformCount; i++) - { - int namelen = -1; - int num = -1; - char name[256] = { 0 }; // Assume no variable names longer than 256 - GLenum type = GL_ZERO; - - // Get the name of the uniforms - glGetActiveUniform(id, i, sizeof(name) - 1, &namelen, &num, &type, name); - - name[namelen] = 0; - - TRACELOGD("SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name)); + name[namelen] = 0; + TRACELOGD("SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name)); + } + } + */ } #endif @@ -4338,7 +4355,8 @@ static void rlLoadShaderDefault(void) "} \n"; #endif - // NOTE: Compiled vertex/fragment shaders are kept for re-use + // NOTE: Compiled vertex/fragment shaders are not deleted, + // they are kept for re-use as default shaders in case some shader loading fails RLGL.State.defaultVShaderId = rlCompileShader(defaultVShaderCode, GL_VERTEX_SHADER); // Compile default vertex shader RLGL.State.defaultFShaderId = rlCompileShader(defaultFShaderCode, GL_FRAGMENT_SHADER); // Compile default fragment shader diff --git a/src/rmodels.c b/src/rmodels.c index 22559e34f..601ce234d 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -4692,13 +4692,12 @@ static Model LoadGLTF(const char *fileName) model.materials[j].maps[MATERIAL_MAP_ALBEDO].texture = LoadTextureFromImage(imAlbedo); UnloadImage(imAlbedo); } - - // Load base color factor (tint) - model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255); - model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255); - model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255); - model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255); } + // Load base color factor (tint) + model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255); + model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255); + model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255); + model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255); // Load metallic/roughness texture if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture) diff --git a/src/rtext.c b/src/rtext.c index 523712a37..f07b8804a 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1091,6 +1091,38 @@ void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSiz DrawTexturePro(font.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint); } +// Draw multiple character (codepoints) +void DrawTextCodepoints(Font font, int *codepoints, int count, Vector2 position, float fontSize, float spacing, Color tint) +{ + int textOffsetY = 0; // Offset between lines (on line break '\n') + float textOffsetX = 0.0f; // Offset X to next character to draw + + float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor + + for (int i = 0; i < count; i++) + { + int index = GetGlyphIndex(font, codepoints[i]); + + if (codepoints[i] == '\n') + { + // NOTE: Fixed line spacing of 1.5 line-height + // TODO: Support custom line spacing defined by user + textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); + textOffsetX = 0.0f; + } + else + { + if ((codepoints[i] != ' ') && (codepoints[i] != '\t')) + { + DrawTextCodepoint(font, codepoints[i], (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint); + } + + if (font.glyphs[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing); + else textOffsetX += ((float)font.glyphs[index].advanceX*scaleFactor + spacing); + } + } +} + // Measure string width for default font int MeasureText(const char *text, int fontSize) { diff --git a/src/rtextures.c b/src/rtextures.c index a7f4323b2..12732274f 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -500,7 +500,8 @@ bool ExportImage(Image image, const char *fileName) else if (IsFileExtension(fileName, ".tga")) success = stbi_write_tga(fileName, image.width, image.height, channels, imgData); #endif #if defined(SUPPORT_FILEFORMAT_JPG) - else if (IsFileExtension(fileName, ".jpg")) success = stbi_write_jpg(fileName, image.width, image.height, channels, imgData, 90); // JPG quality: between 1 and 100 + else if (IsFileExtension(fileName, ".jpg") || + IsFileExtension(fileName, ".jpeg")) success = stbi_write_jpg(fileName, image.width, image.height, channels, imgData, 90); // JPG quality: between 1 and 100 #endif #if defined(SUPPORT_FILEFORMAT_QOI) else if (IsFileExtension(fileName, ".qoi")) @@ -4324,6 +4325,7 @@ static Image LoadPKM(const unsigned char *fileData, unsigned int fileSize) #if defined(SUPPORT_FILEFORMAT_KTX) // Load KTX compressed image data (ETC1/ETC2 compression) +// TODO: Review KTX loading, many things changed! static Image LoadKTX(const unsigned char *fileData, unsigned int fileSize) { unsigned char *fileDataPtr = (unsigned char *)fileData; @@ -4398,6 +4400,8 @@ static Image LoadKTX(const unsigned char *fileData, unsigned int fileSize) if (ktxHeader->glInternalFormat == 0x8D64) image.format = PIXELFORMAT_COMPRESSED_ETC1_RGB; else if (ktxHeader->glInternalFormat == 0x9274) image.format = PIXELFORMAT_COMPRESSED_ETC2_RGB; else if (ktxHeader->glInternalFormat == 0x9278) image.format = PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA; + + // TODO: Support uncompressed data formats? Right now it returns format = 0! } } @@ -4406,11 +4410,12 @@ static Image LoadKTX(const unsigned char *fileData, unsigned int fileSize) // Save image data as KTX file // NOTE: By default KTX 1.1 spec is used, 2.0 is still on draft (01Oct2018) +// TODO: Review KTX saving, many things changed! static int SaveKTX(Image image, const char *fileName) { // KTX file Header (64 bytes) // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ - // v2.0 - http://github.khronos.org/KTX-Specification/ - still on draft, not ready for implementation + // v2.0 - http://github.khronos.org/KTX-Specification/ - Final specs by 2021-04-18 typedef struct { char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" // KTX 2.0: "«KTX 22»\r\n\x1A\n" unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04 diff --git a/src/shell.html b/src/shell.html index 31714f473..333f6528f 100644 --- a/src/shell.html +++ b/src/shell.html @@ -4,28 +4,28 @@ - raylib HTML5 GAME + raylib web game - - + + - + - + - + - +