浏览代码

Multiple code changes:

- Renamed function rlEnableFBO() -> rlEnablePostproFBO()
- Defined struct FBO
- Moved FBO creation to function: rlglLoadFBO()
- Reviewed rlglReadTexturePixels(), trying to support OpenGL ES -IN
PROGRESS-
raysan5 10 年之前
父节点
当前提交
11a8dacb0f
共有 2 个文件被更改,包括 144 次插入52 次删除
  1. 143 51
      src/rlgl.c
  2. 1 1
      src/rlgl.h

+ 143 - 51
src/rlgl.c

@@ -182,6 +182,13 @@ typedef struct {
     unsigned char a;
 } pixel;
 
+// Framebuffer Object type
+typedef struct {
+    GLuint id;
+    GLuint colorTextureId;
+    GLuint depthTextureId;
+} FBO;
+
 #if defined(RLGL_STANDALONE)
 typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
 #endif
@@ -238,7 +245,7 @@ static bool texCompPVRTSupported = false;    // PVR texture compression support
 static bool texCompASTCSupported = false;    // ASTC texture compression support
 
 // Framebuffer object and texture
-static GLuint fbo, fboColorTexture, fboDepthTexture;
+static FBO postproFbo;
 static Model postproQuad;
 
 // Shaders related variables
@@ -278,6 +285,9 @@ static void UpdateBuffers(void);
 static char *TextFileRead(char *fn);
 
 static void LoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compressedFormat);
+
+FBO rlglLoadFBO(int width, int height);
+void rlglUnloadFBO(FBO fbo);
 #endif
 
 #if defined(GRAPHICS_API_OPENGL_11)
@@ -776,10 +786,10 @@ void rlDeleteTextures(unsigned int id)
 }
 
 // Enable rendering to postprocessing FBO
-void rlEnableFBO(void)
+void rlEnablePostproFBO()
 {
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+    glBindFramebuffer(GL_FRAMEBUFFER, postproFbo.id);
 #endif
 }
 
@@ -910,8 +920,8 @@ void rlglInit(void)
     
 #elif defined(GLAD_EXTENSIONS_LOADER)
     // NOTE: glad is generated and contains only required OpenGL version and core extensions
-    if (!gladLoadGL()) TraceLog(ERROR, "Failed to initialize glad\n");
-    //if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) TraceLog(ERROR, "Failed to initialize glad\n");
+    //if (!gladLoadGL()) TraceLog(ERROR, "Failed to initialize glad\n");
+    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) TraceLog(ERROR, "Failed to initialize glad\n"); // No GLFW3 in this module...
 
     if (GLAD_GL_VERSION_3_3)
     {
@@ -1080,44 +1090,78 @@ void rlglInit(void)
 
 // Init postpro system
 // NOTE: Uses global variables screenWidth and screenHeight
+// Modifies global variables: postproFbo, postproQuad
 void rlglInitPostpro(void)
 {
+    postproFbo = rlglLoadFBO(screenWidth, screenHeight);
+
+    if (postproFbo.id > 0)
+    {
+        // Create a simple quad model to render fbo texture
+        VertexData quadData;
+        
+        quadData.vertexCount = 6;
+        
+        float w = screenWidth;
+        float h = screenHeight;
+        
+        float quadPositions[6*3] = { w, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, h, 0.0, 0, h, 0.0, w, h, 0.0, w, 0.0, 0.0 }; 
+        float quadTexcoords[6*2] = { 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0 };
+        float quadNormals[6*3] = { 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0 };
+        unsigned char quadColors[6*4] = { 255 };
+        
+        quadData.vertices = quadPositions;
+        quadData.texcoords = quadTexcoords;
+        quadData.normals = quadNormals;
+        quadData.colors = quadColors;
+        
+        postproQuad = rlglLoadModel(quadData);
+        
+        // NOTE: postproFbo.colorTextureId must be assigned to postproQuad model shader
+    }
+}
+
+// Load a framebuffer object
+FBO rlglLoadFBO(int width, int height)
+{
+    FBO fbo;   
+    fbo.id = 0;
+
 #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, &fboColorTexture);
-    glBindTexture(GL_TEXTURE_2D, fboColorTexture);
+    glGenTextures(1, &fbo.colorTextureId);
+    glBindTexture(GL_TEXTURE_2D, fbo.colorTextureId);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, screenWidth, screenHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
     glBindTexture(GL_TEXTURE_2D, 0);
 
     // Create the renderbuffer that will serve as the depth attachment for the framebuffer.
-    glGenRenderbuffers(1, &fboDepthTexture);
-    glBindRenderbuffer(GL_RENDERBUFFER, fboDepthTexture);
-    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screenWidth, screenHeight);
+    glGenRenderbuffers(1, &fbo.depthTextureId);
+    glBindRenderbuffer(GL_RENDERBUFFER, fbo.depthTextureId);
+    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
     
     // NOTE: We can also use a texture for depth buffer (GL_ARB_depth_texture/GL_OES_depth_texture extensions)
     // A renderbuffer is simpler than a texture and could offer better performance on embedded devices
 /*
-    glGenTextures(1, &fboDepthTexture);
-    glBindTexture(GL_TEXTURE_2D, fboDepthTexture);
+    glGenTextures(1, &fbo.depthTextureId);
+    glBindTexture(GL_TEXTURE_2D, fbo.depthTextureId);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GetScreenWidth(), GetScreenHeight(), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
     glBindTexture(GL_TEXTURE_2D, 0);
 */
-
     // Create the framebuffer object
-    glGenFramebuffers(1, &fbo);
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+    glGenFramebuffers(1, &fbo.id);
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo.id);
 
     // Attach color texture and depth renderbuffer to FBO
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboColorTexture, 0);
-    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fboDepthTexture);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo.colorTextureId, 0);
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo.depthTextureId);
 
     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 
@@ -1135,36 +1179,26 @@ void rlglInitPostpro(void)
             case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete missing attachment"); break;
             default: break;
         }
-    }
-    else
-    {
-        TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", fbo);
-
-        glBindFramebuffer(GL_FRAMEBUFFER, 0);
-
-        // Create a simple quad model to render fbo texture
-        VertexData quadData;
-        
-        quadData.vertexCount = 6;
-        
-        float w = screenWidth;
-        float h = screenHeight;
         
-        float quadPositions[6*3] = { w, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, h, 0.0, 0, h, 0.0, w, h, 0.0, w, 0.0, 0.0 }; 
-        float quadTexcoords[6*2] = { 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0 };
-        float quadNormals[6*3] = { 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0 };
-        unsigned char quadColors[6*4] = { 255 };
-        
-        quadData.vertices = quadPositions;
-        quadData.texcoords = quadTexcoords;
-        quadData.normals = quadNormals;
-        quadData.colors = quadColors;
-        
-        postproQuad = rlglLoadModel(quadData);
-        
-        // NOTE: fboColorTexture id must be assigned to postproQuad model shader
+        glDeleteTextures(1, &fbo.colorTextureId);
+        glDeleteTextures(1, &fbo.depthTextureId);
     }
+    else TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", fbo);
+    
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
 #endif
+
+    return fbo;
+}
+
+// Unload framebuffer object
+void rlglUnloadFBO(FBO fbo)
+{
+    glDeleteFramebuffers(1, &fbo.id);
+    glDeleteTextures(1, &fbo.colorTextureId);
+    glDeleteTextures(1, &fbo.depthTextureId);
+    
+    TraceLog(INFO, "[FBO ID %i] Unloaded framebuffer object successfully", fbo.id);
 }
 
 // Vertex Buffer Object deinitialization (memory free)
@@ -1223,9 +1257,9 @@ void rlglClose(void)
     glDeleteTextures(1, &whiteTexture);
     TraceLog(INFO, "[TEX ID %i] Unloaded texture data (base white texture) from VRAM", whiteTexture);
 
-    if (fbo != 0)
+    if (postproFbo.id != 0)
     {
-        glDeleteFramebuffers(1, &fbo);
+        rlglUnloadFBO(postproFbo);
         
         // Unload postpro quad model data
 #if defined(GRAPHICS_API_OPENGL_11)
@@ -1240,7 +1274,7 @@ void rlglClose(void)
 
         rlDeleteVertexArrays(postproQuad.mesh.vaoId);
         
-        TraceLog(INFO, "[FBO %i] Unloaded postprocessing data", fbo);
+        TraceLog(INFO, "Unloaded postprocessing data");
     }
 
     free(draws);
@@ -2010,7 +2044,7 @@ unsigned char *rlglReadScreenPixels(int width, int height)
 }
 
 // Read texture pixel data
-// NOTE: Retrieving pixel data from GPU not supported on OpenGL ES 2.0
+// NOTE: Retrieving pixel data from GPU (glGetTexImage()) not supported on OpenGL ES 2.0
 void *rlglReadTexturePixels(unsigned int textureId, unsigned int format)
 {
     void *pixels = NULL;
@@ -2028,11 +2062,31 @@ void *rlglReadTexturePixels(unsigned int textureId, unsigned int format)
     int glFormat = 0, glType = 0;
 
     unsigned int size = width*height;
+    
+    // NOTE: GL_LUMINANCE and GL_LUMINANCE_ALPHA are removed since OpenGL 3.1
+    // Must be replaced by GL_RED and GL_RG on Core OpenGL 3.3 and data must be swizzled
 
     switch (format)
     {
+#if defined(GRAPHICS_API_OPENGL_11)
         case UNCOMPRESSED_GRAYSCALE: pixels = (unsigned char *)malloc(size); glFormat = GL_LUMINANCE; glType = GL_UNSIGNED_BYTE; break;            // 8 bit per pixel (no alpha)
         case UNCOMPRESSED_GRAY_ALPHA: pixels = (unsigned char *)malloc(size*2); glFormat = GL_LUMINANCE_ALPHA; glType = GL_UNSIGNED_BYTE; break;   // 16 bpp (2 channels)
+#elif defined(GRAPHICS_API_OPENGL_33) 
+        case UNCOMPRESSED_GRAYSCALE:    // 8 bit per pixel (no alpha)
+        {
+            pixels = (unsigned char *)malloc(size); glFormat = GL_RED; glType = GL_UNSIGNED_BYTE;
+            
+            GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
+            glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
+        } break;       
+        case UNCOMPRESSED_GRAY_ALPHA:   // 16 bpp (2 channels)
+        {
+            pixels = (unsigned char *)malloc(size*2); glFormat = GL_RG; glType = GL_UNSIGNED_BYTE;
+            
+            GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
+            glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
+        } break;
+#endif
         case UNCOMPRESSED_R5G6B5: pixels = (unsigned short *)malloc(size); glFormat = GL_RGB; glType = GL_UNSIGNED_SHORT_5_6_5; break;             // 16 bpp
         case UNCOMPRESSED_R8G8B8: pixels = (unsigned char *)malloc(size*3); glFormat = GL_RGB; glType = GL_UNSIGNED_BYTE; break;                   // 24 bpp
         case UNCOMPRESSED_R5G5B5A1: pixels = (unsigned short *)malloc(size); glFormat = GL_RGBA; glType = GL_UNSIGNED_SHORT_5_5_5_1; break;        // 16 bpp (1 bit alpha)
@@ -2052,6 +2106,44 @@ void *rlglReadTexturePixels(unsigned int textureId, unsigned int format)
     glBindTexture(GL_TEXTURE_2D, 0);
 #endif
 
+#if defined(GRAPHICS_API_OPENGL_ES2)
+    // TODO: Look for some way to retrieve texture width and height from id
+    int width = 1024;
+    int height = 1024;
+
+    FBO fbo = rlglLoadFBO(width, height);
+    
+    // NOTE: Altenatively we can bind texture to color fbo and glReadPixels()
+    
+    // Render texture to fbo
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo.id);
+    glClearColor(0.0, 0.0, 0.0, 0.0);
+    glClearDepthf(1.0f);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    glViewport(0, 0, width, height);
+    //glMatrixMode(GL_PROJECTION);
+    //glLoadIdentity();
+    rlOrtho(0.0, width, height, 0.0, 0.0, 1.0); 
+    //glMatrixMode(GL_MODELVIEW);
+    //glLoadIdentity();
+    //glDisable(GL_TEXTURE_2D);
+    //glDisable(GL_BLEND);
+    glEnable(GL_DEPTH_TEST);
+    
+    //Model quad = GenModelQuad(width, height);
+    //DrawModel(quad, (Vector3){ 0, 0, 0 }, 1.0f, WHITE);
+    
+    pixels = (unsigned char *)malloc(width*height*4*sizeof(unsigned char));
+    
+    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+
+    // Bind framebuffer 0, which means render to back buffer
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    
+    // Clean up temporal fbo
+    rlglUnloadFBO(fbo);
+#endif
+
     return pixels;
 }
 
@@ -2282,7 +2374,7 @@ void SetPostproShader(Shader shader)
     SetModelShader(&postproQuad, shader);
     
     Texture2D texture;
-    texture.id = fboColorTexture;
+    texture.id = postproFbo.colorTextureId;
     texture.width = screenWidth;
     texture.height = screenHeight;
 

+ 1 - 1
src/rlgl.h

@@ -232,7 +232,7 @@ void rlDeleteBuffers(unsigned int id);          // Unload vertex data (VBO) from
 void rlClearColor(byte r, byte g, byte b, byte a);  // Clear color buffer with color
 void rlClearScreenBuffers(void);                // Clear used screen buffers (color and depth)
 int rlGetVersion(void);                         // Returns current OpenGL version
-void rlEnableFBO(void);                         // Enable rendering to postprocessing FBO
+void rlEnablePostproFBO(void);                  // Enable rendering to postprocessing FBO
 
 //------------------------------------------------------------------------------------
 // Functions Declaration - rlgl functionality