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 | ||||
| --------- | ||||
|  | ||||
| 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: 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) | ||||
| ----------------------------------------------- | ||||
|   | ||||
| @@ -10,7 +10,7 @@ The following help is highly appreciated: | ||||
| 	- Translators / Localizators - Can you translate raylib to another language? | ||||
| 	- Documentation / Tutorials / Example writters - Can you write some tutorial / example? | ||||
| 	- 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? | ||||
|  | ||||
| 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) | ||||
|  | ||||
|     | ||||
| [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,  | ||||
| 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  | ||||
| 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. | ||||
|  | ||||
| @@ -41,11 +60,14 @@ features | ||||
|   | ||||
|    *  Written in plain C code (C99) | ||||
|    *  Uses C# PascalCase/camelCase notation | ||||
|    * Hardware accelerated using OpenGL 1.1 | ||||
|    * Transparencies support (RGBA Colors) | ||||
|    * Custom color palette for better use on white background | ||||
|    * Basic 3D Support (camera, basic models, OBJ models, etc) | ||||
|    * Powerful Text module with SpriteFonts support | ||||
|    *  Hardware accelerated with OpenGL (1.1, 3.3+ or ES2) | ||||
|    *  Unique OpenGL abstraction layer [rlgl] | ||||
|    *  Powerful fonts module with SpriteFonts support | ||||
|    *  Multiple textures support, including DDS and mipmaps generation | ||||
|    *  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  | ||||
| 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 shapes.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 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 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)  | ||||
| are placed in the libraries path. It's also recommended to link with file icon.o for fancy raylib icon usage. | ||||
| 	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 | ||||
|  | ||||
| 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 | ||||
| 	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 | ||||
| ------- | ||||
| @@ -109,4 +142,4 @@ The following people have contributed in some way to make raylib project a reali | ||||
|  - [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 | ||||
| ------- | ||||
|  | ||||
| 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. | ||||
|  | ||||
| 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 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 | ||||
|    - Default scene Camera controls (zoom, pan, rotate)    | ||||
|    - Basic Procedural Texture / Image generation (Gradient, Checked, Spot, Noise, Cellular) | ||||
|    - Software mipmapping generation and POT conversion (custom implementation) | ||||
|    - Comments / Functions translation (?) | ||||
|    - Basic Procedural Image Generation (Gradient, Checked, Spot, Noise, Cellular) | ||||
|    - [DONE] Software mipmapping generation and POT conversion (custom implementation) | ||||
|    - TTF fonts support | ||||
|     | ||||
| 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:     | ||||
| *       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) | ||||
| *     | ||||
| @@ -32,50 +32,45 @@ | ||||
| #include <AL/al.h>           // OpenAL basic header | ||||
| #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 "utils.h"           // rRES data decompression utility function | ||||
|  | ||||
| //#include "stb_vorbis.h"      // OGG loading functions | ||||
| #include "stb_vorbis.h"      // OGG loading functions | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Defines and Macros | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Nop... | ||||
| #define MUSIC_STREAM_BUFFERS        2 | ||||
| #define MUSIC_BUFFER_SIZE      4096*8   //4096*32 | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // 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) | ||||
| // NOTE: Anything longer than ~10 seconds should be Music... | ||||
| struct Music { | ||||
| // Music type (file streaming from memory) | ||||
| // NOTE: Anything longer than ~10 seconds should be streamed... | ||||
| typedef struct Music { | ||||
|     stb_vorbis *stream; | ||||
| 	stb_vorbis_info info; | ||||
|      | ||||
|     ALuint id;  | ||||
| 	ALuint buffers[2]; | ||||
| 	ALuint buffers[MUSIC_STREAM_BUFFERS]; | ||||
| 	ALuint source; | ||||
| 	ALenum format; | ||||
|   | ||||
| 	int bufferSize; | ||||
|     int channels; | ||||
|     int sampleRate; | ||||
| 	int totalSamplesLeft; | ||||
| 	bool loop; | ||||
| }; | ||||
| */ | ||||
|      | ||||
| } Music; | ||||
|  | ||||
| // Wave file data | ||||
| 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 dataSize; | ||||
|     short bitsPerSample; | ||||
|     short channels;   | ||||
| } Wave; | ||||
| @@ -83,22 +78,23 @@ typedef struct Wave { | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Global Variables Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
| static bool musicIsPlaying; | ||||
| static Music *currentMusic; | ||||
| bool musicEnabled = false; | ||||
| static Music currentMusic;      // Current music loaded | ||||
|                                 // NOTE: Only one music file playing at a time | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module specific Functions Declaration | ||||
| //---------------------------------------------------------------------------------- | ||||
| static Wave LoadWAV(char *fileName); | ||||
| static void UnloadWAV(Wave wave); | ||||
| //static Ogg LoadOGG(char *fileName); | ||||
| static bool MusicStream(Music music, ALuint buffer); | ||||
| static Wave LoadWAV(const char *fileName); | ||||
| static Wave LoadOGG(char *fileName); | ||||
| static void UnloadWave(Wave wave); | ||||
|  | ||||
| extern bool MusicStreamUpdate(); | ||||
| extern void PlayCurrentMusic(); | ||||
| static bool BufferMusicStream(ALuint buffer);   // Fill music buffers with data | ||||
| 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 | ||||
| @@ -126,13 +122,13 @@ void InitAudioDevice() | ||||
|     alListener3f(AL_POSITION, 0, 0, 0); | ||||
|     alListener3f(AL_VELOCITY, 0, 0, 0); | ||||
|     alListener3f(AL_ORIENTATION, 0, 0, -1); | ||||
|      | ||||
|     musicIsPlaying = false; | ||||
| } | ||||
|  | ||||
| // Close the audio device for the current context, and destroys the context | ||||
| void CloseAudioDevice() | ||||
| { | ||||
|     StopMusicStream();      // Stop music streaming and close current stream | ||||
|  | ||||
|     ALCdevice *device; | ||||
|     ALCcontext *context = alcGetCurrentContext(); | ||||
|      | ||||
| @@ -145,17 +141,27 @@ void CloseAudioDevice() | ||||
|     alcCloseDevice(device); | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module Functions Definition - Sounds loading and playing (.WAV) | ||||
| //---------------------------------------------------------------------------------- | ||||
|  | ||||
| // Load sound to memory | ||||
| Sound LoadSound(char *fileName) | ||||
| { | ||||
|     Sound sound; | ||||
|     Wave wave; | ||||
|      | ||||
|     // NOTE: The entire file is loaded to memory to play it all at once (no-streaming) | ||||
|      | ||||
|     // WAV file loading | ||||
|     // NOTE: Buffer space is allocated inside LoadWAV, Wave must be freed | ||||
|     Wave wave = LoadWAV(fileName); | ||||
|     // Audio file loading | ||||
|     // NOTE: Buffer space is allocated inside function, Wave must be freed | ||||
|      | ||||
|     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; | ||||
|         // The OpenAL format is worked out by looking at the number of channels and the bits per sample | ||||
|         if (wave.channels == 1)  | ||||
| @@ -169,7 +175,6 @@ Sound LoadSound(char *fileName) | ||||
|             else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16; | ||||
|         } | ||||
|          | ||||
|      | ||||
|         // Create an audio source | ||||
|         ALuint source; | ||||
|         alGenSources(1, &source);            // Generate pointer to audio source | ||||
| @@ -186,19 +191,20 @@ Sound LoadSound(char *fileName) | ||||
|         alGenBuffers(1, &buffer);            // Generate pointer 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 | ||||
|         alSourcei(source, AL_BUFFER, buffer); | ||||
|          | ||||
|         // Unallocate WAV data | ||||
|     UnloadWAV(wave); | ||||
|         UnloadWave(wave); | ||||
|          | ||||
|         TraceLog(INFO, "[%s] Sound file loaded successfully", fileName);   | ||||
|         TraceLog(INFO, "[%s] Sample rate: %i - Channels: %i", fileName, wave.sampleRate, wave.channels); | ||||
|          | ||||
|         sound.source = source; | ||||
|         sound.buffer = buffer; | ||||
|     } | ||||
|      | ||||
|     return sound; | ||||
| } | ||||
| @@ -314,7 +320,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId) | ||||
|                         alSourcei(source, AL_BUFFER, buffer); | ||||
|                          | ||||
|                         // Unallocate WAV data | ||||
|                         UnloadWAV(wave); | ||||
|                         UnloadWave(wave); | ||||
|  | ||||
|                         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 | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| void PauseSound(Sound sound) | ||||
| { | ||||
| @@ -421,30 +411,250 @@ bool SoundIsPlaying(Sound sound) | ||||
|     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 | ||||
| void SetVolume(Sound sound, float volume) | ||||
| void SetSoundVolume(Sound sound, float volume) | ||||
| { | ||||
|     alSourcef(sound.source, AL_GAIN, volume); | ||||
| } | ||||
|  | ||||
| // Set pitch for a sound | ||||
| void SetPitch(Sound sound, float pitch) | ||||
| void SetSoundPitch(Sound sound, float 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 | ||||
| static Wave LoadWAV(char *fileName)  | ||||
| static Wave LoadWAV(const char *fileName) | ||||
| { | ||||
|     // Basic WAV headers structs | ||||
|     typedef struct { | ||||
| @@ -543,199 +753,51 @@ static Wave LoadWAV(char *fileName) | ||||
|     return wave; | ||||
| } | ||||
|  | ||||
| // Unload WAV file data | ||||
| static void UnloadWAV(Wave wave) | ||||
| // Load OGG file into Wave structure | ||||
| 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); | ||||
| } | ||||
|  | ||||
| // 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 UnloadDefaultFont();            // [Module: text] Unloads default font from GPU memory | ||||
|  | ||||
| extern bool MusicStreamUpdate();             // [Module: audio] Updates buffers for music streamming | ||||
| extern void PlayCurrentMusic();              // [Module: audio] Plays current music stream | ||||
| extern void UpdateMusicStream();            // [Module: audio] Updates buffers for music streaming | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // 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 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 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 | ||||
| @@ -304,9 +303,7 @@ void EndDrawing() | ||||
|     glfwSwapBuffers(window);            // Swap back and front buffers | ||||
|     glfwPollEvents();                   // Register keyboard/mouse events | ||||
|      | ||||
|     //MusicStreamUpdate(); | ||||
|     //if (!MusicIsPlaying())  | ||||
|     //PlayCurrentMusic(); | ||||
|     UpdateMusicStream();        // NOTE: Function checks if music is enabled | ||||
|      | ||||
|     currentTime = glfwGetTime(); | ||||
|     drawTime = currentTime - previousTime; | ||||
| @@ -748,4 +745,6 @@ static void TakeScreenshot() | ||||
|     free(imgData); | ||||
|  | ||||
|     shotNum++; | ||||
|      | ||||
|     TraceLog(INFO, "[%s] Screenshot taken!", buffer); | ||||
| } | ||||
							
								
								
									
										627
									
								
								src/models.c
									
									
									
									
									
								
							
							
						
						
									
										627
									
								
								src/models.c
									
									
									
									
									
								
							| @@ -25,9 +25,9 @@ | ||||
|  | ||||
| #include "raylib.h" | ||||
|  | ||||
| #include <GL/gl.h>       // OpenGL functions | ||||
| #include <stdio.h>       // Standard input/output functions, used to read model files data | ||||
| #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 "raymath.h"     // Required for data type Matrix and Matrix functions | ||||
| @@ -52,6 +52,7 @@ | ||||
| // Module specific Functions Declaration | ||||
| //---------------------------------------------------------------------------------- | ||||
| static float GetHeightValue(Color pixel); | ||||
| static VertexData LoadOBJ(const char *fileName); | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module Functions Definition | ||||
| @@ -67,9 +68,9 @@ void DrawCube(Vector3 position, float width, float height, float lenght, Color c | ||||
|  | ||||
|     rlPushMatrix(); | ||||
|  | ||||
|         // NOTE: Be careful! Function order matters (scale, translate, rotate) | ||||
|         //rlScalef(2.0f, 2.0f, 2.0f); | ||||
|         // NOTE: Be careful! Function order matters (rotate -> scale -> translate) | ||||
|         //rlTranslatef(0.0f, 0.0f, 0.0f); | ||||
|         //rlScalef(2.0f, 2.0f, 2.0f); | ||||
|         //rlRotatef(45, 0, 1, 0); | ||||
|      | ||||
|         rlBegin(RL_TRIANGLES); | ||||
| @@ -215,9 +216,9 @@ void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float hei | ||||
|     float y = position.y; | ||||
|     float z = position.z; | ||||
|  | ||||
|     rlEnableTexture(texture.glId); | ||||
|     rlEnableTexture(texture.id); | ||||
|      | ||||
|     rlPushMatrix();       | ||||
|     //rlPushMatrix();       | ||||
|         // NOTE: Be careful! Function order matters (scale, translate, rotate) | ||||
|         //rlScalef(2.0f, 2.0f, 2.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(0.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z-lenght/2);  // Top Left Of The Texture and Quad | ||||
|         rlEnd(); | ||||
|     rlPopMatrix(); | ||||
|     //rlPopMatrix(); | ||||
|      | ||||
|     rlDisableTexture(); | ||||
| } | ||||
| @@ -278,8 +279,8 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color | ||||
| { | ||||
|     rlPushMatrix(); | ||||
|         rlTranslatef(centerPos.x, centerPos.y, centerPos.z); | ||||
|         //rlRotatef(rotation, 0, 1, 0); | ||||
|         rlScalef(radius, radius, radius); | ||||
|         //rlRotatef(rotation, 0, 1, 0); | ||||
|          | ||||
|         rlBegin(RL_TRIANGLES); | ||||
|             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) | ||||
| { | ||||
|     rlPushMatrix(); | ||||
|         rlTranslatef(centerPos.x, centerPos.y, centerPos.z); | ||||
|         //rlRotatef(rotation, 0, 1, 0); | ||||
|         //rlTranslatef(centerPos.x, centerPos.y, centerPos.z); | ||||
|         rlScalef(radius, radius, radius); | ||||
|         //rlRotatef(rotation, 0, 1, 0); | ||||
|          | ||||
|         rlBegin(RL_LINES); | ||||
|             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 | ||||
|     rlPushMatrix(); | ||||
|         rlTranslatef(centerPos.x, centerPos.y, centerPos.z); | ||||
|         rlScalef(size.x, 1.0f, size.y); | ||||
|          | ||||
|         // TODO: Review multiples rotations Gimbal-Lock... use matrix or quaternions... | ||||
|         rlRotatef(rotation.x, 1, 0, 0); | ||||
|         rlRotatef(rotation.y, 0, 1, 0); | ||||
|         rlRotatef(rotation.z, 0, 0, 1); | ||||
|         rlScalef(size.x, 1.0f, size.y); | ||||
|      | ||||
|         rlBegin(RL_QUADS); | ||||
|             rlColor4ub(color.r, color.g, color.b, color.a); | ||||
| @@ -568,14 +569,13 @@ void DrawGizmo(Vector3 position) | ||||
|     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 | ||||
|     rlPushMatrix(); | ||||
|         rlTranslatef(position.x, position.y, position.z); | ||||
|         rlRotatef(rotation, 0, 1, 0); | ||||
|         rlScalef(scale, scale, scale); | ||||
|         rlRotatef(rotation.y, 0, 1, 0); | ||||
|  | ||||
|         rlBegin(RL_LINES); | ||||
|             // 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); | ||||
|              | ||||
|             // Extra | ||||
|             if(orbits) | ||||
|             { | ||||
|             int n = 3; | ||||
|              | ||||
|             // 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+6)) * scale/n, position.y + cos(DEG2RAD*(i+6)) * scale/n, 0); | ||||
|             } | ||||
|             } | ||||
|         rlEnd(); | ||||
|     rlPopMatrix(); | ||||
|      | ||||
|     rotation += 0.1f; | ||||
| } | ||||
|  | ||||
| // Load a 3d model (.OBJ) | ||||
| // TODO: Add comments explaining this function process | ||||
| // Load a 3d model | ||||
| Model LoadModel(const char *fileName)                                     | ||||
| { | ||||
|     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 comments[200]; | ||||
|      | ||||
| @@ -661,6 +945,8 @@ Model LoadModel(const char *fileName) | ||||
|  | ||||
|     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)) | ||||
|     { | ||||
|         fscanf(objFile, "%c", &dataType); | ||||
| @@ -671,6 +957,13 @@ Model LoadModel(const char *fileName) | ||||
|             { | ||||
|                 fgets(comments, 200, objFile);                 | ||||
|             } 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': | ||||
|             { | ||||
|                 fscanf(objFile, "%c", &dataType); | ||||
| @@ -753,15 +1046,18 @@ Model LoadModel(const char *fileName) | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     Vector3 midVertices[numVertex]; | ||||
|     Vector3 midNormals[numNormals]; | ||||
|     Vector2 midTexCoords[numTexCoords]; | ||||
|     // Once we know the number of vertices to store, we create required arrays | ||||
|     Vector3 *midVertices = (Vector3 *)malloc(numVertex*sizeof(Vector3)); | ||||
|     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)); | ||||
|     vData.texcoords = (float *)malloc(vData.numVertices * 2 * sizeof(float)); | ||||
|     vData.normals = (float *)malloc(vData.numVertices * 3 * sizeof(float)); | ||||
|     // Additional arrays to store vertex data as floats | ||||
|     vData.vertices = (float *)malloc(vData.vertexCount * 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 countNormals = 0; | ||||
| @@ -771,8 +1067,9 @@ Model LoadModel(const char *fileName) | ||||
|     int tcCounter = 0;      // Used to count texcoords 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)) | ||||
|     { | ||||
|         fscanf(objFile, "%c", &dataType); | ||||
| @@ -872,274 +1169,16 @@ Model LoadModel(const char *fileName) | ||||
|      | ||||
|     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; | ||||
|  | ||||
| #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; | ||||
| } | ||||
|  | ||||
| // 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; | ||||
|         } | ||||
|     } | ||||
|     // Now we can free temp mid* arrays | ||||
|     free(midVertices); | ||||
|     free(midNormals); | ||||
|     free(midTexCoords); | ||||
|      | ||||
|     // 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; | ||||
|  | ||||
| #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); | ||||
|     return vData; | ||||
| } | ||||
							
								
								
									
										102
									
								
								src/raylib.h
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								src/raylib.h
									
									
									
									
									
								
							| @@ -10,13 +10,17 @@ | ||||
| *     Hardware accelerated with OpenGL (1.1, 3.3+ or ES2) | ||||
| *     Unique OpenGL abstraction layer [rlgl] | ||||
| *     Powerful fonts module with SpriteFonts support | ||||
| *     Multiple textures support, including DDS and mipmaps generation | ||||
| *     Basic 3d support for Shapes, Models, Heightmaps and Billboards | ||||
| *     Powerful math module for Vector and Matrix operations [raymath] | ||||
| *     Audio loading and playing | ||||
| *     Audio loading and playing with streaming support | ||||
| *     | ||||
| *   Used external libs: | ||||
| *     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_write (Sean Barret) for image writting (PNG) | ||||
| *     stb_vorbis (Sean Barret) for ogg audio loading | ||||
| *     OpenAL Soft for audio device/context management | ||||
| *     tinfl for data decompression (DEFLATE algorithm) | ||||
| * | ||||
| @@ -25,9 +29,9 @@ | ||||
| *     32bit Textures - All loaded images are converted automatically to RGBA textures | ||||
| *     SpriteFonts - All loaded sprite-font images are converted to RGBA and POT textures | ||||
| *     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,  | ||||
| *   BSD-like license that allows static linking with closed source software: | ||||
| @@ -54,8 +58,6 @@ | ||||
| #ifndef RAYLIB_H | ||||
| #define RAYLIB_H | ||||
|  | ||||
| #include "stb_vorbis.h" | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Some basic Defines | ||||
| //---------------------------------------------------------------------------------- | ||||
| @@ -195,11 +197,22 @@ typedef struct Image { | ||||
| // Texture2D type, bpp always RGBA (32bit) | ||||
| // NOTE: Data stored in GPU memory | ||||
| typedef struct Texture2D { | ||||
|     unsigned int glId; | ||||
|     unsigned int id;        // OpenGL id | ||||
|     int width; | ||||
|     int height; | ||||
| } 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 | ||||
| typedef struct Camera { | ||||
|     Vector3 position; | ||||
| @@ -207,18 +220,23 @@ typedef struct Camera { | ||||
|     Vector3 up; | ||||
| } Camera; | ||||
|  | ||||
| typedef struct Character Character; | ||||
|  | ||||
| // SpriteFont type | ||||
| typedef struct SpriteFont { | ||||
|     Texture2D texture; | ||||
|     int numChars; | ||||
|     Character *charSet; | ||||
| } SpriteFont; | ||||
| // Vertex data definning a mesh | ||||
| typedef struct { | ||||
|     int vertexCount; | ||||
|     float *vertices;            // 3 components per vertex | ||||
|     float *texcoords;           // 2 components per vertex | ||||
|     float *normals;             // 3 components per vertex | ||||
|     float *colors;              // 4 components per vertex | ||||
| } VertexData; | ||||
|  | ||||
| // 3d Model type | ||||
| // NOTE: If using OpenGL 1.1 loaded in CPU; if OpenGL 3.3+ loaded in GPU | ||||
| typedef struct Model Model; // Defined in module: rlgl | ||||
| // NOTE: If using OpenGL 1.1 loaded in CPU (mesh); if OpenGL 3.3+ loaded in GPU (vaoId) | ||||
| typedef struct Model { | ||||
|     VertexData mesh; | ||||
|     unsigned int vaoId; | ||||
|     unsigned int textureId; | ||||
|     //Matrix transform; | ||||
| } Model; | ||||
|  | ||||
| // Sound source type | ||||
| typedef struct Sound { | ||||
| @@ -226,23 +244,6 @@ typedef struct Sound { | ||||
|     unsigned int buffer; | ||||
| } 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 | ||||
| extern "C" {            // Prevents name mangling of functions | ||||
| #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) | ||||
| 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 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 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 LoadSpriteFont(const char *fileName);                                                   // Load a SpriteFont image into 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 DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position,                         // Draw text using SpriteFont and additional parameters | ||||
|                 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 DrawGrid(int slices, float spacing);                                                          // Draw a grid (centered at (0, 0, 0)) | ||||
| 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... | ||||
|  | ||||
| //------------------------------------------------------------------------------------ | ||||
| @@ -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 LoadHeightmap(Image heightmap, float maxHeight);                                             // Load a heightmap image as a 3d model | ||||
| void UnloadModel(Model model);                                                                     // Unload 3d model from memory | ||||
| void DrawModel(Model model, Vector3 position, float scale, Color color);                           // Draw 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 SetModelTexture(Model *model, Texture2D texture);                                             // Link a texture to a model | ||||
|  | ||||
| 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 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) | ||||
| //------------------------------------------------------------------------------------ | ||||
| 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 LoadSoundFromRES(const char *rresName, int resId);        // Load sound to memory from rRES file (raylib Resource) | ||||
| void UnloadSound(Sound sound);                                  // Unload sound | ||||
| Music LoadMusic(char *fileName); | ||||
| void UnloadMusic(Music music); | ||||
|  | ||||
| void PlaySound(Sound sound);                                    // Play a sound | ||||
| void PauseSound(Sound sound);                                   // Pause a sound | ||||
| void StopSound(Sound sound);                                    // Stop playing a sound | ||||
| 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 SetPitch(Sound sound, float pitch);                        // Set pitch for a sound (1.0 is base level) | ||||
| void PlayMusic(Music music); | ||||
| void StopMusic(Music music); | ||||
| bool MusicIsPlaying(); | ||||
| void SetSoundVolume(Sound sound, float volume);                 // Set volume for a sound (1.0 is max level) | ||||
| void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for a sound (1.0 is base level) | ||||
|  | ||||
| void PlayMusicStream(char *fileName);                           // Start music playing (open stream) | ||||
| 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 | ||||
| } | ||||
|   | ||||
| @@ -435,7 +435,7 @@ Matrix MatrixSubstract(Matrix left, Matrix right) | ||||
| } | ||||
|  | ||||
| // Returns translation matrix | ||||
| // TODO: REVIEW | ||||
| // TODO: Review this function | ||||
| Matrix MatrixTranslate(float x, float y, float z) | ||||
| { | ||||
| /* | ||||
| @@ -478,6 +478,7 @@ Matrix MatrixTranslate(float x, float y, float z) | ||||
| } | ||||
|  | ||||
| // Returns rotation matrix | ||||
| // TODO: Review this function | ||||
| Matrix MatrixRotate(float angleX, float angleY, float angleZ) | ||||
| { | ||||
|     Matrix result; | ||||
| @@ -492,6 +493,7 @@ Matrix MatrixRotate(float angleX, float angleY, float angleZ) | ||||
| } | ||||
|  | ||||
| // Create rotation matrix from axis and angle | ||||
| // TODO: Test this function | ||||
| Matrix MatrixFromAxisAngle(Vector3 axis, float angle)  | ||||
| { | ||||
|     Matrix result; | ||||
| @@ -545,7 +547,8 @@ Matrix MatrixFromAxisAngle(Vector3 axis, float angle) | ||||
|     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 result; | ||||
| @@ -661,6 +664,21 @@ Matrix MatrixScale(float x, float y, float z) | ||||
|     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 | ||||
| // NOTE: When multiplying matrices... the order matters! | ||||
| 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 MatrixRotateZ(float angle);                      // Returns z-rotation matrix (angle in radians) | ||||
| 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 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 | ||||
|   | ||||
							
								
								
									
										453
									
								
								src/rlgl.c
									
									
									
									
									
								
							
							
						
						
									
										453
									
								
								src/rlgl.c
									
									
									
									
									
								
							| @@ -31,10 +31,24 @@ | ||||
| #include <stdio.h>          // Standard input / output lib | ||||
| #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 | ||||
|     #include <GL/gl.h>      // Extensions loading lib | ||||
|     #include <GL/gl.h>      // Basic OpenGL include | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_OPENGL_33 | ||||
| @@ -42,7 +56,7 @@ | ||||
|     #include <GL/glew.h>    // Extensions loading lib | ||||
| #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! | ||||
|  | ||||
| @@ -56,18 +70,18 @@ | ||||
| //---------------------------------------------------------------------------------- | ||||
| // 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 { | ||||
|     int vCounter; | ||||
|     int cCounter; | ||||
|     float *vertices;            // 3 components per vertex | ||||
|     float *colors;              // 4 components per vertex | ||||
| } VertexPositionColorBuffer; | ||||
| /* | ||||
|  | ||||
| // Vertex buffer (position + texcoords + color arrays) | ||||
| // NOTE: Not used | ||||
| typedef struct { | ||||
|     int vCounter; | ||||
|     int tcCounter; | ||||
| @@ -76,8 +90,9 @@ typedef struct { | ||||
|     float *texcoords;           // 2 components per vertex | ||||
|     float *colors;              // 4 components per vertex | ||||
| } VertexPositionColorTextureBuffer; | ||||
| */ | ||||
| /* | ||||
|  | ||||
| // Vertex buffer (position + texcoords + normals arrays) | ||||
| // NOTE: Not used | ||||
| typedef struct { | ||||
|     int vCounter; | ||||
|     int tcCounter; | ||||
| @@ -86,7 +101,9 @@ typedef struct { | ||||
|     float *texcoords;           // 2 components per vertex | ||||
|     float *normals;             // 3 components per vertex | ||||
| } VertexPositionTextureNormalBuffer; | ||||
| */ | ||||
|  | ||||
| // Vertex buffer (position + texcoords + colors + indices arrays) | ||||
| // NOTE: Used for quads VAO | ||||
| typedef struct { | ||||
|     int vCounter; | ||||
|     int tcCounter; | ||||
| @@ -97,12 +114,22 @@ typedef struct { | ||||
|     unsigned int *indices;      // 6 indices per quad | ||||
| } VertexPositionColorTextureIndexBuffer; | ||||
|  | ||||
| // Draw call type | ||||
| // NOTE: Used to track required draw-calls, organized by texture | ||||
| typedef struct { | ||||
|     GLuint texId; | ||||
|     int firstVertex;    // Actually, when using glDrawElements, this parameter is useless.. | ||||
|     int vCount; | ||||
|     GLuint textureId; | ||||
|     int vertexCount; | ||||
| } 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 | ||||
| //---------------------------------------------------------------------------------- | ||||
| @@ -140,7 +167,6 @@ static GLuint quadsBuffer[4]; | ||||
|  | ||||
| #ifdef USE_VBO_DOUBLE_BUFFERS | ||||
| // Double buffering | ||||
| // TODO: REVIEW -> Not getting any performance improvement... why? | ||||
| static GLuint vaoQuadsB; | ||||
| static GLuint quadsBufferB[4]; | ||||
| static bool useBufferB = false; | ||||
| @@ -172,6 +198,11 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName); | ||||
| static char *TextFileRead(char *fn); | ||||
| #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 | ||||
| //---------------------------------------------------------------------------------- | ||||
| @@ -216,7 +247,7 @@ void rlMatrixMode(int mode) | ||||
| { | ||||
|     if (mode == RL_PROJECTION) currentMatrix = &projection; | ||||
|     else if (mode == RL_MODELVIEW) currentMatrix = &modelview; | ||||
|     //else if (mode == GL_TEXTURE) TODO: NEVER USED! | ||||
|     //else if (mode == RL_TEXTURE) // Not supported | ||||
|      | ||||
|     currentMatrixMode = mode; | ||||
| } | ||||
| @@ -257,6 +288,7 @@ void rlLoadIdentity() | ||||
| void rlTranslatef(float x, float y, float z) | ||||
| { | ||||
|     Matrix mat = MatrixTranslate(x, y, z); | ||||
|     MatrixTranspose(&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 | ||||
| void rlRotatef(float angleDeg, float x, float y, float z) | ||||
| { | ||||
|     // TODO: Rotation matrix --> REVIEW! | ||||
|     // TODO: Support rotation in multiple axes | ||||
|     Matrix rot = MatrixIdentity(); | ||||
|      | ||||
|     if (x == 1) rot = MatrixRotateX(angleDeg*DEG2RAD); | ||||
|     else if (y == 1) rot = MatrixRotateY(angleDeg*DEG2RAD); | ||||
|     else if (z == 1) rot = MatrixRotateZ(angleDeg*DEG2RAD); | ||||
|      | ||||
|     MatrixTranspose(&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) | ||||
| { | ||||
|     Matrix mat = MatrixScale(x, y, z); | ||||
|     MatrixTranspose(&mat); | ||||
|      | ||||
|     *currentMatrix = MatrixMultiply(*currentMatrix, mat); | ||||
| } | ||||
| @@ -356,12 +391,12 @@ void rlEnd() | ||||
| { | ||||
|     if (useTempBuffer) | ||||
|     { | ||||
|         // IT WORKS!!! --> Refactor... | ||||
|         Matrix mat = *currentMatrix; | ||||
|         MatrixTranspose(&mat); | ||||
|         // NOTE: In this case, *currentMatrix is already transposed because transposing has been applied | ||||
|         // independently to translation-scale-rotation matrices -> t(M1 x M2) = t(M2) x t(M1) | ||||
|         // This way, rlTranslatef(), rlRotatef()... behaviour is the same than OpenGL 1.1 | ||||
|  | ||||
|         // 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 | ||||
|         useTempBuffer = false; | ||||
| @@ -373,7 +408,7 @@ void rlEnd() | ||||
|         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. | ||||
|     switch (currentDrawMode) | ||||
|     { | ||||
| @@ -490,7 +525,7 @@ void rlVertex3f(float x, float y, float z) | ||||
|                  | ||||
|                 quads.vCounter++; | ||||
|                  | ||||
|                 draws[drawsCounter - 1].vCount++; | ||||
|                 draws[drawsCounter - 1].vertexCount++; | ||||
|                  | ||||
|             } break; | ||||
|             default: break; | ||||
| @@ -596,13 +631,12 @@ void rlEnableTexture(unsigned int id) | ||||
| #endif | ||||
|  | ||||
| #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].firstVertex = draws[drawsCounter - 2].vCount; | ||||
|         draws[drawsCounter - 1].vCount = 0; | ||||
|         draws[drawsCounter - 1].textureId = id; | ||||
|         draws[drawsCounter - 1].vertexCount = 0; | ||||
|     } | ||||
| #endif | ||||
| } | ||||
| @@ -710,8 +744,6 @@ void rlglInit() | ||||
|     // Get handles to GLSL uniform vars locations (fragment-shader) | ||||
|     textureLoc = glGetUniformLocation(shaderProgram, "texture0"); | ||||
|      | ||||
|     TraceLog(INFO, "Default shader loaded"); | ||||
|      | ||||
|     InitializeBuffers();    // Init vertex arrays | ||||
|     InitializeVAOs();       // Init VBO and VAO | ||||
|      | ||||
| @@ -723,9 +755,9 @@ void rlglInit() | ||||
|     // Create default white texture for plain colors (required by shader) | ||||
|     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"); | ||||
|      | ||||
|     // Init draw calls tracking system | ||||
| @@ -733,13 +765,12 @@ void rlglInit() | ||||
|      | ||||
|     for (int i = 0; i < MAX_DRAWS_BY_TEXTURE; i++) | ||||
|     { | ||||
|         draws[i].texId = 0; | ||||
|         draws[i].firstVertex = 0; | ||||
|         draws[i].vCount = 0; | ||||
|         draws[i].textureId = 0; | ||||
|         draws[i].vertexCount = 0; | ||||
|     } | ||||
|      | ||||
|     drawsCounter = 1; | ||||
|     draws[drawsCounter - 1].texId = whiteTexture; | ||||
|     draws[drawsCounter - 1].textureId = whiteTexture; | ||||
| } | ||||
|  | ||||
| // Vertex Buffer Object deinitialization (memory free) | ||||
| @@ -789,6 +820,8 @@ void rlglClose() | ||||
|      | ||||
|     // Free GPU texture | ||||
|     glDeleteTextures(1, &whiteTexture); | ||||
|      | ||||
|     free(draws); | ||||
| } | ||||
|  | ||||
| void rlglDraw() | ||||
| @@ -823,7 +856,7 @@ void rlglDraw() | ||||
|      | ||||
|     if (quads.vCounter > 0) | ||||
|     { | ||||
|         int numQuads = 0; | ||||
|         int quadsCount = 0; | ||||
|         int numIndicesToProcess = 0; | ||||
|         int indicesOffset = 0; | ||||
|  | ||||
| @@ -836,21 +869,21 @@ void rlglDraw() | ||||
|             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++) | ||||
|         { | ||||
|             numQuads = draws[i].vCount/4; | ||||
|             numIndicesToProcess = numQuads*6;  // Get number of Quads * 6 index by Quad | ||||
|             quadsCount = draws[i].vertexCount/4; | ||||
|             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 | ||||
|             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 | ||||
|     drawsCounter = 1; | ||||
|     draws[0].texId = whiteTexture; | ||||
|     draws[0].firstVertex = 0; | ||||
|     draws[0].vCount = 0; | ||||
|     draws[0].textureId = whiteTexture; | ||||
|     draws[0].vertexCount = 0; | ||||
|      | ||||
|     // Reset vertex counters for next frame | ||||
|     lines.vCounter = 0; | ||||
| @@ -883,52 +915,71 @@ void rlglDraw() | ||||
| #endif      // End for OpenGL 3.3+ and ES2 only functions | ||||
|  | ||||
| // 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); | ||||
|      | ||||
| #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_TEXTURE_COORD_ARRAY);              // Enable texture coords array | ||||
|     glEnableClientState(GL_NORMAL_ARRAY);                     // Enable normals array | ||||
|          | ||||
|     glVertexPointer(3, GL_FLOAT, 0, model.data.vertices);     // Pointer to vertex coords array | ||||
|     glTexCoordPointer(2, GL_FLOAT, 0, model.data.texcoords);  // Pointer to texture coords array | ||||
|     glNormalPointer(GL_FLOAT, 0, model.data.normals);         // Pointer to normals array | ||||
|     glVertexPointer(3, GL_FLOAT, 0, model.mesh.vertices);     // Pointer to vertex coords array | ||||
|     glTexCoordPointer(2, GL_FLOAT, 0, model.mesh.texcoords);  // Pointer to texture coords 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) | ||||
|      | ||||
|     //TraceLog(DEBUG, "Drawing model.mesh, VertexCount: %i", model.mesh.vertexCount); | ||||
|      | ||||
|     rlPushMatrix(); | ||||
|         rlTranslatef(position.x, position.y, position.z); | ||||
|         //rlRotatef(rotation * GetFrameTime(), 0, 1, 0); | ||||
|         rlScalef(scale, scale, scale); | ||||
|         rlScalef(scale.x, scale.y, scale.z); | ||||
|         //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(); | ||||
|      | ||||
|     glDisableClientState(GL_VERTEX_ARRAY);                     // Disable vertex array | ||||
|     glDisableClientState(GL_TEXTURE_COORD_ARRAY);              // Disable texture coords array | ||||
|     glDisableClientState(GL_NORMAL_ARRAY);                     // Disable normals array | ||||
|      | ||||
|     glDisable(GL_TEXTURE_2D); | ||||
|     glBindTexture(GL_TEXTURE_2D, 0); | ||||
| #endif | ||||
|  | ||||
| #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | ||||
|     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 | ||||
|     glUniformMatrix4fv(projectionMatrixLoc, 1, false, GetMatrixVector(projection)); | ||||
|     glUniformMatrix4fv(modelviewMatrixLoc, 1, false, GetMatrixVector(modelview2)); | ||||
|     glUniformMatrix4fv(modelviewMatrixLoc, 1, false, GetMatrixVector(modelviewworld)); | ||||
|     glUniform1i(textureLoc, 0); | ||||
|      | ||||
|     //TraceLog(DEBUG, "ShaderProgram: %i, VAO ID: %i, VertexCount: %i", shaderProgram, model.vaoId, model.mesh.vertexCount); | ||||
|     | ||||
|     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 | ||||
| #endif | ||||
|  | ||||
| @@ -982,8 +1033,7 @@ void rlglInitGraphicsDevice(int fbWidth, int fbHeight) | ||||
| } | ||||
|  | ||||
| // Convert image data to OpenGL texture (returns OpenGL valid Id) | ||||
| // NOTE: Image is not unloaded, it should be done manually... | ||||
| unsigned int rlglLoadTexture(int width, int height, unsigned char *data) | ||||
| unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool genMipmaps) | ||||
| { | ||||
|     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! | ||||
|     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 | ||||
|  | ||||
|     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_MIN_FILTER, GL_NEAREST);  // Filter for pixel-perfect drawing, alternative: GL_LINEAR | ||||
|     } | ||||
|  | ||||
| #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) | ||||
|     // Trilinear filtering | ||||
|     //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) | ||||
|     //glGenerateMipmap(GL_TEXTURE_2D);    // OpenGL 3.3! | ||||
| #ifdef USE_OPENGL_11 | ||||
|     if (genMipmaps) | ||||
|     { | ||||
|         TraceLog(WARNING, "[ID %i] Mipmaps generated manually on CPU side", id); | ||||
|  | ||||
|         // 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 | ||||
|  | ||||
|     // 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); | ||||
|      | ||||
|     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 | ||||
|      | ||||
|     // Unbind current texture | ||||
|     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; | ||||
| } | ||||
| @@ -1024,50 +1129,41 @@ unsigned int rlglLoadTexture(int width, int height, unsigned char *data) | ||||
|  | ||||
| #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) | ||||
| // NOTE: Expected compressed data from DDS file | ||||
| unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int format) | ||||
| // NOTE: Expected compressed image data and POT image | ||||
| unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compFormat) | ||||
| { | ||||
|     // Create one OpenGL texture | ||||
|     GLuint id; | ||||
|     int compFormat = 0; | ||||
|      | ||||
|     glGenTextures(1, &id); | ||||
|      | ||||
|     TraceLog(DEBUG, "Compressed texture width: %i", width); | ||||
|     TraceLog(DEBUG, "Compressed texture height: %i", height); | ||||
|     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;  | ||||
|         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"); | ||||
|         TraceLog(WARNING, "[ID %i] Texture compressed format not recognized", id); | ||||
|         id = 0; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         glGenTextures(1, &id); | ||||
|  | ||||
|         // Bind the texture | ||||
|         glBindTexture(GL_TEXTURE_2D, id); | ||||
|         glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | ||||
|      | ||||
|         unsigned int blockSize = (compFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;  | ||||
|         unsigned int offset = 0; | ||||
|         int blockSize = 0; | ||||
|         int offset = 0; | ||||
|          | ||||
|         if (compFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) blockSize = 8; | ||||
|         else blockSize = 16; | ||||
|          | ||||
|         // Load the mipmaps  | ||||
|         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; | ||||
|              | ||||
|             glCompressedTexImage2D(GL_TEXTURE_2D, level, compFormat, width, height, 0, size, data + offset);  | ||||
| @@ -1100,20 +1196,28 @@ unsigned int rlglLoadModel(VertexData mesh) | ||||
|   | ||||
|     // Enable vertex attributes | ||||
|     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); | ||||
|     glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0); | ||||
|      | ||||
|     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); | ||||
|     glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0); | ||||
|      | ||||
|     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]); | ||||
|     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.numVertices, mesh.normals, GL_STATIC_DRAW);    | ||||
|     //glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]); | ||||
|     //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.normals, GL_STATIC_DRAW);    | ||||
|     //glEnableVertexAttribArray(normalLoc); | ||||
|     //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; | ||||
| } | ||||
| #endif | ||||
| @@ -1209,6 +1313,9 @@ static GLuint LoadDefaultShaders() | ||||
|     glCompileShader(vertexShader); | ||||
|     glCompileShader(fragmentShader); | ||||
|      | ||||
|     TraceLog(INFO, "[ID %i] Default vertex shader compiled succesfully", vertexShader); | ||||
|     TraceLog(INFO, "[ID %i] Default fragment shader compiled succesfully", fragmentShader); | ||||
|   | ||||
|     program = glCreateProgram(); | ||||
|      | ||||
|     glAttachShader(program, vertexShader); | ||||
| @@ -1219,6 +1326,8 @@ static GLuint LoadDefaultShaders() | ||||
|     glDeleteShader(vertexShader); | ||||
|     glDeleteShader(fragmentShader); | ||||
|      | ||||
|     TraceLog(INFO, "[ID %i] Default shader program loaded succesfully", program); | ||||
|   | ||||
|     return program; | ||||
| } | ||||
|  | ||||
| @@ -1246,6 +1355,9 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName) | ||||
|     glCompileShader(vertexShader); | ||||
|     glCompileShader(fragmentShader); | ||||
|      | ||||
|     TraceLog(INFO, "[ID %i] Vertex shader compiled succesfully", vertexShader); | ||||
|     TraceLog(INFO, "[ID %i] Fragment shader compiled succesfully", fragmentShader); | ||||
|   | ||||
|     program = glCreateProgram(); | ||||
|      | ||||
|     glAttachShader(program, vertexShader); | ||||
| @@ -1256,6 +1368,8 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName) | ||||
|     glDeleteShader(vertexShader); | ||||
|     glDeleteShader(fragmentShader); | ||||
|      | ||||
|     TraceLog(INFO, "[ID %i] Shader program loaded succesfully", program); | ||||
|   | ||||
|     return program; | ||||
| } | ||||
|  | ||||
| @@ -1365,6 +1479,7 @@ static void InitializeVAOs() | ||||
|     glEnableVertexAttribArray(colorLoc); | ||||
|     glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0); | ||||
|      | ||||
|     TraceLog(INFO, "[ID %i] Lines VAO successfully initialized", vaoLines); | ||||
|     //--------------------------------------------------------------  | ||||
|      | ||||
|     // Initialize Triangles VAO | ||||
| @@ -1385,6 +1500,7 @@ static void InitializeVAOs() | ||||
|     glEnableVertexAttribArray(colorLoc); | ||||
|     glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0); | ||||
|      | ||||
|     TraceLog(INFO, "[ID %i] Triangles VAO successfully initialized", vaoTriangles); | ||||
|     //--------------------------------------------------------------  | ||||
|      | ||||
|     // Initialize Quads VAO (Buffer A) | ||||
| @@ -1414,6 +1530,8 @@ static void InitializeVAOs() | ||||
|     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]); | ||||
|     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 | ||||
|     // Initialize Quads VAO (Buffer B) | ||||
|     glGenVertexArrays(1, &vaoQuadsB); | ||||
| @@ -1442,11 +1560,9 @@ static void InitializeVAOs() | ||||
|     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBufferB[3]); | ||||
|     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 | ||||
|   | ||||
|     TraceLog(INFO, "Vertex buffers successfully initialized (lines, triangles, quads)\n"); | ||||
|   | ||||
|     // Unbind the current VAO | ||||
|     glBindVertexArray(0); | ||||
| } | ||||
| @@ -1540,6 +1656,135 @@ static void UpdateBuffers() | ||||
|     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 | ||||
|  | ||||
| #ifdef RLGL_STANDALONE | ||||
| @@ -1555,10 +1800,10 @@ void TraceLog(int msgType, const char *text, ...) | ||||
|      | ||||
|     switch(msgType) | ||||
|     { | ||||
|         case 0: fprintf(stdout, "INFO: "); break; | ||||
|         case 1: fprintf(stdout, "ERROR: "); break; | ||||
|         case 2: fprintf(stdout, "WARNING: "); break; | ||||
|         case 3: fprintf(logstream, "DEBUG: "); break; | ||||
|         case INFO: fprintf(stdout, "INFO: "); break; | ||||
|         case ERROR: fprintf(stdout, "ERROR: "); break; | ||||
|         case WARNING: fprintf(stdout, "WARNING: "); break; | ||||
|         case DEBUG: fprintf(stdout, "DEBUG: "); break; | ||||
|         default: break; | ||||
|     } | ||||
|      | ||||
| @@ -1567,6 +1812,6 @@ void TraceLog(int msgType, const char *text, ...) | ||||
|      | ||||
|     va_end(args); | ||||
|      | ||||
|     if (msgType == 1) exit(1); | ||||
|     if (msgType == ERROR) exit(1); | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										41
									
								
								src/rlgl.h
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								src/rlgl.h
									
									
									
									
									
								
							| @@ -39,16 +39,16 @@ | ||||
| #include "raymath.h"            // Required for data type Matrix and Matrix functions | ||||
|  | ||||
| // Select desired OpenGL version | ||||
| //#define USE_OPENGL_11 | ||||
| #define USE_OPENGL_33 | ||||
| #define USE_OPENGL_11 | ||||
| //#define USE_OPENGL_33 | ||||
| //#define USE_OPENGL_ES2 | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Defines and Macros | ||||
| //---------------------------------------------------------------------------------- | ||||
| #define MAX_LINES_BATCH         8192    // 1024 | ||||
| #define MAX_TRIANGLES_BATCH     2048 | ||||
| #define MAX_QUADS_BATCH         8192 | ||||
| #define MAX_LINES_BATCH         8192    // NOTE: Be careful with limits! | ||||
| #define MAX_TRIANGLES_BATCH     4096    // NOTE: Be careful with limits! | ||||
| #define MAX_QUADS_BATCH         8192    // NOTE: Be careful with limits! | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // 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; | ||||
|  | ||||
| #ifdef RLGL_STANDALONE | ||||
| typedef struct Model Model; | ||||
| #endif | ||||
|  | ||||
|     typedef struct { | ||||
|     int numVertices; | ||||
|         int vertexCount; | ||||
|         float *vertices;            // 3 components per vertex | ||||
|         float *texcoords;           // 2 components per vertex | ||||
|         float *normals;             // 3 components per vertex | ||||
|         float *colors; | ||||
|     } VertexData; | ||||
|  | ||||
| #ifdef USE_OPENGL_11 | ||||
| struct Model { | ||||
|     VertexData data; | ||||
| }; | ||||
| #else | ||||
| struct Model { | ||||
|     typedef struct Model { | ||||
|         VertexData mesh; | ||||
|         unsigned int vaoId; | ||||
|     Matrix transform; | ||||
|     int numVertices; | ||||
| }; | ||||
|         unsigned int textureId; | ||||
|         //Matrix transform; | ||||
|     } Model; | ||||
| #endif | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| @@ -90,8 +84,8 @@ extern "C" {            // Prevents name mangling of functions | ||||
| // Functions Declaration - Matrix operations | ||||
| //------------------------------------------------------------------------------------ | ||||
| void rlMatrixMode(int mode);                    // Choose the current matrix to be transformed | ||||
| void rlPushMatrix();                            // TODO: REVIEW: Required? - Push the current matrix to stack | ||||
| void rlPopMatrix();                             // TODO: REVIEW: Required? - Pop lattest inserted matrix from stack | ||||
| void rlPushMatrix();                            // Push the current matrix to stack | ||||
| void rlPopMatrix();                             // Pop lattest inserted matrix from stack | ||||
| 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 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 rlglClose();                               // De-init rlgl | ||||
| 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); | ||||
| #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) | ||||
| 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) | ||||
|  | ||||
| #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); | ||||
|             rlColor4ub(color2.r, color2.g, color2.b, color2.a); | ||||
|             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); | ||||
|         } | ||||
|     rlEnd(); | ||||
| @@ -149,17 +150,10 @@ void DrawCircleLines(int centerX, int centerY, float radius, Color color) | ||||
| // Draw a color-filled rectangle | ||||
| void DrawRectangle(int posX, int posY, int width, int height, Color color) | ||||
| { | ||||
|     rlBegin(RL_QUADS); | ||||
|         rlColor4ub(color.r, color.g, color.b, color.a); | ||||
|         rlTexCoord2f(0.0f, 0.0f); | ||||
|         rlVertex2i(posX, posY); | ||||
|         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(); | ||||
|     Vector2 position = { (float)posX, (float)posY }; | ||||
|     Vector2 size = { (float)width, (float)height }; | ||||
|  | ||||
|     DrawRectangleV(position, size, color); | ||||
| } | ||||
|  | ||||
| // Draw a color-filled rectangle | ||||
| @@ -172,26 +166,29 @@ void DrawRectangleRec(Rectangle rec, Color color) | ||||
| // NOTE: Gradient goes from bottom (color1) to top (color2) | ||||
| void DrawRectangleGradient(int posX, int posY, int width, int height, Color color1, Color color2) | ||||
| { | ||||
|     rlBegin(RL_QUADS); | ||||
|         rlColor4ub(color1.r, color1.g, color1.b, color1.a); | ||||
|         rlVertex2i(posX, posY); | ||||
|         rlColor4ub(color1.r, color1.g, color1.b, color1.a); | ||||
|         rlVertex2i(posX, 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); | ||||
|         rlVertex2i(posX + width, posY); | ||||
|     rlBegin(RL_TRIANGLES); | ||||
|         rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX, posY); | ||||
|         rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX, posY + height); | ||||
|         rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height); | ||||
|          | ||||
|         rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX, posY); | ||||
|         rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height);         | ||||
|         rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX + width, posY); | ||||
|     rlEnd(); | ||||
| } | ||||
|  | ||||
| // Draw a color-filled rectangle (Vector version) | ||||
| void DrawRectangleV(Vector2 position, Vector2 size, Color color) | ||||
| { | ||||
|     rlBegin(RL_QUADS); | ||||
|     rlBegin(RL_TRIANGLES); | ||||
|         rlColor4ub(color.r, color.g, color.b, color.a); | ||||
|          | ||||
|         rlVertex2i(position.x, position.y); | ||||
|         rlVertex2i(position.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); | ||||
|     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 "utils.h"        // Required for function GetExtendion() | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Defines and Macros | ||||
| //---------------------------------------------------------------------------------- | ||||
| @@ -58,15 +60,6 @@ typedef struct Character { | ||||
|     int h; | ||||
| } Character; | ||||
|  | ||||
| // SpriteFont type, includes texture and charSet array data | ||||
| /* | ||||
| struct SpriteFont { | ||||
|     Texture2D texture; | ||||
|     int numChars; | ||||
|     Character *charSet; | ||||
| }; | ||||
| */ | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // 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 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 const char *GetExtension(const char *fileName); | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module Functions Definition | ||||
| @@ -153,8 +145,7 @@ extern void LoadDefaultFont() | ||||
|         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); | ||||
|      | ||||
|     // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars | ||||
| @@ -192,7 +183,7 @@ extern void LoadDefaultFont() | ||||
|  | ||||
| extern void UnloadDefaultFont() | ||||
| { | ||||
|     rlDeleteTextures(defaultFont.texture.glId); | ||||
|     rlDeleteTextures(defaultFont.texture.id); | ||||
|     free(defaultFont.charSet); | ||||
| } | ||||
|  | ||||
| @@ -277,8 +268,7 @@ SpriteFont LoadSpriteFont(const char* fileName) | ||||
|         image.width = potWidth; | ||||
|         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); | ||||
|     } | ||||
|      | ||||
| @@ -288,7 +278,7 @@ SpriteFont LoadSpriteFont(const char* fileName) | ||||
| // Unload SpriteFont from GPU memory | ||||
| void UnloadSpriteFont(SpriteFont spriteFont) | ||||
| { | ||||
|     rlDeleteTextures(spriteFont.texture.glId); | ||||
|     rlDeleteTextures(spriteFont.texture.id); | ||||
|     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; | ||||
|     else scaleFactor = (float)fontSize / spriteFont.charSet[0].h; | ||||
|  | ||||
|     rlEnableTexture(spriteFont.texture.glId); | ||||
|     rlEnableTexture(spriteFont.texture.id); | ||||
|  | ||||
|     rlBegin(RL_QUADS); | ||||
|         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); | ||||
|      | ||||
|     spriteFont.texture = CreateTexture(image); | ||||
|      | ||||
|     spriteFont.texture = CreateTexture(image, false); | ||||
|     UnloadImage(image);     // Unload image data | ||||
|      | ||||
|     TraceLog(INFO, "[%s] Starting charSet reconstruction", fileName); | ||||
| @@ -641,10 +630,12 @@ static SpriteFont LoadRBMF(const char *fileName) | ||||
|     return spriteFont; | ||||
| } | ||||
|  | ||||
| // Get the extension for a filename | ||||
| static const char *GetExtension(const char *fileName)  | ||||
| // Generate a sprite font from TTF data (font size required) | ||||
| static SpriteFont GenerateFromTTF(const char *fileName, int fontSize) | ||||
| { | ||||
|     const char *dot = strrchr(fileName, '.'); | ||||
|     if(!dot || dot == fileName) return ""; | ||||
|     return dot + 1; | ||||
|     SpriteFont font; | ||||
|      | ||||
|     // 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 struct { | ||||
|     unsigned char *data; | ||||
|     int width; | ||||
|     int height; | ||||
|     int mipmaps; | ||||
|     int format; | ||||
| } ImageDDS; | ||||
|     unsigned char *data;    // Image raw data | ||||
|     int width;              // Image base width | ||||
|     int height;             // Image base height | ||||
|     //int bpp;              // bytes per pixel | ||||
|     //int components;       // num color components | ||||
|     int mipmaps;            // Mipmap levels, 1 by default | ||||
|     int compFormat;         // Compressed data format, 0 if no compression | ||||
| } ImageEx; | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Global Variables Definition | ||||
| @@ -66,8 +68,7 @@ typedef struct { | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module specific Functions Declaration | ||||
| //---------------------------------------------------------------------------------- | ||||
| static const char *GetExtension(const char *fileName); | ||||
| static ImageDDS LoadDDS(const char *fileName); | ||||
| static ImageEx LoadDDS(const char *fileName); | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module Functions Definition | ||||
| @@ -78,6 +79,11 @@ Image LoadImage(const char *fileName) | ||||
| { | ||||
|     Image image; | ||||
|      | ||||
|     // Initial values | ||||
|     image.pixels = NULL; | ||||
|     image.width = 0; | ||||
|     image.height = 0; | ||||
|      | ||||
|     if ((strcmp(GetExtension(fileName),"png") == 0) || | ||||
|         (strcmp(GetExtension(fileName),"bmp") == 0) || | ||||
|         (strcmp(GetExtension(fileName),"tga") == 0) || | ||||
| @@ -115,6 +121,35 @@ Image LoadImage(const char *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); | ||||
|      | ||||
|     // 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) | ||||
| 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; | ||||
|     bool found = false; | ||||
|  | ||||
| @@ -172,8 +208,8 @@ Image LoadImageFromRES(const char *rresName, int resId) | ||||
|                     if (infoHeader.type == 0)   // IMAGE data type | ||||
|                     { | ||||
|                         // TODO: Check data compression type | ||||
|                          | ||||
|                         // NOTE: We suppose compression type 2 (DEFLATE - default) | ||||
|  | ||||
|                         short imgWidth, imgHeight; | ||||
|                         char colorFormat, mipmaps; | ||||
|                      | ||||
| @@ -249,19 +285,26 @@ Texture2D LoadTexture(const char *fileName) | ||||
|  | ||||
|     if (strcmp(GetExtension(fileName),"dds") == 0) | ||||
|     { | ||||
| #ifdef USE_OPENGL_11  | ||||
|         TraceLog(WARNING, "[%s] DDS file loading requires OpenGL 3.2+ or ES 2.0", fileName); | ||||
| #else | ||||
|         ImageDDS image = LoadDDS(fileName); | ||||
|         ImageEx 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.height = image.height; | ||||
|          | ||||
|         if (texture.glId == 0) TraceLog(WARNING, "Compressed texture could not be loaded"); | ||||
|         else TraceLog(INFO, "Compressed texture loaded succesfully"); | ||||
| #endif | ||||
|         if (texture.id == 0) TraceLog(WARNING, "[%s] DDS texture could not be loaded", fileName); | ||||
|         else TraceLog(INFO, "[%s] DDS texture loaded succesfully", fileName); | ||||
|          | ||||
|         free(image.data); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| @@ -269,7 +312,7 @@ Texture2D LoadTexture(const char *fileName) | ||||
|          | ||||
|         if (image.pixels != NULL) | ||||
|         { | ||||
|             texture = CreateTexture(image); | ||||
|             texture = CreateTexture(image, false); | ||||
|             UnloadImage(image); | ||||
|         } | ||||
|     } | ||||
| @@ -283,7 +326,8 @@ Texture2D LoadTextureFromRES(const char *rresName, int resId) | ||||
|     Texture2D texture; | ||||
|  | ||||
|     Image image = LoadImageFromRES(rresName, resId); | ||||
|     texture = CreateTexture(image); | ||||
|     texture = CreateTexture(image, false); | ||||
|     UnloadImage(image); | ||||
|      | ||||
|     return texture; | ||||
| } | ||||
| @@ -297,7 +341,7 @@ void UnloadImage(Image image) | ||||
| // Unload texture from GPU memory | ||||
| void UnloadTexture(Texture2D texture) | ||||
| { | ||||
|     rlDeleteTextures(texture.glId); | ||||
|     rlDeleteTextures(texture.id); | ||||
| } | ||||
|  | ||||
| // Draw a Texture2D | ||||
| @@ -315,76 +359,32 @@ void DrawTextureV(Texture2D texture, Vector2 position, Color tint) | ||||
| // Draw a Texture2D with extended parameters | ||||
| 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... | ||||
|     // 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(); | ||||
|     DrawTexturePro(texture, sourceRec, destRec, origin, rotation, tint); | ||||
| } | ||||
|  | ||||
| // Draw a part of a texture (defined by a rectangle) | ||||
| 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); | ||||
|         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(); | ||||
|     DrawTexturePro(texture, sourceRec, destRec, origin, 0, tint); | ||||
| } | ||||
|  | ||||
| // 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) | ||||
| { | ||||
|     rlEnableTexture(texture.glId); | ||||
|     rlEnableTexture(texture.id); | ||||
|      | ||||
|     // NOTE: First we translate texture to origin to apply rotation and translation from there | ||||
|     rlPushMatrix(); | ||||
|         rlTranslatef(-origin.x, -origin.y, 0);   | ||||
|         rlTranslatef(destRec.x, destRec.y, 0); | ||||
|         rlRotatef(rotation, 0, 0, 1); | ||||
|         rlTranslatef(destRec.x + origin.x, destRec.y + origin.y, 0); | ||||
|         rlTranslatef(-origin.x, -origin.y, 0); | ||||
|              | ||||
|         rlBegin(RL_QUADS); | ||||
|             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); | ||||
|              | ||||
|             // Bottom-right corner for texture and quad | ||||
|             rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height); | ||||
|             rlVertex2f(destRec.width, 0.0f); | ||||
|             rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); | ||||
|             rlVertex2f(0.0f, destRec.height); | ||||
|              | ||||
|             // Top-right corner for texture and quad | ||||
|             rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);  | ||||
|             rlVertex2f(destRec.width, destRec.height); | ||||
|              | ||||
|             // Top-left corner for texture and quad | ||||
|             rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); | ||||
|             rlVertex2f(0.0f, destRec.height); | ||||
|             rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height); | ||||
|             rlVertex2f(destRec.width, 0.0f); | ||||
|         rlEnd(); | ||||
|     rlPopMatrix(); | ||||
|      | ||||
|     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; | ||||
|      | ||||
|     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; | ||||
|          | ||||
|         for (int i = 0; i < image.width * image.height * 4; i += 4) | ||||
|         { | ||||
|         img[i] = image.pixels[j].r; | ||||
|         img[i+1] = image.pixels[j].g; | ||||
|         img[i+2] = image.pixels[j].b; | ||||
|         img[i+3] = image.pixels[j].a; | ||||
|             imgData[i] = image.pixels[j].r; | ||||
|             imgData[i+1] = image.pixels[j].g; | ||||
|             imgData[i+2] = image.pixels[j].b; | ||||
|             imgData[i+3] = image.pixels[j].a; | ||||
|              | ||||
|             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.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; | ||||
| } | ||||
|  | ||||
| // Get the extension for a filename | ||||
| static const char *GetExtension(const char *fileName)  | ||||
| // Loading DDS image data (compressed or uncompressed) | ||||
| // NOTE: Compressed data loading not supported on OpenGL 1.1 | ||||
| ImageEx LoadDDS(const char *fileName) | ||||
| {    | ||||
|     const char *dot = strrchr(fileName, '.'); | ||||
|     if(!dot || dot == fileName) return ""; | ||||
|     return (dot + 1); | ||||
| } | ||||
|     #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 | ||||
|      | ||||
| // Loading DDS image compressed data  | ||||
| ImageDDS LoadDDS(const char *fileName) | ||||
| {    | ||||
|     // TODO: Review and expand DDS file loading to support uncompressed formats and new formats | ||||
|     #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT | ||||
|     #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 | ||||
|     #endif | ||||
|  | ||||
|     #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 | ||||
|     typedef struct { | ||||
| @@ -484,7 +503,7 @@ ImageDDS LoadDDS(const char *fileName) | ||||
|         unsigned int reserved2; | ||||
|     } ddsHeader; | ||||
|      | ||||
|     ImageDDS image; | ||||
|     ImageEx image; | ||||
|     ddsHeader header; | ||||
|  | ||||
|     FILE *ddsFile = fopen(fileName, "rb"); | ||||
| @@ -510,22 +529,60 @@ ImageDDS LoadDDS(const char *fileName) | ||||
|             // Get the surface descriptor | ||||
|             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 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 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; | ||||
|                  | ||||
|                 // 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));  | ||||
|                  | ||||
| @@ -534,12 +591,22 @@ ImageDDS LoadDDS(const char *fileName) | ||||
|                 // Close file pointer | ||||
|                 fclose(ddsFile); | ||||
|                  | ||||
|             //int components = (fourCC == FOURCC_DXT1) ? 3 : 4; // Not required | ||||
|                 image.mipmaps = header.mipMapCount; | ||||
|                 image.compFormat = 0; | ||||
|             | ||||
|             image.width = width; | ||||
|             image.height = height; | ||||
|             image.mipmaps = mipMapCount; | ||||
|             image.format = fourCC; | ||||
|                 switch(header.ddspf.fourCC) | ||||
|                 {  | ||||
|                     case FOURCC_DXT1: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;  | ||||
|                     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 | ||||
| *     | ||||
| *   Uses external lib:     | ||||
| *   Uses external libs:     | ||||
| *       tinfl - zlib DEFLATE algorithm decompression lib | ||||
| *       stb_image_write - PNG writting functions | ||||
| *        | ||||
| *   Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) | ||||
| *     | ||||
| @@ -34,8 +35,8 @@ | ||||
| //#include <string.h>           // String management functions: strlen(), strrchr(), strcmp() | ||||
|  | ||||
| #define STB_IMAGE_WRITE_IMPLEMENTATION | ||||
|  | ||||
| #include "stb_image_write.h"    // Create PNG file | ||||
|  | ||||
| #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 | ||||
| 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; | ||||
|     int traceDebugMsgs = 1; | ||||
|      | ||||
| @@ -150,20 +148,19 @@ void TraceLog(int msgType, const char *text, ...) | ||||
|     traceDebugMsgs = 0; | ||||
| #endif | ||||
|  | ||||
|     if (logstream != NULL) | ||||
|     { | ||||
|     // NOTE: If trace log file not set, output redirected to stdout  | ||||
|     if (logstream == NULL) logstream = stdout; | ||||
|      | ||||
|     switch(msgType) | ||||
|     { | ||||
|             case 0: fprintf(logstream, "INFO: "); break; | ||||
|             case 1: fprintf(logstream, "ERROR: "); break; | ||||
|             case 2: fprintf(logstream, "WARNING: "); break; | ||||
|             case 3: if (traceDebugMsgs) fprintf(logstream, "DEBUG: "); break; | ||||
|         case INFO: fprintf(logstream, "INFO: "); break; | ||||
|         case ERROR: fprintf(logstream, "ERROR: "); break; | ||||
|         case WARNING: fprintf(logstream, "WARNING: "); break; | ||||
|         case DEBUG: if (traceDebugMsgs) fprintf(logstream, "DEBUG: "); break; | ||||
|         default: break; | ||||
|     } | ||||
|      | ||||
|         if (msgType == 3) | ||||
|         { | ||||
|             if (traceDebugMsgs) | ||||
|     if ((msgType != DEBUG) || ((msgType == DEBUG) && (traceDebugMsgs))) | ||||
|     { | ||||
|         va_start(args, text); | ||||
|         vfprintf(logstream, text, args); | ||||
| @@ -171,53 +168,12 @@ void TraceLog(int msgType, const char *text, ...) | ||||
|          | ||||
|         fprintf(logstream, "\n"); | ||||
|     } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             va_start(args, text); | ||||
|             vfprintf(logstream, text, args); | ||||
|             va_end(args); | ||||
|      | ||||
|             fprintf(logstream, "\n"); | ||||
|         } | ||||
|     } | ||||
|     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 == ERROR) exit(1);      // If ERROR message, exit program | ||||
| } | ||||
|  | ||||
|         if (msgType == 3) | ||||
|         { | ||||
|             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) | ||||
| // Open a trace log file (if desired) | ||||
| void TraceLogOpen(const char *logFileName) | ||||
| { | ||||
|     // stdout redirected to stream file | ||||
|     FILE *logstream = fopen(logFileName, "w"); | ||||
| @@ -225,9 +181,25 @@ void InitTraceLogFile(const char *logFileName) | ||||
|     if (logstream == NULL) TraceLog(WARNING, "Unable to open log file"); | ||||
| } | ||||
|  | ||||
| // Closes the trace log file | ||||
| void CloseTraceLogFile() | ||||
| // Close the trace log file | ||||
| void TraceLogClose() | ||||
| { | ||||
|     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 | ||||
| *        | ||||
| *   Uses external lib:     | ||||
| *       tinfl - zlib DEFLATE algorithm decompression lib | ||||
| *        | ||||
| *   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  | ||||
| @@ -32,12 +29,12 @@ | ||||
| //---------------------------------------------------------------------------------- | ||||
| // 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 | ||||
| //---------------------------------------------------------------------------------- | ||||
| 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; | ||||
|  | ||||
| @@ -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 TraceLog(int msgType, const char *text, ...);  // Outputs a trace log message | ||||
| void InitTraceLogFile(const char *logFileName);     // Inits a trace log file | ||||
| void CloseTraceLogFile();                           // Closes the trace log file | ||||
| void TraceLogOpen(const char *logFileName);         // Open a trace log file (if desired) | ||||
| void TraceLogClose();                               // Close the trace log file | ||||
|  | ||||
| const char *GetExtension(const char *fileName); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 raysan5
					raysan5