diff --git a/src/models.c b/src/models.c index 8d772f02..c45e18c8 100644 --- a/src/models.c +++ b/src/models.c @@ -600,7 +600,7 @@ Model LoadHeightmap(Image heightmap, float maxHeight) int mapX = heightmap.width; int mapZ = heightmap.height; - Color *heightmapPixels = GetPixelData(heightmap); + Color *heightmapPixels = GetImageData(heightmap); // NOTE: One vertex per pixel // TODO: Consider resolution when generating model data? @@ -721,7 +721,7 @@ Model LoadCubicmap(Image cubicmap) { VertexData vData; - Color *cubicmapPixels = GetPixelData(cubicmap); + Color *cubicmapPixels = GetImageData(cubicmap); // Map cube size will be 1.0 float mapCubeSide = 1.0f; @@ -1105,8 +1105,6 @@ void UnloadModel(Model model) rlDeleteBuffers(model.mesh.vboId[2]); rlDeleteVertexArrays(model.mesh.vaoId); - //rlDeleteTextures(model.texture.id); - //rlDeleteShader(model.shader.id); } // Link a texture to a model @@ -1114,8 +1112,9 @@ void SetModelTexture(Model *model, Texture2D texture) { if (texture.id <= 0) { - model->texture.id = whiteTexture; // Default white texture (use mesh color) - model->shader.texDiffuseId = whiteTexture; + // Use default white texture (use mesh color) + model->texture.id = whiteTexture; // OpenGL 1.1 + model->shader.texDiffuseId = whiteTexture; // OpenGL 3.3 / ES 2.0 } else { @@ -1124,26 +1123,6 @@ void SetModelTexture(Model *model, Texture2D texture) } } -// Load a custom shader (vertex shader + fragment shader) -Shader LoadShader(char *vsFileName, char *fsFileName) -{ - Shader shader = rlglLoadShader(vsFileName, fsFileName); - - return shader; -} - -// Unload a custom shader from memory -void UnloadShader(Shader shader) -{ - rlDeleteShader(shader.id); -} - -// Set shader for a model -void SetModelShader(Model *model, Shader shader) -{ - rlglSetModelShader(model, shader); -} - // Draw a model (with texture if set) void DrawModel(Model model, Vector3 position, float scale, Color tint) { @@ -1269,7 +1248,7 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec rlDisableTexture(); } - +// Detect collision between two spheres bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB) { bool collision = false; @@ -1285,22 +1264,10 @@ bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, floa return collision; } +// Detect collision between two boxes +// NOTE: Boxes are defined by two points minimum and maximum bool CheckCollisionBoxes(Vector3 minBBox1, Vector3 maxBBox1, Vector3 minBBox2, Vector3 maxBBox2) { - /* - // Get min and max vertex to construct bounds (AABB) - Vector3 minVertex = tempVertices[0]; - Vector3 maxVertex = tempVertices[0]; - - for (int i = 1; i < tempVertices.Count; i++) - { - minVertex = Vector3.Min(minVertex, tempVertices[i]); - maxVertex = Vector3.Max(maxVertex, tempVertices[i]); - } - - bounds = new BoundingBox(minVertex, maxVertex); - */ - bool collision = true; if ((maxBBox1.x >= minBBox2.x) && (minBBox1.x <= maxBBox2.x)) @@ -1313,6 +1280,7 @@ bool CheckCollisionBoxes(Vector3 minBBox1, Vector3 maxBBox1, Vector3 minBBox2, V return collision; } +// Detect collision between box and sphere bool CheckCollisionBoxSphere(Vector3 minBBox, Vector3 maxBBox, Vector3 centerSphere, float radiusSphere) { bool collision = false; @@ -1326,35 +1294,29 @@ bool CheckCollisionBoxSphere(Vector3 minBBox, Vector3 maxBBox, Vector3 centerSph { float dmin = 0; - if (centerSphere.x - minBBox.x <= radiusSphere) - dmin += (centerSphere.x - minBBox.x) * (centerSphere.x - minBBox.x); - else if (maxBBox.x - centerSphere.x <= radiusSphere) - dmin += (centerSphere.x - maxBBox.x) * (centerSphere.x - maxBBox.x); + if (centerSphere.x - minBBox.x <= radiusSphere) dmin += (centerSphere.x - minBBox.x)*(centerSphere.x - minBBox.x); + else if (maxBBox.x - centerSphere.x <= radiusSphere) dmin += (centerSphere.x - maxBBox.x)*(centerSphere.x - maxBBox.x); - if (centerSphere.y - minBBox.y <= radiusSphere) - dmin += (centerSphere.y - minBBox.y) * (centerSphere.y - minBBox.y); - else if (maxBBox.y - centerSphere.y <= radiusSphere) - dmin += (centerSphere.y - maxBBox.y) * (centerSphere.y - maxBBox.y); + if (centerSphere.y - minBBox.y <= radiusSphere) dmin += (centerSphere.y - minBBox.y)*(centerSphere.y - minBBox.y); + else if (maxBBox.y - centerSphere.y <= radiusSphere) dmin += (centerSphere.y - maxBBox.y)*(centerSphere.y - maxBBox.y); - if (centerSphere.z - minBBox.z <= radiusSphere) - dmin += (centerSphere.z - minBBox.z) * (centerSphere.z - minBBox.z); - else if (maxBBox.z - centerSphere.z <= radiusSphere) - dmin += (centerSphere.z - maxBBox.z) * (centerSphere.z - maxBBox.z); + if (centerSphere.z - minBBox.z <= radiusSphere) dmin += (centerSphere.z - minBBox.z)*(centerSphere.z - minBBox.z); + else if (maxBBox.z - centerSphere.z <= radiusSphere) dmin += (centerSphere.z - maxBBox.z)*(centerSphere.z - maxBBox.z); - if (dmin <= radiusSphere * radiusSphere) collision = true; + if (dmin <= radiusSphere*radiusSphere) collision = true; } return collision; } -// TODO +// TODO: Useful function to check collision area? //BoundingBox GetCollisionArea(BoundingBox box1, BoundingBox box2) // Detect and resolve cubicmap collisions // NOTE: player position (or camera) is modified inside this function Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius) { - Color *cubicmapPixels = GetPixelData(cubicmap); + Color *cubicmapPixels = GetImageData(cubicmap); // Detect the cell where the player is located Vector3 impactDirection = { 0, 0, 0 }; @@ -1697,7 +1659,7 @@ static VertexData LoadOBJ(const char *fileName) // Second reading pass: Get vertex data to fill intermediate arrays // NOTE: This second pass is required in case of multiple meshes defined in same OBJ - // TODO: Consider that diferent meshes can have different vertex data available (position, texcoords, normals) + // TODO: Consider that different meshes can have different vertex data available (position, texcoords, normals) while(!feof(objFile)) { fscanf(objFile, "%c", &dataType); diff --git a/src/text.c b/src/text.c index dbbb962f..feed211e 100644 --- a/src/text.c +++ b/src/text.c @@ -238,7 +238,7 @@ SpriteFont LoadSpriteFont(const char *fileName) // At this point we have a data array... - Color *imagePixels = GetPixelData(image); + Color *imagePixels = GetImageData(image); #if defined(PLATFORM_RPI) || defined(PLATFORM_WEB) ImageConvertToPOT(&image, MAGENTA); diff --git a/src/textures.c b/src/textures.c index 42c7810b..b7ab1f7e 100644 --- a/src/textures.c +++ b/src/textures.c @@ -149,6 +149,56 @@ Image LoadImageEx(Color *pixels, int width, int height) return image; } +// Load an image from RAW file +Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize) +{ + Image image; + + image.data = NULL; + image.width = 0; + image.height = 0; + image.mipmaps = 0; + image.format = 0; + + FILE *rawFile = fopen(fileName, "rb"); + + if (rawFile == NULL) + { + TraceLog(WARNING, "[%s] RAW image file could not be opened", fileName); + } + else + { + if (headerSize > 0) fseek(rawFile, headerSize, SEEK_SET); + + unsigned int size = width*height; + + switch (format) + { + case UNCOMPRESSED_GRAYSCALE: image.data = (unsigned char *)malloc(size); break; // 8 bit per pixel (no alpha) + case UNCOMPRESSED_GRAY_ALPHA: image.data = (unsigned char *)malloc(size*2); size *= 2; break; // 16 bpp (2 channels) + case UNCOMPRESSED_R5G6B5: image.data = (unsigned short *)malloc(size); break; // 16 bpp + case UNCOMPRESSED_R8G8B8: image.data = (unsigned char *)malloc(size*3); size *= 3; break; // 24 bpp + case UNCOMPRESSED_R5G5B5A1: image.data = (unsigned short *)malloc(size); break; // 16 bpp (1 bit alpha) + case UNCOMPRESSED_R4G4B4A4: image.data = (unsigned short *)malloc(size); break; // 16 bpp (4 bit alpha) + case UNCOMPRESSED_R8G8B8A8: image.data = (unsigned char *)malloc(size*4); size *= 4; break; // 32 bpp + default: TraceLog(WARNING, "Image format not suported"); break; + } + + fread(image.data, size, 1, rawFile); + + // TODO: Check if data have been read + + image.width = width; + image.height = height; + image.mipmaps = 0; + image.format = format; + + fclose(rawFile); + } + + return image; +} + // Load an image from rRES file (raylib Resource) // TODO: Review function to support multiple color modes Image LoadImageFromRES(const char *rresName, int resId) @@ -301,6 +351,18 @@ Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat, in return texture; } +// Load an image as texture from rRES file (raylib Resource) +Texture2D LoadTextureFromRES(const char *rresName, int resId) +{ + Texture2D texture; + + Image image = LoadImageFromRES(rresName, resId); + texture = LoadTextureFromImage(image); + UnloadImage(image); + + return texture; +} + // Load a texture from image data // NOTE: image is not unloaded, it must be done manually Texture2D LoadTextureFromImage(Image image) @@ -324,18 +386,6 @@ Texture2D LoadTextureFromImage(Image image) return texture; } -// Load an image as texture from rRES file (raylib Resource) -Texture2D LoadTextureFromRES(const char *rresName, int resId) -{ - Texture2D texture; - - Image image = LoadImageFromRES(rresName, resId); - texture = LoadTextureFromImage(image); - UnloadImage(image); - - return texture; -} - // Unload image from CPU memory (RAM) void UnloadImage(Image image) { @@ -348,46 +398,8 @@ void UnloadTexture(Texture2D texture) rlDeleteTextures(texture.id); } -// Convert image to POT (power-of-two) -// NOTE: Requirement on OpenGL ES 2.0 (RPI, HTML5) -void ImageConvertToPOT(Image *image, Color fillColor) -{ - // TODO: Review for new image struct - /* - // Just add the required amount of pixels at the right and bottom sides of image... - int potWidth = GetNextPOT(image->width); - int potHeight = GetNextPOT(image->height); - - // Check if POT texture generation is required (if texture is not already POT) - if ((potWidth != image->width) || (potHeight != image->height)) - { - Color *imgDataPixelPOT = NULL; - - // Generate POT array from NPOT data - imgDataPixelPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color)); - - for (int j = 0; j < potHeight; j++) - { - for (int i = 0; i < potWidth; i++) - { - if ((j < image->height) && (i < image->width)) imgDataPixelPOT[j*potWidth + i] = image->data[j*image->width + i]; - else imgDataPixelPOT[j*potWidth + i] = fillColor; - } - } - - TraceLog(WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight); - - free(image->pixels); - - image->pixels = imgDataPixelPOT; - image->width = potWidth; - image->height = potHeight; - } - */ -} - // Get pixel data from image in the form of Color struct array -Color *GetPixelData(Image image) +Color *GetImageData(Image image) { Color *pixels = (Color *)malloc(image.width*image.height*sizeof(Color)); @@ -497,7 +509,7 @@ void ImageConvertFormat(Image *image, int newFormat) { if ((image->format != newFormat) && (image->format < 8) && (newFormat < 8)) { - Color *pixels = GetPixelData(*image); + Color *pixels = GetImageData(*image); free(image->data); @@ -627,13 +639,83 @@ void ImageConvertFormat(Image *image, int newFormat) else TraceLog(WARNING, "Image data format is compressed, can not be converted"); } -/* -Image ImageCopy(Image image); -void ImageCrop(Image *image, Rectangle crop); -void ImageResize(Image *image, int newWidth, int newHeight); -void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); -void ImageDrawText(Image *dst, const char *text, Vector2 position, int size, Color color); -*/ + +// Convert image to POT (power-of-two) +// NOTE: Requirement on OpenGL ES 2.0 (RPI, HTML5) +void ImageConvertToPOT(Image *image, Color fillColor) +{ + // TODO: Review for new image struct + /* + // Just add the required amount of pixels at the right and bottom sides of image... + int potWidth = GetNextPOT(image->width); + int potHeight = GetNextPOT(image->height); + + // Check if POT texture generation is required (if texture is not already POT) + if ((potWidth != image->width) || (potHeight != image->height)) + { + Color *imgDataPixelPOT = NULL; + + // Generate POT array from NPOT data + imgDataPixelPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color)); + + for (int j = 0; j < potHeight; j++) + { + for (int i = 0; i < potWidth; i++) + { + if ((j < image->height) && (i < image->width)) imgDataPixelPOT[j*potWidth + i] = image->data[j*image->width + i]; + else imgDataPixelPOT[j*potWidth + i] = fillColor; + } + } + + TraceLog(WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight); + + free(image->pixels); + + image->pixels = imgDataPixelPOT; + image->width = potWidth; + image->height = potHeight; + } + */ +} + +// Copy an image to a new image +Image ImageCopy(Image image) +{ + Image newImage; + + int size = image.width*image.height; + + switch (image.format) + { + case UNCOMPRESSED_GRAYSCALE: newImage.data = (unsigned char *)malloc(size); break; // 8 bit per pixel (no alpha) + case UNCOMPRESSED_GRAY_ALPHA: newImage.data = (unsigned char *)malloc(size*2); size *= 2; break; // 16 bpp (2 channels) + case UNCOMPRESSED_R5G6B5: newImage.data = (unsigned short *)malloc(size); size *= 2; break; // 16 bpp + case UNCOMPRESSED_R8G8B8: newImage.data = (unsigned char *)malloc(size*3); size *= 3; break; // 24 bpp + case UNCOMPRESSED_R5G5B5A1: newImage.data = (unsigned short *)malloc(size); size *= 2; break; // 16 bpp (1 bit alpha) + case UNCOMPRESSED_R4G4B4A4: newImage.data = (unsigned short *)malloc(size); size *= 2; break; // 16 bpp (4 bit alpha) + case UNCOMPRESSED_R8G8B8A8: newImage.data = (unsigned char *)malloc(size*4); size *= 4; break; // 32 bpp + default: TraceLog(WARNING, "Image format not suported for copy"); break; + } + + if (newImage.data != NULL) + { + // NOTE: Size must be provided in bytes + memcpy(newImage.data, image.data, size); + + newImage.width = image.width; + newImage.height = image.height; + newImage.mipmaps = image.mipmaps; + newImage.format = image.format; + } + + return newImage; +} + +// TODO: Some useful functions to deal with images +//void ImageCrop(Image *image, Rectangle crop) {} +//void ImageResize(Image *image, int newWidth, int newHeight) {} +//void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) {} +//void ImageDrawText(Image *dst, const char *text, Vector2 position, int size, Color color) {} // Generate GPU mipmaps for a texture void GenTextureMipmaps(Texture2D texture) @@ -1310,47 +1392,3 @@ static Image LoadASTC(const char *fileName) return image; } - -// Load RAW image file -static Image LoadRAW(const char *fileName, int width, int height, int format, int headerSize) -{ - Image image; - - image.data = NULL; - image.width = 0; - image.height = 0; - image.mipmaps = 0; - image.format = 0; - - FILE *rawFile = fopen(fileName, "rb"); - - if (rawFile == NULL) - { - TraceLog(WARNING, "[%s] RAW image file could not be opened", fileName); - } - else - { - if (headerSize > 0) fseek(rawFile, headerSize, SEEK_SET); - - int dataSize = 0; - - // TODO: Calculate data size and allocate memory - switch (format) - { - - } - - fread(image.data, dataSize, 1, rawFile); - - // TODO: Check if data have been read - - image.width = width; - image.height = height; - image.mipmaps = 0; - image.format = format; - - fclose(rawFile); - } - - return image; -} \ No newline at end of file