Skip to content

Commit

Permalink
ADDED: LoadTextureCubemap()
Browse files Browse the repository at this point in the history
Probably uncomplete, not tested yet...
  • Loading branch information
raysan5 committed Feb 4, 2019
1 parent 5755c5e commit fce48e8
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 28 deletions.
14 changes: 14 additions & 0 deletions src/raylib.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@ typedef struct Texture2D {
// Texture type, same as Texture2D
typedef Texture2D Texture;

// TextureCubemap type, actually, same as Texture2D
typedef Texture2D TextureCubemap;

// RenderTexture2D type, for texture rendering
typedef struct RenderTexture2D {
unsigned int id; // OpenGL Framebuffer Object (FBO) id
Expand Down Expand Up @@ -749,6 +752,16 @@ typedef enum {
FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x
} TextureFilterMode;

// Cubemap layout type
typedef enum {
CUBEMAP_AUTO_DETECT = 0, // Automatically detect layout type
CUBEMAP_LINE_VERTICAL, // Layout is defined by a vertical line with faces
CUBEMAP_LINE_HORIZONTAL, // Layout is defined by an horizontal line with faces
CUBEMAP_CROSS_THREE_BY_FOUR, // Layout is defined by a 3x4 cross with cubemap faces
CUBEMAP_CROSS_FOUR_BY_THREE, // Layout is defined by a 4x3 cross with cubemap faces
CUBEMAP_PANORAMA // Layout is defined by a panorama image (equirectangular map)
} CubemapLayoutType;

// Texture parameters: wrap mode
typedef enum {
WRAP_REPEAT = 0, // Repeats texture in tiled mode
Expand Down Expand Up @@ -1049,6 +1062,7 @@ RLAPI void ExportImage(Image image, const char *fileName);
RLAPI void ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes
RLAPI Texture2D LoadTexture(const char *fileName); // Load texture from file into GPU memory (VRAM)
RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data
RLAPI TextureCubemap LoadTextureCubemap(Image image, int layoutType); // Load cubemap from image, multiple image cubemap layouts supported
RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer)
RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM)
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
Expand Down
135 changes: 108 additions & 27 deletions src/rlgl.h
Original file line number Diff line number Diff line change
Expand Up @@ -450,14 +450,18 @@ Vector3 rlUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coo

// Textures data management
unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount); // Load texture in GPU
unsigned int rlLoadTextureCubemap(void *data, int size, int format); // Load texture cubemap
void rlUpdateTexture(unsigned int id, int width, int height, int format, const void *data); // Update GPU texture with new data
void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned int *glFormat, unsigned int *glType); // Get OpenGL internal formats
void rlUnloadTexture(unsigned int id); // Unload texture from GPU memory
void rlUnloadTexture(unsigned int id); // Unload texture from GPU memory

void rlGenerateMipmaps(Texture2D *texture); // Generate mipmap data for selected texture
void *rlReadTexturePixels(Texture2D texture); // Read texture pixel data
unsigned char *rlReadScreenPixels(int width, int height); // Read screen pixel data (color buffer)
RenderTexture2D rlLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with color and depth attachments)
RenderTexture2D rlLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with default color and depth attachments)
RenderTexture2D rlLoadRenderTextureEx(int width, int height, int colorFormat, int depthBits, bool useDepthTexture);
void rlAttachRenderTexture(RenderTexture target, unsigned int textureId); // Attach/detach color buffer texture to an FBO (returns previous attachment)
bool rlCompleteRenderTexture(RenderTexture target); // Verify rendertexture is complete

// Vertex data management
void rlLoadMesh(Mesh *mesh, bool dynamic); // Upload vertex data into GPU and provided VAO/VBO ids
Expand Down Expand Up @@ -699,9 +703,9 @@ typedef struct DynamicBuffer {
typedef struct DrawCall {
int mode; // Drawing mode: LINES, TRIANGLES, QUADS
int vertexCount; // Number of vertex of the draw
//GLuint vaoId; // Vertex Array id to be used on the draw
//GLuint shaderId; // Shader id to be used on the draw
GLuint textureId; // Texture id to be used on the draw
//unsigned int vaoId; // Vertex Array id to be used on the draw
//unsigned int shaderId; // Shader id to be used on the draw
unsigned int textureId; // Texture id to be used on the draw
//Matrix projection; // Projection matrix for this draw
//Matrix modelview; // Modelview matrix for this draw
} DrawCall;
Expand All @@ -713,7 +717,8 @@ typedef struct VrStereoConfig {
Shader distortionShader; // VR stereo rendering distortion shader
Matrix eyesProjection[2]; // VR stereo rendering eyes projection matrices
Matrix eyesViewOffset[2]; // VR stereo rendering eyes view offset matrices
int eyesViewport[2][4]; // VR stereo rendering eyes viewports [x, y, w, h]
int eyeViewportRight[4]; // VR stereo rendering right eye viewport [x, y, w, h]
int eyeViewportLeft[4]; // VR stereo rendering left eye viewport [x, y, w, h]
} VrStereoConfig;
#endif

Expand Down Expand Up @@ -1816,7 +1821,7 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi
{
glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding

GLuint id = 0;
unsigned int id = 0;

// Check texture format support by OpenGL 1.1 (compressed textures not supported)
#if defined(GRAPHICS_API_OPENGL_11)
Expand Down Expand Up @@ -2039,26 +2044,81 @@ void rlUnloadTexture(unsigned int id)
if (id > 0) glDeleteTextures(1, &id);
}

// Load a texture to be used for rendering (fbo with color and depth attachments)
RenderTexture2D rlLoadRenderTexture(int width, int height)
// Load texture cubemap
// NOTE: Cubemap data is expected to be 6 images in a single column,
// expected the following convention: +X, -X, +Y, -Y, +Z, -Z
unsigned int rlLoadTextureCubemap(void *data, int size, int format)
{
RenderTexture2D target = { 0 };
unsigned int cubemapId = 0;
unsigned int dataSize = GetPixelDataSize(size, size, format);

target.id = 0;
glGenTextures(1, &cubemapId);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapId);

unsigned int glInternalFormat, glFormat, glType;
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);

// Load cubemap faces
for (unsigned int i = 0; i < 6; i++)
{
if (glInternalFormat != -1)
{
if (format < COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, size, size, 0, glFormat, glType, (unsigned char *)data + i*dataSize);
#if !defined(GRAPHICS_API_OPENGL_11)
else glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, size, size, 0, dataSize, (unsigned char *)data + i*dataSize);
#endif
#if defined(GRAPHICS_API_OPENGL_33)
if (format == UNCOMPRESSED_GRAYSCALE)
{
GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
}
else if (format == UNCOMPRESSED_GRAY_ALPHA)
{
#if defined(GRAPHICS_API_OPENGL_21)
GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ALPHA };
#elif defined(GRAPHICS_API_OPENGL_33)
GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
#endif
glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
}
#endif
}
}

// Set cubemap texture sampling parameters
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#if defined(GRAPHICS_API_OPENGL_33)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // Flag not supported on OpenGL ES 2.0
#endif

glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

return cubemapId;
}

// Load a texture to be used for rendering (fbo with default color and depth attachments)
// NOTE: If colorFormat or depthBits are no supported, no attachment is done
RenderTexture2D rlLoadRenderTexture(int width, int height) //, int colorFormat, int depthBits, bool useDepthTexture);
{
RenderTexture2D target = { 0 };

#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Create the framebuffer object
glGenFramebuffers(1, &target.id);
glBindFramebuffer(GL_FRAMEBUFFER, target.id);

// Create fbo color texture attachment
//-----------------------------------------------------------------------------------------------------
target.texture.id = 0;
target.texture.width = width;
target.texture.height = height;
target.texture.format = UNCOMPRESSED_R8G8B8A8;
target.texture.mipmaps = 1;

target.depth.id = 0;
target.depth.width = width;
target.depth.height = height;
target.depth.format = 19; //DEPTH_COMPONENT_24BIT
target.depth.mipmaps = 1;

#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Create the texture that will serve as the color attachment for the framebuffer
glGenTextures(1, &target.texture.id);
glBindTexture(GL_TEXTURE_2D, target.texture.id);
Expand All @@ -2068,7 +2128,16 @@ RenderTexture2D rlLoadRenderTexture(int width, int height)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);

//-----------------------------------------------------------------------------------------------------

// Create fbo depth renderbuffer/texture
//-----------------------------------------------------------------------------------------------------
target.depth.id = 0;
target.depth.width = width;
target.depth.height = height;
target.depth.format = 19; //DEPTH_COMPONENT_24BIT
target.depth.mipmaps = 1;

#if defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2)
#define USE_DEPTH_RENDERBUFFER
#else
Expand All @@ -2092,19 +2161,20 @@ RenderTexture2D rlLoadRenderTexture(int width, int height)
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
#endif

// Create the framebuffer object
glGenFramebuffers(1, &target.id);
glBindFramebuffer(GL_FRAMEBUFFER, target.id);

//-----------------------------------------------------------------------------------------------------

// Attach color texture and depth renderbuffer to FBO
//-----------------------------------------------------------------------------------------------------
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target.texture.id, 0);
#if defined(USE_DEPTH_RENDERBUFFER)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, target.depth.id);
#elif defined(USE_DEPTH_TEXTURE)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, target.depth.id, 0);
#endif
//-----------------------------------------------------------------------------------------------------

// Check if fbo is complete with attachments (valid)
//-----------------------------------------------------------------------------------------------------
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

if (status != GL_FRAMEBUFFER_COMPLETE)
Expand Down Expand Up @@ -2135,13 +2205,24 @@ RenderTexture2D rlLoadRenderTexture(int width, int height)
glDeleteFramebuffers(1, &target.id);
}
else TraceLog(LOG_INFO, "[FBO ID %i] Framebuffer object created successfully", target.id);
//-----------------------------------------------------------------------------------------------------

glBindFramebuffer(GL_FRAMEBUFFER, 0);
#endif

return target;
}

// Improved FBO generation function to allow selecting the attached color buffer pixel format
// and the depth buffer type (Renderbuffer or Texture) and size
// NOTE: Be careful on supported pixel formats...
//RenderTexture rlLoadRenderTexture(int width, int height, int colorFormat, int depthBits, bool useDepthTexture);
// Attach/detach color buffer texture to an FBO (returns previous attachment)
//Texture2D rlAttachRenderTexture(RenderTexture target, Texture2D texture);

//void rlRenderTextureColorAttach(RenderTexture target, Texture2D texture);
//bool rlRenderTextureComplete(RenderTexture target); // Verify valid rendertexture

// Generate mipmap data for selected texture
void rlGenerateMipmaps(Texture2D *texture)
{
Expand Down Expand Up @@ -2855,7 +2936,7 @@ Shader LoadShaderCode(char *vsCode, char *fsCode)
name[namelen] = 0;

// Get the location of the named uniform
GLuint location = glGetUniformLocation(shader.id, name);
unsigned int location = glGetUniformLocation(shader.id, name);

TraceLog(LOG_DEBUG, "[SHDR ID %i] Active uniform [%s] set at location: %i", shader.id, name, location);
}
Expand Down Expand Up @@ -4315,8 +4396,8 @@ static void SetStereoConfig(VrDeviceInfo hmd)
vrConfig.eyesViewOffset[1] = MatrixTranslate(hmd.interpupillaryDistance*0.5f, 0.075f, 0.045f);

// Compute eyes Viewports
//vrConfig.eyesViewport[0] = { 0.0f, 0.0f, (float)hmd.hResolution/2, (float)hmd.vResolution };
//vrConfig.eyesViewport[1] = { hmd.hResolution/2.0f, 0.0f, (float)hmd.hResolution/2, (float) hmd.vResolution };
//vrConfig.eyeViewportRight[0] = (int[4]){ 0, 0, hmd.hResolution/2, hmd.vResolution };
//vrConfig.eyeViewportLeft[0] = (int[4]){ hmd.hResolution/2, 0, hmd.hResolution/2, hmd.vResolution };
}

// Set internal projection and modelview matrix depending on eyes tracking data
Expand Down
86 changes: 85 additions & 1 deletion src/textures.c
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,92 @@ Texture2D LoadTextureFromImage(Image image)
return texture;
}

// Load cubemap from image, multiple image cubemap layouts supported
TextureCubemap LoadTextureCubemap(Image image, int layoutType)
{
TextureCubemap cubemap = { 0 };

if (layoutType == CUBEMAP_AUTO_DETECT) // Try to automatically guess layout type
{
// Check image width/height to determine the type of cubemap provided
if (image.width > image.height)
{
if ((image.width/6) == image.height) { layoutType = CUBEMAP_LINE_HORIZONTAL; cubemap.width = image.width/6; }
else if ((image.width/4) == (image.height/3)) { layoutType = CUBEMAP_CROSS_FOUR_BY_THREE; cubemap.width = image.width/4; }
else if (image.width >= (int)((float)image.height*1.85f)) { layoutType = CUBEMAP_PANORAMA; cubemap.width = image.width/4; }
}
else if (image.height > image.width)
{
if ((image.height/6) == image.width) { layoutType = CUBEMAP_LINE_VERTICAL; cubemap.width = image.height/6; }
else if ((image.width/3) == (image.height/4)) { layoutType = CUBEMAP_CROSS_THREE_BY_FOUR; cubemap.width = image.width/3; }
}

cubemap.height = cubemap.width;
}

int size = cubemap.width;

if (layoutType != CUBEMAP_AUTO_DETECT)
{
//unsigned int dataSize = GetPixelDataSize(size, size, format);
//void *facesData = malloc(size*size*dataSize*6); // Get memory for 6 faces in a column

Image faces = { 0 }; // Vertical column image
Rectangle faceRecs[6] = { 0 }; // Face source rectangles
for (int i = 0; i < 6; i++) faceRecs[i] = (Rectangle){ 0, 0, size, size };

if (layoutType == CUBEMAP_LINE_VERTICAL)
{
faces = image;
for (int i = 0; i < 6; i++) faceRecs[i].y = size*i;
}
else if (layoutType == CUBEMAP_PANORAMA)
{
// TODO: Convert panorama image to square faces...
}
else
{
if (layoutType == CUBEMAP_LINE_HORIZONTAL) for (int i = 0; i < 6; i++) faceRecs[i].x = size*i;
else if (layoutType == CUBEMAP_CROSS_THREE_BY_FOUR)
{
faceRecs[0].x = size; faceRecs[0].y = size;
faceRecs[1].x = size; faceRecs[1].y = 3*size;
faceRecs[2].x = size; faceRecs[2].y = 0;
faceRecs[3].x = size; faceRecs[3].y = 2*size;
faceRecs[4].x = 0; faceRecs[4].y = size;
faceRecs[5].x = 2*size; faceRecs[5].y = size;
}
else if (layoutType == CUBEMAP_CROSS_FOUR_BY_THREE)
{
faceRecs[0].x = 2*size; faceRecs[0].y = size;
faceRecs[1].x = 0; faceRecs[1].y = size;
faceRecs[2].x = size; faceRecs[2].y = 0;
faceRecs[3].x = size; faceRecs[3].y = 2*size;
faceRecs[4].x = size; faceRecs[4].y = size;
faceRecs[5].x = 3*size; faceRecs[5].y = size;
}

// Convert image data to 6 faces in a vertical column, that's the optimum layout for loading
faces = GenImageColor(size, size*6, MAGENTA);
ImageFormat(&faces, image.format);

// TODO: Image formating does not work with compressed textures!
}

for (int i = 0; i < 6; i++) ImageDraw(&faces, image, faceRecs[i], (Rectangle){ 0, size*i, size, size });

cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format);
if (cubemap.id == 0) TraceLog(LOG_WARNING, "Cubemap image could not be loaded.");

UnloadImage(faces);
}
else TraceLog(LOG_WARNING, "Cubemap image layout can not be detected.");

return cubemap;
}

// Load texture for rendering (framebuffer)
// NOTE: Render texture is loaded by default with RGBA color attachment and depth RenderBuffer
RenderTexture2D LoadRenderTexture(int width, int height)
{
RenderTexture2D target = rlLoadRenderTexture(width, height);
Expand Down Expand Up @@ -1666,7 +1751,6 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
int index; // Index position in sprite font
unsigned char character; // Current character

// TODO: ISSUE: Measured text size does not seem to be correct... issue on ImageDraw()
Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing);

TraceLog(LOG_DEBUG, "Text Image size: %f, %f", imSize.x, imSize.y);
Expand Down

0 comments on commit fce48e8

Please sign in to comment.