|
|
@ -624,7 +624,7 @@ RLAPI unsigned char *rlReadScreenPixels(int width, int height); // Rea |
|
|
|
|
|
|
|
// Framebuffer management (fbo) |
|
|
|
RLAPI unsigned int rlLoadFramebuffer(int width, int height); // Load an empty framebuffer |
|
|
|
RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType); // Attach texture/renderbuffer to a framebuffer |
|
|
|
RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer |
|
|
|
RLAPI bool rlFramebufferComplete(unsigned int id); // Verify framebuffer is complete |
|
|
|
RLAPI void rlUnloadFramebuffer(unsigned int id); // Delete framebuffer from GPU |
|
|
|
|
|
|
@ -651,13 +651,9 @@ RLAPI void rlSetMatrixModelview(Matrix view); // Set |
|
|
|
RLAPI void rlSetMatrixProjectionStereo(Matrix right, Matrix left); // Set eyes projection matrices for stereo rendering |
|
|
|
RLAPI void rlSetMatrixViewOffsetStereo(Matrix right, Matrix left); // Set eyes view offsets matrices for stereo rendering |
|
|
|
|
|
|
|
// Texture maps generation (PBR) |
|
|
|
// TODO: Redesign or remove to avoid requiring external shaders |
|
|
|
RLAPI TextureCubemap rlGenTextureCubemap(Shader shader, Texture2D panorama, int size, int format); // Generate cubemap (6 faces) from equirectangular (panorama) texture |
|
|
|
RLAPI TextureCubemap rlGenTextureIrradiance(Shader shader, TextureCubemap cubemap, int size); // Generate irradiance cubemap using cubemap texture |
|
|
|
RLAPI TextureCubemap rlGenTexturePrefilter(Shader shader, TextureCubemap cubemap, int size); // Generate prefilter cubemap using cubemap texture |
|
|
|
RLAPI Texture2D rlGenTextureBRDF(Shader shader, int size); // Generate a generic BRDF texture |
|
|
|
|
|
|
|
// Quick and dirty cube/quad buffers load->draw->unload |
|
|
|
RLAPI void rlLoadDrawCube(void); // Load and draw a cube |
|
|
|
RLAPI void rlLoadDrawQuad(void); // Load and draw a quad |
|
|
|
#if defined(__cplusplus) |
|
|
|
} |
|
|
|
#endif |
|
|
@ -912,9 +908,6 @@ static PFNGLVERTEXATTRIBDIVISOREXTPROC glVertexAttribDivisor = NULL; |
|
|
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) |
|
|
|
static Shader rlLoadShaderDefault(void); // Load default shader (just vertex positioning and texture coloring) |
|
|
|
static void rlUnloadShaderDefault(void); // Unload default shader |
|
|
|
|
|
|
|
static void rlGenDrawCube(void); // Generate and draw cube |
|
|
|
static void rlGenDrawQuad(void); // Generate and draw quad |
|
|
|
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 |
|
|
|
#if defined(GRAPHICS_API_OPENGL_11) |
|
|
|
static int rlGenerateMipmapsData(unsigned char *data, int baseWidth, int baseHeight); // Generate mipmaps data on CPU side |
|
|
@ -2966,7 +2959,7 @@ unsigned int rlLoadFramebuffer(int width, int height) |
|
|
|
|
|
|
|
// Attach color buffer texture to an fbo (unloads previous attachment) |
|
|
|
// NOTE: Attach type: 0-Color, 1-Depth renderbuffer, 2-Depth texture |
|
|
|
void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType) |
|
|
|
void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel) |
|
|
|
{ |
|
|
|
#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT) |
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fboId); |
|
|
@ -2982,20 +2975,20 @@ void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, |
|
|
|
case RL_ATTACHMENT_COLOR_CHANNEL6: |
|
|
|
case RL_ATTACHMENT_COLOR_CHANNEL7: |
|
|
|
{ |
|
|
|
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_2D, texId, mi">0); |
|
|
|
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_2D, texId, n">mipLevel); |
|
|
|
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_RENDERBUFFER, texId); |
|
|
|
else if (texType >= RL_ATTACHMENT_CUBEMAP_POSITIVE_X) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_CUBE_MAP_POSITIVE_X + texType, texId, mi">0); |
|
|
|
else if (texType >= RL_ATTACHMENT_CUBEMAP_POSITIVE_X) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_CUBE_MAP_POSITIVE_X + texType, texId, n">mipLevel); |
|
|
|
|
|
|
|
} break; |
|
|
|
case RL_ATTACHMENT_DEPTH: |
|
|
|
{ |
|
|
|
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texId, mi">0); |
|
|
|
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texId, n">mipLevel); |
|
|
|
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, texId); |
|
|
|
|
|
|
|
} break; |
|
|
|
case RL_ATTACHMENT_STENCIL: |
|
|
|
{ |
|
|
|
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texId, mi">0); |
|
|
|
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texId, n">mipLevel); |
|
|
|
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, texId); |
|
|
|
|
|
|
|
} break; |
|
|
@ -3623,312 +3616,119 @@ void rlSetMatrixViewOffsetStereo(Matrix right, Matrix left) |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
// Texture maps generation (PBR) |
|
|
|
//------------------------------------------------------------------------------------------- |
|
|
|
// Generate cubemap texture from HDR texture |
|
|
|
TextureCubemap rlGenTextureCubemap(Shader shader, Texture2D panorama, int size, int format) |
|
|
|
// Load and draw a 1x1 XY quad in NDC |
|
|
|
void rlLoadDrawQuad(void) |
|
|
|
{ |
|
|
|
TextureCubemap cubemap = { 0 }; |
|
|
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) |
|
|
|
rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube |
|
|
|
|
|
|
|
// STEP 1: Setup framebuffer |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
unsigned int rbo = rlLoadTextureDepth(size, size, true); |
|
|
|
cubemap.id = rlLoadTextureCubemap(NULL, size, format); |
|
|
|
|
|
|
|
unsigned int fbo = rlLoadFramebuffer(size, size); |
|
|
|
rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER); |
|
|
|
rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X); |
|
|
|
|
|
|
|
// Check if framebuffer is complete with attachments (valid) |
|
|
|
if (rlFramebufferComplete(fbo)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", fbo); |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
|
|
|
|
// STEP 2: Draw to framebuffer |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
// NOTE: Shader is used to convert HDR equirectangular environment map to cubemap equivalent (6 faces) |
|
|
|
rlEnableShader(shader.id); |
|
|
|
|
|
|
|
// Define projection matrix and send it to shader |
|
|
|
Matrix matFboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); |
|
|
|
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_PROJECTION], matFboProjection); |
|
|
|
|
|
|
|
// Define view matrix for every side of the cubemap |
|
|
|
Matrix fboViews[6] = { |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }) |
|
|
|
}; |
|
|
|
|
|
|
|
#if !defined(GENTEXTURECUBEMAP_USE_BATCH_SYSTEM) |
|
|
|
rlActiveTextureSlot(0); |
|
|
|
rlEnableTexture(panorama.id); |
|
|
|
#endif |
|
|
|
|
|
|
|
rlViewport(0, 0, size, size); // Set viewport to current fbo dimensions |
|
|
|
|
|
|
|
for (int i = 0; i < 6; i++) |
|
|
|
{ |
|
|
|
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_VIEW], fboViews[i]); |
|
|
|
rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i); |
|
|
|
|
|
|
|
rlEnableFramebuffer(fbo); |
|
|
|
#if defined(GENTEXTURECUBEMAP_USE_BATCH_SYSTEM) |
|
|
|
rlSetTexture(panorama.id); // WARNING: It must be called after enabling current framebuffer if using internal batch system! |
|
|
|
#endif |
|
|
|
rlClearScreenBuffers(); |
|
|
|
rlGenDrawCube(); |
|
|
|
|
|
|
|
#if defined(GENTEXTURECUBEMAP_USE_BATCH_SYSTEM) |
|
|
|
// Using internal batch system instead of raw OpenGL cube creating+drawing |
|
|
|
// NOTE: DrawCubeV() is actually provided by models.c! -> rlGenTextureCubemap() should be moved to user code! |
|
|
|
DrawCubeV(Vector3Zero(), Vector3One(), WHITE); |
|
|
|
rlDrawRenderBatch(RLGL.currentBatch); |
|
|
|
#endif |
|
|
|
} |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
|
|
|
|
// STEP 3: Unload framebuffer and reset state |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
rlDisableShader(); // Unbind shader |
|
|
|
rlDisableTexture(); // Unbind texture |
|
|
|
rlDisableFramebuffer(); // Unbind framebuffer |
|
|
|
rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer) |
|
|
|
|
|
|
|
// Reset viewport dimensions to default |
|
|
|
rlViewport(0, 0, rlGetFramebufferWidth(), rlGetFramebufferHeight()); |
|
|
|
rlEnableBackfaceCulling(); |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
|
|
|
|
cubemap.width = size; |
|
|
|
cubemap.height = size; |
|
|
|
cubemap.mipmaps = 1; |
|
|
|
cubemap.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32; |
|
|
|
#endif |
|
|
|
return cubemap; |
|
|
|
} |
|
|
|
|
|
|
|
// Generate irradiance texture using cubemap data |
|
|
|
TextureCubemap rlGenTextureIrradiance(Shader shader, TextureCubemap cubemap, int size) |
|
|
|
{ |
|
|
|
TextureCubemap irradiance = { 0 }; |
|
|
|
|
|
|
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) |
|
|
|
rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube |
|
|
|
|
|
|
|
// STEP 1: Setup framebuffer |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
unsigned int rbo = rlLoadTextureDepth(size, size, true); |
|
|
|
irradiance.id = rlLoadTextureCubemap(NULL, size, PIXELFORMAT_UNCOMPRESSED_R32G32B32); |
|
|
|
|
|
|
|
unsigned int fbo = rlLoadFramebuffer(size, size); |
|
|
|
rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER); |
|
|
|
rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X); |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
|
|
|
|
// STEP 2: Draw to framebuffer |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
// NOTE: Shader is used to solve diffuse integral by convolution to create an irradiance cubemap |
|
|
|
rlEnableShader(shader.id); |
|
|
|
|
|
|
|
// Define projection matrix and send it to shader |
|
|
|
Matrix matFboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); |
|
|
|
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_PROJECTION], matFboProjection); |
|
|
|
|
|
|
|
// Define view matrix for every side of the cubemap |
|
|
|
Matrix fboViews[6] = { |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }) |
|
|
|
}; |
|
|
|
|
|
|
|
rlActiveTextureSlot(0); |
|
|
|
rlEnableTextureCubemap(cubemap.id); |
|
|
|
|
|
|
|
rlViewport(0, 0, size, size); // Set viewport to current fbo dimensions |
|
|
|
|
|
|
|
for (int i = 0; i < 6; i++) |
|
|
|
{ |
|
|
|
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_VIEW], fboViews[i]); |
|
|
|
rlFramebufferAttach(fbo, irradiance.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i); |
|
|
|
unsigned int quadVAO = 0; |
|
|
|
unsigned int quadVBO = 0; |
|
|
|
|
|
|
|
rlEnableFramebuffer(fbo); |
|
|
|
rlClearScreenBuffers(); |
|
|
|
rlGenDrawCube(); |
|
|
|
} |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
|
|
|
|
// STEP 3: Unload framebuffer and reset state |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
rlDisableShader(); // Unbind shader |
|
|
|
rlDisableTexture(); // Unbind texture |
|
|
|
rlDisableFramebuffer(); // Unbind framebuffer |
|
|
|
rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer) |
|
|
|
|
|
|
|
// Reset viewport dimensions to default |
|
|
|
rlViewport(0, 0, rlGetFramebufferWidth(), rlGetFramebufferHeight()); |
|
|
|
rlEnableBackfaceCulling(); |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
|
|
|
|
irradiance.width = size; |
|
|
|
irradiance.height = size; |
|
|
|
irradiance.mipmaps = 1; |
|
|
|
irradiance.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32; |
|
|
|
#endif |
|
|
|
return irradiance; |
|
|
|
} |
|
|
|
|
|
|
|
// Generate prefilter texture using cubemap data |
|
|
|
TextureCubemap rlGenTexturePrefilter(Shader shader, TextureCubemap cubemap, int size) |
|
|
|
{ |
|
|
|
TextureCubemap prefilter = { 0 }; |
|
|
|
|
|
|
|
#if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2) |
|
|
|
rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube |
|
|
|
|
|
|
|
// STEP 1: Setup framebuffer |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
unsigned int rbo = rlLoadTextureDepth(size, size, true); |
|
|
|
prefilter.id = rlLoadTextureCubemap(NULL, size, PIXELFORMAT_UNCOMPRESSED_R32G32B32); |
|
|
|
rlTextureParameters(prefilter.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_MIP_LINEAR); |
|
|
|
|
|
|
|
unsigned int fbo = rlLoadFramebuffer(size, size); |
|
|
|
rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER); |
|
|
|
rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X); |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
|
|
|
|
// Generate mipmaps for the prefiltered HDR texture |
|
|
|
glGenerateMipmap(GL_TEXTURE_CUBE_MAP); |
|
|
|
|
|
|
|
// STEP 2: Draw to framebuffer |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
// NOTE: Shader is used to prefilter HDR and store data into mipmap levels |
|
|
|
|
|
|
|
// Define projection matrix and send it to shader |
|
|
|
Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); |
|
|
|
rlEnableShader(shader.id); |
|
|
|
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_PROJECTION], fboProjection); |
|
|
|
|
|
|
|
// Define view matrix for every side of the cubemap |
|
|
|
Matrix fboViews[6] = { |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), |
|
|
|
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }) |
|
|
|
float vertices[] = { |
|
|
|
// Positions Texcoords |
|
|
|
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, |
|
|
|
1.0f, 1.0f, 0.0f, 1.0f, 1.0f, |
|
|
|
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
}; |
|
|
|
|
|
|
|
rlActiveTextureSlot(0); |
|
|
|
rlEnableTextureCubemap(cubemap.id); |
|
|
|
|
|
|
|
// TODO: Locations should be taken out of this function... too shader dependant... |
|
|
|
int roughnessLoc = rlGetLocationUniform(shader.id, "roughness"); |
|
|
|
|
|
|
|
rlEnableFramebuffer(fbo); |
|
|
|
|
|
|
|
#define MAX_MIPMAP_LEVELS 5 // Max number of prefilter texture mipmaps |
|
|
|
|
|
|
|
for (int mip = 0; mip < MAX_MIPMAP_LEVELS; mip++) |
|
|
|
{ |
|
|
|
// Resize framebuffer according to mip-level size. |
|
|
|
unsigned int mipWidth = size*(int)powf(0.5f, (float)mip); |
|
|
|
unsigned int mipHeight = size*(int)powf(0.5f, (float)mip); |
|
|
|
|
|
|
|
rlViewport(0, 0, mipWidth, mipHeight); |
|
|
|
|
|
|
|
glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
|
|
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mipWidth, mipHeight); |
|
|
|
|
|
|
|
float roughness = (float)mip/(float)(MAX_MIPMAP_LEVELS - 1); |
|
|
|
rlSetUniform(roughnessLoc, &roughness, SHADER_UNIFORM_FLOAT); |
|
|
|
// Gen VAO to contain VBO |
|
|
|
glGenVertexArrays(1, &quadVAO); |
|
|
|
glBindVertexArray(quadVAO); |
|
|
|
|
|
|
|
for (int i = 0; i < 6; i++) |
|
|
|
{ |
|
|
|
//rlEnableShader(shader.id); |
|
|
|
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_VIEW], fboViews[i]); |
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilter.id, mip); |
|
|
|
//rlFramebufferAttach(fbo, irradiance.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i); // TODO: Support mip levels? |
|
|
|
|
|
|
|
rlEnableFramebuffer(fbo); |
|
|
|
rlClearScreenBuffers(); |
|
|
|
rlGenDrawCube(); |
|
|
|
} |
|
|
|
} |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
// Gen and fill vertex buffer (VBO) |
|
|
|
glGenBuffers(1, &quadVBO); |
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, quadVBO); |
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW); |
|
|
|
|
|
|
|
// STEP 3: Unload framebuffer and reset state |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
rlDisableShader(); // Unbind shader |
|
|
|
rlDisableTexture(); // Unbind texture |
|
|
|
rlDisableFramebuffer(); // Unbind framebuffer |
|
|
|
rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer) |
|
|
|
// Bind vertex attributes (position, texcoords) |
|
|
|
glEnableVertexAttribArray(0); |
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)0); // Positions |
|
|
|
glEnableVertexAttribArray(1); |
|
|
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)(3*sizeof(float))); // Texcoords |
|
|
|
|
|
|
|
// Reset viewport dimensions to default |
|
|
|
rlViewport(0, 0, rlGetFramebufferWidth(), rlGetFramebufferHeight()); |
|
|
|
rlEnableBackfaceCulling(); |
|
|
|
o">//------------------------------------------------------------------------------------------ |
|
|
|
// Draw quad |
|
|
|
glBindVertexArray(quadVAO); |
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
|
|
|
glBindVertexArray(0); |
|
|
|
|
|
|
|
prefilter.width = size; |
|
|
|
prefilter.height = size; |
|
|
|
//prefilter.mipmaps = 1 + (int)floor(log(size)/log(2)); // MAX_MIPMAP_LEVELS |
|
|
|
//prefilter.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32; |
|
|
|
#endif |
|
|
|
return prefilter; |
|
|
|
// Delete buffers (VBO and VAO) |
|
|
|
glDeleteBuffers(1, &quadVBO); |
|
|
|
glDeleteVertexArrays(1, &quadVAO); |
|
|
|
} |
|
|
|
|
|
|
|
// Generate BRDF texture using cubemap data |
|
|
|
// TODO: Review implementation: https://github.com/HectorMF/BRDFGenerator |
|
|
|
Texture2D rlGenTextureBRDF(Shader shader, int size) |
|
|
|
// Load and draw a 1x1 3D cube in NDC |
|
|
|
void rlLoadDrawCube(void) |
|
|
|
{ |
|
|
|
Texture2D brdf = { 0 }; |
|
|
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) |
|
|
|
// STEP 1: Setup framebuffer |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
unsigned int rbo = rlLoadTextureDepth(size, size, true); |
|
|
|
brdf.id = rlLoadTexture(NULL, size, size, PIXELFORMAT_UNCOMPRESSED_R32G32B32, 1); |
|
|
|
|
|
|
|
unsigned int fbo = rlLoadFramebuffer(size, size); |
|
|
|
rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER); |
|
|
|
rlFramebufferAttach(fbo, brdf.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D); |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
unsigned int cubeVAO = 0; |
|
|
|
unsigned int cubeVBO = 0; |
|
|
|
|
|
|
|
// STEP 2: Draw to framebuffer |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
// NOTE: Render BRDF LUT into a quad using FBO |
|
|
|
rlEnableShader(shader.id); |
|
|
|
float vertices[] = { |
|
|
|
// Positions Normals Texcoords |
|
|
|
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, |
|
|
|
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, |
|
|
|
1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, |
|
|
|
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, |
|
|
|
-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, |
|
|
|
1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, |
|
|
|
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, |
|
|
|
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, |
|
|
|
-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, |
|
|
|
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
-1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, |
|
|
|
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, |
|
|
|
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, |
|
|
|
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, |
|
|
|
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
-1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, |
|
|
|
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, |
|
|
|
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f |
|
|
|
}; |
|
|
|
|
|
|
|
rlViewport(0, 0, size, size); |
|
|
|
// Gen VAO to contain VBO |
|
|
|
glGenVertexArrays(1, &cubeVAO); |
|
|
|
glBindVertexArray(cubeVAO); |
|
|
|
|
|
|
|
rlEnableFramebuffer(fbo); |
|
|
|
rlClearScreenBuffers(); |
|
|
|
rlGenDrawQuad(); |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
// Gen and fill vertex buffer (VBO) |
|
|
|
glGenBuffers(1, &cubeVBO); |
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); |
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); |
|
|
|
|
|
|
|
// STEP 3: Unload framebuffer and reset state |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
rlDisableShader(); // Unbind shader |
|
|
|
rlDisableTexture(); // Unbind texture |
|
|
|
rlDisableFramebuffer(); // Unbind framebuffer |
|
|
|
rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer) |
|
|
|
// Bind vertex attributes (position, normals, texcoords) |
|
|
|
glBindVertexArray(cubeVAO); |
|
|
|
glEnableVertexAttribArray(0); |
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)0); // Positions |
|
|
|
glEnableVertexAttribArray(1); |
|
|
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(3*sizeof(float))); // Normals |
|
|
|
glEnableVertexAttribArray(2); |
|
|
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(6*sizeof(float))); // Texcoords |
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0); |
|
|
|
glBindVertexArray(0); |
|
|
|
|
|
|
|
// Reset viewport dimensions to default |
|
|
|
rlViewport(0, 0, rlGetFramebufferWidth(), rlGetFramebufferHeight()); |
|
|
|
//------------------------------------------------------------------------------------------ |
|
|
|
// Draw cube |
|
|
|
glBindVertexArray(cubeVAO); |
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 36); |
|
|
|
glBindVertexArray(0); |
|
|
|
|
|
|
|
brdf.width = size; |
|
|
|
brdf.height = size; |
|
|
|
brdf.mipmaps = 1; |
|
|
|
brdf.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32; |
|
|
|
#endif |
|
|
|
return brdf; |
|
|
|
// Delete VBO and VAO |
|
|
|
glDeleteBuffers(1, &cubeVBO); |
|
|
|
glDeleteVertexArrays(1, &cubeVAO); |
|
|
|
} |
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------- |
|
|
@ -4048,121 +3848,6 @@ static void rlUnloadShaderDefault(void) |
|
|
|
|
|
|
|
RL_FREE(RLGL.State.defaultShader.locs); |
|
|
|
} |
|
|
|
|
|
|
|
// Renders a 1x1 XY quad in NDC |
|
|
|
static void rlGenDrawQuad(void) |
|
|
|
{ |
|
|
|
unsigned int quadVAO = 0; |
|
|
|
unsigned int quadVBO = 0; |
|
|
|
|
|
|
|
float vertices[] = { |
|
|
|
// Positions Texcoords |
|
|
|
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, |
|
|
|
1.0f, 1.0f, 0.0f, 1.0f, 1.0f, |
|
|
|
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
}; |
|
|
|
|
|
|
|
// Gen VAO to contain VBO |
|
|
|
glGenVertexArrays(1, &quadVAO); |
|
|
|
glBindVertexArray(quadVAO); |
|
|
|
|
|
|
|
// Gen and fill vertex buffer (VBO) |
|
|
|
glGenBuffers(1, &quadVBO); |
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, quadVBO); |
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW); |
|
|
|
|
|
|
|
// Bind vertex attributes (position, texcoords) |
|
|
|
glEnableVertexAttribArray(0); |
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)0); // Positions |
|
|
|
glEnableVertexAttribArray(1); |
|
|
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)(3*sizeof(float))); // Texcoords |
|
|
|
|
|
|
|
// Draw quad |
|
|
|
glBindVertexArray(quadVAO); |
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
|
|
|
glBindVertexArray(0); |
|
|
|
|
|
|
|
// Delete buffers (VBO and VAO) |
|
|
|
glDeleteBuffers(1, &quadVBO); |
|
|
|
glDeleteVertexArrays(1, &quadVAO); |
|
|
|
} |
|
|
|
|
|
|
|
// Renders a 1x1 3D cube in NDC |
|
|
|
static void rlGenDrawCube(void) |
|
|
|
{ |
|
|
|
unsigned int cubeVAO = 0; |
|
|
|
unsigned int cubeVBO = 0; |
|
|
|
|
|
|
|
float vertices[] = { |
|
|
|
// Positions Normals Texcoords |
|
|
|
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, |
|
|
|
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, |
|
|
|
1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, |
|
|
|
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, |
|
|
|
-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, |
|
|
|
1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, |
|
|
|
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, |
|
|
|
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, |
|
|
|
-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, |
|
|
|
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
-1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, |
|
|
|
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, |
|
|
|
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, |
|
|
|
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, |
|
|
|
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
-1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, |
|
|
|
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, |
|
|
|
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, |
|
|
|
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, |
|
|
|
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f |
|
|
|
}; |
|
|
|
|
|
|
|
// Gen VAO to contain VBO |
|
|
|
glGenVertexArrays(1, &cubeVAO); |
|
|
|
glBindVertexArray(cubeVAO); |
|
|
|
|
|
|
|
// Gen and fill vertex buffer (VBO) |
|
|
|
glGenBuffers(1, &cubeVBO); |
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); |
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); |
|
|
|
|
|
|
|
// Bind vertex attributes (position, normals, texcoords) |
|
|
|
glBindVertexArray(cubeVAO); |
|
|
|
glEnableVertexAttribArray(0); |
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)0); // Positions |
|
|
|
glEnableVertexAttribArray(1); |
|
|
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(3*sizeof(float))); // Normals |
|
|
|
glEnableVertexAttribArray(2); |
|
|
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(6*sizeof(float))); // Texcoords |
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0); |
|
|
|
glBindVertexArray(0); |
|
|
|
|
|
|
|
// Draw cube |
|
|
|
glBindVertexArray(cubeVAO); |
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 36); |
|
|
|
glBindVertexArray(0); |
|
|
|
|
|
|
|
// Delete VBO and VAO |
|
|
|
glDeleteBuffers(1, &cubeVBO); |
|
|
|
glDeleteVertexArrays(1, &cubeVAO); |
|
|
|
} |
|
|
|
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 |
|
|
|
|
|
|
|
#if defined(GRAPHICS_API_OPENGL_11) |
|
|
|