diff options
Diffstat (limited to 'src/textures.c')
| -rw-r--r-- | src/textures.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/src/textures.c b/src/textures.c new file mode 100644 index 00000000..1a7e23a7 --- /dev/null +++ b/src/textures.c @@ -0,0 +1,275 @@ +/********************************************************************************************* +* +* raylib.textures +* +* Basic functions to load and draw Textures (2d) +* +* Uses external lib: +* stb_image - Multiple formats image loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC) +* +* 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 +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" + +#include <GL/gl.h> // OpenGL functions +#include <stdlib.h> // Declares malloc() and free() for memory management +#include "stb_image.h" // Used to read image data (multiple formats support) + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// Nop... + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef unsigned char byte; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +// It's lonely here... + +//---------------------------------------------------------------------------------- +// Module specific Functions Declaration +//---------------------------------------------------------------------------------- +// No private (static) functions in this module (.c file) + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- + +// Load an image into CPU memory (RAM) +Image LoadImage(const char *fileName) +{ + Image image; + + int imgWidth; + int imgHeight; + int imgBpp; + + // NOTE: Using stb_image to load images (Supports: BMP, TGA, PNG, JPG, ...) + byte *imgData = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4); // Force loading to 4 components (RGBA) + + // Convert array to pixel array for working convenience + image.pixels = (Color *)malloc(imgWidth * imgHeight * sizeof(Color)); + + int pix = 0; + + for (int i = 0; i < (imgWidth * imgHeight * 4); i += 4) + { + image.pixels[pix].r = imgData[i]; + image.pixels[pix].g = imgData[i+1]; + image.pixels[pix].b = imgData[i+2]; + image.pixels[pix].a = imgData[i+3]; + pix++; + } + + stbi_image_free(imgData); + + image.width = imgWidth; + image.height = imgHeight; + + // ALTERNATIVE: We can load pixel data directly into Color struct pixels array, + // to do that struct data alignment should be the right one (4 byte); it is. + //image.pixels = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4); + + return image; +} + +// Unload image from CPU memory (RAM) +void UnloadImage(Image image) +{ + free(image.pixels); +} + +// Load an image as texture into GPU memory +Texture2D LoadTexture(const char *fileName) +{ + Texture2D texture; + + int imgWidth; + int imgHeight; + int imgBpp; + + // NOTE: Using stb_image to load images (Supports: BMP, TGA, PNG, JPG, ...) + byte *imgData = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4); // Force loading to 4 components (RGBA) + + // Convert loaded data to OpenGL texture + //---------------------------------------- + GLuint id; + glGenTextures(1, &id); // Generate Pointer to the Texture + + glBindTexture(GL_TEXTURE_2D, id); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repead on x-axis + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repead on y-axis + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, imgWidth, imgHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgData); + + // NOTE: Not using mipmappings (texture for 2D drawing) + // At this point we have the image converted to texture and uploaded to GPU + + stbi_image_free(imgData); // Now we can free loaded data from RAM memory + + texture.glId = id; + texture.width = imgWidth; + texture.height = imgHeight; + + return texture; +} + +// Load an image as texture (and convert to POT with mipmaps) +Texture2D LoadTextureEx(const char *fileName, bool createPOT, bool mipmaps) +{ + Texture2D texture; + + // TODO: Load and image and convert to Power-Of-Two + // NOTE: Conversion could be done just adding extra space to image or by scaling image + // NOTE: If scaling image, be careful with scaling algorithm (aproximation, bilinear, bicubic...) + + // TODO: Generate all required mipmap levels from image and convert to testure (not that easy) + // NOTE: If using OpenGL 1.1, the only option is doing mipmap generation on CPU side (i.e. gluBuild2DMipmaps) + // NOTE: raylib tries to minimize external dependencies so, we are not using GLU + // NOTE: Re-implement some function similar to gluBuild2DMipmaps (not that easy...) + + return texture; +} + +// Unload texture from GPU memory +void UnloadTexture(Texture2D texture) +{ + glDeleteTextures(1, &texture.glId); +} + +// Draw a Texture2D +void DrawTexture(Texture2D texture, int posX, int posY, Color tint) +{ + DrawTextureEx(texture, (Vector2){ (float)posX, (float)posY}, 0, 1.0f, tint); +} + +// Draw a Texture2D with extended parameters +void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint) +{ + glEnable(GL_TEXTURE_2D); // Enable textures usage + + glBindTexture(GL_TEXTURE_2D, texture.glId); + + glPushMatrix(); + // NOTE: Rotation is applied before translation and scaling, even being called in inverse order... + // NOTE: Rotation point is upper-left corner + glTranslatef(position.x, position.y, 0); + glScalef(scale, scale, 1.0f); + glRotatef(rotation, 0, 0, 1); + + glBegin(GL_QUADS); + glColor4ub(tint.r, tint.g, tint.b, tint.a); + glNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer + glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f); // Bottom-left corner for texture and quad + glTexCoord2f(1.0f, 0.0f); glVertex2f(texture.width, 0.0f); // Bottom-right corner for texture and quad + glTexCoord2f(1.0f, 1.0f); glVertex2f(texture.width, texture.height); // Top-right corner for texture and quad + glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, texture.height); // Top-left corner for texture and quad + glEnd(); + glPopMatrix(); + + glDisable(GL_TEXTURE_2D); // Disable textures usage +} + +// Draw a part of a texture (defined by a rectangle) +void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, float scale, Color tint) +{ + glEnable(GL_TEXTURE_2D); // Enable textures usage + + glBindTexture(GL_TEXTURE_2D, texture.glId); + + glPushMatrix(); + glTranslatef(position.x, position.y, 0); + glScalef(scale, scale, 1.0f); + //glRotatef(rotation, 0, 0, 1); + + glBegin(GL_QUADS); + glColor4ub(tint.r, tint.g, tint.b, tint.a); + glNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer + + // Bottom-left corner for texture and quad + glTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height); + glVertex2f(0.0f, 0.0f); + + // Bottom-right corner for texture and quad + glTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height); + glVertex2f(sourceRec.width, 0.0f); + + // Top-right corner for texture and quad + glTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); + glVertex2f(sourceRec.width, sourceRec.height); + + // Top-left corner for texture and quad + glTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); + glVertex2f(0.0f, sourceRec.height); + glEnd(); + glPopMatrix(); + + glDisable(GL_TEXTURE_2D); // Disable textures usage +} + +// Creates a bitmap (BMP) file from an array of pixel data +// NOTE: This function is only used by module [core], not explicitly available to raylib users +extern void WriteBitmap(const char *fileName, const Color *imgDataPixel, int width, int height) +{ + int filesize = 54 + 3*width*height; + + unsigned char bmpFileHeader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0}; // Standard BMP file header + unsigned char bmpInfoHeader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0}; // Standard BMP info header + + bmpFileHeader[2] = (unsigned char)(filesize); + bmpFileHeader[3] = (unsigned char)(filesize>>8); + bmpFileHeader[4] = (unsigned char)(filesize>>16); + bmpFileHeader[5] = (unsigned char)(filesize>>24); + + bmpInfoHeader[4] = (unsigned char)(width); + bmpInfoHeader[5] = (unsigned char)(width>>8); + bmpInfoHeader[6] = (unsigned char)(width>>16); + bmpInfoHeader[7] = (unsigned char)(width>>24); + bmpInfoHeader[8] = (unsigned char)(height); + bmpInfoHeader[9] = (unsigned char)(height>>8); + bmpInfoHeader[10] = (unsigned char)(height>>16); + bmpInfoHeader[11] = (unsigned char)(height>>24); + + FILE *bmpFile = fopen(fileName, "wb"); // Define a pointer to bitmap file and open it in write-binary mode + + // NOTE: fwrite parameters are: data pointer, size in bytes of each element to be written, number of elements, file-to-write pointer + fwrite(bmpFileHeader, sizeof(unsigned char), 14, bmpFile); // Write BMP file header data + fwrite(bmpInfoHeader, sizeof(unsigned char), 40, bmpFile); // Write BMP info header data + + // Write pixel data to file + for (int y = 0; y < height ; y++) + { + for (int x = 0; x < width; x++) + { + fputc(imgDataPixel[x + y*width].b, bmpFile); + fputc(imgDataPixel[x + y*width].g, bmpFile); + fputc(imgDataPixel[x + y*width].r, bmpFile); + } + } + + fclose(bmpFile); // Close bitmap file +}
\ No newline at end of file |
