mirror of
				https://github.com/raysan5/raylib.git
				synced 2025-10-26 12:27:01 +00:00 
			
		
		
		
	raylib 1.1
View CHANGELOG for a detailed list of changes
This commit is contained in:
		
							
								
								
									
										35
									
								
								CHANGELOG
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								CHANGELOG
									
									
									
									
									
								
							| @@ -1,11 +1,44 @@ | |||||||
| changelog | changelog | ||||||
| --------- | --------- | ||||||
|  |  | ||||||
| Current Release:    raylib 1.0.6 (March 2014) | Current Release:    raylib 1.1.0 (April 2014) | ||||||
|  |  | ||||||
| NOTE: Only versions marked as 'Release' are available on release folder, updates are only available as source. | NOTE: Only versions marked as 'Release' are available on release folder, updates are only available as source. | ||||||
| NOTE: Current Release includes all previous updates. | NOTE: Current Release includes all previous updates. | ||||||
|  |  | ||||||
|  | ----------------------------------------------- | ||||||
|  | Release:     raylib 1.1.0 (19 April 2014) | ||||||
|  | ----------------------------------------------- | ||||||
|  | NOTE:  | ||||||
|  |   This version supposed a complete internal redesign of the library to support OpenGL 3.3+ and OpenGL ES 2.0. | ||||||
|  |   New module [rlgl] has been added to 'translate' immediate mode style functions (i.e. rlVertex3f()) to GL 1.1, 3.3+ or ES2. | ||||||
|  |   Another new module [raymath] has also been added with lot of useful 3D math vector-matrix-quaternion functions. | ||||||
|  |  | ||||||
|  | [rlgl] New module, abstracts OpenGL rendering (multiple versions support) | ||||||
|  | [raymath] New module, useful 3D math vector-matrix-quaternion functions | ||||||
|  | [core] Adapt all OpenGL code (initialization, drawing) to use [rlgl] | ||||||
|  | [shapes] Rewrite all shapes drawing functions to use [rlgl] | ||||||
|  | [textures] Adapt texture GPU loading to use [rlgl] | ||||||
|  | [textures] Added support for DDS images (compressed and uncompressed) | ||||||
|  | [textures] CreateTexture() - Redesigned to add mipmap automatic generation | ||||||
|  | [textures] DrawTexturePro() - Redesigned and corrected bugs | ||||||
|  | [models] Rewrite all 3d-shapes drawing functions to use [rlgl] | ||||||
|  | [models] Adapt model loading and drawing to use [rlgl] | ||||||
|  | [models] Model struct updated to include texture id | ||||||
|  | [models] SetModelTexture() - Added, link a texture to a model | ||||||
|  | [models] DrawModelEx() - Redesigned with extended parameters | ||||||
|  | [audio] Added music streaming support (OGG files) | ||||||
|  | [audio] Added support for OGG files as Sound | ||||||
|  | [audio] PlayMusicStream() - Added, open a new music stream and play it | ||||||
|  | [audio] StopMusicStream() - Added, stop music stream playing and close stream | ||||||
|  | [audio] PauseMusicStream() - Added, pause music stream playing | ||||||
|  | [audio] MusicIsPlaying() - Added, to check if music is playing | ||||||
|  | [audio] SetMusicVolume() - Added, set volume for music | ||||||
|  | [audio] GetMusicTimeLength() - Added, get current music time length (in seconds) | ||||||
|  | [audio] GetMusicTimePlayed() - Added, get current music time played (in seconds) | ||||||
|  | [utils] Added log tracing functionality - TraceLog(), TraceLogOpen(), TraceLogClose() | ||||||
|  | [*] Log tracing messages all around the code | ||||||
|  |  | ||||||
| ----------------------------------------------- | ----------------------------------------------- | ||||||
| Release:     raylib 1.0.6 (16 March 2014) | Release:     raylib 1.0.6 (16 March 2014) | ||||||
| ----------------------------------------------- | ----------------------------------------------- | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ The following help is highly appreciated: | |||||||
| 	- Translators / Localizators - Can you translate raylib to another language? | 	- Translators / Localizators - Can you translate raylib to another language? | ||||||
| 	- Documentation / Tutorials / Example writters - Can you write some tutorial / example? | 	- Documentation / Tutorials / Example writters - Can you write some tutorial / example? | ||||||
| 	- Web Development - Can you help with the web? Can you setup a forum? | 	- Web Development - Can you help with the web? Can you setup a forum? | ||||||
| 	- Porting to Linux and OSX - Can you compile and test raylib on another OS? | 	- Porting to Linux, OSX... - Can you compile and test raylib on another OS? | ||||||
| 	- Testers of current features and multiple systems - Can you find some bug on raylib? | 	- Testers of current features and multiple systems - Can you find some bug on raylib? | ||||||
|  |  | ||||||
| If you can not help on any of the above points but you still want to contribute in some way... please, consider helping  | If you can not help on any of the above points but you still want to contribute in some way... please, consider helping  | ||||||
| @@ -34,4 +34,4 @@ contact | |||||||
|    * Facebook: [http://www.facebook.com/raylibgames](http://www.facebook.com/raylibgames) |    * Facebook: [http://www.facebook.com/raylibgames](http://www.facebook.com/raylibgames) | ||||||
|  |  | ||||||
|     |     | ||||||
| [raysan5]: mailto:raysan@raysanweb.com "Ramon Santamaria - Ray San" | [raysan5]: mailto:raysan5@gmail.com "Ramon Santamaria - Ray San" | ||||||
|   | |||||||
							
								
								
									
										63
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								README.md
									
									
									
									
									
								
							| @@ -28,11 +28,30 @@ like no transparencies support or no hardware acceleration. | |||||||
| So, I decided to create my own lib, hardware accelerated, clear function names, quite organized, well structured,  | So, I decided to create my own lib, hardware accelerated, clear function names, quite organized, well structured,  | ||||||
| plain C coding and, the most important, primarily intended to LEARN videogames programming. | plain C coding and, the most important, primarily intended to LEARN videogames programming. | ||||||
|  |  | ||||||
| I've coded quite a lot in C# and XNA and I really love it (in fact, my students learn C# with XNA after C),  | I've coded quite a lot in C# and XNA and I really love it (in fact, my students learn C# after C),  | ||||||
| so, I decided to use C# language notation and XNA naming conventions. That way, students can jump from  | so, I decided to use C# language notation and XNA naming conventions. That way, students can jump from  | ||||||
| raylib to XNA (or MonoGame) extremely easily. | raylib to XNA, MonoGame or similar libs extremely easily. | ||||||
|  |  | ||||||
| raylib started as a weekend project and after three months of hard work, here it is the first version.  | raylib started as a weekend project and after three months of hard work, first version was published. | ||||||
|  |  | ||||||
|  | Enjoy it. | ||||||
|  |  | ||||||
|  | notes on raylib 1.1 | ||||||
|  | ------------------- | ||||||
|  |  | ||||||
|  | On April 2014, after 6 month of first raylib release, raybil 1.1 has been released. This new version presents a | ||||||
|  | complete internal redesign of the library to support OpenGL 1.1, OpenGL 3.3+ and OpenGL ES 2.0. | ||||||
|  |  | ||||||
|  | A new module named [rlgl] (https://github.com/raysan5/raylib/blob/master/src/rlgl.h) has been added to the library. This new module translate raylib-OpenGL-style  | ||||||
|  | immediate mode functions (i.e. rlVertex3f(), rlBegin(), ...) to different versions of OpenGL (1.1, 3.3+, ES2), selectable by one define. | ||||||
|  |  | ||||||
|  | [rlgl] (https://github.com/raysan5/raylib/blob/master/src/rlgl.h) also comes with a second new module named [raymath] (https://github.com/raysan5/raylib/blob/master/src/raymath.h), which includes | ||||||
|  | a bunch of useful functions for 3d-math with vectors, matrices and quaternions. | ||||||
|  |  | ||||||
|  | Some other big changes of this new version have been the support for OGG files loading and stream playing, and the | ||||||
|  | support of DDS texture files (compressed and uncompressed) along with mipmaps support. | ||||||
|  |  | ||||||
|  | Lots of code changes and lot of testing have concluded in this amazing new raylib 1.1. | ||||||
|  |  | ||||||
| Enjoy it. | Enjoy it. | ||||||
|  |  | ||||||
| @@ -41,11 +60,14 @@ features | |||||||
|   |   | ||||||
|    *  Written in plain C code (C99) |    *  Written in plain C code (C99) | ||||||
|    *  Uses C# PascalCase/camelCase notation |    *  Uses C# PascalCase/camelCase notation | ||||||
|    * Hardware accelerated using OpenGL 1.1 |    *  Hardware accelerated with OpenGL (1.1, 3.3+ or ES2) | ||||||
|    * Transparencies support (RGBA Colors) |    *  Unique OpenGL abstraction layer [rlgl] | ||||||
|    * Custom color palette for better use on white background |    *  Powerful fonts module with SpriteFonts support | ||||||
|    * Basic 3D Support (camera, basic models, OBJ models, etc) |    *  Multiple textures support, including DDS and mipmaps generation | ||||||
|    * Powerful Text module with SpriteFonts support |    *  Basic 3d support for Shapes, Models, Heightmaps and Billboards | ||||||
|  |    *  Powerful math module for Vector and Matrix operations [raymath] | ||||||
|  |    *  Audio loading and playing with streaming support | ||||||
|  |    *  Custom color palette for fancy visuals on raywhite background | ||||||
|  |  | ||||||
| raylib uses on its core module the outstanding [GLFW3] (http://www.glfw.org/) library. The best option by far I found for  | raylib uses on its core module the outstanding [GLFW3] (http://www.glfw.org/) library. The best option by far I found for  | ||||||
| window/context and input management (clean, focused, great license, well documented, modern, ...).  | window/context and input management (clean, focused, great license, well documented, modern, ...).  | ||||||
| @@ -75,19 +97,30 @@ raylib could be build with the following command lines (Using GCC compiler): | |||||||
| 	gcc -c core.c -std=c99 -Wall | 	gcc -c core.c -std=c99 -Wall | ||||||
| 	gcc -c shapes.c -std=c99 -Wall | 	gcc -c shapes.c -std=c99 -Wall | ||||||
| 	gcc -c textures.c -std=c99 -Wall | 	gcc -c textures.c -std=c99 -Wall | ||||||
| 	gcc -c stb_image.c -std=c99 -Wall |  | ||||||
| 	gcc -c text.c -std=c99 -Wall | 	gcc -c text.c -std=c99 -Wall | ||||||
| 	gcc -c models.c -std=c99 -Wall | 	gcc -c models.c -std=c99 -Wall | ||||||
| 	gcc -c vector3.c -std=c99 -Wall | 	gcc -c raymath.c -std=c99 -Wall | ||||||
|  |     gcc -c rlgl.c -std=c99 -Wall | ||||||
| 	gcc -c audio.c -std=c99 -Wall | 	gcc -c audio.c -std=c99 -Wall | ||||||
|     gcc -c utils.c -std=c99 -Wall |     gcc -c utils.c -std=c99 -Wall | ||||||
| 	ar rcs raylib.a core.o shapes.o textures.o stb_image.o text.o models.o vector3.o utils.o audio.o |     gcc -c stb_image.c -std=c99 -Wall | ||||||
|  |     gcc -c stb_vorbis.c -std=c99 -Wall | ||||||
|      |      | ||||||
| To compile examples, make sure raylib.h is placed in include path and libraries raylib (libraylib.a) and glfw3 (libglfw3.a)  | 	ar rcs libraylib.a core.o shapes.o textures.o stb_image.o text.o models.o raymath.o rlgl.o utils.o stb_vorbis.o audio.o | ||||||
| are placed in the libraries path. It's also recommended to link with file icon.o for fancy raylib icon usage. |  | ||||||
|  | To compile examples, make sure raylib.h is placed in the include path and the following libraries are placed in the libraries path: | ||||||
|  |  | ||||||
|  |     libraylib.a   - raylib | ||||||
|  |     libglfw3.a    - GLFW3 (static version) | ||||||
|  |     libglew32.a   - GLEW, OpenGL extension loading, only required if using OpenGL 3.3+ or ES2 | ||||||
|  |     libopenal32.a - OpenAL, audio device management | ||||||
|  |      | ||||||
|  | It's also recommended to link with file icon.o for fancy raylib icon usage. Linking command: | ||||||
|  |  | ||||||
| 	cd raylib/examples | 	cd raylib/examples | ||||||
| 	gcc -o test_code.exe test_code.c icon.o -lraylib -lglfw3 -lopengl32 -lgdi32 -std=c99 -Wl,--subsystem,windows | 	gcc -o test_code.exe test_code.c icon.o -lraylib -lglfw3 -lglew32 -lopenal32 -lopengl32 -lgdi32 -std=c99 -Wl,--subsystem,windows | ||||||
|  |      | ||||||
|  | If you have any doubt, [let me know][raysan5]. | ||||||
|  |  | ||||||
| contact | contact | ||||||
| ------- | ------- | ||||||
| @@ -109,4 +142,4 @@ The following people have contributed in some way to make raylib project a reali | |||||||
|  - [Elendow](http://www.elendow.com) |  - [Elendow](http://www.elendow.com) | ||||||
|  |  | ||||||
| 	 | 	 | ||||||
| [raysan5]: mailto:raysan@raysanweb.com "Ramon Santamaria - Ray San" | [raysan5]: mailto:raysan5@gmail.com "Ramon Santamaria - Ray San" | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								ROADMAP.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								ROADMAP.md
									
									
									
									
									
								
							| @@ -1,7 +1,7 @@ | |||||||
| roadmap | roadmap | ||||||
| ------- | ------- | ||||||
|  |  | ||||||
| First version of raylib is quite complete and functional but there is still a lot of things I would like to improve. | Current version of raylib is quite complete and functional but there is still a lot of things I would like to improve. | ||||||
| Here it is a list of features I would like to add and functions to improve. | Here it is a list of features I would like to add and functions to improve. | ||||||
|  |  | ||||||
| Around the source code there are some TODO points with pending revisions/bugs and here it is a list of features I would like to add. | Around the source code there are some TODO points with pending revisions/bugs and here it is a list of features I would like to add. | ||||||
| @@ -10,13 +10,13 @@ raylib v1.x | |||||||
|  |  | ||||||
|    - [DONE] Review Billboard Drawing functions |    - [DONE] Review Billboard Drawing functions | ||||||
|    - [DONE] Review Heightmap Loading and Drawing functions - Load Heightmap directly as a Model |    - [DONE] Review Heightmap Loading and Drawing functions - Load Heightmap directly as a Model | ||||||
|    - Lighting support (only 3d mode) - CreateLight() |    - Lighting support (only 3d mode) | ||||||
|    - [DONE] Simple Collision Detection functions |    - [DONE] Simple Collision Detection functions | ||||||
|    - Default scene Camera controls (zoom, pan, rotate)    |    - Default scene Camera controls (zoom, pan, rotate)    | ||||||
|    - Basic Procedural Texture / Image generation (Gradient, Checked, Spot, Noise, Cellular) |    - Basic Procedural Image Generation (Gradient, Checked, Spot, Noise, Cellular) | ||||||
|    - Software mipmapping generation and POT conversion (custom implementation) |    - [DONE] Software mipmapping generation and POT conversion (custom implementation) | ||||||
|    - Comments / Functions translation (?) |    - TTF fonts support | ||||||
|     |     | ||||||
| Any feature missing? Do you have a request? [Let me know!][raysan5] | Any feature missing? Do you have a request? [Let me know!][raysan5] | ||||||
|  |  | ||||||
| [raysan5]: mailto:raysan@raysanweb.com "Ramon Santamaria - Ray San" | [raysan5]: mailto:raysan5@gmail.com "Ramon Santamaria - Ray San" | ||||||
|   | |||||||
							
								
								
									
										584
									
								
								src/audio.c
									
									
									
									
									
								
							
							
						
						
									
										584
									
								
								src/audio.c
									
									
									
									
									
								
							| @@ -6,7 +6,7 @@ | |||||||
| *     | *     | ||||||
| *   Uses external lib:     | *   Uses external lib:     | ||||||
| *       OpenAL - Audio device management lib | *       OpenAL - Audio device management lib | ||||||
| *       TODO: stb_vorbis - Ogg audio files loading | *       stb_vorbis - Ogg audio files loading | ||||||
| *        | *        | ||||||
| *   Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) | *   Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) | ||||||
| *     | *     | ||||||
| @@ -32,50 +32,45 @@ | |||||||
| #include <AL/al.h>           // OpenAL basic header | #include <AL/al.h>           // OpenAL basic header | ||||||
| #include <AL/alc.h>          // OpenAL context header (like OpenGL, OpenAL requires a context to work) | #include <AL/alc.h>          // OpenAL context header (like OpenGL, OpenAL requires a context to work) | ||||||
|  |  | ||||||
| #include <stdlib.h>          // To use exit() function | #include <stdlib.h>          // Declares malloc() and free() for memory management | ||||||
|  | #include <string.h>          // Required for strcmp() | ||||||
| #include <stdio.h>           // Used for .WAV loading | #include <stdio.h>           // Used for .WAV loading | ||||||
|  |  | ||||||
| #include "utils.h"           // rRES data decompression utility function | #include "utils.h"           // rRES data decompression utility function | ||||||
|  |  | ||||||
| //#include "stb_vorbis.h"      // OGG loading functions | #include "stb_vorbis.h"      // OGG loading functions | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Defines and Macros | // Defines and Macros | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Nop... | #define MUSIC_STREAM_BUFFERS        2 | ||||||
|  | #define MUSIC_BUFFER_SIZE      4096*8   //4096*32 | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Types and Structures Definition | // Types and Structures Definition | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Sound source type (all file loaded in memory) |  | ||||||
| /* |  | ||||||
| struct Sound { |  | ||||||
|     unsigned int source; |  | ||||||
|     unsigned int buffer; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| // Music type (file streamming from memory) | // Music type (file streaming from memory) | ||||||
| // NOTE: Anything longer than ~10 seconds should be Music... | // NOTE: Anything longer than ~10 seconds should be streamed... | ||||||
| struct Music { | typedef struct Music { | ||||||
|     stb_vorbis *stream; |     stb_vorbis *stream; | ||||||
| 	stb_vorbis_info info; |  | ||||||
|      |      | ||||||
|     ALuint id;  | 	ALuint buffers[MUSIC_STREAM_BUFFERS]; | ||||||
| 	ALuint buffers[2]; |  | ||||||
| 	ALuint source; | 	ALuint source; | ||||||
| 	ALenum format; | 	ALenum format; | ||||||
|   |   | ||||||
| 	int bufferSize; |     int channels; | ||||||
|  |     int sampleRate; | ||||||
| 	int totalSamplesLeft; | 	int totalSamplesLeft; | ||||||
| 	bool loop; | 	bool loop; | ||||||
| }; |      | ||||||
| */ | } Music; | ||||||
|  |  | ||||||
| // Wave file data | // Wave file data | ||||||
| typedef struct Wave { | typedef struct Wave { | ||||||
|     unsigned char *data;      // Buffer data pointer |     void *data;                 // Buffer data pointer | ||||||
|  |     unsigned int dataSize;      // Data size in bytes | ||||||
|     unsigned int sampleRate; |     unsigned int sampleRate; | ||||||
|     unsigned int dataSize; |  | ||||||
|     short bitsPerSample; |     short bitsPerSample; | ||||||
|     short channels;   |     short channels;   | ||||||
| } Wave; | } Wave; | ||||||
| @@ -83,22 +78,23 @@ typedef struct Wave { | |||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Global Variables Definition | // Global Variables Definition | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| static bool musicIsPlaying; | bool musicEnabled = false; | ||||||
| static Music *currentMusic; | static Music currentMusic;      // Current music loaded | ||||||
|  |                                 // NOTE: Only one music file playing at a time | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Module specific Functions Declaration | // Module specific Functions Declaration | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| static Wave LoadWAV(char *fileName); | static Wave LoadWAV(const char *fileName); | ||||||
| static void UnloadWAV(Wave wave); | static Wave LoadOGG(char *fileName); | ||||||
| //static Ogg LoadOGG(char *fileName); | static void UnloadWave(Wave wave); | ||||||
| static bool MusicStream(Music music, ALuint buffer); |  | ||||||
|  |  | ||||||
| extern bool MusicStreamUpdate(); | static bool BufferMusicStream(ALuint buffer);   // Fill music buffers with data | ||||||
| extern void PlayCurrentMusic(); | static void EmptyMusicStream();                 // Empty music buffers | ||||||
|  | extern void UpdateMusicStream();                // Updates buffers (refill) for music streaming | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Module Functions Definition - Window and OpenGL Context Functions | // Module Functions Definition - Audio Device initialization and Closing | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
|  |  | ||||||
| // Initialize audio device and context | // Initialize audio device and context | ||||||
| @@ -126,13 +122,13 @@ void InitAudioDevice() | |||||||
|     alListener3f(AL_POSITION, 0, 0, 0); |     alListener3f(AL_POSITION, 0, 0, 0); | ||||||
|     alListener3f(AL_VELOCITY, 0, 0, 0); |     alListener3f(AL_VELOCITY, 0, 0, 0); | ||||||
|     alListener3f(AL_ORIENTATION, 0, 0, -1); |     alListener3f(AL_ORIENTATION, 0, 0, -1); | ||||||
|      |  | ||||||
|     musicIsPlaying = false; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Close the audio device for the current context, and destroys the context | // Close the audio device for the current context, and destroys the context | ||||||
| void CloseAudioDevice() | void CloseAudioDevice() | ||||||
| { | { | ||||||
|  |     StopMusicStream();      // Stop music streaming and close current stream | ||||||
|  |  | ||||||
|     ALCdevice *device; |     ALCdevice *device; | ||||||
|     ALCcontext *context = alcGetCurrentContext(); |     ALCcontext *context = alcGetCurrentContext(); | ||||||
|      |      | ||||||
| @@ -145,17 +141,27 @@ void CloseAudioDevice() | |||||||
|     alcCloseDevice(device); |     alcCloseDevice(device); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | //---------------------------------------------------------------------------------- | ||||||
|  | // Module Functions Definition - Sounds loading and playing (.WAV) | ||||||
|  | //---------------------------------------------------------------------------------- | ||||||
|  |  | ||||||
| // Load sound to memory | // Load sound to memory | ||||||
| Sound LoadSound(char *fileName) | Sound LoadSound(char *fileName) | ||||||
| { | { | ||||||
|     Sound sound; |     Sound sound; | ||||||
|  |     Wave wave; | ||||||
|      |      | ||||||
|     // NOTE: The entire file is loaded to memory to play it all at once (no-streaming) |     // NOTE: The entire file is loaded to memory to play it all at once (no-streaming) | ||||||
|      |      | ||||||
|     // WAV file loading |     // Audio file loading | ||||||
|     // NOTE: Buffer space is allocated inside LoadWAV, Wave must be freed |     // NOTE: Buffer space is allocated inside function, Wave must be freed | ||||||
|     Wave wave = LoadWAV(fileName); |  | ||||||
|      |      | ||||||
|  |     if (strcmp(GetExtension(fileName),"wav") == 0) wave = LoadWAV(fileName); | ||||||
|  |     else if (strcmp(GetExtension(fileName),"ogg") == 0) wave = LoadOGG(fileName); | ||||||
|  |     else TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName); | ||||||
|  |      | ||||||
|  |     if (wave.data != NULL) | ||||||
|  |     { | ||||||
|         ALenum format = 0; |         ALenum format = 0; | ||||||
|         // The OpenAL format is worked out by looking at the number of channels and the bits per sample |         // The OpenAL format is worked out by looking at the number of channels and the bits per sample | ||||||
|         if (wave.channels == 1)  |         if (wave.channels == 1)  | ||||||
| @@ -169,7 +175,6 @@ Sound LoadSound(char *fileName) | |||||||
|             else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16; |             else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|      |  | ||||||
|         // Create an audio source |         // Create an audio source | ||||||
|         ALuint source; |         ALuint source; | ||||||
|         alGenSources(1, &source);            // Generate pointer to audio source |         alGenSources(1, &source);            // Generate pointer to audio source | ||||||
| @@ -186,19 +191,20 @@ Sound LoadSound(char *fileName) | |||||||
|         alGenBuffers(1, &buffer);            // Generate pointer to buffer |         alGenBuffers(1, &buffer);            // Generate pointer to buffer | ||||||
|  |  | ||||||
|         // Upload sound data to buffer |         // Upload sound data to buffer | ||||||
|     alBufferData(buffer, format, (void*)wave.data, wave.dataSize, wave.sampleRate); |         alBufferData(buffer, format, wave.data, wave.dataSize, wave.sampleRate); | ||||||
|  |  | ||||||
|         // Attach sound buffer to source |         // Attach sound buffer to source | ||||||
|         alSourcei(source, AL_BUFFER, buffer); |         alSourcei(source, AL_BUFFER, buffer); | ||||||
|          |          | ||||||
|         // Unallocate WAV data |         // Unallocate WAV data | ||||||
|     UnloadWAV(wave); |         UnloadWave(wave); | ||||||
|          |          | ||||||
|         TraceLog(INFO, "[%s] Sound file loaded successfully", fileName);   |         TraceLog(INFO, "[%s] Sound file loaded successfully", fileName);   | ||||||
|         TraceLog(INFO, "[%s] Sample rate: %i - Channels: %i", fileName, wave.sampleRate, wave.channels); |         TraceLog(INFO, "[%s] Sample rate: %i - Channels: %i", fileName, wave.sampleRate, wave.channels); | ||||||
|          |          | ||||||
|         sound.source = source; |         sound.source = source; | ||||||
|         sound.buffer = buffer; |         sound.buffer = buffer; | ||||||
|  |     } | ||||||
|      |      | ||||||
|     return sound; |     return sound; | ||||||
| } | } | ||||||
| @@ -314,7 +320,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId) | |||||||
|                         alSourcei(source, AL_BUFFER, buffer); |                         alSourcei(source, AL_BUFFER, buffer); | ||||||
|                          |                          | ||||||
|                         // Unallocate WAV data |                         // Unallocate WAV data | ||||||
|                         UnloadWAV(wave); |                         UnloadWave(wave); | ||||||
|  |  | ||||||
|                         TraceLog(INFO, "[%s] Sound loaded successfully from resource, sample rate: %i", rresName, (int)sampleRate); |                         TraceLog(INFO, "[%s] Sound loaded successfully from resource, sample rate: %i", rresName, (int)sampleRate); | ||||||
|                          |                          | ||||||
| @@ -381,22 +387,6 @@ void PlaySound(Sound sound) | |||||||
|     //alGetSourcef(sound.source, AL_SEC_OFFSET, &result);   // AL_SAMPLE_OFFSET |     //alGetSourcef(sound.source, AL_SEC_OFFSET, &result);   // AL_SAMPLE_OFFSET | ||||||
| } | } | ||||||
|  |  | ||||||
| // Play a sound with extended options |  | ||||||
| // TODO: This function should be reviewed... |  | ||||||
| void PlaySoundEx(Sound sound, float timePosition, bool loop) |  | ||||||
| { |  | ||||||
|     // TODO: Review |  | ||||||
|      |  | ||||||
|     // Change the current position (e.g. skip some part of the sound) |  | ||||||
|     // NOTE: Only work when the entire file is in a single buffer |  | ||||||
|     //alSourcei(sound.source, AL_BYTE_OFFSET, int(position * sampleRate)); |  | ||||||
|  |  | ||||||
|     alSourcePlay(sound.source);        // Play the sound |  | ||||||
|      |  | ||||||
|     if (loop) alSourcei(sound.source, AL_LOOPING, AL_TRUE); |  | ||||||
|     else alSourcei(sound.source, AL_LOOPING, AL_FALSE); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Pause a sound | // Pause a sound | ||||||
| void PauseSound(Sound sound) | void PauseSound(Sound sound) | ||||||
| { | { | ||||||
| @@ -421,30 +411,250 @@ bool SoundIsPlaying(Sound sound) | |||||||
|     return playing; |     return playing; | ||||||
| } | } | ||||||
|  |  | ||||||
| // Check if music is playing |  | ||||||
| bool MusicIsPlaying(Music music) |  | ||||||
| { |  | ||||||
|     ALenum state; |  | ||||||
|      |  | ||||||
|     alGetSourcei(music.source, AL_SOURCE_STATE, &state); |  | ||||||
|      |  | ||||||
|     return (state == AL_PLAYING); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Set volume for a sound | // Set volume for a sound | ||||||
| void SetVolume(Sound sound, float volume) | void SetSoundVolume(Sound sound, float volume) | ||||||
| { | { | ||||||
|     alSourcef(sound.source, AL_GAIN, volume); |     alSourcef(sound.source, AL_GAIN, volume); | ||||||
| } | } | ||||||
|  |  | ||||||
| // Set pitch for a sound | // Set pitch for a sound | ||||||
| void SetPitch(Sound sound, float pitch) | void SetSoundPitch(Sound sound, float pitch) | ||||||
| { | { | ||||||
|     alSourcef(sound.source, AL_PITCH, pitch); |     alSourcef(sound.source, AL_PITCH, pitch); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | //---------------------------------------------------------------------------------- | ||||||
|  | // Module Functions Definition - Music loading and stream playing (.OGG) | ||||||
|  | //---------------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | // Start music playing (open stream) | ||||||
|  | void PlayMusicStream(char *fileName) | ||||||
|  | { | ||||||
|  |     if (strcmp(GetExtension(fileName),"ogg") == 0) | ||||||
|  |     { | ||||||
|  |         // Stop current music, clean buffers, unload current stream | ||||||
|  |         StopMusicStream(); | ||||||
|  |      | ||||||
|  |         // Open audio stream | ||||||
|  |         currentMusic.stream = stb_vorbis_open_filename(fileName, NULL, NULL); | ||||||
|  |          | ||||||
|  |         if (currentMusic.stream == NULL) TraceLog(WARNING, "[%s] Could not open ogg audio file", fileName); | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             // Get file info | ||||||
|  |             stb_vorbis_info info = stb_vorbis_get_info(currentMusic.stream); | ||||||
|  |              | ||||||
|  |             currentMusic.channels = info.channels; | ||||||
|  |             currentMusic.sampleRate = info.sample_rate; | ||||||
|  |              | ||||||
|  |             TraceLog(INFO, "[%s] Ogg sample rate: %i", fileName, info.sample_rate); | ||||||
|  |             TraceLog(INFO, "[%s] Ogg channels: %i", fileName, info.channels); | ||||||
|  |             TraceLog(INFO, "[%s] Temp memory required: %i", fileName, info.temp_memory_required); | ||||||
|  |              | ||||||
|  |             if (info.channels == 2) currentMusic.format = AL_FORMAT_STEREO16; | ||||||
|  |             else currentMusic.format = AL_FORMAT_MONO16; | ||||||
|  |              | ||||||
|  |             currentMusic.loop = true;                  // We loop by default | ||||||
|  |             musicEnabled = true; | ||||||
|  |              | ||||||
|  |             // Create an audio source | ||||||
|  |             alGenSources(1, ¤tMusic.source);     // Generate pointer to audio source | ||||||
|  |  | ||||||
|  |             alSourcef(currentMusic.source, AL_PITCH, 1);     | ||||||
|  |             alSourcef(currentMusic.source, AL_GAIN, 1); | ||||||
|  |             alSource3f(currentMusic.source, AL_POSITION, 0, 0, 0); | ||||||
|  |             alSource3f(currentMusic.source, AL_VELOCITY, 0, 0, 0); | ||||||
|  |             //alSourcei(currentMusic.source, AL_LOOPING, AL_TRUE);     // ERROR: Buffers do not queue! | ||||||
|  |              | ||||||
|  |             // Generate two OpenAL buffers | ||||||
|  |             alGenBuffers(2, currentMusic.buffers); | ||||||
|  |  | ||||||
|  |             // Fill buffers with music... | ||||||
|  |             BufferMusicStream(currentMusic.buffers[0]); | ||||||
|  |             BufferMusicStream(currentMusic.buffers[1]); | ||||||
|  |              | ||||||
|  |             // Queue buffers and start playing | ||||||
|  |             alSourceQueueBuffers(currentMusic.source, 2, currentMusic.buffers); | ||||||
|  |             alSourcePlay(currentMusic.source); | ||||||
|  |              | ||||||
|  |             // NOTE: Regularly, we must check if a buffer has been processed and refill it: MusicStreamUpdate() | ||||||
|  |  | ||||||
|  |             currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Stop music playing (close stream) | ||||||
|  | void StopMusicStream() | ||||||
|  | { | ||||||
|  |     if (musicEnabled) | ||||||
|  |     { | ||||||
|  |         alSourceStop(currentMusic.source); | ||||||
|  |          | ||||||
|  |         EmptyMusicStream();     // Empty music buffers | ||||||
|  |          | ||||||
|  |         alDeleteSources(1, ¤tMusic.source); | ||||||
|  |         alDeleteBuffers(2, currentMusic.buffers); | ||||||
|  |          | ||||||
|  |         stb_vorbis_close(currentMusic.stream); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     musicEnabled = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Pause music playing | ||||||
|  | void PauseMusicStream() | ||||||
|  | { | ||||||
|  |     // TODO: Record music is paused or check if music available! | ||||||
|  |     alSourcePause(currentMusic.source); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Check if music is playing | ||||||
|  | bool MusicIsPlaying() | ||||||
|  | { | ||||||
|  |     ALenum state; | ||||||
|  |      | ||||||
|  |     alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state); | ||||||
|  |      | ||||||
|  |     return (state == AL_PLAYING); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Set volume for music | ||||||
|  | void SetMusicVolume(float volume) | ||||||
|  | { | ||||||
|  |     alSourcef(currentMusic.source, AL_GAIN, volume); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Get current music time length (in seconds) | ||||||
|  | float GetMusicTimeLength() | ||||||
|  | { | ||||||
|  |     float totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic.stream); | ||||||
|  |      | ||||||
|  |     return totalSeconds; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Get current music time played (in seconds) | ||||||
|  | float GetMusicTimePlayed() | ||||||
|  | { | ||||||
|  |     int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels; | ||||||
|  |      | ||||||
|  |     int samplesPlayed = totalSamples - currentMusic.totalSamplesLeft; | ||||||
|  |      | ||||||
|  |     float secondsPlayed = (float)samplesPlayed / (currentMusic.sampleRate * currentMusic.channels); | ||||||
|  |      | ||||||
|  |     return secondsPlayed; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //---------------------------------------------------------------------------------- | ||||||
|  | // Module specific Functions Definition | ||||||
|  | //---------------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | // Fill music buffers with new data from music stream | ||||||
|  | static bool BufferMusicStream(ALuint buffer) | ||||||
|  | { | ||||||
|  | 	short pcm[MUSIC_BUFFER_SIZE]; | ||||||
|  |      | ||||||
|  | 	int  size = 0;              // Total size of data steamed (in bytes) | ||||||
|  | 	int  streamedBytes = 0;     // Bytes of data obtained in one samples get | ||||||
|  |      | ||||||
|  |     bool active = true;         // We can get more data from stream (not finished) | ||||||
|  |      | ||||||
|  |     if (musicEnabled) | ||||||
|  |     { | ||||||
|  |         while (size < MUSIC_BUFFER_SIZE) | ||||||
|  |         { | ||||||
|  |             streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic.stream, currentMusic.channels, pcm + size, MUSIC_BUFFER_SIZE - size); | ||||||
|  |              | ||||||
|  |             if (streamedBytes > 0) size += (streamedBytes*currentMusic.channels); | ||||||
|  |             else break; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         TraceLog(DEBUG, "Streaming music data to buffer. Bytes streamed: %i", size); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  | 	if (size > 0) | ||||||
|  |     { | ||||||
|  |         alBufferData(buffer, currentMusic.format, pcm, size*sizeof(short), currentMusic.sampleRate); | ||||||
|  |          | ||||||
|  |         currentMusic.totalSamplesLeft -= size; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         active = false; | ||||||
|  |         TraceLog(WARNING, "No more data obtained from stream"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | 	return active; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Empty music buffers | ||||||
|  | static void EmptyMusicStream() | ||||||
|  | { | ||||||
|  |     ALuint buffer = 0;  | ||||||
|  |     int queued = 0; | ||||||
|  |      | ||||||
|  |     alGetSourcei(currentMusic.source, AL_BUFFERS_QUEUED, &queued); | ||||||
|  |      | ||||||
|  |     while(queued > 0) | ||||||
|  |     { | ||||||
|  |         alSourceUnqueueBuffers(currentMusic.source, 1, &buffer); | ||||||
|  |          | ||||||
|  |         queued--; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Update (re-fill) music buffers if data already processed | ||||||
|  | extern void UpdateMusicStream() | ||||||
|  | { | ||||||
|  |     ALuint buffer = 0; | ||||||
|  |     ALint processed = 0; | ||||||
|  |     bool active = true; | ||||||
|  |      | ||||||
|  |     if (musicEnabled) | ||||||
|  |     { | ||||||
|  |         // Get the number of already processed buffers (if any) | ||||||
|  |         alGetSourcei(currentMusic.source, AL_BUFFERS_PROCESSED, &processed); | ||||||
|  |          | ||||||
|  |         while (processed > 0) | ||||||
|  |         { | ||||||
|  |             // Recover processed buffer for refill | ||||||
|  |             alSourceUnqueueBuffers(currentMusic.source, 1, &buffer); | ||||||
|  |  | ||||||
|  |             // Refill buffer | ||||||
|  |             active = BufferMusicStream(buffer); | ||||||
|  |              | ||||||
|  |             // If no more data to stream, restart music (if loop) | ||||||
|  |             if ((!active) && (currentMusic.loop))    | ||||||
|  |             { | ||||||
|  |                 if (currentMusic.loop) | ||||||
|  |                 { | ||||||
|  |                     stb_vorbis_seek_start(currentMusic.stream); | ||||||
|  |                     currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels; | ||||||
|  |                      | ||||||
|  |                     active = BufferMusicStream(buffer); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             // Add refilled buffer to queue again... don't let the music stop! | ||||||
|  |             alSourceQueueBuffers(currentMusic.source, 1, &buffer); | ||||||
|  |              | ||||||
|  |             if(alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Ogg playing, error buffering data..."); | ||||||
|  |              | ||||||
|  |             processed--; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         ALenum state; | ||||||
|  |         alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state); | ||||||
|  |          | ||||||
|  |         if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic.source); | ||||||
|  |          | ||||||
|  |         if (!active) StopMusicStream(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| // Load WAV file into Wave structure | // Load WAV file into Wave structure | ||||||
| static Wave LoadWAV(char *fileName)  | static Wave LoadWAV(const char *fileName) | ||||||
| { | { | ||||||
|     // Basic WAV headers structs |     // Basic WAV headers structs | ||||||
|     typedef struct { |     typedef struct { | ||||||
| @@ -543,199 +753,51 @@ static Wave LoadWAV(char *fileName) | |||||||
|     return wave; |     return wave; | ||||||
| } | } | ||||||
|  |  | ||||||
| // Unload WAV file data | // Load OGG file into Wave structure | ||||||
| static void UnloadWAV(Wave wave) | static Wave LoadOGG(char *fileName) | ||||||
|  | { | ||||||
|  |     Wave wave; | ||||||
|  |      | ||||||
|  |     stb_vorbis *oggFile = stb_vorbis_open_filename(fileName, NULL, NULL); | ||||||
|  |     stb_vorbis_info info = stb_vorbis_get_info(oggFile); | ||||||
|  |      | ||||||
|  |     wave.sampleRate = info.sample_rate; | ||||||
|  |     wave.bitsPerSample = 16; | ||||||
|  |     wave.channels = info.channels; | ||||||
|  |      | ||||||
|  |     TraceLog(DEBUG, "[%s] Ogg sample rate: %i", fileName, info.sample_rate); | ||||||
|  |     TraceLog(DEBUG, "[%s] Ogg channels: %i", fileName, info.channels); | ||||||
|  |  | ||||||
|  |     int totalSamplesLength = (stb_vorbis_stream_length_in_samples(oggFile) * info.channels); | ||||||
|  |      | ||||||
|  |     wave.dataSize = totalSamplesLength*sizeof(short);   // Size must be in bytes | ||||||
|  |      | ||||||
|  |     TraceLog(DEBUG, "[%s] Samples length: %i", fileName, totalSamplesLength); | ||||||
|  |      | ||||||
|  |     float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile); | ||||||
|  |      | ||||||
|  |     TraceLog(DEBUG, "[%s] Total seconds: %f", fileName, totalSeconds); | ||||||
|  |      | ||||||
|  |     if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio lenght is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds); | ||||||
|  |      | ||||||
|  |     int totalSamples = totalSeconds*info.sample_rate*info.channels; | ||||||
|  |     | ||||||
|  |     TraceLog(DEBUG, "[%s] Total samples calculated: %i", fileName, totalSamples); | ||||||
|  |      | ||||||
|  |     //short *data  | ||||||
|  |     wave.data = malloc(sizeof(short)*totalSamplesLength); | ||||||
|  |  | ||||||
|  |     int samplesObtained = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, wave.data, totalSamplesLength); | ||||||
|  |      | ||||||
|  |     TraceLog(DEBUG, "[%s] Samples obtained: %i", fileName, samplesObtained); | ||||||
|  |  | ||||||
|  |     stb_vorbis_close(oggFile); | ||||||
|  |      | ||||||
|  |     return wave; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Unload Wave data | ||||||
|  | static void UnloadWave(Wave wave) | ||||||
| { | { | ||||||
|     free(wave.data); |     free(wave.data); | ||||||
| } | } | ||||||
|  |  | ||||||
| // TODO: Ogg data loading |  | ||||||
| Music LoadMusic(char *fileName) |  | ||||||
| { |  | ||||||
|     Music music; |  | ||||||
|      |  | ||||||
|     // Open audio stream |  | ||||||
|     music.stream = stb_vorbis_open_filename(fileName, NULL, NULL); |  | ||||||
|      |  | ||||||
| 	if (music.stream == NULL) TraceLog(WARNING, "Could not open ogg audio file"); |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         // Get file info |  | ||||||
|         music.info = stb_vorbis_get_info(music.stream); |  | ||||||
|          |  | ||||||
|         printf("Ogg sample rate: %i\n", music.info.sample_rate); |  | ||||||
|         printf("Ogg channels: %i\n", music.info.channels); |  | ||||||
|         printf("Temp memory required: %i\n", music.info.temp_memory_required); |  | ||||||
|          |  | ||||||
|         if (music.info.channels == 2) music.format = AL_FORMAT_STEREO16; |  | ||||||
|         else music.format = AL_FORMAT_MONO16; |  | ||||||
|          |  | ||||||
|         music.bufferSize = 4096*8; |  | ||||||
|         music.loop = true;          // We loop by default |  | ||||||
|          |  | ||||||
|         // Create an audio source |  | ||||||
|         alGenSources(1, &music.source);             // Generate pointer to audio source |  | ||||||
|  |  | ||||||
|         alSourcef(music.source, AL_PITCH, 1);     |  | ||||||
|         alSourcef(music.source, AL_GAIN, 1); |  | ||||||
|         alSource3f(music.source, AL_POSITION, 0, 0, 0); |  | ||||||
|         alSource3f(music.source, AL_VELOCITY, 0, 0, 0); |  | ||||||
|         alSourcei(music.source, AL_LOOPING, AL_TRUE);     // We loop by default |  | ||||||
|          |  | ||||||
|         // Convert loaded data to OpenAL buffers |  | ||||||
|         alGenBuffers(2, music.buffers); |  | ||||||
|     /* |  | ||||||
|         if (!MusicStream(music, music.buffers[0])) exit(1); |  | ||||||
|         if (!MusicStream(music, music.buffers[1])) exit(1); |  | ||||||
|          |  | ||||||
|         alSourceQueueBuffers(music.source, 2, music.buffers); |  | ||||||
|       |  | ||||||
|         PlayMusic(music); |  | ||||||
|     */  |  | ||||||
|         music.totalSamplesLeft = stb_vorbis_stream_length_in_samples(music.stream) * music.info.channels; |  | ||||||
|       |  | ||||||
|         currentMusic = &music; |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     return music; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void UnloadMusic(Music music) |  | ||||||
| { |  | ||||||
|     StopMusic(music); |  | ||||||
|  |  | ||||||
|     alDeleteSources(1, &music.source); |  | ||||||
| 	alDeleteBuffers(2, music.buffers); |  | ||||||
|      |  | ||||||
| 	stb_vorbis_close(music.stream); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void PlayMusic(Music music) |  | ||||||
| { |  | ||||||
|     //if (MusicIsPlaying(music)) return true; |  | ||||||
|  |  | ||||||
|     if (!MusicStream(music, music.buffers[0])) TraceLog(WARNING, "MusicStream returned 0"); |  | ||||||
|     if (!MusicStream(music, music.buffers[1])) TraceLog(WARNING, "MusicStream returned 0"); |  | ||||||
|      |  | ||||||
|     alSourceQueueBuffers(music.source, 2, music.buffers); |  | ||||||
|     alSourcePlay(music.source); |  | ||||||
|  |  | ||||||
|     TraceLog(INFO, "Playing music"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| extern void PlayCurrentMusic() |  | ||||||
| { |  | ||||||
|     if (!MusicStream(*currentMusic, currentMusic->buffers[0])) TraceLog(WARNING, "MusicStream returned 0"); |  | ||||||
|     if (!MusicStream(*currentMusic, currentMusic->buffers[1])) TraceLog(WARNING, "MusicStream returned 0"); |  | ||||||
|      |  | ||||||
|     alSourceQueueBuffers(currentMusic->source, 2, currentMusic->buffers); |  | ||||||
|     alSourcePlay(currentMusic->source); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Stop reproducing music |  | ||||||
| void StopMusic(Music music) |  | ||||||
| { |  | ||||||
|     alSourceStop(music.source); |  | ||||||
|      |  | ||||||
|     musicIsPlaying = false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static bool MusicStream(Music music, ALuint buffer) |  | ||||||
| { |  | ||||||
| 	//Uncomment this to avoid VLAs |  | ||||||
| 	//#define BUFFER_SIZE 4096*32 |  | ||||||
| 	#ifndef BUFFER_SIZE//VLAs ftw |  | ||||||
| 	#define BUFFER_SIZE (music.bufferSize) |  | ||||||
| 	#endif |  | ||||||
| 	ALshort pcm[BUFFER_SIZE]; |  | ||||||
|      |  | ||||||
| 	int  size = 0; |  | ||||||
| 	int  result = 0; |  | ||||||
|   |  | ||||||
| 	while (size < BUFFER_SIZE) |  | ||||||
|     { |  | ||||||
| 		result = stb_vorbis_get_samples_short_interleaved(music.stream, music.info.channels, pcm+size, BUFFER_SIZE-size); |  | ||||||
|          |  | ||||||
| 		if (result > 0) size += (result*music.info.channels); |  | ||||||
| 		else break; |  | ||||||
| 	} |  | ||||||
|   |  | ||||||
| 	if (size == 0) return false; |  | ||||||
|   |  | ||||||
| 	alBufferData(buffer, music.format, pcm, size*sizeof(ALshort), music.info.sample_rate); |  | ||||||
|      |  | ||||||
| 	music.totalSamplesLeft -= size; |  | ||||||
| 	 |  | ||||||
|     #undef BUFFER_SIZE |  | ||||||
|   |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| /* |  | ||||||
| extern bool MusicStreamUpdate() |  | ||||||
| { |  | ||||||
| 	ALint processed = 0; |  | ||||||
|   |  | ||||||
|     alGetSourcei(currentMusic->source, AL_BUFFERS_PROCESSED, &processed); |  | ||||||
|   |  | ||||||
|     while (processed--) |  | ||||||
|     { |  | ||||||
|         ALuint buffer = 0; |  | ||||||
|          |  | ||||||
|         alSourceUnqueueBuffers(currentMusic->source, 1, &buffer); |  | ||||||
|   |  | ||||||
| 		if (!MusicStream(*currentMusic, buffer)) |  | ||||||
|         { |  | ||||||
| 			bool shouldExit = true; |  | ||||||
|   |  | ||||||
| 			if (currentMusic->loop) |  | ||||||
|             { |  | ||||||
| 				stb_vorbis_seek_start(currentMusic->stream); |  | ||||||
| 				currentMusic->totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic->stream) * currentMusic->info.channels; |  | ||||||
| 				 |  | ||||||
|                 shouldExit = !MusicStream(*currentMusic, buffer); |  | ||||||
| 			} |  | ||||||
|   |  | ||||||
| 			if (shouldExit) return false; |  | ||||||
| 		} |  | ||||||
|          |  | ||||||
| 		alSourceQueueBuffers(currentMusic->source, 1, &buffer); |  | ||||||
| 	} |  | ||||||
|   |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| */ |  | ||||||
| extern bool MusicStreamUpdate() |  | ||||||
| { |  | ||||||
|     int processed; |  | ||||||
|     bool active = true; |  | ||||||
|   |  | ||||||
|     alGetSourcei(currentMusic->source, AL_BUFFERS_PROCESSED, &processed); |  | ||||||
|      |  | ||||||
|     printf("Data processed: %i\n", processed); |  | ||||||
|   |  | ||||||
|     while (processed--) |  | ||||||
|     { |  | ||||||
|         ALuint buffer = 0; |  | ||||||
|          |  | ||||||
|         alSourceUnqueueBuffers(currentMusic->source, 1, &buffer); |  | ||||||
|  |  | ||||||
|         active = MusicStream(*currentMusic, buffer); |  | ||||||
|   |  | ||||||
|         alSourceQueueBuffers(currentMusic->source, 1, &buffer); |  | ||||||
|     } |  | ||||||
|   |  | ||||||
|     return active; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void MusicStreamEmpty() |  | ||||||
| { |  | ||||||
|     int queued; |  | ||||||
|      |  | ||||||
|     alGetSourcei(currentMusic->source, AL_BUFFERS_QUEUED, &queued); |  | ||||||
|      |  | ||||||
|     while(queued--) |  | ||||||
|     { |  | ||||||
|         ALuint buffer;   |  | ||||||
|         alSourceUnqueueBuffers(currentMusic->source, 1, &buffer); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										11
									
								
								src/core.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/core.c
									
									
									
									
									
								
							| @@ -92,8 +92,7 @@ static Color background = { 0, 0, 0, 0 };   // Screen background color | |||||||
| extern void LoadDefaultFont();              // [Module: text] Loads default font on InitWindow() | extern void LoadDefaultFont();              // [Module: text] Loads default font on InitWindow() | ||||||
| extern void UnloadDefaultFont();            // [Module: text] Unloads default font from GPU memory | extern void UnloadDefaultFont();            // [Module: text] Unloads default font from GPU memory | ||||||
|  |  | ||||||
| extern bool MusicStreamUpdate();             // [Module: audio] Updates buffers for music streamming | extern void UpdateMusicStream();            // [Module: audio] Updates buffers for music streaming | ||||||
| extern void PlayCurrentMusic();              // [Module: audio] Plays current music stream |  | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Module specific Functions Declaration | // Module specific Functions Declaration | ||||||
| @@ -103,7 +102,7 @@ static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, i | |||||||
| static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);            // GLFW3 Srolling Callback, runs on mouse wheel | static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);            // GLFW3 Srolling Callback, runs on mouse wheel | ||||||
| static void CursorEnterCallback(GLFWwindow* window, int enter);                            // GLFW3 Cursor Enter Callback, cursor enters client area | static void CursorEnterCallback(GLFWwindow* window, int enter);                            // GLFW3 Cursor Enter Callback, cursor enters client area | ||||||
| static void WindowSizeCallback(GLFWwindow* window, int width, int height);                 // GLFW3 WindowSize Callback, runs when window is resized | static void WindowSizeCallback(GLFWwindow* window, int width, int height);                 // GLFW3 WindowSize Callback, runs when window is resized | ||||||
| static void TakeScreenshot();                                                              // Takes a bitmap (BMP) screenshot and saves it in the same folder as executable | static void TakeScreenshot();                                                              // Takes a screenshot and saves it in the same folder as executable | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Module Functions Definition - Window and OpenGL Context Functions | // Module Functions Definition - Window and OpenGL Context Functions | ||||||
| @@ -304,9 +303,7 @@ void EndDrawing() | |||||||
|     glfwSwapBuffers(window);            // Swap back and front buffers |     glfwSwapBuffers(window);            // Swap back and front buffers | ||||||
|     glfwPollEvents();                   // Register keyboard/mouse events |     glfwPollEvents();                   // Register keyboard/mouse events | ||||||
|      |      | ||||||
|     //MusicStreamUpdate(); |     UpdateMusicStream();        // NOTE: Function checks if music is enabled | ||||||
|     //if (!MusicIsPlaying())  |  | ||||||
|     //PlayCurrentMusic(); |  | ||||||
|      |      | ||||||
|     currentTime = glfwGetTime(); |     currentTime = glfwGetTime(); | ||||||
|     drawTime = currentTime - previousTime; |     drawTime = currentTime - previousTime; | ||||||
| @@ -748,4 +745,6 @@ static void TakeScreenshot() | |||||||
|     free(imgData); |     free(imgData); | ||||||
|  |  | ||||||
|     shotNum++; |     shotNum++; | ||||||
|  |      | ||||||
|  |     TraceLog(INFO, "[%s] Screenshot taken!", buffer); | ||||||
| } | } | ||||||
							
								
								
									
										627
									
								
								src/models.c
									
									
									
									
									
								
							
							
						
						
									
										627
									
								
								src/models.c
									
									
									
									
									
								
							| @@ -25,9 +25,9 @@ | |||||||
|  |  | ||||||
| #include "raylib.h" | #include "raylib.h" | ||||||
|  |  | ||||||
| #include <GL/gl.h>       // OpenGL functions |  | ||||||
| #include <stdio.h>       // Standard input/output functions, used to read model files data | #include <stdio.h>       // Standard input/output functions, used to read model files data | ||||||
| #include <stdlib.h>      // Declares malloc() and free() for memory management | #include <stdlib.h>      // Declares malloc() and free() for memory management | ||||||
|  | #include <string.h>      // Required for strcmp() | ||||||
| #include <math.h>        // Used for sin, cos, tan | #include <math.h>        // Used for sin, cos, tan | ||||||
|  |  | ||||||
| #include "raymath.h"     // Required for data type Matrix and Matrix functions | #include "raymath.h"     // Required for data type Matrix and Matrix functions | ||||||
| @@ -52,6 +52,7 @@ | |||||||
| // Module specific Functions Declaration | // Module specific Functions Declaration | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| static float GetHeightValue(Color pixel); | static float GetHeightValue(Color pixel); | ||||||
|  | static VertexData LoadOBJ(const char *fileName); | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Module Functions Definition | // Module Functions Definition | ||||||
| @@ -67,9 +68,9 @@ void DrawCube(Vector3 position, float width, float height, float lenght, Color c | |||||||
|  |  | ||||||
|     rlPushMatrix(); |     rlPushMatrix(); | ||||||
|  |  | ||||||
|         // NOTE: Be careful! Function order matters (scale, translate, rotate) |         // NOTE: Be careful! Function order matters (rotate -> scale -> translate) | ||||||
|         //rlScalef(2.0f, 2.0f, 2.0f); |  | ||||||
|         //rlTranslatef(0.0f, 0.0f, 0.0f); |         //rlTranslatef(0.0f, 0.0f, 0.0f); | ||||||
|  |         //rlScalef(2.0f, 2.0f, 2.0f); | ||||||
|         //rlRotatef(45, 0, 1, 0); |         //rlRotatef(45, 0, 1, 0); | ||||||
|      |      | ||||||
|         rlBegin(RL_TRIANGLES); |         rlBegin(RL_TRIANGLES); | ||||||
| @@ -215,9 +216,9 @@ void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float hei | |||||||
|     float y = position.y; |     float y = position.y; | ||||||
|     float z = position.z; |     float z = position.z; | ||||||
|  |  | ||||||
|     rlEnableTexture(texture.glId); |     rlEnableTexture(texture.id); | ||||||
|      |      | ||||||
|     rlPushMatrix();       |     //rlPushMatrix();       | ||||||
|         // NOTE: Be careful! Function order matters (scale, translate, rotate) |         // NOTE: Be careful! Function order matters (scale, translate, rotate) | ||||||
|         //rlScalef(2.0f, 2.0f, 2.0f); |         //rlScalef(2.0f, 2.0f, 2.0f); | ||||||
|         //rlTranslatef(2.0f, 0.0f, 0.0f); |         //rlTranslatef(2.0f, 0.0f, 0.0f); | ||||||
| @@ -262,7 +263,7 @@ void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float hei | |||||||
|             rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z+lenght/2);  // Top Right Of The Texture and Quad |             rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z+lenght/2);  // Top Right Of The Texture and Quad | ||||||
|             rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z-lenght/2);  // Top Left Of The Texture and Quad |             rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z-lenght/2);  // Top Left Of The Texture and Quad | ||||||
|         rlEnd(); |         rlEnd(); | ||||||
|     rlPopMatrix(); |     //rlPopMatrix(); | ||||||
|      |      | ||||||
|     rlDisableTexture(); |     rlDisableTexture(); | ||||||
| } | } | ||||||
| @@ -278,8 +279,8 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color | |||||||
| { | { | ||||||
|     rlPushMatrix(); |     rlPushMatrix(); | ||||||
|         rlTranslatef(centerPos.x, centerPos.y, centerPos.z); |         rlTranslatef(centerPos.x, centerPos.y, centerPos.z); | ||||||
|         //rlRotatef(rotation, 0, 1, 0); |  | ||||||
|         rlScalef(radius, radius, radius); |         rlScalef(radius, radius, radius); | ||||||
|  |         //rlRotatef(rotation, 0, 1, 0); | ||||||
|          |          | ||||||
|         rlBegin(RL_TRIANGLES); |         rlBegin(RL_TRIANGLES); | ||||||
|             rlColor4ub(color.r, color.g, color.b, color.a); |             rlColor4ub(color.r, color.g, color.b, color.a); | ||||||
| @@ -317,9 +318,9 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color | |||||||
| void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color) | void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color) | ||||||
| { | { | ||||||
|     rlPushMatrix(); |     rlPushMatrix(); | ||||||
|         rlTranslatef(centerPos.x, centerPos.y, centerPos.z); |         //rlTranslatef(centerPos.x, centerPos.y, centerPos.z); | ||||||
|         //rlRotatef(rotation, 0, 1, 0); |  | ||||||
|         rlScalef(radius, radius, radius); |         rlScalef(radius, radius, radius); | ||||||
|  |         //rlRotatef(rotation, 0, 1, 0); | ||||||
|          |          | ||||||
|         rlBegin(RL_LINES); |         rlBegin(RL_LINES); | ||||||
|             rlColor4ub(color.r, color.g, color.b, color.a); |             rlColor4ub(color.r, color.g, color.b, color.a); | ||||||
| @@ -447,12 +448,12 @@ void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color) | |||||||
|     // NOTE: Plane is always created on XZ ground and then rotated |     // NOTE: Plane is always created on XZ ground and then rotated | ||||||
|     rlPushMatrix(); |     rlPushMatrix(); | ||||||
|         rlTranslatef(centerPos.x, centerPos.y, centerPos.z); |         rlTranslatef(centerPos.x, centerPos.y, centerPos.z); | ||||||
|  |         rlScalef(size.x, 1.0f, size.y); | ||||||
|          |          | ||||||
|         // TODO: Review multiples rotations Gimbal-Lock... use matrix or quaternions... |         // TODO: Review multiples rotations Gimbal-Lock... use matrix or quaternions... | ||||||
|         rlRotatef(rotation.x, 1, 0, 0); |         rlRotatef(rotation.x, 1, 0, 0); | ||||||
|         rlRotatef(rotation.y, 0, 1, 0); |         rlRotatef(rotation.y, 0, 1, 0); | ||||||
|         rlRotatef(rotation.z, 0, 0, 1); |         rlRotatef(rotation.z, 0, 0, 1); | ||||||
|         rlScalef(size.x, 1.0f, size.y); |  | ||||||
|      |      | ||||||
|         rlBegin(RL_QUADS); |         rlBegin(RL_QUADS); | ||||||
|             rlColor4ub(color.r, color.g, color.b, color.a); |             rlColor4ub(color.r, color.g, color.b, color.a); | ||||||
| @@ -568,14 +569,13 @@ void DrawGizmo(Vector3 position) | |||||||
|     rlPopMatrix(); |     rlPopMatrix(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void DrawGizmoEx(Vector3 position, Vector3 rot, float scale, bool orbits) | void DrawGizmoEx(Vector3 position, Vector3 rotation, float scale) | ||||||
| {    | {    | ||||||
|     static float rotation = 0; |  | ||||||
|     // NOTE: RGB = XYZ |     // NOTE: RGB = XYZ | ||||||
|     rlPushMatrix(); |     rlPushMatrix(); | ||||||
|         rlTranslatef(position.x, position.y, position.z); |         rlTranslatef(position.x, position.y, position.z); | ||||||
|         rlRotatef(rotation, 0, 1, 0); |  | ||||||
|         rlScalef(scale, scale, scale); |         rlScalef(scale, scale, scale); | ||||||
|  |         rlRotatef(rotation.y, 0, 1, 0); | ||||||
|  |  | ||||||
|         rlBegin(RL_LINES); |         rlBegin(RL_LINES); | ||||||
|             // X Axis |             // X Axis | ||||||
| @@ -612,8 +612,6 @@ void DrawGizmoEx(Vector3 position, Vector3 rot, float scale, bool orbits) | |||||||
|             rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x - .1, position.y, position.z - .9); |             rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x - .1, position.y, position.z - .9); | ||||||
|              |              | ||||||
|             // Extra |             // Extra | ||||||
|             if(orbits) |  | ||||||
|             { |  | ||||||
|             int n = 3; |             int n = 3; | ||||||
|              |              | ||||||
|             // X Axis |             // X Axis | ||||||
| @@ -636,19 +634,305 @@ void DrawGizmoEx(Vector3 position, Vector3 rot, float scale, bool orbits) | |||||||
|                 rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + sin(DEG2RAD*i) * scale/n, position.y + cos(DEG2RAD*i) * scale/n, 0); |                 rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + sin(DEG2RAD*i) * scale/n, position.y + cos(DEG2RAD*i) * scale/n, 0); | ||||||
|                 rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + sin(DEG2RAD*(i+6)) * scale/n, position.y + cos(DEG2RAD*(i+6)) * scale/n, 0); |                 rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + sin(DEG2RAD*(i+6)) * scale/n, position.y + cos(DEG2RAD*(i+6)) * scale/n, 0); | ||||||
|             } |             } | ||||||
|             } |  | ||||||
|         rlEnd(); |         rlEnd(); | ||||||
|     rlPopMatrix(); |     rlPopMatrix(); | ||||||
|      |  | ||||||
|     rotation += 0.1f; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Load a 3d model (.OBJ) | // Load a 3d model | ||||||
| // TODO: Add comments explaining this function process |  | ||||||
| Model LoadModel(const char *fileName)                                     | Model LoadModel(const char *fileName)                                     | ||||||
| { | { | ||||||
|     VertexData vData; |     VertexData vData; | ||||||
|      |      | ||||||
|  |     if (strcmp(GetExtension(fileName),"obj") == 0) vData = LoadOBJ(fileName); | ||||||
|  |     else TraceLog(WARNING, "[%s] Model extension not recognized, it can't be loaded", fileName);  | ||||||
|  |  | ||||||
|  |     Model model; | ||||||
|  |  | ||||||
|  |     model.mesh = vData;                     // Model mesh is vertex data | ||||||
|  |     model.textureId = 0; | ||||||
|  |      | ||||||
|  | #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | ||||||
|  |     model.vaoId = rlglLoadModel(vData);     // Use loaded data to generate VAO | ||||||
|  |     model.textureId = 1;                    // Default whiteTexture | ||||||
|  |  | ||||||
|  |     // Now that vertex data is uploaded to GPU, we can free arrays | ||||||
|  |     //free(vData.vertices); | ||||||
|  |     //free(vData.texcoords); | ||||||
|  |     //free(vData.normals); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     return model; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Load a heightmap image as a 3d model | ||||||
|  | Model LoadHeightmap(Image heightmap, float maxHeight) | ||||||
|  | { | ||||||
|  |     VertexData vData; | ||||||
|  |  | ||||||
|  |     int mapX = heightmap.width; | ||||||
|  |     int mapZ = heightmap.height; | ||||||
|  |      | ||||||
|  |     // NOTE: One vertex per pixel | ||||||
|  |     // TODO: Consider resolution when generating model data? | ||||||
|  |     int numTriangles = (mapX-1)*(mapZ-1)*2;    // One quad every four pixels | ||||||
|  |    | ||||||
|  |     vData.vertexCount = numTriangles*3; | ||||||
|  |  | ||||||
|  |     vData.vertices = (float *)malloc(vData.vertexCount * 3 * sizeof(float)); | ||||||
|  |     vData.normals = (float *)malloc(vData.vertexCount * 3 * sizeof(float)); | ||||||
|  |     vData.texcoords = (float *)malloc(vData.vertexCount * 2 * sizeof(float)); | ||||||
|  |      | ||||||
|  |     int vCounter = 0;       // Used to count vertices float by float | ||||||
|  |     int tcCounter = 0;      // Used to count texcoords float by float | ||||||
|  |     int nCounter = 0;       // Used to count normals float by float | ||||||
|  |      | ||||||
|  |     int trisCounter = 0; | ||||||
|  |      | ||||||
|  |     float scaleFactor = maxHeight/255;    // TODO: Review scaleFactor calculation | ||||||
|  |  | ||||||
|  |     for(int z = 0; z < mapZ-1; z++) | ||||||
|  |     { | ||||||
|  |         for(int x = 0; x < mapX-1; x++) | ||||||
|  |         { | ||||||
|  |             // Fill vertices array with data | ||||||
|  |             //---------------------------------------------------------- | ||||||
|  |              | ||||||
|  |             // one triangle - 3 vertex | ||||||
|  |             vData.vertices[vCounter] = x; | ||||||
|  |             vData.vertices[vCounter + 1] = GetHeightValue(heightmap.pixels[x + z*mapX])*scaleFactor; | ||||||
|  |             vData.vertices[vCounter + 2] = z; | ||||||
|  |              | ||||||
|  |             vData.vertices[vCounter + 3] = x; | ||||||
|  |             vData.vertices[vCounter + 4] = GetHeightValue(heightmap.pixels[x + (z+1)*mapX])*scaleFactor; | ||||||
|  |             vData.vertices[vCounter + 5] = z+1; | ||||||
|  |              | ||||||
|  |             vData.vertices[vCounter + 6] = x+1; | ||||||
|  |             vData.vertices[vCounter + 7] = GetHeightValue(heightmap.pixels[(x+1) + z*mapX])*scaleFactor; | ||||||
|  |             vData.vertices[vCounter + 8] = z; | ||||||
|  |              | ||||||
|  |             // another triangle - 3 vertex | ||||||
|  |             vData.vertices[vCounter + 9] = vData.vertices[vCounter + 6]; | ||||||
|  |             vData.vertices[vCounter + 10] = vData.vertices[vCounter + 7]; | ||||||
|  |             vData.vertices[vCounter + 11] = vData.vertices[vCounter + 8]; | ||||||
|  |              | ||||||
|  |             vData.vertices[vCounter + 12] = vData.vertices[vCounter + 3]; | ||||||
|  |             vData.vertices[vCounter + 13] = vData.vertices[vCounter + 4]; | ||||||
|  |             vData.vertices[vCounter + 14] = vData.vertices[vCounter + 5]; | ||||||
|  |              | ||||||
|  |             vData.vertices[vCounter + 15] = x+1; | ||||||
|  |             vData.vertices[vCounter + 16] = GetHeightValue(heightmap.pixels[(x+1) + (z+1)*mapX])*scaleFactor; | ||||||
|  |             vData.vertices[vCounter + 17] = z+1; | ||||||
|  |             vCounter += 18;     // 6 vertex, 18 floats | ||||||
|  |              | ||||||
|  |             // Fill texcoords array with data | ||||||
|  |             //-------------------------------------------------------------- | ||||||
|  |             vData.texcoords[tcCounter] = (float)x / (mapX-1); | ||||||
|  |             vData.texcoords[tcCounter + 1] = (float)z / (mapZ-1); | ||||||
|  |              | ||||||
|  |             vData.texcoords[tcCounter + 2] = (float)x / (mapX-1); | ||||||
|  |             vData.texcoords[tcCounter + 3] = (float)(z+1) / (mapZ-1); | ||||||
|  |              | ||||||
|  |             vData.texcoords[tcCounter + 4] = (float)(x+1) / (mapX-1); | ||||||
|  |             vData.texcoords[tcCounter + 5] = (float)z / (mapZ-1); | ||||||
|  |              | ||||||
|  |             vData.texcoords[tcCounter + 6] = vData.texcoords[tcCounter + 4]; | ||||||
|  |             vData.texcoords[tcCounter + 7] = vData.texcoords[tcCounter + 5]; | ||||||
|  |              | ||||||
|  |             vData.texcoords[tcCounter + 8] = vData.texcoords[tcCounter + 2]; | ||||||
|  |             vData.texcoords[tcCounter + 9] = vData.texcoords[tcCounter + 1]; | ||||||
|  |              | ||||||
|  |             vData.texcoords[tcCounter + 10] = (float)(x+1) / (mapX-1); | ||||||
|  |             vData.texcoords[tcCounter + 11] = (float)(z+1) / (mapZ-1); | ||||||
|  |             tcCounter += 12;    // 6 texcoords, 12 floats | ||||||
|  |              | ||||||
|  |             // Fill normals array with data | ||||||
|  |             //-------------------------------------------------------------- | ||||||
|  |             // NOTE: Current Model implementation doe not use normals!  | ||||||
|  |             for (int i = 0; i < 18; i += 3) | ||||||
|  |             { | ||||||
|  |                 vData.normals[nCounter + i] = 0.0f; | ||||||
|  |                 vData.normals[nCounter + i + 1] = 1.0f; | ||||||
|  |                 vData.normals[nCounter + i + 2] = 0.0f; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             // TODO: Calculate normals in an efficient way | ||||||
|  |              | ||||||
|  |             nCounter += 18;     // 6 vertex, 18 floats | ||||||
|  |              | ||||||
|  |             trisCounter += 2; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct | ||||||
|  |  | ||||||
|  |     Model model; | ||||||
|  |  | ||||||
|  |     model.mesh = vData;                     // Model mesh is vertex data | ||||||
|  |     model.textureId = 0; | ||||||
|  |      | ||||||
|  | #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | ||||||
|  |     model.vaoId = rlglLoadModel(vData);     // Use loaded data to generate VAO | ||||||
|  |     model.textureId = 1;                    // Default whiteTexture | ||||||
|  |  | ||||||
|  |     // Now that vertex data is uploaded to GPU, we can free arrays | ||||||
|  |     //free(vData.vertices); | ||||||
|  |     //free(vData.texcoords); | ||||||
|  |     //free(vData.normals); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     return model; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Unload 3d model from memory | ||||||
|  | void UnloadModel(Model model) | ||||||
|  | { | ||||||
|  |     free(model.mesh.vertices); | ||||||
|  |     free(model.mesh.texcoords); | ||||||
|  |     free(model.mesh.normals); | ||||||
|  |  | ||||||
|  | #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | ||||||
|  |     rlDeleteVertexArrays(model.vaoId); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SetModelTexture(Model *model, Texture2D texture) | ||||||
|  | { | ||||||
|  |     if (texture.id <= 0) model->textureId = 1;  // Default white texture (use mesh color) | ||||||
|  |     else model->textureId = texture.id; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Draw a model (with texture if set) | ||||||
|  | void DrawModel(Model model, Vector3 position, float scale, Color tint) | ||||||
|  | { | ||||||
|  |     Vector3 vScale = { scale, scale, scale }; | ||||||
|  |     Vector3 rotation = { 0, 0, 0 }; | ||||||
|  |  | ||||||
|  |     rlglDrawModel(model, position, rotation, vScale, tint, false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Draw a model with extended parameters | ||||||
|  | void DrawModelEx(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color tint) | ||||||
|  | { | ||||||
|  |     rlglDrawModel(model, position, rotation, scale, tint, false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Draw a model wires (with texture if set) | ||||||
|  | void DrawModelWires(Model model, Vector3 position, float scale, Color color) | ||||||
|  | { | ||||||
|  |     Vector3 vScale = { scale, scale, scale }; | ||||||
|  |     Vector3 rotation = { 0, 0, 0 }; | ||||||
|  |  | ||||||
|  |     rlglDrawModel(model, position, rotation, vScale, color, true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Draw a billboard | ||||||
|  | void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint) | ||||||
|  | { | ||||||
|  |     // NOTE: Billboard size will maintain texture aspect ratio, size will be billboard width | ||||||
|  |     Vector2 sizeRatio = { size, size * (float)texture.height/texture.width }; | ||||||
|  |      | ||||||
|  |     Matrix viewMatrix = MatrixLookAt(camera.position, camera.target, camera.up); | ||||||
|  |     MatrixTranspose(&viewMatrix); | ||||||
|  |      | ||||||
|  |     Vector3 right = { viewMatrix.m0, viewMatrix.m4, viewMatrix.m8 }; | ||||||
|  |     Vector3 up = { viewMatrix.m1, viewMatrix.m5, viewMatrix.m9 }; | ||||||
|  | /*     | ||||||
|  |     d-------c | ||||||
|  |     |       | | ||||||
|  |     |   *   | | ||||||
|  |     |       | | ||||||
|  |     a-------b | ||||||
|  | */   | ||||||
|  |     VectorScale(&right, sizeRatio.x/2); | ||||||
|  |     VectorScale(&up, sizeRatio.y/2); | ||||||
|  |      | ||||||
|  |     Vector3 p1 = VectorAdd(right, up); | ||||||
|  |     Vector3 p2 = VectorSubtract(right, up); | ||||||
|  |  | ||||||
|  |     Vector3 a = VectorSubtract(center, p2); | ||||||
|  |     Vector3 b = VectorAdd(center, p1); | ||||||
|  |     Vector3 c = VectorAdd(center, p2); | ||||||
|  |     Vector3 d = VectorSubtract(center, p1); | ||||||
|  |      | ||||||
|  |     rlEnableTexture(texture.id); | ||||||
|  |        | ||||||
|  |     rlBegin(RL_QUADS); | ||||||
|  |         rlColor4ub(tint.r, tint.g, tint.b, tint.a); | ||||||
|  |         rlNormal3f(0.0f, 1.0f, 0.0f);  | ||||||
|  |         rlTexCoord2f(0.0f, 0.0f); rlVertex3f(a.x, a.y, a.z); | ||||||
|  |         rlTexCoord2f(1.0f, 0.0f); rlVertex3f(b.x, b.y, b.z); | ||||||
|  |         rlTexCoord2f(1.0f, 1.0f); rlVertex3f(c.x, c.y, c.z); | ||||||
|  |         rlTexCoord2f(0.0f, 1.0f); rlVertex3f(d.x, d.y, d.z); | ||||||
|  |     rlEnd(); | ||||||
|  |      | ||||||
|  |     rlDisableTexture(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Draw a billboard (part of a texture defined by a rectangle) | ||||||
|  | void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint) | ||||||
|  | { | ||||||
|  |     // NOTE: Billboard size will maintain sourceRec aspect ratio, size will represent billboard width | ||||||
|  |     Vector2 sizeRatio = { size, size * (float)sourceRec.height/sourceRec.width }; | ||||||
|  |  | ||||||
|  |     Matrix viewMatrix = MatrixLookAt(camera.position, camera.target, camera.up); | ||||||
|  |     MatrixTranspose(&viewMatrix); | ||||||
|  |      | ||||||
|  |     Vector3 right = { viewMatrix.m0, viewMatrix.m4, viewMatrix.m8 }; | ||||||
|  |     Vector3 up = { viewMatrix.m1, viewMatrix.m5, viewMatrix.m9 }; | ||||||
|  | /*     | ||||||
|  |     d-------c | ||||||
|  |     |       | | ||||||
|  |     |   *   | | ||||||
|  |     |       | | ||||||
|  |     a-------b | ||||||
|  | */   | ||||||
|  |     VectorScale(&right, sizeRatio.x/2); | ||||||
|  |     VectorScale(&up, sizeRatio.y/2); | ||||||
|  |  | ||||||
|  |     Vector3 p1 = VectorAdd(right, up); | ||||||
|  |     Vector3 p2 = VectorSubtract(right, up); | ||||||
|  |  | ||||||
|  |     Vector3 a = VectorSubtract(center, p2); | ||||||
|  |     Vector3 b = VectorAdd(center, p1); | ||||||
|  |     Vector3 c = VectorAdd(center, p2); | ||||||
|  |     Vector3 d = VectorSubtract(center, p1); | ||||||
|  |      | ||||||
|  |     rlEnableTexture(texture.id); | ||||||
|  |      | ||||||
|  |     rlBegin(RL_QUADS); | ||||||
|  |         rlColor4ub(tint.r, tint.g, tint.b, tint.a); | ||||||
|  |          | ||||||
|  |         // Bottom-left corner for texture and quad | ||||||
|  |         rlTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height);  | ||||||
|  |         rlVertex3f(a.x, a.y, a.z); | ||||||
|  |          | ||||||
|  |         // Bottom-right corner for texture and quad | ||||||
|  |         rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height); | ||||||
|  |         rlVertex3f(b.x, b.y, b.z); | ||||||
|  |          | ||||||
|  |         // Top-right corner for texture and quad | ||||||
|  |         rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);  | ||||||
|  |         rlVertex3f(c.x, c.y, c.z); | ||||||
|  |          | ||||||
|  |         // Top-left corner for texture and quad | ||||||
|  |         rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); | ||||||
|  |         rlVertex3f(d.x, d.y, d.z); | ||||||
|  |     rlEnd(); | ||||||
|  |      | ||||||
|  |     rlDisableTexture(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Get current vertex y altitude (proportional to pixel colors in grayscale) | ||||||
|  | static float GetHeightValue(Color pixel) | ||||||
|  | { | ||||||
|  |     return (((float)pixel.r + (float)pixel.g + (float)pixel.b)/3); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Load OBJ mesh data | ||||||
|  | static VertexData LoadOBJ(const char *fileName) | ||||||
|  | { | ||||||
|  |     VertexData vData; | ||||||
|  |      | ||||||
|     char dataType; |     char dataType; | ||||||
|     char comments[200]; |     char comments[200]; | ||||||
|      |      | ||||||
| @@ -661,6 +945,8 @@ Model LoadModel(const char *fileName) | |||||||
|  |  | ||||||
|     objFile = fopen(fileName, "rt"); |     objFile = fopen(fileName, "rt"); | ||||||
|      |      | ||||||
|  |     // First pass over all file to get numVertex, numNormals, numTexCoords, numTriangles | ||||||
|  |     // NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition) | ||||||
|     while(!feof(objFile)) |     while(!feof(objFile)) | ||||||
|     { |     { | ||||||
|         fscanf(objFile, "%c", &dataType); |         fscanf(objFile, "%c", &dataType); | ||||||
| @@ -671,6 +957,13 @@ Model LoadModel(const char *fileName) | |||||||
|             { |             { | ||||||
|                 fgets(comments, 200, objFile);                 |                 fgets(comments, 200, objFile);                 | ||||||
|             } break; |             } break; | ||||||
|  |             case 'o':         // New object | ||||||
|  |             { | ||||||
|  |                 // TODO: Read multiple objects, we need to know numMeshes + verticesPerMesh | ||||||
|  |                  | ||||||
|  |                 // NOTE: One OBJ file can contain multible meshes defined, one after every 'o' | ||||||
|  |                  | ||||||
|  |             } break; | ||||||
|             case 'v': |             case 'v': | ||||||
|             { |             { | ||||||
|                 fscanf(objFile, "%c", &dataType); |                 fscanf(objFile, "%c", &dataType); | ||||||
| @@ -753,15 +1046,18 @@ Model LoadModel(const char *fileName) | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     Vector3 midVertices[numVertex]; |     // Once we know the number of vertices to store, we create required arrays | ||||||
|     Vector3 midNormals[numNormals]; |     Vector3 *midVertices = (Vector3 *)malloc(numVertex*sizeof(Vector3)); | ||||||
|     Vector2 midTexCoords[numTexCoords]; |     Vector3 *midNormals = (Vector3 *)malloc(numNormals*sizeof(Vector3)); | ||||||
|  |     Vector2 *midTexCoords = (Vector2 *)malloc(numTexCoords*sizeof(Vector2)); | ||||||
|      |      | ||||||
|     vData.numVertices = numTriangles*3; |     vData.vertexCount = numTriangles*3; | ||||||
|      |      | ||||||
|     vData.vertices = (float *)malloc(vData.numVertices * 3 * sizeof(float)); |     // Additional arrays to store vertex data as floats | ||||||
|     vData.texcoords = (float *)malloc(vData.numVertices * 2 * sizeof(float)); |     vData.vertices = (float *)malloc(vData.vertexCount * 3 * sizeof(float)); | ||||||
|     vData.normals = (float *)malloc(vData.numVertices * 3 * sizeof(float)); |     vData.texcoords = (float *)malloc(vData.vertexCount * 2 * sizeof(float)); | ||||||
|  |     vData.normals = (float *)malloc(vData.vertexCount * 3 * sizeof(float)); | ||||||
|  |     vData.colors = (float *)malloc(vData.vertexCount * 4 * sizeof(float)); | ||||||
|      |      | ||||||
|     int countVertex = 0; |     int countVertex = 0; | ||||||
|     int countNormals = 0; |     int countNormals = 0; | ||||||
| @@ -771,8 +1067,9 @@ Model LoadModel(const char *fileName) | |||||||
|     int tcCounter = 0;      // Used to count texcoords float by float |     int tcCounter = 0;      // Used to count texcoords float by float | ||||||
|     int nCounter = 0;       // Used to count normals float by float |     int nCounter = 0;       // Used to count normals float by float | ||||||
|      |      | ||||||
|     rewind(objFile); |     rewind(objFile);        // Return to the beginning of the file, to read again | ||||||
|      |      | ||||||
|  |     // Reading again file to get vertex data | ||||||
|     while(!feof(objFile)) |     while(!feof(objFile)) | ||||||
|     { |     { | ||||||
|         fscanf(objFile, "%c", &dataType); |         fscanf(objFile, "%c", &dataType); | ||||||
| @@ -872,274 +1169,16 @@ Model LoadModel(const char *fileName) | |||||||
|      |      | ||||||
|     fclose(objFile); |     fclose(objFile); | ||||||
|      |      | ||||||
|     // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct |     // NOTE: We set all vertex colors to white | ||||||
|  |     for (int i = 0; i < (4*vData.vertexCount); i++) vData.colors[i] = 1.0f; | ||||||
|      |      | ||||||
|     Model model; |     // Now we can free temp mid* arrays | ||||||
|  |     free(midVertices); | ||||||
| #ifdef USE_OPENGL_11 |     free(midNormals); | ||||||
|     model.data = vData;      // model data is vertex data   |     free(midTexCoords); | ||||||
| #else    |  | ||||||
|     model.vaoId = rlglLoadModel(vData);     // Use loaded data to generate VAO |  | ||||||
|      |  | ||||||
|     // Now that vertex data is uploaded to GPU, we can free arrays |  | ||||||
|     free(vData.vertices); |  | ||||||
|     free(vData.texcoords); |  | ||||||
|     free(vData.normals); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     return model; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Load a heightmap image as a 3d model |  | ||||||
| Model LoadHeightmap(Image heightmap, float maxHeight) |  | ||||||
| { |  | ||||||
|     VertexData vData; |  | ||||||
|  |  | ||||||
|     int mapX = heightmap.width; |  | ||||||
|     int mapZ = heightmap.height; |  | ||||||
|      |  | ||||||
|     // NOTE: One vertex per pixel |  | ||||||
|     // TODO: Consider resolution when generating model data? |  | ||||||
|     int numTriangles = (mapX-1)*(mapZ-1)*2;    // One quad every four pixels |  | ||||||
|    |  | ||||||
|     vData.numVertices = numTriangles*3; |  | ||||||
|  |  | ||||||
|     vData.vertices = (float *)malloc(vData.numVertices * 3 * sizeof(float)); |  | ||||||
|     vData.normals = (float *)malloc(vData.numVertices * 3 * sizeof(float)); |  | ||||||
|     vData.texcoords = (float *)malloc(vData.numVertices * 2 * sizeof(float)); |  | ||||||
|      |  | ||||||
|     int vCounter = 0;       // Used to count vertices float by float |  | ||||||
|     int tcCounter = 0;      // Used to count texcoords float by float |  | ||||||
|     int nCounter = 0;       // Used to count normals float by float |  | ||||||
|      |  | ||||||
|     int trisCounter = 0; |  | ||||||
|      |  | ||||||
|     float scaleFactor = maxHeight/255;    // TODO: Review scaleFactor calculation |  | ||||||
|  |  | ||||||
|     for(int z = 0; z < mapZ-1; z++) |  | ||||||
|     { |  | ||||||
|         for(int x = 0; x < mapX-1; x++) |  | ||||||
|         { |  | ||||||
|             // Fill vertices array with data |  | ||||||
|             //---------------------------------------------------------- |  | ||||||
|              |  | ||||||
|             // one triangle - 3 vertex |  | ||||||
|             vData.vertices[vCounter] = x; |  | ||||||
|             vData.vertices[vCounter + 1] = GetHeightValue(heightmap.pixels[x + z*mapX])*scaleFactor; |  | ||||||
|             vData.vertices[vCounter + 2] = z; |  | ||||||
|              |  | ||||||
|             vData.vertices[vCounter + 3] = x; |  | ||||||
|             vData.vertices[vCounter + 4] = GetHeightValue(heightmap.pixels[x + (z+1)*mapX])*scaleFactor; |  | ||||||
|             vData.vertices[vCounter + 5] = z+1; |  | ||||||
|              |  | ||||||
|             vData.vertices[vCounter + 6] = x+1; |  | ||||||
|             vData.vertices[vCounter + 7] = GetHeightValue(heightmap.pixels[(x+1) + z*mapX])*scaleFactor; |  | ||||||
|             vData.vertices[vCounter + 8] = z; |  | ||||||
|              |  | ||||||
|             // another triangle - 3 vertex |  | ||||||
|             vData.vertices[vCounter + 9] = vData.vertices[vCounter + 6]; |  | ||||||
|             vData.vertices[vCounter + 10] = vData.vertices[vCounter + 7]; |  | ||||||
|             vData.vertices[vCounter + 11] = vData.vertices[vCounter + 8]; |  | ||||||
|              |  | ||||||
|             vData.vertices[vCounter + 12] = vData.vertices[vCounter + 3]; |  | ||||||
|             vData.vertices[vCounter + 13] = vData.vertices[vCounter + 4]; |  | ||||||
|             vData.vertices[vCounter + 14] = vData.vertices[vCounter + 5]; |  | ||||||
|              |  | ||||||
|             vData.vertices[vCounter + 15] = x+1; |  | ||||||
|             vData.vertices[vCounter + 16] = GetHeightValue(heightmap.pixels[(x+1) + (z+1)*mapX])*scaleFactor; |  | ||||||
|             vData.vertices[vCounter + 17] = z+1; |  | ||||||
|             vCounter += 18;     // 6 vertex, 18 floats |  | ||||||
|              |  | ||||||
|             // Fill texcoords array with data |  | ||||||
|             //-------------------------------------------------------------- |  | ||||||
|             vData.texcoords[tcCounter] = (float)x / (mapX-1); |  | ||||||
|             vData.texcoords[tcCounter + 1] = (float)z / (mapZ-1); |  | ||||||
|              |  | ||||||
|             vData.texcoords[tcCounter + 2] = (float)x / (mapX-1); |  | ||||||
|             vData.texcoords[tcCounter + 3] = (float)(z+1) / (mapZ-1); |  | ||||||
|              |  | ||||||
|             vData.texcoords[tcCounter + 4] = (float)(x+1) / (mapX-1); |  | ||||||
|             vData.texcoords[tcCounter + 5] = (float)z / (mapZ-1); |  | ||||||
|              |  | ||||||
|             vData.texcoords[tcCounter + 6] = vData.texcoords[tcCounter + 4]; |  | ||||||
|             vData.texcoords[tcCounter + 7] = vData.texcoords[tcCounter + 5]; |  | ||||||
|              |  | ||||||
|             vData.texcoords[tcCounter + 8] = vData.texcoords[tcCounter + 2]; |  | ||||||
|             vData.texcoords[tcCounter + 9] = vData.texcoords[tcCounter + 1]; |  | ||||||
|              |  | ||||||
|             vData.texcoords[tcCounter + 10] = (float)(x+1) / (mapX-1); |  | ||||||
|             vData.texcoords[tcCounter + 11] = (float)(z+1) / (mapZ-1); |  | ||||||
|             tcCounter += 12;    // 6 texcoords, 12 floats |  | ||||||
|              |  | ||||||
|             // Fill normals array with data |  | ||||||
|             //-------------------------------------------------------------- |  | ||||||
|             // TODO: Review normals calculation |  | ||||||
|             for (int i = 0; i < 18; i += 3) |  | ||||||
|             { |  | ||||||
|                 vData.normals[nCounter + i] = 0.0f; |  | ||||||
|                 vData.normals[nCounter + i + 1] = 1.0f; |  | ||||||
|                 vData.normals[nCounter + i + 2] = 0.0f; |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|             nCounter += 18;     // 6 vertex, 18 floats |  | ||||||
|              |  | ||||||
|             trisCounter += 2; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|      |      | ||||||
|     // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct |     // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct | ||||||
|  |     TraceLog(INFO, "[%s] Model loaded successfully in RAM (CPU)", fileName); | ||||||
|      |      | ||||||
|     Model model; |     return vData; | ||||||
|  |  | ||||||
| #ifdef USE_OPENGL_11 |  | ||||||
|     model.data = vData;      // model data is vertex data   |  | ||||||
| #else    |  | ||||||
|     model.vaoId = rlglLoadModel(vData);     // Use loaded data to generate VAO |  | ||||||
|  |  | ||||||
|     // Now that vertex data is uploaded to GPU, we can free arrays |  | ||||||
|     free(vData.vertices); |  | ||||||
|     free(vData.texcoords); |  | ||||||
|     free(vData.normals); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     return model; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Unload 3d model from memory |  | ||||||
| void UnloadModel(Model model) |  | ||||||
| { |  | ||||||
| #ifdef USE_OPENGL_11 |  | ||||||
|     free(model.data.vertices); |  | ||||||
|     free(model.data.texcoords); |  | ||||||
|     free(model.data.normals); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) |  | ||||||
|     rlDeleteVertexArrays(model.vaoId); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Draw a model |  | ||||||
| void DrawModel(Model model, Vector3 position, float scale, Color color) |  | ||||||
| { |  | ||||||
|     rlglDrawModel(model, position, scale, false); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Draw a textured model |  | ||||||
| void DrawModelEx(Model model, Texture2D texture, Vector3 position, float scale, Color tint) |  | ||||||
| { |  | ||||||
|     rlEnableTexture(texture.glId); |  | ||||||
|      |  | ||||||
|     DrawModel(model, position, scale, tint); |  | ||||||
|      |  | ||||||
|     rlDisableTexture(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Draw a model wires |  | ||||||
| void DrawModelWires(Model model, Vector3 position, float scale, Color color) |  | ||||||
| { |  | ||||||
|     rlglDrawModel(model, position, scale, true); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Draw a billboard |  | ||||||
| void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint) |  | ||||||
| { |  | ||||||
|     // NOTE: Billboard size will maintain texture aspect ratio, size will be billboard width |  | ||||||
|     Vector2 sizeRatio = { size, size * (float)texture.height/texture.width }; |  | ||||||
|      |  | ||||||
|     Matrix viewMatrix = MatrixLookAt(camera.position, camera.target, camera.up); |  | ||||||
|     MatrixTranspose(&viewMatrix); |  | ||||||
|      |  | ||||||
|     Vector3 right = { viewMatrix.m0, viewMatrix.m4, viewMatrix.m8 }; |  | ||||||
|     Vector3 up = { viewMatrix.m1, viewMatrix.m5, viewMatrix.m9 }; |  | ||||||
| /*     |  | ||||||
|     d-------c |  | ||||||
|     |       | |  | ||||||
|     |   *   | |  | ||||||
|     |       | |  | ||||||
|     a-------b |  | ||||||
| */   |  | ||||||
|     VectorScale(&right, sizeRatio.x/2); |  | ||||||
|     VectorScale(&up, sizeRatio.y/2); |  | ||||||
|      |  | ||||||
|     Vector3 p1 = VectorAdd(right, up); |  | ||||||
|     Vector3 p2 = VectorSubtract(right, up); |  | ||||||
|  |  | ||||||
|     Vector3 a = VectorSubtract(center, p2); |  | ||||||
|     Vector3 b = VectorAdd(center, p1); |  | ||||||
|     Vector3 c = VectorAdd(center, p2); |  | ||||||
|     Vector3 d = VectorSubtract(center, p1); |  | ||||||
|      |  | ||||||
|     rlEnableTexture(texture.glId); |  | ||||||
|        |  | ||||||
|     rlBegin(RL_QUADS); |  | ||||||
|         rlColor4ub(tint.r, tint.g, tint.b, tint.a); |  | ||||||
|         rlNormal3f(0.0f, 1.0f, 0.0f);  |  | ||||||
|         rlTexCoord2f(0.0f, 0.0f); rlVertex3f(a.x, a.y, a.z); |  | ||||||
|         rlTexCoord2f(1.0f, 0.0f); rlVertex3f(b.x, b.y, b.z); |  | ||||||
|         rlTexCoord2f(1.0f, 1.0f); rlVertex3f(c.x, c.y, c.z); |  | ||||||
|         rlTexCoord2f(0.0f, 1.0f); rlVertex3f(d.x, d.y, d.z); |  | ||||||
|     rlEnd(); |  | ||||||
|      |  | ||||||
|     rlDisableTexture(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Draw a billboard (part of a texture defined by a rectangle) |  | ||||||
| void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint) |  | ||||||
| { |  | ||||||
|     // NOTE: Billboard size will maintain sourceRec aspect ratio, size will represent billboard width |  | ||||||
|     Vector2 sizeRatio = { size, size * (float)sourceRec.height/sourceRec.width }; |  | ||||||
|  |  | ||||||
|     Matrix viewMatrix = MatrixLookAt(camera.position, camera.target, camera.up); |  | ||||||
|     MatrixTranspose(&viewMatrix); |  | ||||||
|      |  | ||||||
|     Vector3 right = { viewMatrix.m0, viewMatrix.m4, viewMatrix.m8 }; |  | ||||||
|     Vector3 up = { viewMatrix.m1, viewMatrix.m5, viewMatrix.m9 }; |  | ||||||
| /*     |  | ||||||
|     d-------c |  | ||||||
|     |       | |  | ||||||
|     |   *   | |  | ||||||
|     |       | |  | ||||||
|     a-------b |  | ||||||
| */   |  | ||||||
|     VectorScale(&right, sizeRatio.x/2); |  | ||||||
|     VectorScale(&up, sizeRatio.y/2); |  | ||||||
|  |  | ||||||
|     Vector3 p1 = VectorAdd(right, up); |  | ||||||
|     Vector3 p2 = VectorSubtract(right, up); |  | ||||||
|  |  | ||||||
|     Vector3 a = VectorSubtract(center, p2); |  | ||||||
|     Vector3 b = VectorAdd(center, p1); |  | ||||||
|     Vector3 c = VectorAdd(center, p2); |  | ||||||
|     Vector3 d = VectorSubtract(center, p1); |  | ||||||
|      |  | ||||||
|     rlEnableTexture(texture.glId); |  | ||||||
|      |  | ||||||
|     rlBegin(RL_QUADS); |  | ||||||
|         rlColor4ub(tint.r, tint.g, tint.b, tint.a); |  | ||||||
|          |  | ||||||
|         // Bottom-left corner for texture and quad |  | ||||||
|         rlTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height);  |  | ||||||
|         rlVertex3f(a.x, a.y, a.z); |  | ||||||
|          |  | ||||||
|         // Bottom-right corner for texture and quad |  | ||||||
|         rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height); |  | ||||||
|         rlVertex3f(b.x, b.y, b.z); |  | ||||||
|          |  | ||||||
|         // Top-right corner for texture and quad |  | ||||||
|         rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);  |  | ||||||
|         rlVertex3f(c.x, c.y, c.z); |  | ||||||
|          |  | ||||||
|         // Top-left corner for texture and quad |  | ||||||
|         rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); |  | ||||||
|         rlVertex3f(d.x, d.y, d.z); |  | ||||||
|     rlEnd(); |  | ||||||
|      |  | ||||||
|     rlDisableTexture(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Get current vertex y altitude (proportional to pixel colors in grayscale) |  | ||||||
| static float GetHeightValue(Color pixel) |  | ||||||
| { |  | ||||||
|     return (((float)pixel.r + (float)pixel.g + (float)pixel.b)/3); |  | ||||||
| } | } | ||||||
							
								
								
									
										102
									
								
								src/raylib.h
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								src/raylib.h
									
									
									
									
									
								
							| @@ -10,13 +10,17 @@ | |||||||
| *     Hardware accelerated with OpenGL (1.1, 3.3+ or ES2) | *     Hardware accelerated with OpenGL (1.1, 3.3+ or ES2) | ||||||
| *     Unique OpenGL abstraction layer [rlgl] | *     Unique OpenGL abstraction layer [rlgl] | ||||||
| *     Powerful fonts module with SpriteFonts support | *     Powerful fonts module with SpriteFonts support | ||||||
|  | *     Multiple textures support, including DDS and mipmaps generation | ||||||
| *     Basic 3d support for Shapes, Models, Heightmaps and Billboards | *     Basic 3d support for Shapes, Models, Heightmaps and Billboards | ||||||
| *     Powerful math module for Vector and Matrix operations [raymath] | *     Powerful math module for Vector and Matrix operations [raymath] | ||||||
| *     Audio loading and playing | *     Audio loading and playing with streaming support | ||||||
| *     | *     | ||||||
| *   Used external libs: | *   Used external libs: | ||||||
| *     GLFW3 (www.glfw.org) for window/context management and input | *     GLFW3 (www.glfw.org) for window/context management and input | ||||||
|  | *     GLEW for OpenGL extensions loading (3.3+ and ES2) | ||||||
| *     stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC) | *     stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC) | ||||||
|  | *     stb_image_write (Sean Barret) for image writting (PNG) | ||||||
|  | *     stb_vorbis (Sean Barret) for ogg audio loading | ||||||
| *     OpenAL Soft for audio device/context management | *     OpenAL Soft for audio device/context management | ||||||
| *     tinfl for data decompression (DEFLATE algorithm) | *     tinfl for data decompression (DEFLATE algorithm) | ||||||
| * | * | ||||||
| @@ -25,9 +29,9 @@ | |||||||
| *     32bit Textures - All loaded images are converted automatically to RGBA textures | *     32bit Textures - All loaded images are converted automatically to RGBA textures | ||||||
| *     SpriteFonts - All loaded sprite-font images are converted to RGBA and POT textures | *     SpriteFonts - All loaded sprite-font images are converted to RGBA and POT textures | ||||||
| *     One custom default font is loaded automatically when InitWindow() | *     One custom default font is loaded automatically when InitWindow() | ||||||
| *     If using OpenGL 3.3+, one default shader is loaded automatically (internally defined) | *     If using OpenGL 3.3+ or ES2, one default shader is loaded automatically (internally defined) | ||||||
| * | * | ||||||
| *   -- LICENSE (raylib v1.1, March 2014) -- | *   -- LICENSE (raylib v1.1, April 2014) -- | ||||||
| * | * | ||||||
| *   raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified,  | *   raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified,  | ||||||
| *   BSD-like license that allows static linking with closed source software: | *   BSD-like license that allows static linking with closed source software: | ||||||
| @@ -54,8 +58,6 @@ | |||||||
| #ifndef RAYLIB_H | #ifndef RAYLIB_H | ||||||
| #define RAYLIB_H | #define RAYLIB_H | ||||||
|  |  | ||||||
| #include "stb_vorbis.h" |  | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Some basic Defines | // Some basic Defines | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| @@ -195,11 +197,22 @@ typedef struct Image { | |||||||
| // Texture2D type, bpp always RGBA (32bit) | // Texture2D type, bpp always RGBA (32bit) | ||||||
| // NOTE: Data stored in GPU memory | // NOTE: Data stored in GPU memory | ||||||
| typedef struct Texture2D { | typedef struct Texture2D { | ||||||
|     unsigned int glId; |     unsigned int id;        // OpenGL id | ||||||
|     int width; |     int width; | ||||||
|     int height; |     int height; | ||||||
| } Texture2D; | } Texture2D; | ||||||
|  |  | ||||||
|  | // Character type (one font glyph) | ||||||
|  | // NOTE: Defined in module: text | ||||||
|  | typedef struct Character Character; | ||||||
|  |  | ||||||
|  | // SpriteFont type, includes texture and charSet array data | ||||||
|  | typedef struct SpriteFont { | ||||||
|  |     Texture2D texture; | ||||||
|  |     int numChars; | ||||||
|  |     Character *charSet; | ||||||
|  | } SpriteFont; | ||||||
|  |  | ||||||
| // Camera type, defines a camera position/orientation in 3d space | // Camera type, defines a camera position/orientation in 3d space | ||||||
| typedef struct Camera { | typedef struct Camera { | ||||||
|     Vector3 position; |     Vector3 position; | ||||||
| @@ -207,18 +220,23 @@ typedef struct Camera { | |||||||
|     Vector3 up; |     Vector3 up; | ||||||
| } Camera; | } Camera; | ||||||
|  |  | ||||||
| typedef struct Character Character; | // Vertex data definning a mesh | ||||||
|  | typedef struct { | ||||||
| // SpriteFont type |     int vertexCount; | ||||||
| typedef struct SpriteFont { |     float *vertices;            // 3 components per vertex | ||||||
|     Texture2D texture; |     float *texcoords;           // 2 components per vertex | ||||||
|     int numChars; |     float *normals;             // 3 components per vertex | ||||||
|     Character *charSet; |     float *colors;              // 4 components per vertex | ||||||
| } SpriteFont; | } VertexData; | ||||||
|  |  | ||||||
| // 3d Model type | // 3d Model type | ||||||
| // NOTE: If using OpenGL 1.1 loaded in CPU; if OpenGL 3.3+ loaded in GPU | // NOTE: If using OpenGL 1.1 loaded in CPU (mesh); if OpenGL 3.3+ loaded in GPU (vaoId) | ||||||
| typedef struct Model Model; // Defined in module: rlgl | typedef struct Model { | ||||||
|  |     VertexData mesh; | ||||||
|  |     unsigned int vaoId; | ||||||
|  |     unsigned int textureId; | ||||||
|  |     //Matrix transform; | ||||||
|  | } Model; | ||||||
|  |  | ||||||
| // Sound source type | // Sound source type | ||||||
| typedef struct Sound { | typedef struct Sound { | ||||||
| @@ -226,23 +244,6 @@ typedef struct Sound { | |||||||
|     unsigned int buffer; |     unsigned int buffer; | ||||||
| } Sound; | } Sound; | ||||||
|  |  | ||||||
| typedef struct OggStream OggStream; |  | ||||||
|  |  | ||||||
| // Music type (streamming) |  | ||||||
| typedef struct Music { |  | ||||||
|     stb_vorbis *stream; |  | ||||||
| 	stb_vorbis_info info; |  | ||||||
|      |  | ||||||
|     unsigned int source; |  | ||||||
| 	unsigned int buffers[2]; |  | ||||||
|  |  | ||||||
| 	int format; |  | ||||||
|   |  | ||||||
| 	int bufferSize; |  | ||||||
| 	int totalSamplesLeft; |  | ||||||
| 	bool loop; |  | ||||||
| } Music; |  | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" {            // Prevents name mangling of functions | extern "C" {            // Prevents name mangling of functions | ||||||
| #endif | #endif | ||||||
| @@ -342,7 +343,7 @@ Image LoadImage(const char *fileName); | |||||||
| Image LoadImageFromRES(const char *rresName, int resId);                                           // Load an image from rRES file (raylib Resource) | Image LoadImageFromRES(const char *rresName, int resId);                                           // Load an image from rRES file (raylib Resource) | ||||||
| Texture2D LoadTexture(const char *fileName);                                                       // Load an image as texture into GPU memory | Texture2D LoadTexture(const char *fileName);                                                       // Load an image as texture into GPU memory | ||||||
| Texture2D LoadTextureFromRES(const char *rresName, int resId);                                     // Load an image as texture from rRES file (raylib Resource) | Texture2D LoadTextureFromRES(const char *rresName, int resId);                                     // Load an image as texture from rRES file (raylib Resource) | ||||||
| Texture2D CreateTexture(Image image);                                                              // Create a Texture2D from Image data | Texture2D CreateTexture(Image image, bool genMipmaps);                                             // Create a Texture2D from Image data (and generate mipmaps) | ||||||
| void UnloadImage(Image image);                                                                     // Unload image from CPU memory (RAM) | void UnloadImage(Image image);                                                                     // Unload image from CPU memory (RAM) | ||||||
| void UnloadTexture(Texture2D texture);                                                             // Unload texture from GPU memory | void UnloadTexture(Texture2D texture);                                                             // Unload texture from GPU memory | ||||||
|  |  | ||||||
| @@ -359,6 +360,7 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V | |||||||
| SpriteFont GetDefaultFont();                                                                       // Get the default SpriteFont | SpriteFont GetDefaultFont();                                                                       // Get the default SpriteFont | ||||||
| SpriteFont LoadSpriteFont(const char *fileName);                                                   // Load a SpriteFont image into GPU memory | SpriteFont LoadSpriteFont(const char *fileName);                                                   // Load a SpriteFont image into GPU memory | ||||||
| void UnloadSpriteFont(SpriteFont spriteFont);                                                      // Unload SpriteFont from GPU memory | void UnloadSpriteFont(SpriteFont spriteFont);                                                      // Unload SpriteFont from GPU memory | ||||||
|  |  | ||||||
| void DrawText(const char *text, int posX, int posY, int fontSize, Color color);                    // Draw text (using default font) | void DrawText(const char *text, int posX, int posY, int fontSize, Color color);                    // Draw text (using default font) | ||||||
| void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position,                         // Draw text using SpriteFont and additional parameters | void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position,                         // Draw text using SpriteFont and additional parameters | ||||||
|                 int fontSize, int spacing, Color tint); |                 int fontSize, int spacing, Color tint); | ||||||
| @@ -384,7 +386,7 @@ void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color); | |||||||
| void DrawPlaneEx(Vector3 centerPos, Vector2 size, Vector3 rotation, int slicesX, int slicesZ, Color color); // Draw a plane with divisions | void DrawPlaneEx(Vector3 centerPos, Vector2 size, Vector3 rotation, int slicesX, int slicesZ, Color color); // Draw a plane with divisions | ||||||
| void DrawGrid(int slices, float spacing);                                                          // Draw a grid (centered at (0, 0, 0)) | void DrawGrid(int slices, float spacing);                                                          // Draw a grid (centered at (0, 0, 0)) | ||||||
| void DrawGizmo(Vector3 position);                                                                  // Draw simple gizmo | void DrawGizmo(Vector3 position);                                                                  // Draw simple gizmo | ||||||
| void DrawGizmoEx(Vector3 position, Vector3 rot, float scale, bool orbits);                    // Draw gizmo with extended parameters | void DrawGizmoEx(Vector3 position, Vector3 rotation, float scale);                                 // Draw gizmo with extended parameters | ||||||
| //DrawTorus(), DrawTeapot() are useless... | //DrawTorus(), DrawTeapot() are useless... | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------------ | //------------------------------------------------------------------------------------ | ||||||
| @@ -394,9 +396,12 @@ Model LoadModel(const char *fileName); | |||||||
| //Model LoadModelFromRES(const char *rresName, int resId);                                         // TODO: Load a 3d model from rRES file (raylib Resource) | //Model LoadModelFromRES(const char *rresName, int resId);                                         // TODO: Load a 3d model from rRES file (raylib Resource) | ||||||
| Model LoadHeightmap(Image heightmap, float maxHeight);                                             // Load a heightmap image as a 3d model | Model LoadHeightmap(Image heightmap, float maxHeight);                                             // Load a heightmap image as a 3d model | ||||||
| void UnloadModel(Model model);                                                                     // Unload 3d model from memory | void UnloadModel(Model model);                                                                     // Unload 3d model from memory | ||||||
| void DrawModel(Model model, Vector3 position, float scale, Color color);                           // Draw a model | void SetModelTexture(Model *model, Texture2D texture);                                             // Link a texture to a model | ||||||
| void DrawModelEx(Model model, Texture2D texture, Vector3 position, float scale, Color tint);       // Draw a textured model |  | ||||||
| void DrawModelWires(Model model, Vector3 position, float scale, Color color);                      // Draw a model wires | void DrawModel(Model model, Vector3 position, float scale, Color tint);                            // Draw a model (with texture if set) | ||||||
|  | void DrawModelEx(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color tint);      // Draw a model with extended parameters | ||||||
|  | void DrawModelWires(Model model, Vector3 position, float scale, Color color);                      // Draw a model wires (with texture if set) | ||||||
|  |  | ||||||
| void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint);                         // Draw a billboard texture | void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint);                         // Draw a billboard texture | ||||||
| void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec  | void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec  | ||||||
|  |  | ||||||
| @@ -404,22 +409,25 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec | |||||||
| // Audio Loading and Playing Functions (Module: audio) | // Audio Loading and Playing Functions (Module: audio) | ||||||
| //------------------------------------------------------------------------------------ | //------------------------------------------------------------------------------------ | ||||||
| void InitAudioDevice();                                         // Initialize audio device and context | void InitAudioDevice();                                         // Initialize audio device and context | ||||||
| void CloseAudioDevice();                                        // Close the audio device and context | void CloseAudioDevice();                                        // Close the audio device and context (and music stream) | ||||||
|  |  | ||||||
| Sound LoadSound(char *fileName);                                // Load sound to memory | Sound LoadSound(char *fileName);                                // Load sound to memory | ||||||
| Sound LoadSoundFromRES(const char *rresName, int resId);        // Load sound to memory from rRES file (raylib Resource) | Sound LoadSoundFromRES(const char *rresName, int resId);        // Load sound to memory from rRES file (raylib Resource) | ||||||
| void UnloadSound(Sound sound);                                  // Unload sound | void UnloadSound(Sound sound);                                  // Unload sound | ||||||
| Music LoadMusic(char *fileName); |  | ||||||
| void UnloadMusic(Music music); |  | ||||||
|  |  | ||||||
| void PlaySound(Sound sound);                                    // Play a sound | void PlaySound(Sound sound);                                    // Play a sound | ||||||
| void PauseSound(Sound sound);                                   // Pause a sound | void PauseSound(Sound sound);                                   // Pause a sound | ||||||
| void StopSound(Sound sound);                                    // Stop playing a sound | void StopSound(Sound sound);                                    // Stop playing a sound | ||||||
| bool SoundIsPlaying(Sound sound);                               // Check if a sound is currently playing | bool SoundIsPlaying(Sound sound);                               // Check if a sound is currently playing | ||||||
| void SetVolume(Sound sound, float volume);                      // Set volume for a sound (1.0 is base level) | void SetSoundVolume(Sound sound, float volume);                 // Set volume for a sound (1.0 is max level) | ||||||
| void SetPitch(Sound sound, float pitch);                        // Set pitch for a sound (1.0 is base level) | void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for a sound (1.0 is base level) | ||||||
| void PlayMusic(Music music); |  | ||||||
| void StopMusic(Music music); | void PlayMusicStream(char *fileName);                           // Start music playing (open stream) | ||||||
| bool MusicIsPlaying(); | void StopMusicStream();                                         // Stop music playing (close stream) | ||||||
|  | void PauseMusicStream();                                        // Pause music playing | ||||||
|  | bool MusicIsPlaying();                                          // Check if music is playing | ||||||
|  | void SetMusicVolume(float volume);                              // Set volume for music (1.0 is max level) | ||||||
|  | float GetMusicTimeLength();                                     // Get current music time length (in seconds) | ||||||
|  | float GetMusicTimePlayed();                                     // Get current music time played (in seconds) | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|   | |||||||
| @@ -435,7 +435,7 @@ Matrix MatrixSubstract(Matrix left, Matrix right) | |||||||
| } | } | ||||||
|  |  | ||||||
| // Returns translation matrix | // Returns translation matrix | ||||||
| // TODO: REVIEW | // TODO: Review this function | ||||||
| Matrix MatrixTranslate(float x, float y, float z) | Matrix MatrixTranslate(float x, float y, float z) | ||||||
| { | { | ||||||
| /* | /* | ||||||
| @@ -478,6 +478,7 @@ Matrix MatrixTranslate(float x, float y, float z) | |||||||
| } | } | ||||||
|  |  | ||||||
| // Returns rotation matrix | // Returns rotation matrix | ||||||
|  | // TODO: Review this function | ||||||
| Matrix MatrixRotate(float angleX, float angleY, float angleZ) | Matrix MatrixRotate(float angleX, float angleY, float angleZ) | ||||||
| { | { | ||||||
|     Matrix result; |     Matrix result; | ||||||
| @@ -492,6 +493,7 @@ Matrix MatrixRotate(float angleX, float angleY, float angleZ) | |||||||
| } | } | ||||||
|  |  | ||||||
| // Create rotation matrix from axis and angle | // Create rotation matrix from axis and angle | ||||||
|  | // TODO: Test this function | ||||||
| Matrix MatrixFromAxisAngle(Vector3 axis, float angle)  | Matrix MatrixFromAxisAngle(Vector3 axis, float angle)  | ||||||
| { | { | ||||||
|     Matrix result; |     Matrix result; | ||||||
| @@ -545,7 +547,8 @@ Matrix MatrixFromAxisAngle(Vector3 axis, float angle) | |||||||
|     return result; |     return result; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // Create rotation matrix from axis and angle | // Create rotation matrix from axis and angle (version 2) | ||||||
|  | // TODO: Test this function | ||||||
| Matrix MatrixFromAxisAngle2(Vector3 axis, float angle) | Matrix MatrixFromAxisAngle2(Vector3 axis, float angle) | ||||||
| { | { | ||||||
|     Matrix result; |     Matrix result; | ||||||
| @@ -661,6 +664,21 @@ Matrix MatrixScale(float x, float y, float z) | |||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Returns transformation matrix for a given translation, rotation and scale | ||||||
|  | // NOTE: Transformation order is rotation -> scale -> translation | ||||||
|  | Matrix MatrixTransform(Vector3 translation, Vector3 rotation, Vector3 scale) | ||||||
|  | { | ||||||
|  |     Matrix result = MatrixIdentity(); | ||||||
|  |      | ||||||
|  |     Matrix mRotation = MatrixRotate(rotation.x, rotation.y, rotation.z); | ||||||
|  |     Matrix mScale = MatrixScale(scale.x, scale.y, scale.z); | ||||||
|  |     Matrix mTranslate = MatrixTranslate(translation.x, translation.y, translation.z); | ||||||
|  |  | ||||||
|  |     result = MatrixMultiply(MatrixMultiply(mRotation, mScale), mTranslate); | ||||||
|  |  | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
| // Returns two matrix multiplication | // Returns two matrix multiplication | ||||||
| // NOTE: When multiplying matrices... the order matters! | // NOTE: When multiplying matrices... the order matters! | ||||||
| Matrix MatrixMultiply(Matrix left, Matrix right) | Matrix MatrixMultiply(Matrix left, Matrix right) | ||||||
|   | |||||||
| @@ -115,6 +115,7 @@ Matrix MatrixRotateX(float angle);                      // Returns x-rotation ma | |||||||
| Matrix MatrixRotateY(float angle);                      // Returns y-rotation matrix (angle in radians) | Matrix MatrixRotateY(float angle);                      // Returns y-rotation matrix (angle in radians) | ||||||
| Matrix MatrixRotateZ(float angle);                      // Returns z-rotation matrix (angle in radians) | Matrix MatrixRotateZ(float angle);                      // Returns z-rotation matrix (angle in radians) | ||||||
| Matrix MatrixScale(float x, float y, float z);          // Returns scaling matrix | Matrix MatrixScale(float x, float y, float z);          // Returns scaling matrix | ||||||
|  | Matrix MatrixTransform(Vector3 translation, Vector3 rotation, Vector3 scale);   // Returns transformation matrix for a given translation, rotation and scale | ||||||
| Matrix MatrixMultiply(Matrix left, Matrix right);       // Returns two matrix multiplication | Matrix MatrixMultiply(Matrix left, Matrix right);       // Returns two matrix multiplication | ||||||
| Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far);  // Returns perspective projection matrix | Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far);  // Returns perspective projection matrix | ||||||
| Matrix MatrixPerspective(double fovy, double aspect, double near, double far);                        // Returns perspective projection matrix | Matrix MatrixPerspective(double fovy, double aspect, double near, double far);                        // Returns perspective projection matrix | ||||||
|   | |||||||
							
								
								
									
										453
									
								
								src/rlgl.c
									
									
									
									
									
								
							
							
						
						
									
										453
									
								
								src/rlgl.c
									
									
									
									
									
								
							| @@ -31,10 +31,24 @@ | |||||||
| #include <stdio.h>          // Standard input / output lib | #include <stdio.h>          // Standard input / output lib | ||||||
| #include <stdlib.h>         // Declares malloc() and free() for memory management, rand() | #include <stdlib.h>         // Declares malloc() and free() for memory management, rand() | ||||||
|  |  | ||||||
| // TODO: Security check in case multiple USE_OPENGL_* defined | // Security check in case no USE_OPENGL_* defined | ||||||
|  | #if !defined(USE_OPENGL_11) && !defined(USE_OPENGL_33) && !defined(USE_OPENGL_ES2) | ||||||
|  |     #define USE_OPENGL_11 | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | // Security check in case multiple USE_OPENGL_* defined | ||||||
|  | #ifdef USE_OPENGL_11 | ||||||
|  |     #ifdef USE_OPENGL_33 | ||||||
|  |         #undef USE_OPENGL_33 | ||||||
|  |     #endif | ||||||
|  |      | ||||||
|  |     #ifdef USE_OPENGL_ES2 | ||||||
|  |         #undef USE_OPENGL_ES2 | ||||||
|  |     #endif    | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #ifdef USE_OPENGL_11 | #ifdef USE_OPENGL_11 | ||||||
|     #include <GL/gl.h>      // Extensions loading lib |     #include <GL/gl.h>      // Basic OpenGL include | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef USE_OPENGL_33 | #ifdef USE_OPENGL_33 | ||||||
| @@ -42,7 +56,7 @@ | |||||||
|     #include <GL/glew.h>    // Extensions loading lib |     #include <GL/glew.h>    // Extensions loading lib | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| //#include "glad.h"         // Extensions loading lib? --> REVIEW | //#include "glad.h"         // Other extensions loading lib? --> REVIEW | ||||||
|  |  | ||||||
| #define USE_VBO_DOUBLE_BUFFERS    // Enable VBO double buffers usage --> REVIEW! | #define USE_VBO_DOUBLE_BUFFERS    // Enable VBO double buffers usage --> REVIEW! | ||||||
|  |  | ||||||
| @@ -56,18 +70,18 @@ | |||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Types and Structures Definition | // Types and Structures Definition | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| typedef struct { |  | ||||||
|     int numQuads; |  | ||||||
|     int texId; |  | ||||||
| } QuadsByTexture; |  | ||||||
|  |  | ||||||
|  | // Vertex buffer (position + color arrays) | ||||||
|  | // NOTE: Used for lines and triangles VAOs | ||||||
| typedef struct { | typedef struct { | ||||||
|     int vCounter; |     int vCounter; | ||||||
|     int cCounter; |     int cCounter; | ||||||
|     float *vertices;            // 3 components per vertex |     float *vertices;            // 3 components per vertex | ||||||
|     float *colors;              // 4 components per vertex |     float *colors;              // 4 components per vertex | ||||||
| } VertexPositionColorBuffer; | } VertexPositionColorBuffer; | ||||||
| /* |  | ||||||
|  | // Vertex buffer (position + texcoords + color arrays) | ||||||
|  | // NOTE: Not used | ||||||
| typedef struct { | typedef struct { | ||||||
|     int vCounter; |     int vCounter; | ||||||
|     int tcCounter; |     int tcCounter; | ||||||
| @@ -76,8 +90,9 @@ typedef struct { | |||||||
|     float *texcoords;           // 2 components per vertex |     float *texcoords;           // 2 components per vertex | ||||||
|     float *colors;              // 4 components per vertex |     float *colors;              // 4 components per vertex | ||||||
| } VertexPositionColorTextureBuffer; | } VertexPositionColorTextureBuffer; | ||||||
| */ |  | ||||||
| /* | // Vertex buffer (position + texcoords + normals arrays) | ||||||
|  | // NOTE: Not used | ||||||
| typedef struct { | typedef struct { | ||||||
|     int vCounter; |     int vCounter; | ||||||
|     int tcCounter; |     int tcCounter; | ||||||
| @@ -86,7 +101,9 @@ typedef struct { | |||||||
|     float *texcoords;           // 2 components per vertex |     float *texcoords;           // 2 components per vertex | ||||||
|     float *normals;             // 3 components per vertex |     float *normals;             // 3 components per vertex | ||||||
| } VertexPositionTextureNormalBuffer; | } VertexPositionTextureNormalBuffer; | ||||||
| */ |  | ||||||
|  | // Vertex buffer (position + texcoords + colors + indices arrays) | ||||||
|  | // NOTE: Used for quads VAO | ||||||
| typedef struct { | typedef struct { | ||||||
|     int vCounter; |     int vCounter; | ||||||
|     int tcCounter; |     int tcCounter; | ||||||
| @@ -97,12 +114,22 @@ typedef struct { | |||||||
|     unsigned int *indices;      // 6 indices per quad |     unsigned int *indices;      // 6 indices per quad | ||||||
| } VertexPositionColorTextureIndexBuffer; | } VertexPositionColorTextureIndexBuffer; | ||||||
|  |  | ||||||
|  | // Draw call type | ||||||
|  | // NOTE: Used to track required draw-calls, organized by texture | ||||||
| typedef struct { | typedef struct { | ||||||
|     GLuint texId; |     GLuint textureId; | ||||||
|     int firstVertex;    // Actually, when using glDrawElements, this parameter is useless.. |     int vertexCount; | ||||||
|     int vCount; |  | ||||||
| } DrawCall; | } DrawCall; | ||||||
|  |  | ||||||
|  | // pixel type (same as Color type) | ||||||
|  | // NOTE: Used exclusively in mipmap generation functions | ||||||
|  | typedef struct { | ||||||
|  |     unsigned char r; | ||||||
|  |     unsigned char g; | ||||||
|  |     unsigned char b; | ||||||
|  |     unsigned char a; | ||||||
|  | } pixel; | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Global Variables Definition | // Global Variables Definition | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| @@ -140,7 +167,6 @@ static GLuint quadsBuffer[4]; | |||||||
|  |  | ||||||
| #ifdef USE_VBO_DOUBLE_BUFFERS | #ifdef USE_VBO_DOUBLE_BUFFERS | ||||||
| // Double buffering | // Double buffering | ||||||
| // TODO: REVIEW -> Not getting any performance improvement... why? |  | ||||||
| static GLuint vaoQuadsB; | static GLuint vaoQuadsB; | ||||||
| static GLuint quadsBufferB[4]; | static GLuint quadsBufferB[4]; | ||||||
| static bool useBufferB = false; | static bool useBufferB = false; | ||||||
| @@ -172,6 +198,11 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName); | |||||||
| static char *TextFileRead(char *fn); | static char *TextFileRead(char *fn); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef USE_OPENGL_11 | ||||||
|  | static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight); | ||||||
|  | static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Module Functions Definition - Matrix operations | // Module Functions Definition - Matrix operations | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| @@ -216,7 +247,7 @@ void rlMatrixMode(int mode) | |||||||
| { | { | ||||||
|     if (mode == RL_PROJECTION) currentMatrix = &projection; |     if (mode == RL_PROJECTION) currentMatrix = &projection; | ||||||
|     else if (mode == RL_MODELVIEW) currentMatrix = &modelview; |     else if (mode == RL_MODELVIEW) currentMatrix = &modelview; | ||||||
|     //else if (mode == GL_TEXTURE) TODO: NEVER USED! |     //else if (mode == RL_TEXTURE) // Not supported | ||||||
|      |      | ||||||
|     currentMatrixMode = mode; |     currentMatrixMode = mode; | ||||||
| } | } | ||||||
| @@ -257,6 +288,7 @@ void rlLoadIdentity() | |||||||
| void rlTranslatef(float x, float y, float z) | void rlTranslatef(float x, float y, float z) | ||||||
| { | { | ||||||
|     Matrix mat = MatrixTranslate(x, y, z); |     Matrix mat = MatrixTranslate(x, y, z); | ||||||
|  |     MatrixTranspose(&mat); | ||||||
|      |      | ||||||
|     *currentMatrix = MatrixMultiply(*currentMatrix, mat); |     *currentMatrix = MatrixMultiply(*currentMatrix, mat); | ||||||
| } | } | ||||||
| @@ -264,13 +296,15 @@ void rlTranslatef(float x, float y, float z) | |||||||
| // Multiply the current matrix by a rotation matrix | // Multiply the current matrix by a rotation matrix | ||||||
| void rlRotatef(float angleDeg, float x, float y, float z) | void rlRotatef(float angleDeg, float x, float y, float z) | ||||||
| { | { | ||||||
|     // TODO: Rotation matrix --> REVIEW! |     // TODO: Support rotation in multiple axes | ||||||
|     Matrix rot = MatrixIdentity(); |     Matrix rot = MatrixIdentity(); | ||||||
|      |      | ||||||
|     if (x == 1) rot = MatrixRotateX(angleDeg*DEG2RAD); |     if (x == 1) rot = MatrixRotateX(angleDeg*DEG2RAD); | ||||||
|     else if (y == 1) rot = MatrixRotateY(angleDeg*DEG2RAD); |     else if (y == 1) rot = MatrixRotateY(angleDeg*DEG2RAD); | ||||||
|     else if (z == 1) rot = MatrixRotateZ(angleDeg*DEG2RAD); |     else if (z == 1) rot = MatrixRotateZ(angleDeg*DEG2RAD); | ||||||
|      |      | ||||||
|  |     MatrixTranspose(&rot); | ||||||
|  |      | ||||||
|     *currentMatrix = MatrixMultiply(*currentMatrix, rot); |     *currentMatrix = MatrixMultiply(*currentMatrix, rot); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -278,6 +312,7 @@ void rlRotatef(float angleDeg, float x, float y, float z) | |||||||
| void rlScalef(float x, float y, float z) | void rlScalef(float x, float y, float z) | ||||||
| { | { | ||||||
|     Matrix mat = MatrixScale(x, y, z); |     Matrix mat = MatrixScale(x, y, z); | ||||||
|  |     MatrixTranspose(&mat); | ||||||
|      |      | ||||||
|     *currentMatrix = MatrixMultiply(*currentMatrix, mat); |     *currentMatrix = MatrixMultiply(*currentMatrix, mat); | ||||||
| } | } | ||||||
| @@ -356,12 +391,12 @@ void rlEnd() | |||||||
| { | { | ||||||
|     if (useTempBuffer) |     if (useTempBuffer) | ||||||
|     { |     { | ||||||
|         // IT WORKS!!! --> Refactor... |         // NOTE: In this case, *currentMatrix is already transposed because transposing has been applied | ||||||
|         Matrix mat = *currentMatrix; |         // independently to translation-scale-rotation matrices -> t(M1 x M2) = t(M2) x t(M1) | ||||||
|         MatrixTranspose(&mat); |         // This way, rlTranslatef(), rlRotatef()... behaviour is the same than OpenGL 1.1 | ||||||
|  |  | ||||||
|         // Apply transformation matrix to all temp vertices |         // Apply transformation matrix to all temp vertices | ||||||
|         for (int i = 0; i < tempBufferCount; i++) VectorTransform(&tempBuffer[i], mat); |         for (int i = 0; i < tempBufferCount; i++) VectorTransform(&tempBuffer[i], *currentMatrix); | ||||||
|          |          | ||||||
|         // Deactivate tempBuffer usage to allow rlVertex3f do its job |         // Deactivate tempBuffer usage to allow rlVertex3f do its job | ||||||
|         useTempBuffer = false; |         useTempBuffer = false; | ||||||
| @@ -373,7 +408,7 @@ void rlEnd() | |||||||
|         tempBufferCount = 0; |         tempBufferCount = 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Make sure vertexCounter is the same for vertices-texcoords-normals-colors |     // Make sure vertexCount is the same for vertices-texcoords-normals-colors | ||||||
|     // NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls. |     // NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls. | ||||||
|     switch (currentDrawMode) |     switch (currentDrawMode) | ||||||
|     { |     { | ||||||
| @@ -490,7 +525,7 @@ void rlVertex3f(float x, float y, float z) | |||||||
|                  |                  | ||||||
|                 quads.vCounter++; |                 quads.vCounter++; | ||||||
|                  |                  | ||||||
|                 draws[drawsCounter - 1].vCount++; |                 draws[drawsCounter - 1].vertexCount++; | ||||||
|                  |                  | ||||||
|             } break; |             } break; | ||||||
|             default: break; |             default: break; | ||||||
| @@ -596,13 +631,12 @@ void rlEnableTexture(unsigned int id) | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | ||||||
|     if (draws[drawsCounter - 1].texId != id) |     if (draws[drawsCounter - 1].textureId != id) | ||||||
|     { |     { | ||||||
|         if (draws[drawsCounter - 1].vCount > 0) drawsCounter++; |         if (draws[drawsCounter - 1].vertexCount > 0) drawsCounter++; | ||||||
|          |          | ||||||
|         draws[drawsCounter - 1].texId = id; |         draws[drawsCounter - 1].textureId = id; | ||||||
|         draws[drawsCounter - 1].firstVertex = draws[drawsCounter - 2].vCount; |         draws[drawsCounter - 1].vertexCount = 0; | ||||||
|         draws[drawsCounter - 1].vCount = 0; |  | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| @@ -710,8 +744,6 @@ void rlglInit() | |||||||
|     // Get handles to GLSL uniform vars locations (fragment-shader) |     // Get handles to GLSL uniform vars locations (fragment-shader) | ||||||
|     textureLoc = glGetUniformLocation(shaderProgram, "texture0"); |     textureLoc = glGetUniformLocation(shaderProgram, "texture0"); | ||||||
|      |      | ||||||
|     TraceLog(INFO, "Default shader loaded"); |  | ||||||
|      |  | ||||||
|     InitializeBuffers();    // Init vertex arrays |     InitializeBuffers();    // Init vertex arrays | ||||||
|     InitializeVAOs();       // Init VBO and VAO |     InitializeVAOs();       // Init VBO and VAO | ||||||
|      |      | ||||||
| @@ -723,9 +755,9 @@ void rlglInit() | |||||||
|     // Create default white texture for plain colors (required by shader) |     // Create default white texture for plain colors (required by shader) | ||||||
|     unsigned char pixels[4] = { 255, 255, 255, 255 };   // 1 pixel RGBA (4 bytes) |     unsigned char pixels[4] = { 255, 255, 255, 255 };   // 1 pixel RGBA (4 bytes) | ||||||
|      |      | ||||||
|     whiteTexture = rlglLoadTexture(1, 1, pixels); |     whiteTexture = rlglLoadTexture(pixels, 1, 1, false); | ||||||
|      |      | ||||||
|     if (whiteTexture != 0) TraceLog(INFO, "Base white texture successfully created, id: %i", whiteTexture); |     if (whiteTexture != 0) TraceLog(INFO, "[ID %i] Base white texture created successfully", whiteTexture); | ||||||
|     else TraceLog(WARNING, "Base white texture could not be created"); |     else TraceLog(WARNING, "Base white texture could not be created"); | ||||||
|      |      | ||||||
|     // Init draw calls tracking system |     // Init draw calls tracking system | ||||||
| @@ -733,13 +765,12 @@ void rlglInit() | |||||||
|      |      | ||||||
|     for (int i = 0; i < MAX_DRAWS_BY_TEXTURE; i++) |     for (int i = 0; i < MAX_DRAWS_BY_TEXTURE; i++) | ||||||
|     { |     { | ||||||
|         draws[i].texId = 0; |         draws[i].textureId = 0; | ||||||
|         draws[i].firstVertex = 0; |         draws[i].vertexCount = 0; | ||||||
|         draws[i].vCount = 0; |  | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     drawsCounter = 1; |     drawsCounter = 1; | ||||||
|     draws[drawsCounter - 1].texId = whiteTexture; |     draws[drawsCounter - 1].textureId = whiteTexture; | ||||||
| } | } | ||||||
|  |  | ||||||
| // Vertex Buffer Object deinitialization (memory free) | // Vertex Buffer Object deinitialization (memory free) | ||||||
| @@ -789,6 +820,8 @@ void rlglClose() | |||||||
|      |      | ||||||
|     // Free GPU texture |     // Free GPU texture | ||||||
|     glDeleteTextures(1, &whiteTexture); |     glDeleteTextures(1, &whiteTexture); | ||||||
|  |      | ||||||
|  |     free(draws); | ||||||
| } | } | ||||||
|  |  | ||||||
| void rlglDraw() | void rlglDraw() | ||||||
| @@ -823,7 +856,7 @@ void rlglDraw() | |||||||
|      |      | ||||||
|     if (quads.vCounter > 0) |     if (quads.vCounter > 0) | ||||||
|     { |     { | ||||||
|         int numQuads = 0; |         int quadsCount = 0; | ||||||
|         int numIndicesToProcess = 0; |         int numIndicesToProcess = 0; | ||||||
|         int indicesOffset = 0; |         int indicesOffset = 0; | ||||||
|  |  | ||||||
| @@ -836,21 +869,21 @@ void rlglDraw() | |||||||
|             glBindVertexArray(vaoQuads); |             glBindVertexArray(vaoQuads); | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         //TraceLog(INFO, "Draws required per frame: %i", drawsCounter); |         //TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter); | ||||||
|       |       | ||||||
|         for (int i = 0; i < drawsCounter; i++) |         for (int i = 0; i < drawsCounter; i++) | ||||||
|         { |         { | ||||||
|             numQuads = draws[i].vCount/4; |             quadsCount = draws[i].vertexCount/4; | ||||||
|             numIndicesToProcess = numQuads*6;  // Get number of Quads * 6 index by Quad |             numIndicesToProcess = quadsCount*6;  // Get number of Quads * 6 index by Quad | ||||||
|              |              | ||||||
|             //TraceLog(INFO, "Quads to render: %i - Vertex Count: %i", numQuads, draws[i].vCount); |             //TraceLog(DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount); | ||||||
|  |  | ||||||
|             glBindTexture(GL_TEXTURE_2D, draws[i].texId); |             glBindTexture(GL_TEXTURE_2D, draws[i].textureId); | ||||||
|              |              | ||||||
|             // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process |             // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process | ||||||
|             glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid*) (sizeof(GLuint) * indicesOffset)); |             glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid*) (sizeof(GLuint) * indicesOffset)); | ||||||
|  |  | ||||||
|             indicesOffset += draws[i].vCount/4*6; |             indicesOffset += draws[i].vertexCount/4*6; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @@ -859,9 +892,8 @@ void rlglDraw() | |||||||
|      |      | ||||||
|     // Reset draws counter |     // Reset draws counter | ||||||
|     drawsCounter = 1; |     drawsCounter = 1; | ||||||
|     draws[0].texId = whiteTexture; |     draws[0].textureId = whiteTexture; | ||||||
|     draws[0].firstVertex = 0; |     draws[0].vertexCount = 0; | ||||||
|     draws[0].vCount = 0; |  | ||||||
|      |      | ||||||
|     // Reset vertex counters for next frame |     // Reset vertex counters for next frame | ||||||
|     lines.vCounter = 0; |     lines.vCounter = 0; | ||||||
| @@ -883,52 +915,71 @@ void rlglDraw() | |||||||
| #endif      // End for OpenGL 3.3+ and ES2 only functions | #endif      // End for OpenGL 3.3+ and ES2 only functions | ||||||
|  |  | ||||||
| // Draw a 3d model | // Draw a 3d model | ||||||
| void rlglDrawModel(Model model, Vector3 position, float scale, bool wires) | void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color color, bool wires) | ||||||
| { | { | ||||||
|     if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); |     if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); | ||||||
|      |      | ||||||
| #ifdef USE_OPENGL_11 | #ifdef USE_OPENGL_11 | ||||||
|     // NOTE: For models we use Vertex Arrays (OpenGL 1.1) |     glEnable(GL_TEXTURE_2D); | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, model.textureId); | ||||||
|  |  | ||||||
|  |     // NOTE: On OpenGL 1.1 we use Vertex Arrays to draw model | ||||||
|     glEnableClientState(GL_VERTEX_ARRAY);                     // Enable vertex array |     glEnableClientState(GL_VERTEX_ARRAY);                     // Enable vertex array | ||||||
|     glEnableClientState(GL_TEXTURE_COORD_ARRAY);              // Enable texture coords array |     glEnableClientState(GL_TEXTURE_COORD_ARRAY);              // Enable texture coords array | ||||||
|     glEnableClientState(GL_NORMAL_ARRAY);                     // Enable normals array |     glEnableClientState(GL_NORMAL_ARRAY);                     // Enable normals array | ||||||
|          |          | ||||||
|     glVertexPointer(3, GL_FLOAT, 0, model.data.vertices);     // Pointer to vertex coords array |     glVertexPointer(3, GL_FLOAT, 0, model.mesh.vertices);     // Pointer to vertex coords array | ||||||
|     glTexCoordPointer(2, GL_FLOAT, 0, model.data.texcoords);  // Pointer to texture coords array |     glTexCoordPointer(2, GL_FLOAT, 0, model.mesh.texcoords);  // Pointer to texture coords array | ||||||
|     glNormalPointer(GL_FLOAT, 0, model.data.normals);         // Pointer to normals array |     glNormalPointer(GL_FLOAT, 0, model.mesh.normals);         // Pointer to normals array | ||||||
|     //glColorPointer(4, GL_UNSIGNED_BYTE, 0, model.colors);   // Pointer to colors array (NOT USED) |     //glColorPointer(4, GL_UNSIGNED_BYTE, 0, model.colors);   // Pointer to colors array (NOT USED) | ||||||
|      |      | ||||||
|  |     //TraceLog(DEBUG, "Drawing model.mesh, VertexCount: %i", model.mesh.vertexCount); | ||||||
|  |      | ||||||
|     rlPushMatrix(); |     rlPushMatrix(); | ||||||
|         rlTranslatef(position.x, position.y, position.z); |         rlTranslatef(position.x, position.y, position.z); | ||||||
|         //rlRotatef(rotation * GetFrameTime(), 0, 1, 0); |         rlScalef(scale.x, scale.y, scale.z); | ||||||
|         rlScalef(scale, scale, scale); |         //rlRotatef(rotation, 0, 1, 0); | ||||||
|          |          | ||||||
|         rlColor4ub(1.0f, 1.0f, 1.0f, 1.0f); |         // TODO: If rotate in multiple axis, get rotation matrix and use rlMultMatrix() | ||||||
|  |  | ||||||
|         glDrawArrays(GL_TRIANGLES, 0, model.data.numVertices); |         rlColor4ub(color.r, color.g, color.b, color.a); | ||||||
|  |  | ||||||
|  |         glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount); | ||||||
|     rlPopMatrix(); |     rlPopMatrix(); | ||||||
|      |      | ||||||
|     glDisableClientState(GL_VERTEX_ARRAY);                     // Disable vertex array |     glDisableClientState(GL_VERTEX_ARRAY);                     // Disable vertex array | ||||||
|     glDisableClientState(GL_TEXTURE_COORD_ARRAY);              // Disable texture coords array |     glDisableClientState(GL_TEXTURE_COORD_ARRAY);              // Disable texture coords array | ||||||
|     glDisableClientState(GL_NORMAL_ARRAY);                     // Disable normals array |     glDisableClientState(GL_NORMAL_ARRAY);                     // Disable normals array | ||||||
|  |      | ||||||
|  |     glDisable(GL_TEXTURE_2D); | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, 0); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | ||||||
|     glUseProgram(shaderProgram);        // Use our shader |     glUseProgram(shaderProgram);        // Use our shader | ||||||
|      |      | ||||||
|     Matrix modelview2 = MatrixMultiply(model.transform, modelview); |     // Get transform matrix (rotation -> scale -> translation) | ||||||
|  |     Matrix transform = MatrixTransform(position, rotation, scale); | ||||||
|  |     Matrix modelviewworld = MatrixMultiply(transform, modelview); | ||||||
|      |      | ||||||
|     // NOTE: Drawing in OpenGL 3.3+, transform is passed to shader |     // NOTE: Drawing in OpenGL 3.3+, transform is passed to shader | ||||||
|     glUniformMatrix4fv(projectionMatrixLoc, 1, false, GetMatrixVector(projection)); |     glUniformMatrix4fv(projectionMatrixLoc, 1, false, GetMatrixVector(projection)); | ||||||
|     glUniformMatrix4fv(modelviewMatrixLoc, 1, false, GetMatrixVector(modelview2)); |     glUniformMatrix4fv(modelviewMatrixLoc, 1, false, GetMatrixVector(modelviewworld)); | ||||||
|     glUniform1i(textureLoc, 0); |     glUniform1i(textureLoc, 0); | ||||||
|      |      | ||||||
|  |     //TraceLog(DEBUG, "ShaderProgram: %i, VAO ID: %i, VertexCount: %i", shaderProgram, model.vaoId, model.mesh.vertexCount); | ||||||
|  |     | ||||||
|     glBindVertexArray(model.vaoId); |     glBindVertexArray(model.vaoId); | ||||||
|     //glBindTexture(GL_TEXTURE_2D, model.textureId); |  | ||||||
|      |      | ||||||
|     glDrawArrays(GL_TRIANGLES, 0, model.numVertices); |     // TODO: Update vertex color | ||||||
|  |     glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]); | ||||||
|  |     glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*model.mesh.vertexCount, model.mesh.colors); | ||||||
|      |      | ||||||
|     //glBindTexture(GL_TEXTURE_2D, 0);    // Unbind textures |     glBindTexture(GL_TEXTURE_2D, model.textureId); | ||||||
|  |  | ||||||
|  |     glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount); | ||||||
|  |  | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, 0);    // Unbind textures | ||||||
|     glBindVertexArray(0);               // Unbind VAO |     glBindVertexArray(0);               // Unbind VAO | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -982,8 +1033,7 @@ void rlglInitGraphicsDevice(int fbWidth, int fbHeight) | |||||||
| } | } | ||||||
|  |  | ||||||
| // Convert image data to OpenGL texture (returns OpenGL valid Id) | // Convert image data to OpenGL texture (returns OpenGL valid Id) | ||||||
| // NOTE: Image is not unloaded, it should be done manually... | unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool genMipmaps) | ||||||
| unsigned int rlglLoadTexture(int width, int height, unsigned char *data) |  | ||||||
| { | { | ||||||
|     glBindTexture(GL_TEXTURE_2D,0); // Free any old binding |     glBindTexture(GL_TEXTURE_2D,0); // Free any old binding | ||||||
|  |  | ||||||
| @@ -996,27 +1046,82 @@ unsigned int rlglLoadTexture(int width, int height, unsigned char *data) | |||||||
|     // NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used! |     // NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used! | ||||||
|     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);       // Set texture to repead on x-axis |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);       // Set texture to repead on x-axis | ||||||
|     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);       // Set texture to repead on y-axis |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);       // Set texture to repead on y-axis | ||||||
|  |  | ||||||
|  |     bool texIsPOT = false; | ||||||
|  |      | ||||||
|  |     // Check if width and height are power-of-two (POT) | ||||||
|  |     if (((width > 0) && ((width & (width - 1)) == 0)) && ((height > 0) && ((height & (height - 1)) == 0))) texIsPOT = true; | ||||||
|  |      | ||||||
|  |     if (!texIsPOT) | ||||||
|  |     { | ||||||
|  |         TraceLog(WARNING, "[ID %i] Texture is not power-of-two, mipmaps can not be generated", id); | ||||||
|  |          | ||||||
|  |         genMipmaps = false; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // If mipmaps are being used, we configure mag-min filters accordingly | ||||||
|  |     if (genMipmaps) | ||||||
|  |     { | ||||||
|  |         // Trilinear filtering with mipmaps | ||||||
|  |         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||||||
|  |         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);   // Activate use of mipmaps (must be available) | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         // Not using mipmappings | ||||||
|         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  // Filter for pixel-perfect drawing, alternative: GL_LINEAR  |         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  // Filter for pixel-perfect drawing, alternative: GL_LINEAR  | ||||||
|         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  // Filter for pixel-perfect drawing, alternative: GL_LINEAR |         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  // Filter for pixel-perfect drawing, alternative: GL_LINEAR | ||||||
|  |     } | ||||||
|  |  | ||||||
| #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | #ifdef USE_OPENGL_11 | ||||||
|     // Trilinear filtering |     if (genMipmaps) | ||||||
|     //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |     { | ||||||
|     //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);   // Activate use of mipmaps (must be available) |         TraceLog(WARNING, "[ID %i] Mipmaps generated manually on CPU side", id); | ||||||
|     //glGenerateMipmap(GL_TEXTURE_2D);    // OpenGL 3.3! |  | ||||||
|  |         // Compute required mipmaps | ||||||
|  |         // NOTE: data size is reallocated to fit mipmaps data | ||||||
|  |         int mipmapCount = GenerateMipmaps(data, width, height); | ||||||
|  |  | ||||||
|  |         int offset = 0; | ||||||
|  |         int size = 0; | ||||||
|  |          | ||||||
|  |         int mipWidth = width; | ||||||
|  |         int mipHeight = height; | ||||||
|  |          | ||||||
|  |         // Load the mipmaps        | ||||||
|  |         for (int level = 0; level < mipmapCount; level++) | ||||||
|  |         { | ||||||
|  |             glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, mipWidth, mipHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data + offset); | ||||||
|  |              | ||||||
|  |             size = mipWidth*mipHeight*4; | ||||||
|  |             offset += size; | ||||||
|  |              | ||||||
|  |             mipWidth /= 2; | ||||||
|  |             mipHeight /= 2; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|     // NOTE: Not using mipmappings (texture for 2D drawing) |  | ||||||
|     // At this point we have the image converted to texture and uploaded to GPU | #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | ||||||
|  |  | ||||||
|     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); |     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); | ||||||
|      |      | ||||||
|  |     if (genMipmaps) | ||||||
|  |     { | ||||||
|  |         glGenerateMipmap(GL_TEXTURE_2D);  // Generate mipmaps automatically | ||||||
|  |         TraceLog(INFO, "[ID %i] Mipmaps generated automatically for new texture", id); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  | #endif | ||||||
|  |  | ||||||
|     // At this point we have the image converted to texture and uploaded to GPU |     // At this point we have the image converted to texture and uploaded to GPU | ||||||
|      |      | ||||||
|     // Unbind current texture |     // Unbind current texture | ||||||
|     glBindTexture(GL_TEXTURE_2D, 0); |     glBindTexture(GL_TEXTURE_2D, 0); | ||||||
|      |      | ||||||
|     TraceLog(INFO, "New texture created, id: %i (%i x %i)", id, width, height); |     TraceLog(INFO, "[ID %i] New texture created (%i x %i)", id, width, height); | ||||||
|      |      | ||||||
|     return id; |     return id; | ||||||
| } | } | ||||||
| @@ -1024,50 +1129,41 @@ unsigned int rlglLoadTexture(int width, int height, unsigned char *data) | |||||||
|  |  | ||||||
| #ifdef USE_OPENGL_33 | #ifdef USE_OPENGL_33 | ||||||
|  |  | ||||||
| #define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII |  | ||||||
| #define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII |  | ||||||
| #define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII |  | ||||||
|  |  | ||||||
| // Convert image data to OpenGL texture (returns OpenGL valid Id) | // Convert image data to OpenGL texture (returns OpenGL valid Id) | ||||||
| // NOTE: Expected compressed data from DDS file | // NOTE: Expected compressed image data and POT image | ||||||
| unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int format) | unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compFormat) | ||||||
| { | { | ||||||
|     // Create one OpenGL texture |     // Create one OpenGL texture | ||||||
|     GLuint id; |     GLuint id; | ||||||
|     int compFormat = 0; |      | ||||||
|  |     glGenTextures(1, &id); | ||||||
|      |      | ||||||
|     TraceLog(DEBUG, "Compressed texture width: %i", width); |     TraceLog(DEBUG, "Compressed texture width: %i", width); | ||||||
|     TraceLog(DEBUG, "Compressed texture height: %i", height); |     TraceLog(DEBUG, "Compressed texture height: %i", height); | ||||||
|     TraceLog(DEBUG, "Compressed texture mipmap levels: %i", mipmapCount); |     TraceLog(DEBUG, "Compressed texture mipmap levels: %i", mipmapCount); | ||||||
|     TraceLog(DEBUG, "Compressed texture format: 0x%x", format); |     TraceLog(DEBUG, "Compressed texture format: 0x%x", compFormat); | ||||||
|          |          | ||||||
|     switch(format)  |     if (compFormat == 0) | ||||||
|     { |     { | ||||||
|         case FOURCC_DXT1: compFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;  |         TraceLog(WARNING, "[ID %i] Texture compressed format not recognized", id); | ||||||
|         case FOURCC_DXT3: compFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;  |  | ||||||
|         case FOURCC_DXT5: compFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;  |  | ||||||
|         default: compFormat = -1; break; |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     if (compFormat == -1) |  | ||||||
|     { |  | ||||||
|         TraceLog(WARNING, "Texture compressed format not recognized"); |  | ||||||
|         id = 0; |         id = 0; | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|         glGenTextures(1, &id); |  | ||||||
|  |  | ||||||
|         // Bind the texture |         // Bind the texture | ||||||
|         glBindTexture(GL_TEXTURE_2D, id); |         glBindTexture(GL_TEXTURE_2D, id); | ||||||
|         glPixelStorei(GL_UNPACK_ALIGNMENT, 1); |         glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | ||||||
|      |      | ||||||
|         unsigned int blockSize = (compFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;  |         int blockSize = 0; | ||||||
|         unsigned int offset = 0; |         int offset = 0; | ||||||
|  |          | ||||||
|  |         if (compFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) blockSize = 8; | ||||||
|  |         else blockSize = 16; | ||||||
|          |          | ||||||
|         // Load the mipmaps  |         // Load the mipmaps  | ||||||
|         for (int level = 0; level < mipmapCount && (width || height); level++)  |         for (int level = 0; level < mipmapCount && (width || height); level++)  | ||||||
|         {  |         {  | ||||||
|  |             // NOTE: size specifies the number of bytes of image data (S3TC/DXTC) | ||||||
|             unsigned int size = ((width + 3)/4)*((height + 3)/4)*blockSize; |             unsigned int size = ((width + 3)/4)*((height + 3)/4)*blockSize; | ||||||
|              |              | ||||||
|             glCompressedTexImage2D(GL_TEXTURE_2D, level, compFormat, width, height, 0, size, data + offset);  |             glCompressedTexImage2D(GL_TEXTURE_2D, level, compFormat, width, height, 0, size, data + offset);  | ||||||
| @@ -1100,20 +1196,28 @@ unsigned int rlglLoadModel(VertexData mesh) | |||||||
|   |   | ||||||
|     // Enable vertex attributes |     // Enable vertex attributes | ||||||
|     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]); |     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]); | ||||||
|     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.numVertices, mesh.vertices, GL_STATIC_DRAW); |     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.vertices, GL_STATIC_DRAW); | ||||||
|     glEnableVertexAttribArray(vertexLoc); |     glEnableVertexAttribArray(vertexLoc); | ||||||
|     glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0); |     glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0); | ||||||
|      |      | ||||||
|     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]); |     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]); | ||||||
|     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.numVertices, mesh.texcoords, GL_STATIC_DRAW);       |     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.vertexCount, mesh.texcoords, GL_STATIC_DRAW);       | ||||||
|     glEnableVertexAttribArray(texcoordLoc); |     glEnableVertexAttribArray(texcoordLoc); | ||||||
|     glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0); |     glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0); | ||||||
|      |      | ||||||
|     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]); |     //glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]); | ||||||
|     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.numVertices, mesh.normals, GL_STATIC_DRAW);    |     //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.normals, GL_STATIC_DRAW);    | ||||||
|     //glEnableVertexAttribArray(normalLoc); |     //glEnableVertexAttribArray(normalLoc); | ||||||
|     //glVertexAttribPointer(normalLoc, 3, GL_FLOAT, 0, 0, 0); |     //glVertexAttribPointer(normalLoc, 3, GL_FLOAT, 0, 0, 0); | ||||||
|      |      | ||||||
|  |     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]); | ||||||
|  |     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*mesh.vertexCount, mesh.colors, GL_STATIC_DRAW);    | ||||||
|  |     glEnableVertexAttribArray(colorLoc); | ||||||
|  |     glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0); | ||||||
|  |      | ||||||
|  |     if (vaoModel > 0) TraceLog(INFO, "[ID %i] Model uploaded successfully to VRAM (GPU)", vaoModel); | ||||||
|  |     else TraceLog(WARNING, "Model could not be uploaded to VRAM (GPU)"); | ||||||
|  |      | ||||||
|     return vaoModel; |     return vaoModel; | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| @@ -1209,6 +1313,9 @@ static GLuint LoadDefaultShaders() | |||||||
|     glCompileShader(vertexShader); |     glCompileShader(vertexShader); | ||||||
|     glCompileShader(fragmentShader); |     glCompileShader(fragmentShader); | ||||||
|      |      | ||||||
|  |     TraceLog(INFO, "[ID %i] Default vertex shader compiled succesfully", vertexShader); | ||||||
|  |     TraceLog(INFO, "[ID %i] Default fragment shader compiled succesfully", fragmentShader); | ||||||
|  |   | ||||||
|     program = glCreateProgram(); |     program = glCreateProgram(); | ||||||
|      |      | ||||||
|     glAttachShader(program, vertexShader); |     glAttachShader(program, vertexShader); | ||||||
| @@ -1219,6 +1326,8 @@ static GLuint LoadDefaultShaders() | |||||||
|     glDeleteShader(vertexShader); |     glDeleteShader(vertexShader); | ||||||
|     glDeleteShader(fragmentShader); |     glDeleteShader(fragmentShader); | ||||||
|      |      | ||||||
|  |     TraceLog(INFO, "[ID %i] Default shader program loaded succesfully", program); | ||||||
|  |   | ||||||
|     return program; |     return program; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1246,6 +1355,9 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName) | |||||||
|     glCompileShader(vertexShader); |     glCompileShader(vertexShader); | ||||||
|     glCompileShader(fragmentShader); |     glCompileShader(fragmentShader); | ||||||
|      |      | ||||||
|  |     TraceLog(INFO, "[ID %i] Vertex shader compiled succesfully", vertexShader); | ||||||
|  |     TraceLog(INFO, "[ID %i] Fragment shader compiled succesfully", fragmentShader); | ||||||
|  |   | ||||||
|     program = glCreateProgram(); |     program = glCreateProgram(); | ||||||
|      |      | ||||||
|     glAttachShader(program, vertexShader); |     glAttachShader(program, vertexShader); | ||||||
| @@ -1256,6 +1368,8 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName) | |||||||
|     glDeleteShader(vertexShader); |     glDeleteShader(vertexShader); | ||||||
|     glDeleteShader(fragmentShader); |     glDeleteShader(fragmentShader); | ||||||
|      |      | ||||||
|  |     TraceLog(INFO, "[ID %i] Shader program loaded succesfully", program); | ||||||
|  |   | ||||||
|     return program; |     return program; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1365,6 +1479,7 @@ static void InitializeVAOs() | |||||||
|     glEnableVertexAttribArray(colorLoc); |     glEnableVertexAttribArray(colorLoc); | ||||||
|     glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0); |     glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0); | ||||||
|      |      | ||||||
|  |     TraceLog(INFO, "[ID %i] Lines VAO successfully initialized", vaoLines); | ||||||
|     //--------------------------------------------------------------  |     //--------------------------------------------------------------  | ||||||
|      |      | ||||||
|     // Initialize Triangles VAO |     // Initialize Triangles VAO | ||||||
| @@ -1385,6 +1500,7 @@ static void InitializeVAOs() | |||||||
|     glEnableVertexAttribArray(colorLoc); |     glEnableVertexAttribArray(colorLoc); | ||||||
|     glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0); |     glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0); | ||||||
|      |      | ||||||
|  |     TraceLog(INFO, "[ID %i] Triangles VAO successfully initialized", vaoTriangles); | ||||||
|     //--------------------------------------------------------------  |     //--------------------------------------------------------------  | ||||||
|      |      | ||||||
|     // Initialize Quads VAO (Buffer A) |     // Initialize Quads VAO (Buffer A) | ||||||
| @@ -1414,6 +1530,8 @@ static void InitializeVAOs() | |||||||
|     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]); |     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]); | ||||||
|     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW); |     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW); | ||||||
|      |      | ||||||
|  |     TraceLog(INFO, "[ID %i] Quads VAO successfully initialized", vaoQuads); | ||||||
|  |      | ||||||
| #ifdef USE_VBO_DOUBLE_BUFFERS | #ifdef USE_VBO_DOUBLE_BUFFERS | ||||||
|     // Initialize Quads VAO (Buffer B) |     // Initialize Quads VAO (Buffer B) | ||||||
|     glGenVertexArrays(1, &vaoQuadsB); |     glGenVertexArrays(1, &vaoQuadsB); | ||||||
| @@ -1442,11 +1560,9 @@ static void InitializeVAOs() | |||||||
|     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBufferB[3]); |     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBufferB[3]); | ||||||
|     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW); |     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW); | ||||||
|      |      | ||||||
|     TraceLog(INFO, "Using VBO double buffering"); |     TraceLog(INFO, "[ID %i] Second Quads VAO successfully initilized (double buffering)", vaoQuadsB); | ||||||
| #endif | #endif | ||||||
|   |   | ||||||
|     TraceLog(INFO, "Vertex buffers successfully initialized (lines, triangles, quads)\n"); |  | ||||||
|   |  | ||||||
|     // Unbind the current VAO |     // Unbind the current VAO | ||||||
|     glBindVertexArray(0); |     glBindVertexArray(0); | ||||||
| } | } | ||||||
| @@ -1540,6 +1656,135 @@ static void UpdateBuffers() | |||||||
|     glBindVertexArray(0); |     glBindVertexArray(0); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif //defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | ||||||
|  |  | ||||||
|  | #ifdef USE_OPENGL_11 | ||||||
|  |  | ||||||
|  | // Mipmaps data is generated after image data | ||||||
|  | static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight) | ||||||
|  | { | ||||||
|  |     int mipmapCount = 1;                // Required mipmap levels count (including base level) | ||||||
|  |     int width = baseWidth; | ||||||
|  |     int height = baseHeight; | ||||||
|  |     int size = baseWidth*baseHeight*4;  // Size in bytes (will include mipmaps...) | ||||||
|  |  | ||||||
|  |     // Count mipmap levels required | ||||||
|  |     while ((width != 1) && (height != 1)) | ||||||
|  |     { | ||||||
|  |         if (width != 1) width /= 2; | ||||||
|  |         if (height != 1) height /= 2; | ||||||
|  |          | ||||||
|  |         TraceLog(DEBUG, "Next mipmap size: %i x %i", width, height); | ||||||
|  |          | ||||||
|  |         mipmapCount++; | ||||||
|  |          | ||||||
|  |         size += (width*height*4);       // Add mipmap size (in bytes) | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     TraceLog(DEBUG, "Total mipmaps required: %i", mipmapCount); | ||||||
|  |     TraceLog(DEBUG, "Total size of data required: %i", size); | ||||||
|  |      | ||||||
|  |     unsigned char *temp = realloc(data, size); | ||||||
|  |      | ||||||
|  |     if (temp != NULL) data = temp; | ||||||
|  |     else TraceLog(WARNING, "Mipmaps required memory could not be allocated"); | ||||||
|  |      | ||||||
|  |     width = baseWidth; | ||||||
|  |     height = baseHeight; | ||||||
|  |     size = (width*height*4); | ||||||
|  |      | ||||||
|  |     // Generate mipmaps | ||||||
|  |     // NOTE: Every mipmap data is stored after data | ||||||
|  |     pixel *image = (pixel *)malloc(width*height*sizeof(pixel)); | ||||||
|  |     pixel *mipmap = NULL; | ||||||
|  |     int offset = 0; | ||||||
|  |     int j = 0; | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < size; i += 4) | ||||||
|  |     { | ||||||
|  |         image[j].r = data[i]; | ||||||
|  |         image[j].g = data[i + 1]; | ||||||
|  |         image[j].b = data[i + 2]; | ||||||
|  |         image[j].a = data[i + 3]; | ||||||
|  |         j++; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     TraceLog(DEBUG, "Mipmap base (%i, %i)", width, height); | ||||||
|  |      | ||||||
|  |     for (int mip = 1; mip < mipmapCount; mip++) | ||||||
|  |     { | ||||||
|  |         mipmap = GenNextMipmap(image, width, height); | ||||||
|  |          | ||||||
|  |         offset += (width*height*4); // Size of last mipmap | ||||||
|  |         j = 0; | ||||||
|  |          | ||||||
|  |         width /= 2; | ||||||
|  |         height /= 2; | ||||||
|  |         size = (width*height*4);    // Mipmap size to store after offset | ||||||
|  |  | ||||||
|  |         // Add mipmap to data | ||||||
|  |         for (int i = 0; i < size; i += 4) | ||||||
|  |         { | ||||||
|  |             data[offset + i] = mipmap[j].r; | ||||||
|  |             data[offset + i + 1] = mipmap[j].g; | ||||||
|  |             data[offset + i + 2] = mipmap[j].b; | ||||||
|  |             data[offset + i + 3] = mipmap[j].a;  | ||||||
|  |             j++; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         free(image); | ||||||
|  |          | ||||||
|  |         image = mipmap; | ||||||
|  |         mipmap = NULL; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     free(mipmap);       // free mipmap data | ||||||
|  |      | ||||||
|  |     return mipmapCount; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Manual mipmap generation (basic scaling algorithm) | ||||||
|  | static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight) | ||||||
|  | { | ||||||
|  |     int x2, y2; | ||||||
|  |     pixel prow, pcol; | ||||||
|  |  | ||||||
|  |     int width = srcWidth / 2; | ||||||
|  |     int height = srcHeight / 2; | ||||||
|  |  | ||||||
|  |     pixel *mipmap = (pixel *)malloc(width*height*sizeof(pixel)); | ||||||
|  |  | ||||||
|  |     // Scaling algorithm works perfectly (box-filter) | ||||||
|  |     for (int y = 0; y < height; y++)  | ||||||
|  |     { | ||||||
|  |         y2 = 2 * y; | ||||||
|  |  | ||||||
|  |         for (int x = 0; x < width; x++)  | ||||||
|  |         { | ||||||
|  |             x2 = 2 * x; | ||||||
|  |  | ||||||
|  |             prow.r = (srcData[y2*srcWidth + x2].r + srcData[y2*srcWidth + x2 + 1].r)/2; | ||||||
|  |             prow.g = (srcData[y2*srcWidth + x2].g + srcData[y2*srcWidth + x2 + 1].g)/2; | ||||||
|  |             prow.b = (srcData[y2*srcWidth + x2].b + srcData[y2*srcWidth + x2 + 1].b)/2; | ||||||
|  |             prow.a = (srcData[y2*srcWidth + x2].a + srcData[y2*srcWidth + x2 + 1].a)/2; | ||||||
|  |  | ||||||
|  |             pcol.r = (srcData[(y2+1)*srcWidth + x2].r + srcData[(y2+1)*srcWidth + x2 + 1].r)/2; | ||||||
|  |             pcol.g = (srcData[(y2+1)*srcWidth + x2].g + srcData[(y2+1)*srcWidth + x2 + 1].g)/2; | ||||||
|  |             pcol.b = (srcData[(y2+1)*srcWidth + x2].b + srcData[(y2+1)*srcWidth + x2 + 1].b)/2; | ||||||
|  |             pcol.a = (srcData[(y2+1)*srcWidth + x2].a + srcData[(y2+1)*srcWidth + x2 + 1].a)/2; | ||||||
|  |  | ||||||
|  |             mipmap[y*width + x].r = (prow.r + pcol.r)/2; | ||||||
|  |             mipmap[y*width + x].g = (prow.g + pcol.g)/2; | ||||||
|  |             mipmap[y*width + x].b = (prow.b + pcol.b)/2; | ||||||
|  |             mipmap[y*width + x].a = (prow.a + pcol.a)/2; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     TraceLog(DEBUG, "Mipmap generated successfully (%i, %i)", width, height); | ||||||
|  |  | ||||||
|  |     return mipmap; | ||||||
|  | } | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef RLGL_STANDALONE | #ifdef RLGL_STANDALONE | ||||||
| @@ -1555,10 +1800,10 @@ void TraceLog(int msgType, const char *text, ...) | |||||||
|      |      | ||||||
|     switch(msgType) |     switch(msgType) | ||||||
|     { |     { | ||||||
|         case 0: fprintf(stdout, "INFO: "); break; |         case INFO: fprintf(stdout, "INFO: "); break; | ||||||
|         case 1: fprintf(stdout, "ERROR: "); break; |         case ERROR: fprintf(stdout, "ERROR: "); break; | ||||||
|         case 2: fprintf(stdout, "WARNING: "); break; |         case WARNING: fprintf(stdout, "WARNING: "); break; | ||||||
|         case 3: fprintf(logstream, "DEBUG: "); break; |         case DEBUG: fprintf(stdout, "DEBUG: "); break; | ||||||
|         default: break; |         default: break; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @@ -1567,6 +1812,6 @@ void TraceLog(int msgType, const char *text, ...) | |||||||
|      |      | ||||||
|     va_end(args); |     va_end(args); | ||||||
|      |      | ||||||
|     if (msgType == 1) exit(1); |     if (msgType == ERROR) exit(1); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
							
								
								
									
										41
									
								
								src/rlgl.h
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								src/rlgl.h
									
									
									
									
									
								
							| @@ -39,16 +39,16 @@ | |||||||
| #include "raymath.h"            // Required for data type Matrix and Matrix functions | #include "raymath.h"            // Required for data type Matrix and Matrix functions | ||||||
|  |  | ||||||
| // Select desired OpenGL version | // Select desired OpenGL version | ||||||
| //#define USE_OPENGL_11 | #define USE_OPENGL_11 | ||||||
| #define USE_OPENGL_33 | //#define USE_OPENGL_33 | ||||||
| //#define USE_OPENGL_ES2 | //#define USE_OPENGL_ES2 | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Defines and Macros | // Defines and Macros | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| #define MAX_LINES_BATCH         8192    // 1024 | #define MAX_LINES_BATCH         8192    // NOTE: Be careful with limits! | ||||||
| #define MAX_TRIANGLES_BATCH     2048 | #define MAX_TRIANGLES_BATCH     4096    // NOTE: Be careful with limits! | ||||||
| #define MAX_QUADS_BATCH         8192 | #define MAX_QUADS_BATCH         8192    // NOTE: Be careful with limits! | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Types and Structures Definition | // Types and Structures Definition | ||||||
| @@ -60,26 +60,20 @@ typedef enum { RL_PROJECTION, RL_MODELVIEW, RL_TEXTURE } MatrixMode; | |||||||
| typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode; | typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode; | ||||||
|  |  | ||||||
| #ifdef RLGL_STANDALONE | #ifdef RLGL_STANDALONE | ||||||
| typedef struct Model Model; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     typedef struct { |     typedef struct { | ||||||
|     int numVertices; |         int vertexCount; | ||||||
|         float *vertices;            // 3 components per vertex |         float *vertices;            // 3 components per vertex | ||||||
|         float *texcoords;           // 2 components per vertex |         float *texcoords;           // 2 components per vertex | ||||||
|         float *normals;             // 3 components per vertex |         float *normals;             // 3 components per vertex | ||||||
|  |         float *colors; | ||||||
|     } VertexData; |     } VertexData; | ||||||
|  |  | ||||||
| #ifdef USE_OPENGL_11 |     typedef struct Model { | ||||||
| struct Model { |         VertexData mesh; | ||||||
|     VertexData data; |  | ||||||
| }; |  | ||||||
| #else |  | ||||||
| struct Model { |  | ||||||
|         unsigned int vaoId; |         unsigned int vaoId; | ||||||
|     Matrix transform; |         unsigned int textureId; | ||||||
|     int numVertices; |         //Matrix transform; | ||||||
| }; |     } Model; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| @@ -90,8 +84,8 @@ extern "C" {            // Prevents name mangling of functions | |||||||
| // Functions Declaration - Matrix operations | // Functions Declaration - Matrix operations | ||||||
| //------------------------------------------------------------------------------------ | //------------------------------------------------------------------------------------ | ||||||
| void rlMatrixMode(int mode);                    // Choose the current matrix to be transformed | void rlMatrixMode(int mode);                    // Choose the current matrix to be transformed | ||||||
| void rlPushMatrix();                            // TODO: REVIEW: Required? - Push the current matrix to stack | void rlPushMatrix();                            // Push the current matrix to stack | ||||||
| void rlPopMatrix();                             // TODO: REVIEW: Required? - Pop lattest inserted matrix from stack | void rlPopMatrix();                             // Pop lattest inserted matrix from stack | ||||||
| void rlLoadIdentity();                          // Reset current matrix to identity matrix | void rlLoadIdentity();                          // Reset current matrix to identity matrix | ||||||
| void rlTranslatef(float x, float y, float z);   // Multiply the current matrix by a translation matrix | void rlTranslatef(float x, float y, float z);   // Multiply the current matrix by a translation matrix | ||||||
| void rlRotatef(float angleDeg, float x, float y, float z);  // Multiply the current matrix by a rotation matrix | void rlRotatef(float angleDeg, float x, float y, float z);  // Multiply the current matrix by a rotation matrix | ||||||
| @@ -132,13 +126,14 @@ void rlClearScreenBuffers();                // Clear used screen buffers (color | |||||||
| void rlglInit();                                // Initialize rlgl (shaders, VAO, VBO...) | void rlglInit();                                // Initialize rlgl (shaders, VAO, VBO...) | ||||||
| void rlglClose();                               // De-init rlgl | void rlglClose();                               // De-init rlgl | ||||||
| void rlglDraw();                                // Draw VAOs | void rlglDraw();                                // Draw VAOs | ||||||
| unsigned int rlglLoadModel(VertexData data); | unsigned int rlglLoadModel(VertexData mesh); | ||||||
| unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int format); | unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int format); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| void rlglDrawModel(Model model, Vector3 position, float scale, bool wires);   // Draw model | void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color color, bool wires); | ||||||
|  |  | ||||||
| void rlglInitGraphicsDevice(int fbWidth, int fbHeight);  // Initialize Graphics Device (OpenGL stuff) | void rlglInitGraphicsDevice(int fbWidth, int fbHeight);  // Initialize Graphics Device (OpenGL stuff) | ||||||
| unsigned int rlglLoadTexture(int width, int height, unsigned char *pixels); // Load in GPU OpenGL texture | unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool genMipmaps); // Load in GPU OpenGL texture | ||||||
| byte *rlglReadScreenPixels(int width, int height);    // Read screen pixel data (color buffer) | byte *rlglReadScreenPixels(int width, int height);    // Read screen pixel data (color buffer) | ||||||
|  |  | ||||||
| #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | ||||||
|   | |||||||
							
								
								
									
										39
									
								
								src/shapes.c
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								src/shapes.c
									
									
									
									
									
								
							| @@ -112,6 +112,7 @@ void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Co | |||||||
|             rlVertex2i(centerX, centerY); |             rlVertex2i(centerX, centerY); | ||||||
|             rlColor4ub(color2.r, color2.g, color2.b, color2.a); |             rlColor4ub(color2.r, color2.g, color2.b, color2.a); | ||||||
|             rlVertex2f(centerX + sin(DEG2RAD*i) * radius, centerY + cos(DEG2RAD*i) * radius); |             rlVertex2f(centerX + sin(DEG2RAD*i) * radius, centerY + cos(DEG2RAD*i) * radius); | ||||||
|  |             rlColor4ub(color2.r, color2.g, color2.b, color2.a); | ||||||
|             rlVertex2f(centerX + sin(DEG2RAD*(i+2)) * radius, centerY + cos(DEG2RAD*(i+2)) * radius); |             rlVertex2f(centerX + sin(DEG2RAD*(i+2)) * radius, centerY + cos(DEG2RAD*(i+2)) * radius); | ||||||
|         } |         } | ||||||
|     rlEnd(); |     rlEnd(); | ||||||
| @@ -149,17 +150,10 @@ void DrawCircleLines(int centerX, int centerY, float radius, Color color) | |||||||
| // Draw a color-filled rectangle | // Draw a color-filled rectangle | ||||||
| void DrawRectangle(int posX, int posY, int width, int height, Color color) | void DrawRectangle(int posX, int posY, int width, int height, Color color) | ||||||
| { | { | ||||||
|     rlBegin(RL_QUADS); |     Vector2 position = { (float)posX, (float)posY }; | ||||||
|         rlColor4ub(color.r, color.g, color.b, color.a); |     Vector2 size = { (float)width, (float)height }; | ||||||
|         rlTexCoord2f(0.0f, 0.0f); |  | ||||||
|         rlVertex2i(posX, posY); |     DrawRectangleV(position, size, color); | ||||||
|         rlTexCoord2f(0.0f, 1.0f);  |  | ||||||
|         rlVertex2i(posX, posY + height); |  | ||||||
|         rlTexCoord2f(1.0f, 1.0f);  |  | ||||||
|         rlVertex2i(posX + width, posY + height); |  | ||||||
|         rlTexCoord2f(1.0f, 0.0f); |  | ||||||
|         rlVertex2i(posX + width, posY); |  | ||||||
|     rlEnd(); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Draw a color-filled rectangle | // Draw a color-filled rectangle | ||||||
| @@ -172,26 +166,29 @@ void DrawRectangleRec(Rectangle rec, Color color) | |||||||
| // NOTE: Gradient goes from bottom (color1) to top (color2) | // NOTE: Gradient goes from bottom (color1) to top (color2) | ||||||
| void DrawRectangleGradient(int posX, int posY, int width, int height, Color color1, Color color2) | void DrawRectangleGradient(int posX, int posY, int width, int height, Color color1, Color color2) | ||||||
| { | { | ||||||
|     rlBegin(RL_QUADS); |     rlBegin(RL_TRIANGLES); | ||||||
|         rlColor4ub(color1.r, color1.g, color1.b, color1.a); |         rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX, posY); | ||||||
|         rlVertex2i(posX, posY); |         rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX, posY + height); | ||||||
|         rlColor4ub(color1.r, color1.g, color1.b, color1.a); |         rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height); | ||||||
|         rlVertex2i(posX, posY + height); |          | ||||||
|         rlColor4ub(color2.r, color2.g, color2.b, color2.a); |         rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX, posY); | ||||||
|         rlVertex2i(posX + width, posY + height); |         rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height);         | ||||||
|         rlColor4ub(color2.r, color2.g, color2.b, color2.a); |         rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX + width, posY); | ||||||
|         rlVertex2i(posX + width, posY); |  | ||||||
|     rlEnd(); |     rlEnd(); | ||||||
| } | } | ||||||
|  |  | ||||||
| // Draw a color-filled rectangle (Vector version) | // Draw a color-filled rectangle (Vector version) | ||||||
| void DrawRectangleV(Vector2 position, Vector2 size, Color color) | void DrawRectangleV(Vector2 position, Vector2 size, Color color) | ||||||
| { | { | ||||||
|     rlBegin(RL_QUADS); |     rlBegin(RL_TRIANGLES); | ||||||
|         rlColor4ub(color.r, color.g, color.b, color.a); |         rlColor4ub(color.r, color.g, color.b, color.a); | ||||||
|  |          | ||||||
|         rlVertex2i(position.x, position.y); |         rlVertex2i(position.x, position.y); | ||||||
|         rlVertex2i(position.x, position.y + size.y); |         rlVertex2i(position.x, position.y + size.y); | ||||||
|         rlVertex2i(position.x + size.x, position.y + size.y); |         rlVertex2i(position.x + size.x, position.y + size.y); | ||||||
|  |          | ||||||
|  |         rlVertex2i(position.x, position.y); | ||||||
|  |         rlVertex2i(position.x + size.x, position.y + size.y);         | ||||||
|         rlVertex2i(position.x + size.x, position.y); |         rlVertex2i(position.x + size.x, position.y); | ||||||
|     rlEnd(); |     rlEnd(); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										39
									
								
								src/text.c
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								src/text.c
									
									
									
									
									
								
							| @@ -35,6 +35,8 @@ | |||||||
|  |  | ||||||
| #include "rlgl.h"         // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 | #include "rlgl.h"         // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 | ||||||
|  |  | ||||||
|  | #include "utils.h"        // Required for function GetExtendion() | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Defines and Macros | // Defines and Macros | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| @@ -58,15 +60,6 @@ typedef struct Character { | |||||||
|     int h; |     int h; | ||||||
| } Character; | } Character; | ||||||
|  |  | ||||||
| // SpriteFont type, includes texture and charSet array data |  | ||||||
| /* |  | ||||||
| struct SpriteFont { |  | ||||||
|     Texture2D texture; |  | ||||||
|     int numChars; |  | ||||||
|     Character *charSet; |  | ||||||
| }; |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Global variables | // Global variables | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| @@ -85,7 +78,6 @@ static bool PixelIsMagenta(Color p);                // Check if a pixel is magen | |||||||
| static int ParseImageData(Color *imgDataPixel, int imgWidth, int imgHeight, Character **charSet);    // Parse image pixel data to obtain character set measures | static int ParseImageData(Color *imgDataPixel, int imgWidth, int imgHeight, Character **charSet);    // Parse image pixel data to obtain character set measures | ||||||
| static int GetNextPOT(int num);                     // Calculate next power-of-two value for a given value | static int GetNextPOT(int num);                     // Calculate next power-of-two value for a given value | ||||||
| static SpriteFont LoadRBMF(const char *fileName);   // Load a rBMF font file (raylib BitMap Font) | static SpriteFont LoadRBMF(const char *fileName);   // Load a rBMF font file (raylib BitMap Font) | ||||||
| static const char *GetExtension(const char *fileName); |  | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Module Functions Definition | // Module Functions Definition | ||||||
| @@ -153,8 +145,7 @@ extern void LoadDefaultFont() | |||||||
|         if (counter > 256) counter = 0;         // Security check... |         if (counter > 256) counter = 0;         // Security check... | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     defaultFont.texture = CreateTexture(image); // Convert loaded image to OpenGL texture |     defaultFont.texture = CreateTexture(image, false); // Convert loaded image to OpenGL texture | ||||||
|  |  | ||||||
|     UnloadImage(image); |     UnloadImage(image); | ||||||
|      |      | ||||||
|     // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars |     // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars | ||||||
| @@ -192,7 +183,7 @@ extern void LoadDefaultFont() | |||||||
|  |  | ||||||
| extern void UnloadDefaultFont() | extern void UnloadDefaultFont() | ||||||
| { | { | ||||||
|     rlDeleteTextures(defaultFont.texture.glId); |     rlDeleteTextures(defaultFont.texture.id); | ||||||
|     free(defaultFont.charSet); |     free(defaultFont.charSet); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -277,8 +268,7 @@ SpriteFont LoadSpriteFont(const char* fileName) | |||||||
|         image.width = potWidth; |         image.width = potWidth; | ||||||
|         image.height = potHeight; |         image.height = potHeight; | ||||||
|          |          | ||||||
|         spriteFont.texture = CreateTexture(image); // Convert loaded image to OpenGL texture |         spriteFont.texture = CreateTexture(image, false); // Convert loaded image to OpenGL texture | ||||||
|  |  | ||||||
|         UnloadImage(image); |         UnloadImage(image); | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @@ -288,7 +278,7 @@ SpriteFont LoadSpriteFont(const char* fileName) | |||||||
| // Unload SpriteFont from GPU memory | // Unload SpriteFont from GPU memory | ||||||
| void UnloadSpriteFont(SpriteFont spriteFont) | void UnloadSpriteFont(SpriteFont spriteFont) | ||||||
| { | { | ||||||
|     rlDeleteTextures(spriteFont.texture.glId); |     rlDeleteTextures(spriteFont.texture.id); | ||||||
|     free(spriteFont.charSet); |     free(spriteFont.charSet); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -322,7 +312,7 @@ void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, int f | |||||||
|     if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f; |     if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f; | ||||||
|     else scaleFactor = (float)fontSize / spriteFont.charSet[0].h; |     else scaleFactor = (float)fontSize / spriteFont.charSet[0].h; | ||||||
|  |  | ||||||
|     rlEnableTexture(spriteFont.texture.glId); |     rlEnableTexture(spriteFont.texture.id); | ||||||
|  |  | ||||||
|     rlBegin(RL_QUADS); |     rlBegin(RL_QUADS); | ||||||
|         for(int i = 0; i < length; i++) |         for(int i = 0; i < length; i++) | ||||||
| @@ -596,8 +586,7 @@ static SpriteFont LoadRBMF(const char *fileName) | |||||||
|      |      | ||||||
|     TraceLog(INFO, "[%s] Image reconstructed correctly, now converting it to texture", fileName); |     TraceLog(INFO, "[%s] Image reconstructed correctly, now converting it to texture", fileName); | ||||||
|      |      | ||||||
|     spriteFont.texture = CreateTexture(image); |     spriteFont.texture = CreateTexture(image, false); | ||||||
|      |  | ||||||
|     UnloadImage(image);     // Unload image data |     UnloadImage(image);     // Unload image data | ||||||
|      |      | ||||||
|     TraceLog(INFO, "[%s] Starting charSet reconstruction", fileName); |     TraceLog(INFO, "[%s] Starting charSet reconstruction", fileName); | ||||||
| @@ -641,10 +630,12 @@ static SpriteFont LoadRBMF(const char *fileName) | |||||||
|     return spriteFont; |     return spriteFont; | ||||||
| } | } | ||||||
|  |  | ||||||
| // Get the extension for a filename | // Generate a sprite font from TTF data (font size required) | ||||||
| static const char *GetExtension(const char *fileName)  | static SpriteFont GenerateFromTTF(const char *fileName, int fontSize) | ||||||
| { | { | ||||||
|     const char *dot = strrchr(fileName, '.'); |     SpriteFont font; | ||||||
|     if(!dot || dot == fileName) return ""; |      | ||||||
|     return dot + 1; |     // TODO: Load TTF and generate bitmap font and chars data | ||||||
|  |      | ||||||
|  |     return font; | ||||||
| } | } | ||||||
							
								
								
									
										295
									
								
								src/textures.c
									
									
									
									
									
								
							
							
						
						
									
										295
									
								
								src/textures.c
									
									
									
									
									
								
							| @@ -46,12 +46,14 @@ | |||||||
| typedef unsigned char byte; | typedef unsigned char byte; | ||||||
|  |  | ||||||
| typedef struct { | typedef struct { | ||||||
|     unsigned char *data; |     unsigned char *data;    // Image raw data | ||||||
|     int width; |     int width;              // Image base width | ||||||
|     int height; |     int height;             // Image base height | ||||||
|     int mipmaps; |     //int bpp;              // bytes per pixel | ||||||
|     int format; |     //int components;       // num color components | ||||||
| } ImageDDS; |     int mipmaps;            // Mipmap levels, 1 by default | ||||||
|  |     int compFormat;         // Compressed data format, 0 if no compression | ||||||
|  | } ImageEx; | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Global Variables Definition | // Global Variables Definition | ||||||
| @@ -66,8 +68,7 @@ typedef struct { | |||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Module specific Functions Declaration | // Module specific Functions Declaration | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| static const char *GetExtension(const char *fileName); | static ImageEx LoadDDS(const char *fileName); | ||||||
| static ImageDDS LoadDDS(const char *fileName); |  | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Module Functions Definition | // Module Functions Definition | ||||||
| @@ -78,6 +79,11 @@ Image LoadImage(const char *fileName) | |||||||
| { | { | ||||||
|     Image image; |     Image image; | ||||||
|      |      | ||||||
|  |     // Initial values | ||||||
|  |     image.pixels = NULL; | ||||||
|  |     image.width = 0; | ||||||
|  |     image.height = 0; | ||||||
|  |      | ||||||
|     if ((strcmp(GetExtension(fileName),"png") == 0) || |     if ((strcmp(GetExtension(fileName),"png") == 0) || | ||||||
|         (strcmp(GetExtension(fileName),"bmp") == 0) || |         (strcmp(GetExtension(fileName),"bmp") == 0) || | ||||||
|         (strcmp(GetExtension(fileName),"tga") == 0) || |         (strcmp(GetExtension(fileName),"tga") == 0) || | ||||||
| @@ -115,6 +121,35 @@ Image LoadImage(const char *fileName) | |||||||
|          |          | ||||||
|         TraceLog(INFO, "[%s] Image loaded successfully", fileName); |         TraceLog(INFO, "[%s] Image loaded successfully", fileName); | ||||||
|     } |     } | ||||||
|  |     else if (strcmp(GetExtension(fileName),"dds") == 0) | ||||||
|  |     { | ||||||
|  |         // NOTE: DDS uncompressed images can also be loaded (discarding mipmaps...) | ||||||
|  |          | ||||||
|  |         ImageEx imageDDS = LoadDDS(fileName); | ||||||
|  |          | ||||||
|  |         if (imageDDS.compFormat == 0) | ||||||
|  |         { | ||||||
|  |             image.pixels = (Color *)malloc(imageDDS.width * imageDDS.height * sizeof(Color)); | ||||||
|  |             image.width = imageDDS.width; | ||||||
|  |             image.height = imageDDS.height; | ||||||
|  |              | ||||||
|  |             int pix = 0; | ||||||
|  |          | ||||||
|  |             for (int i = 0; i < (image.width * image.height * 4); i += 4) | ||||||
|  |             { | ||||||
|  |                 image.pixels[pix].r = imageDDS.data[i]; | ||||||
|  |                 image.pixels[pix].g = imageDDS.data[i+1]; | ||||||
|  |                 image.pixels[pix].b = imageDDS.data[i+2]; | ||||||
|  |                 image.pixels[pix].a = imageDDS.data[i+3]; | ||||||
|  |                 pix++; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             free(imageDDS.data); | ||||||
|  |              | ||||||
|  |             TraceLog(INFO, "[%s] Image loaded successfully", fileName); | ||||||
|  |         } | ||||||
|  |         else TraceLog(WARNING, "[%s] Compressed image data could not be loaded", fileName);     | ||||||
|  |     } | ||||||
|     else TraceLog(WARNING, "[%s] Image extension not recognized, it can't be loaded", fileName); |     else TraceLog(WARNING, "[%s] Image extension not recognized, it can't be loaded", fileName); | ||||||
|      |      | ||||||
|     // ALTERNATIVE: We can load pixel data directly into Color struct pixels array,  |     // ALTERNATIVE: We can load pixel data directly into Color struct pixels array,  | ||||||
| @@ -127,7 +162,8 @@ Image LoadImage(const char *fileName) | |||||||
| // Load an image from rRES file (raylib Resource) | // Load an image from rRES file (raylib Resource) | ||||||
| Image LoadImageFromRES(const char *rresName, int resId) | Image LoadImageFromRES(const char *rresName, int resId) | ||||||
| { | { | ||||||
|     // NOTE: rresName could be directly a char array with all the data!!! ---> TODO! |     // TODO: rresName could be directly a char array with all the data! --> support it! :P | ||||||
|  |      | ||||||
|     Image image; |     Image image; | ||||||
|     bool found = false; |     bool found = false; | ||||||
|  |  | ||||||
| @@ -172,8 +208,8 @@ Image LoadImageFromRES(const char *rresName, int resId) | |||||||
|                     if (infoHeader.type == 0)   // IMAGE data type |                     if (infoHeader.type == 0)   // IMAGE data type | ||||||
|                     { |                     { | ||||||
|                         // TODO: Check data compression type |                         // TODO: Check data compression type | ||||||
|                          |  | ||||||
|                         // NOTE: We suppose compression type 2 (DEFLATE - default) |                         // NOTE: We suppose compression type 2 (DEFLATE - default) | ||||||
|  |  | ||||||
|                         short imgWidth, imgHeight; |                         short imgWidth, imgHeight; | ||||||
|                         char colorFormat, mipmaps; |                         char colorFormat, mipmaps; | ||||||
|                      |                      | ||||||
| @@ -249,19 +285,26 @@ Texture2D LoadTexture(const char *fileName) | |||||||
|  |  | ||||||
|     if (strcmp(GetExtension(fileName),"dds") == 0) |     if (strcmp(GetExtension(fileName),"dds") == 0) | ||||||
|     { |     { | ||||||
| #ifdef USE_OPENGL_11  |         ImageEx image = LoadDDS(fileName); | ||||||
|         TraceLog(WARNING, "[%s] DDS file loading requires OpenGL 3.2+ or ES 2.0", fileName); |  | ||||||
| #else |  | ||||||
|         ImageDDS image = LoadDDS(fileName); |  | ||||||
|          |          | ||||||
|         texture.glId = rlglLoadCompressedTexture(image.data, image.width, image.height, image.mipmaps, image.format); |         if (image.compFormat == 0) | ||||||
|  |         { | ||||||
|  |             texture.id = rlglLoadTexture(image.data, image.width, image.height, false); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  | #ifdef USE_OPENGL_33 | ||||||
|  |             texture.id = rlglLoadCompressedTexture(image.data, image.width, image.height, image.mipmaps, image.compFormat); | ||||||
|  | #endif | ||||||
|  |         } | ||||||
|          |          | ||||||
|         texture.width = image.width; |         texture.width = image.width; | ||||||
|         texture.height = image.height; |         texture.height = image.height; | ||||||
|          |          | ||||||
|         if (texture.glId == 0) TraceLog(WARNING, "Compressed texture could not be loaded"); |         if (texture.id == 0) TraceLog(WARNING, "[%s] DDS texture could not be loaded", fileName); | ||||||
|         else TraceLog(INFO, "Compressed texture loaded succesfully"); |         else TraceLog(INFO, "[%s] DDS texture loaded succesfully", fileName); | ||||||
| #endif |          | ||||||
|  |         free(image.data); | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
| @@ -269,7 +312,7 @@ Texture2D LoadTexture(const char *fileName) | |||||||
|          |          | ||||||
|         if (image.pixels != NULL) |         if (image.pixels != NULL) | ||||||
|         { |         { | ||||||
|             texture = CreateTexture(image); |             texture = CreateTexture(image, false); | ||||||
|             UnloadImage(image); |             UnloadImage(image); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -283,7 +326,8 @@ Texture2D LoadTextureFromRES(const char *rresName, int resId) | |||||||
|     Texture2D texture; |     Texture2D texture; | ||||||
|  |  | ||||||
|     Image image = LoadImageFromRES(rresName, resId); |     Image image = LoadImageFromRES(rresName, resId); | ||||||
|     texture = CreateTexture(image); |     texture = CreateTexture(image, false); | ||||||
|  |     UnloadImage(image); | ||||||
|      |      | ||||||
|     return texture; |     return texture; | ||||||
| } | } | ||||||
| @@ -297,7 +341,7 @@ void UnloadImage(Image image) | |||||||
| // Unload texture from GPU memory | // Unload texture from GPU memory | ||||||
| void UnloadTexture(Texture2D texture) | void UnloadTexture(Texture2D texture) | ||||||
| { | { | ||||||
|     rlDeleteTextures(texture.glId); |     rlDeleteTextures(texture.id); | ||||||
| } | } | ||||||
|  |  | ||||||
| // Draw a Texture2D | // Draw a Texture2D | ||||||
| @@ -315,76 +359,32 @@ void DrawTextureV(Texture2D texture, Vector2 position, Color tint) | |||||||
| // Draw a Texture2D with extended parameters | // Draw a Texture2D with extended parameters | ||||||
| void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint) | void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint) | ||||||
| { | { | ||||||
|     rlEnableTexture(texture.glId); |     Rectangle sourceRec = { 0, 0, texture.width, texture.height }; | ||||||
|  |     Rectangle destRec = { (int)position.x, (int)position.y, texture.width*scale, texture.height*scale }; | ||||||
|  |     Vector2 origin = { 0, 0 }; | ||||||
|      |      | ||||||
|     // NOTE: Rotation is applied before translation and scaling, even being called in inverse order... |     DrawTexturePro(texture, sourceRec, destRec, origin, rotation, tint); | ||||||
|     // NOTE: Rotation point is upper-left corner     |  | ||||||
|     rlPushMatrix(); |  | ||||||
|         //rlTranslatef(position.x, position.y, 0.0); |  | ||||||
|         rlRotatef(rotation, 0, 0, 1); |  | ||||||
|         rlScalef(scale, scale, 1.0f); |  | ||||||
|      |  | ||||||
|         rlBegin(RL_QUADS); |  | ||||||
|             rlColor4ub(tint.r, tint.g, tint.b, tint.a); |  | ||||||
|             rlNormal3f(0.0f, 0.0f, 1.0f);                               // Normal vector pointing towards viewer |  | ||||||
|              |  | ||||||
|             rlTexCoord2f(0.0f, 0.0f); |  | ||||||
|             rlVertex2f(position.x, position.y);                         // Bottom-left corner for texture and quad |  | ||||||
|              |  | ||||||
|             rlTexCoord2f(0.0f, 1.0f);  |  | ||||||
|             rlVertex2f(position.x, position.y + texture.height);        // Bottom-right corner for texture and quad |  | ||||||
|              |  | ||||||
|             rlTexCoord2f(1.0f, 1.0f);  |  | ||||||
|             rlVertex2f(position.x + texture.width, position.y + texture.height);  // Top-right corner for texture and quad |  | ||||||
|              |  | ||||||
|             rlTexCoord2f(1.0f, 0.0f);  |  | ||||||
|             rlVertex2f(position.x + texture.width, position.y);         // Top-left corner for texture and quad |  | ||||||
|         rlEnd(); |  | ||||||
|     rlPopMatrix(); |  | ||||||
|      |  | ||||||
|     rlDisableTexture(); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Draw a part of a texture (defined by a rectangle) | // Draw a part of a texture (defined by a rectangle) | ||||||
| void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint) | void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint) | ||||||
| { | { | ||||||
|     rlEnableTexture(texture.glId); |     Rectangle destRec = { (int)position.x, (int)position.y, sourceRec.width, sourceRec.height }; | ||||||
|  |     Vector2 origin = { 0, 0 }; | ||||||
|      |      | ||||||
|     rlBegin(RL_QUADS); |     DrawTexturePro(texture, sourceRec, destRec, origin, 0, tint); | ||||||
|         rlColor4ub(tint.r, tint.g, tint.b, tint.a); |  | ||||||
|         rlNormal3f(0.0f, 0.0f, 1.0f);                          // Normal vector pointing towards viewer |  | ||||||
|          |  | ||||||
|         // Bottom-left corner for texture and quad |  | ||||||
|         rlTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height);  |  | ||||||
|         rlVertex2f(position.x, position.y); |  | ||||||
|          |  | ||||||
|         // Bottom-right corner for texture and quad |  | ||||||
|         rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); |  | ||||||
|         rlVertex2f(position.x, position.y + sourceRec.height); |  | ||||||
|          |  | ||||||
|         // Top-right corner for texture and quad |  | ||||||
|         rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);  |  | ||||||
|         rlVertex2f(position.x + sourceRec.width, position.y + sourceRec.height); |  | ||||||
|          |  | ||||||
|         // Top-left corner for texture and quad  |  | ||||||
|         rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height); |  | ||||||
|         rlVertex2f(position.x + sourceRec.width, position.y); |  | ||||||
|     rlEnd(); |  | ||||||
|      |  | ||||||
|     rlDisableTexture(); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Draw a part of a texture (defined by a rectangle) with 'pro' parameters | // Draw a part of a texture (defined by a rectangle) with 'pro' parameters | ||||||
| // TODO: Test this function... | // NOTE: origin is relative to destination rectangle size | ||||||
| void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint) | void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint) | ||||||
| { | { | ||||||
|     rlEnableTexture(texture.glId); |     rlEnableTexture(texture.id); | ||||||
|      |      | ||||||
|     // NOTE: First we translate texture to origin to apply rotation and translation from there |  | ||||||
|     rlPushMatrix(); |     rlPushMatrix(); | ||||||
|         rlTranslatef(-origin.x, -origin.y, 0);   |         rlTranslatef(destRec.x, destRec.y, 0); | ||||||
|         rlRotatef(rotation, 0, 0, 1); |         rlRotatef(rotation, 0, 0, 1); | ||||||
|         rlTranslatef(destRec.x + origin.x, destRec.y + origin.y, 0); |         rlTranslatef(-origin.x, -origin.y, 0); | ||||||
|              |              | ||||||
|         rlBegin(RL_QUADS); |         rlBegin(RL_QUADS); | ||||||
|             rlColor4ub(tint.r, tint.g, tint.b, tint.a); |             rlColor4ub(tint.r, tint.g, tint.b, tint.a); | ||||||
| @@ -395,64 +395,83 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V | |||||||
|             rlVertex2f(0.0f, 0.0f); |             rlVertex2f(0.0f, 0.0f); | ||||||
|              |              | ||||||
|             // Bottom-right corner for texture and quad |             // Bottom-right corner for texture and quad | ||||||
|             rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height); |             rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); | ||||||
|             rlVertex2f(destRec.width, 0.0f); |             rlVertex2f(0.0f, destRec.height); | ||||||
|              |              | ||||||
|             // Top-right corner for texture and quad |             // Top-right corner for texture and quad | ||||||
|             rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);  |             rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);  | ||||||
|             rlVertex2f(destRec.width, destRec.height); |             rlVertex2f(destRec.width, destRec.height); | ||||||
|              |              | ||||||
|             // Top-left corner for texture and quad |             // Top-left corner for texture and quad | ||||||
|             rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); |             rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height); | ||||||
|             rlVertex2f(0.0f, destRec.height); |             rlVertex2f(destRec.width, 0.0f); | ||||||
|         rlEnd(); |         rlEnd(); | ||||||
|     rlPopMatrix(); |     rlPopMatrix(); | ||||||
|      |      | ||||||
|     rlDisableTexture(); |     rlDisableTexture(); | ||||||
| } | } | ||||||
|  |  | ||||||
| Texture2D CreateTexture(Image image) | // Create a texture from an image | ||||||
|  | // NOTE: image is not unloaded, iot must be done manually | ||||||
|  | Texture2D CreateTexture(Image image, bool genMipmaps) | ||||||
| { | { | ||||||
|     Texture2D texture; |     Texture2D texture; | ||||||
|      |      | ||||||
|     unsigned char *img = malloc(image.width * image.height * 4); |     // Init texture to default values | ||||||
|  |     texture.id = 0; | ||||||
|  |     texture.width = 0; | ||||||
|  |     texture.height = 0; | ||||||
|  |      | ||||||
|  |     if (image.pixels != NULL) | ||||||
|  |     { | ||||||
|  |         unsigned char *imgData = malloc(image.width * image.height * 4); | ||||||
|          |          | ||||||
|         int j = 0; |         int j = 0; | ||||||
|          |          | ||||||
|         for (int i = 0; i < image.width * image.height * 4; i += 4) |         for (int i = 0; i < image.width * image.height * 4; i += 4) | ||||||
|         { |         { | ||||||
|         img[i] = image.pixels[j].r; |             imgData[i] = image.pixels[j].r; | ||||||
|         img[i+1] = image.pixels[j].g; |             imgData[i+1] = image.pixels[j].g; | ||||||
|         img[i+2] = image.pixels[j].b; |             imgData[i+2] = image.pixels[j].b; | ||||||
|         img[i+3] = image.pixels[j].a; |             imgData[i+3] = image.pixels[j].a; | ||||||
|              |              | ||||||
|             j++; |             j++; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     texture.glId = rlglLoadTexture(image.width, image.height, img); |         // NOTE: rlglLoadTexture() can generate mipmaps (POT image required) | ||||||
|  |         texture.id = rlglLoadTexture(imgData, image.width, image.height, genMipmaps); | ||||||
|  |  | ||||||
|         texture.width = image.width; |         texture.width = image.width; | ||||||
|         texture.height = image.height; |         texture.height = image.height; | ||||||
|          |          | ||||||
|     TraceLog(INFO, "Texture created succesfully"); |         TraceLog(INFO, "[ID %i] Texture created succesfully", texture.id); | ||||||
|          |          | ||||||
|     free(img); |         free(imgData); | ||||||
|  |     } | ||||||
|  |     else TraceLog(WARNING, "Texture could not be created, image data is not valid"); | ||||||
|      |      | ||||||
|     return texture; |     return texture; | ||||||
| } | } | ||||||
|  |  | ||||||
| // Get the extension for a filename | // Loading DDS image data (compressed or uncompressed) | ||||||
| static const char *GetExtension(const char *fileName)  | // NOTE: Compressed data loading not supported on OpenGL 1.1 | ||||||
|  | ImageEx LoadDDS(const char *fileName) | ||||||
| {    | {    | ||||||
|     const char *dot = strrchr(fileName, '.'); |     #define FOURCC_DXT1 0x31545844  // Equivalent to "DXT1" in ASCII | ||||||
|     if(!dot || dot == fileName) return ""; |     #define FOURCC_DXT3 0x33545844  // Equivalent to "DXT3" in ASCII | ||||||
|     return (dot + 1); |     #define FOURCC_DXT5 0x35545844  // Equivalent to "DXT5" in ASCII | ||||||
| } |  | ||||||
|      |      | ||||||
| // Loading DDS image compressed data  |     #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT | ||||||
| ImageDDS LoadDDS(const char *fileName) |     #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 | ||||||
| {    |     #endif | ||||||
|     // TODO: Review and expand DDS file loading to support uncompressed formats and new formats |  | ||||||
|  |     #ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT | ||||||
|  |     #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 | ||||||
|  |     #endif | ||||||
|  |  | ||||||
|  |     #ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT | ||||||
|  |     #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 | ||||||
|  |     #endif | ||||||
|      |      | ||||||
|     // DDS Pixel Format |     // DDS Pixel Format | ||||||
|     typedef struct { |     typedef struct { | ||||||
| @@ -484,7 +503,7 @@ ImageDDS LoadDDS(const char *fileName) | |||||||
|         unsigned int reserved2; |         unsigned int reserved2; | ||||||
|     } ddsHeader; |     } ddsHeader; | ||||||
|      |      | ||||||
|     ImageDDS image; |     ImageEx image; | ||||||
|     ddsHeader header; |     ddsHeader header; | ||||||
|  |  | ||||||
|     FILE *ddsFile = fopen(fileName, "rb"); |     FILE *ddsFile = fopen(fileName, "rb"); | ||||||
| @@ -510,22 +529,60 @@ ImageDDS LoadDDS(const char *fileName) | |||||||
|             // Get the surface descriptor |             // Get the surface descriptor | ||||||
|             fread(&header, sizeof(ddsHeader), 1, ddsFile); |             fread(&header, sizeof(ddsHeader), 1, ddsFile); | ||||||
|  |  | ||||||
|             int height = header.height; |  | ||||||
|             int width = header.width; |  | ||||||
|             int linearSize = header.pitchOrLinearSize; |  | ||||||
|             int mipMapCount = header.mipMapCount; |  | ||||||
|             int fourCC = header.ddspf.fourCC; |  | ||||||
|              |  | ||||||
|             TraceLog(DEBUG, "[%s] DDS file header size: %i", fileName, sizeof(ddsHeader)); |             TraceLog(DEBUG, "[%s] DDS file header size: %i", fileName, sizeof(ddsHeader)); | ||||||
|              |  | ||||||
|             TraceLog(DEBUG, "[%s] DDS file pixel format size: %i", fileName, header.ddspf.size); |             TraceLog(DEBUG, "[%s] DDS file pixel format size: %i", fileName, header.ddspf.size); | ||||||
|             TraceLog(DEBUG, "[%s] DDS file pixel format flags: 0x%x", fileName, header.ddspf.flags); |             TraceLog(DEBUG, "[%s] DDS file pixel format flags: 0x%x", fileName, header.ddspf.flags); | ||||||
|             TraceLog(DEBUG, "[%s] DDS file format: 0x%x", fileName, fourCC); |             TraceLog(DEBUG, "[%s] DDS file format: 0x%x", fileName, header.ddspf.fourCC); | ||||||
|              |              | ||||||
|  |             image.width = header.width; | ||||||
|  |             image.height = header.height; | ||||||
|  |             image.mipmaps = 1; | ||||||
|  |             image.compFormat = 0; | ||||||
|  |              | ||||||
|  |             if (header.ddspf.flags == 0x40 && header.ddspf.rgbBitCount == 24)   // DDS_RGB, no compressed | ||||||
|  |             { | ||||||
|  |                 image.data = (unsigned char *)malloc(header.width * header.height * 4); | ||||||
|  |                 unsigned char *buffer = (unsigned char *)malloc(header.width * header.height * 3); | ||||||
|  |              | ||||||
|  |                 fread(buffer, image.width*image.height*3, 1, ddsFile); | ||||||
|  |                  | ||||||
|  |                 unsigned char *src = buffer; | ||||||
|  |                 unsigned char *dest = image.data; | ||||||
|  |                  | ||||||
|  |                 for(int y = 0; y < image.height; y++)  | ||||||
|  |                 { | ||||||
|  |                     for(int x = 0; x < image.width; x++)  | ||||||
|  |                     { | ||||||
|  |                         *dest++ = *src++; | ||||||
|  |                         *dest++ = *src++; | ||||||
|  |                         *dest++ = *src++; | ||||||
|  |                         *dest++ = 255; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 free(buffer); | ||||||
|  |             } | ||||||
|  |             else if (header.ddspf.flags == 0x41 && header.ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed | ||||||
|  |             { | ||||||
|  |                 image.data = (unsigned char *)malloc(header.width * header.height * 4); | ||||||
|  |              | ||||||
|  |                 fread(image.data, image.width*image.height*4, 1, ddsFile); | ||||||
|  |              | ||||||
|  |                 image.mipmaps = 1; | ||||||
|  |                 image.compFormat = 0; | ||||||
|  |             } | ||||||
|  |             else if ((header.ddspf.flags == 0x04) && (header.ddspf.fourCC > 0)) | ||||||
|  |             { | ||||||
|  | #ifdef USE_OPENGL_11  | ||||||
|  |                 TraceLog(WARNING, "[%s] DDS image uses compression, not supported by current OpenGL version", fileName); | ||||||
|  |                 TraceLog(WARNING, "[%s] DDS compressed files require OpenGL 3.2+ or ES 2.0", fileName); | ||||||
|  |                 fclose(ddsFile); | ||||||
|  | #else | ||||||
|                 int bufsize; |                 int bufsize; | ||||||
|                  |                  | ||||||
|                 // Calculate data size, including all mipmaps |                 // Calculate data size, including all mipmaps | ||||||
|             bufsize = mipMapCount > 1 ? linearSize * 2 : linearSize;  |                 if (header.mipMapCount > 1) bufsize = header.pitchOrLinearSize * 2; | ||||||
|  |                 else bufsize = header.pitchOrLinearSize;  | ||||||
|                  |                  | ||||||
|                 image.data = (unsigned char*)malloc(bufsize * sizeof(unsigned char));  |                 image.data = (unsigned char*)malloc(bufsize * sizeof(unsigned char));  | ||||||
|                  |                  | ||||||
| @@ -534,12 +591,22 @@ ImageDDS LoadDDS(const char *fileName) | |||||||
|                 // Close file pointer |                 // Close file pointer | ||||||
|                 fclose(ddsFile); |                 fclose(ddsFile); | ||||||
|                  |                  | ||||||
|             //int components = (fourCC == FOURCC_DXT1) ? 3 : 4; // Not required |                 image.mipmaps = header.mipMapCount; | ||||||
|  |                 image.compFormat = 0; | ||||||
|             |             | ||||||
|             image.width = width; |                 switch(header.ddspf.fourCC) | ||||||
|             image.height = height; |                 {  | ||||||
|             image.mipmaps = mipMapCount; |                     case FOURCC_DXT1: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;  | ||||||
|             image.format = fourCC; |                     case FOURCC_DXT3: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;  | ||||||
|  |                     case FOURCC_DXT5: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;  | ||||||
|  |                     default: break; | ||||||
|  |                 } | ||||||
|  |              | ||||||
|  |                 // NOTE: Image num color components not required... for now... | ||||||
|  |                 //if (fourCC == FOURCC_DXT1) image.components = 3; | ||||||
|  |                 //else image.components = 4; | ||||||
|  | #endif | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|   | |||||||
							
								
								
									
										92
									
								
								src/utils.c
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								src/utils.c
									
									
									
									
									
								
							| @@ -4,8 +4,9 @@ | |||||||
| * | * | ||||||
| *   Utils Functions Definitions | *   Utils Functions Definitions | ||||||
| *     | *     | ||||||
| *   Uses external lib:     | *   Uses external libs:     | ||||||
| *       tinfl - zlib DEFLATE algorithm decompression lib | *       tinfl - zlib DEFLATE algorithm decompression lib | ||||||
|  | *       stb_image_write - PNG writting functions | ||||||
| *        | *        | ||||||
| *   Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) | *   Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) | ||||||
| *     | *     | ||||||
| @@ -34,8 +35,8 @@ | |||||||
| //#include <string.h>           // String management functions: strlen(), strrchr(), strcmp() | //#include <string.h>           // String management functions: strlen(), strrchr(), strcmp() | ||||||
|  |  | ||||||
| #define STB_IMAGE_WRITE_IMPLEMENTATION | #define STB_IMAGE_WRITE_IMPLEMENTATION | ||||||
|  |  | ||||||
| #include "stb_image_write.h"    // Create PNG file | #include "stb_image_write.h"    // Create PNG file | ||||||
|  |  | ||||||
| #include "tinfl.c" | #include "tinfl.c" | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| @@ -140,9 +141,6 @@ void WritePNG(const char *fileName, unsigned char *imgData, int width, int heigh | |||||||
| // NOTE: If a file has been init, output log is written there | // NOTE: If a file has been init, output log is written there | ||||||
| void TraceLog(int msgType, const char *text, ...) | void TraceLog(int msgType, const char *text, ...) | ||||||
| { | { | ||||||
|     // TODO: This function requires some refactoring... |  | ||||||
|  |  | ||||||
|     // NOTE: If trace log file has been set, stdout is being redirected to a file |  | ||||||
|     va_list args; |     va_list args; | ||||||
|     int traceDebugMsgs = 1; |     int traceDebugMsgs = 1; | ||||||
|      |      | ||||||
| @@ -150,20 +148,19 @@ void TraceLog(int msgType, const char *text, ...) | |||||||
|     traceDebugMsgs = 0; |     traceDebugMsgs = 0; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|     if (logstream != NULL) |     // NOTE: If trace log file not set, output redirected to stdout  | ||||||
|     { |     if (logstream == NULL) logstream = stdout; | ||||||
|  |      | ||||||
|     switch(msgType) |     switch(msgType) | ||||||
|     { |     { | ||||||
|             case 0: fprintf(logstream, "INFO: "); break; |         case INFO: fprintf(logstream, "INFO: "); break; | ||||||
|             case 1: fprintf(logstream, "ERROR: "); break; |         case ERROR: fprintf(logstream, "ERROR: "); break; | ||||||
|             case 2: fprintf(logstream, "WARNING: "); break; |         case WARNING: fprintf(logstream, "WARNING: "); break; | ||||||
|             case 3: if (traceDebugMsgs) fprintf(logstream, "DEBUG: "); break; |         case DEBUG: if (traceDebugMsgs) fprintf(logstream, "DEBUG: "); break; | ||||||
|         default: break; |         default: break; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|         if (msgType == 3) |     if ((msgType != DEBUG) || ((msgType == DEBUG) && (traceDebugMsgs))) | ||||||
|         { |  | ||||||
|             if (traceDebugMsgs) |  | ||||||
|     { |     { | ||||||
|         va_start(args, text); |         va_start(args, text); | ||||||
|         vfprintf(logstream, text, args); |         vfprintf(logstream, text, args); | ||||||
| @@ -171,53 +168,12 @@ void TraceLog(int msgType, const char *text, ...) | |||||||
|          |          | ||||||
|         fprintf(logstream, "\n"); |         fprintf(logstream, "\n"); | ||||||
|     } |     } | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             va_start(args, text); |  | ||||||
|             vfprintf(logstream, text, args); |  | ||||||
|             va_end(args); |  | ||||||
|      |      | ||||||
|             fprintf(logstream, "\n"); |     if (msgType == ERROR) exit(1);      // If ERROR message, exit program | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     {    |  | ||||||
|         switch(msgType) |  | ||||||
|         { |  | ||||||
|             case 0: fprintf(stdout, "INFO: "); break; |  | ||||||
|             case 1: fprintf(stdout, "ERROR: "); break; |  | ||||||
|             case 2: fprintf(stdout, "WARNING: "); break; |  | ||||||
|             case 3: if (traceDebugMsgs) fprintf(stdout, "DEBUG: "); break; |  | ||||||
|             default: break; |  | ||||||
| } | } | ||||||
|  |  | ||||||
|         if (msgType == 3) | // Open a trace log file (if desired) | ||||||
|         { | void TraceLogOpen(const char *logFileName) | ||||||
|             if (traceDebugMsgs) |  | ||||||
|             { |  | ||||||
|                 va_start(args, text); |  | ||||||
|                 vfprintf(stdout, text, args); |  | ||||||
|                 va_end(args); |  | ||||||
|                  |  | ||||||
|                 fprintf(stdout, "\n"); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             va_start(args, text); |  | ||||||
|             vfprintf(stdout, text, args); |  | ||||||
|             va_end(args); |  | ||||||
|              |  | ||||||
|             fprintf(stdout, "\n"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     if (msgType == 1) exit(1);      // If ERROR message, exit program |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Inits a trace log file |  | ||||||
| void InitTraceLogFile(const char *logFileName) |  | ||||||
| { | { | ||||||
|     // stdout redirected to stream file |     // stdout redirected to stream file | ||||||
|     FILE *logstream = fopen(logFileName, "w"); |     FILE *logstream = fopen(logFileName, "w"); | ||||||
| @@ -225,9 +181,25 @@ void InitTraceLogFile(const char *logFileName) | |||||||
|     if (logstream == NULL) TraceLog(WARNING, "Unable to open log file"); |     if (logstream == NULL) TraceLog(WARNING, "Unable to open log file"); | ||||||
| } | } | ||||||
|  |  | ||||||
| // Closes the trace log file | // Close the trace log file | ||||||
| void CloseTraceLogFile() | void TraceLogClose() | ||||||
| { | { | ||||||
|     if (logstream != NULL) fclose(logstream); |     if (logstream != NULL) fclose(logstream); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Keep track of memory allocated | ||||||
|  | // NOTE: mallocType defines the type of data allocated | ||||||
|  | void RecordMalloc(int mallocType, int mallocSize, const char *msg) | ||||||
|  | { | ||||||
|  |     // TODO: Investigate how to record memory allocation data... | ||||||
|  |     // Maybe creating my own malloc function... | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Get the extension for a filename | ||||||
|  | const char *GetExtension(const char *fileName)  | ||||||
|  | { | ||||||
|  |     const char *dot = strrchr(fileName, '.'); | ||||||
|  |     if(!dot || dot == fileName) return ""; | ||||||
|  |     return (dot + 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								src/utils.h
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/utils.h
									
									
									
									
									
								
							| @@ -4,9 +4,6 @@ | |||||||
| * | * | ||||||
| *   Some utility functions: rRES files data decompression | *   Some utility functions: rRES files data decompression | ||||||
| *        | *        | ||||||
| *   Uses external lib:     |  | ||||||
| *       tinfl - zlib DEFLATE algorithm decompression lib |  | ||||||
| *        |  | ||||||
| *   Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) | *   Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) | ||||||
| *     | *     | ||||||
| *   This software is provided "as-is", without any express or implied warranty. In no event  | *   This software is provided "as-is", without any express or implied warranty. In no event  | ||||||
| @@ -32,12 +29,12 @@ | |||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Some basic Defines | // Some basic Defines | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| //#define DO_NOT_TRACE_DEBUG_MSGS   // Use this define to avoid DEBUG tracing | #define DO_NOT_TRACE_DEBUG_MSGS   // Use this define to avoid DEBUG tracing | ||||||
|  |  | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| // Types and Structures Definition | // Types and Structures Definition | ||||||
| //---------------------------------------------------------------------------------- | //---------------------------------------------------------------------------------- | ||||||
| typedef enum { IMAGE, SOUND, MODEL, TEXT, RAW } DataType; | typedef enum { IMAGE = 0, SOUND, MODEL, TEXT, RAW } DataType; | ||||||
|  |  | ||||||
| typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; | typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; | ||||||
|  |  | ||||||
| @@ -68,8 +65,10 @@ void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int he | |||||||
| void WritePNG(const char *fileName, unsigned char *imgData, int width, int height); | void WritePNG(const char *fileName, unsigned char *imgData, int width, int height); | ||||||
|  |  | ||||||
| void TraceLog(int msgType, const char *text, ...);  // Outputs a trace log message | void TraceLog(int msgType, const char *text, ...);  // Outputs a trace log message | ||||||
| void InitTraceLogFile(const char *logFileName);     // Inits a trace log file | void TraceLogOpen(const char *logFileName);         // Open a trace log file (if desired) | ||||||
| void CloseTraceLogFile();                           // Closes the trace log file | void TraceLogClose();                               // Close the trace log file | ||||||
|  |  | ||||||
|  | const char *GetExtension(const char *fileName); | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 raysan5
					raysan5