Răsfoiți Sursa

Added support for render to texture (use RenderTexture2D)

Now it's possible to render to texture, old postprocessing system will
be removed on next raylib version.
raysan5 9 ani în urmă
părinte
comite
66b096d978

+ 3 - 0
examples/resources/shaders/base.vs

@@ -3,8 +3,10 @@
 in vec3 vertexPosition;
 in vec2 vertexTexCoord;
 in vec3 vertexNormal;
+in vec4 vertexColor;
 
 out vec2 fragTexCoord;
+out vec4 fragTintColor;
 
 uniform mat4 mvpMatrix;
 
@@ -13,6 +15,7 @@ uniform mat4 mvpMatrix;
 void main()
 {
     fragTexCoord = vertexTexCoord;
+    fragTintColor = vertexColor;
     
     gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
 }

+ 2 - 1
examples/resources/shaders/bloom.fs

@@ -1,11 +1,12 @@
 #version 330
 
 in vec2 fragTexCoord;
+in vec4 fragTintColor;
 
 out vec4 fragColor;
 
 uniform sampler2D texture0;
-uniform vec4 fragTintColor;
+//uniform vec4 fragTintColor;
 
 // NOTE: Add here your custom variables
 

+ 26 - 10
examples/shaders_postprocessing.c

@@ -41,7 +41,11 @@ int main()
     Shader shader = LoadShader("resources/shaders/base.vs", 
                                "resources/shaders/bloom.fs");               // Load postpro shader
 
-    SetPostproShader(shader);               // Set fullscreen postprocessing shader
+    // NOTE: Old postprocessing system is not flexible enough despite being very easy to use
+    //SetPostproShader(shader);               // Set fullscreen postprocessing shader
+    
+    // New postprocessing system let the user create multiple RenderTexture2D and perform multiple render passes
+    RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight);
     
     // Setup orbital camera
     SetCameraMode(CAMERA_ORBITAL);          // Set an orbital camera mode
@@ -65,15 +69,26 @@ int main()
 
             ClearBackground(RAYWHITE);
 
-            Begin3dMode(camera);
+            BeginTextureMode(target);   // Enable render to texture RenderTexture2D
+
+                Begin3dMode(camera);
 
-                DrawModel(dwarf, position, 2.0f, WHITE);   // Draw 3d model with texture
+                    DrawModel(dwarf, position, 2.0f, WHITE);   // Draw 3d model with texture
 
-                DrawGrid(10, 1.0f);     // Draw a grid
+                    DrawGrid(10, 1.0f);     // Draw a grid
 
-            End3dMode();
+                End3dMode();
+          
+                DrawText("HELLO TEXTURE!!!", 120, 200, 60, RED);
+                
+            EndTextureMode();           // End drawing to texture (now we have a texture available for next passes)
+            
+            SetCustomShader(shader);
+            // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom)
+            DrawTextureRec(target.texture, (Rectangle){ 0, target.texture.height, target.texture.width, -target.texture.height }, (Vector2){ 0, 0 }, WHITE);
+            SetDefaultShader();
             
-            DrawText("(c) Dwarf 3D model by David Moreno", screenWidth - 200, screenHeight - 20, 10, BLACK);
+            DrawText("(c) Dwarf 3D model by David Moreno", screenWidth - 200, screenHeight - 20, 10, DARKGRAY);
 
             DrawFPS(10, 10);
 
@@ -83,11 +98,12 @@ int main()
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
-    UnloadShader(shader);       // Unload shader
-    UnloadTexture(texture);     // Unload texture
-    UnloadModel(dwarf);         // Unload model
+    UnloadShader(shader);           // Unload shader
+    UnloadTexture(texture);         // Unload texture
+    UnloadModel(dwarf);             // Unload model
+    UnloadRenderTexture(target);    // Unload render texture
 
-    CloseWindow();              // Close window and OpenGL context
+    CloseWindow();                  // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
 
     return 0;

+ 21 - 1
src/core.c

@@ -545,7 +545,7 @@ void BeginDrawing(void)
 
     if (IsPosproShaderEnabled()) rlEnablePostproFBO();
 
-    rlClearScreenBuffers();
+    rlClearScreenBuffers();             // Clear current framebuffers
 
     rlLoadIdentity();                   // Reset current matrix (MODELVIEW)
 
@@ -656,6 +656,26 @@ void End3dMode(void)
     rlDisableDepthTest();               // Disable DEPTH_TEST for 2D
 }
 
+// Initializes render texture for drawing
+void BeginTextureMode(RenderTexture2D target)
+{
+    rlglDraw();                         // Draw Buffers (Only OpenGL 3+ and ES2)
+
+    rlEnableRenderTexture(target.id);
+    
+    rlClearScreenBuffers();             // Clear render texture buffers
+
+    rlLoadIdentity();                   // Reset current matrix (MODELVIEW)
+}
+
+// Ends drawing to render texture
+void EndTextureMode(void)
+{
+    rlglDraw();                         // Draw Buffers (Only OpenGL 3+ and ES2)
+
+    rlDisableRenderTexture();
+}
+
 // Set target FPS for the game
 void SetTargetFPS(int fps)
 {

+ 11 - 0
src/raylib.h

@@ -324,6 +324,13 @@ typedef struct Texture2D {
     int format;             // Data format (TextureFormat)
 } Texture2D;
 
+// RenderTexture2D type, for texture rendering
+typedef struct RenderTexture2D {
+    unsigned int id;        // Render texture (fbo) id
+    Texture2D texture;      // Color buffer attachment texture
+    Texture2D depth;        // Depth buffer attachment texture
+} RenderTexture2D;
+
 // SpriteFont type, includes texture and charSet array data
 typedef struct SpriteFont {
     Texture2D texture;      // Font texture
@@ -565,6 +572,8 @@ void EndDrawing(void);                                      // End canvas drawin
 
 void Begin3dMode(Camera camera);                            // Initializes 3D mode for drawing (Camera setup)
 void End3dMode(void);                                       // Ends 3D mode and returns to default 2D orthographic mode
+void BeginTextureMode(RenderTexture2D target);              // Initializes render texture for drawing
+void EndTextureMode(void);                                  // Ends drawing to render texture
 
 Ray GetMouseRay(Vector2 mousePosition, Camera camera);      // Returns a ray trace from mouse position
 Vector2 WorldToScreen(Vector3 position, Camera camera);     // Returns the screen space position from a 3d world space position
@@ -714,8 +723,10 @@ Texture2D LoadTexture(const char *fileName);
 Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat);                     // Load a texture from raw data into GPU memory
 Texture2D LoadTextureFromRES(const char *rresName, int resId);                                     // Load an image as texture from rRES file (raylib Resource)
 Texture2D LoadTextureFromImage(Image image);                                                       // Load a texture from image data
+RenderTexture2D LoadRenderTexture(int width, int height);                                          // Load a texture to be used for rendering
 void UnloadImage(Image image);                                                                     // Unload image from CPU memory (RAM)
 void UnloadTexture(Texture2D texture);                                                             // Unload texture from GPU memory
+void UnloadRenderTexture(RenderTexture2D target);                                                  // Unload render texture from GPU memory
 Color *GetImageData(Image image);                                                                  // Get pixel data from image as a Color struct array
 Image GetTextureData(Texture2D texture);                                                           // Get pixel data from GPU texture and return an Image
 void ImageToPOT(Image *image, Color fillColor);                                                    // Convert image to POT (power-of-two)

+ 117 - 1
src/rlgl.c

@@ -785,6 +785,20 @@ void rlDisableTexture(void)
 #endif
 }
 
+void rlEnableRenderTexture(unsigned int id)
+{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+    glBindFramebuffer(GL_FRAMEBUFFER, id);
+#endif
+}
+
+void rlDisableRenderTexture(void)
+{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+#endif
+}
+
 // Enable depth test
 void rlEnableDepthTest(void)
 {
@@ -803,6 +817,16 @@ void rlDeleteTextures(unsigned int id)
     glDeleteTextures(1, &id);
 }
 
+// Unload render texture from GPU memory
+void rlDeleteRenderTextures(RenderTexture2D target)
+{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+    glDeleteFramebuffers(1, &target.id);
+    glDeleteTextures(1, &target.texture.id);
+    glDeleteTextures(1, &target.depth.id);
+#endif
+}
+
 // Enable rendering to postprocessing FBO
 void rlEnablePostproFBO()
 {
@@ -1163,7 +1187,7 @@ FBO rlglLoadFBO(int width, int height)
         glDeleteTextures(1, &fbo.colorTextureId);
         glDeleteTextures(1, &fbo.depthTextureId);
     }
-    else TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", fbo);
+    else TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", fbo.id);
     
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
 #endif
@@ -1833,6 +1857,98 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
     return id;
 }
 
+// Load a texture to be used for rendering (fbo with color and depth attachments)
+RenderTexture2D rlglLoadRenderTexture(int width, int height)
+{
+    RenderTexture2D target;
+    
+    target.id = 0;
+    
+    target.texture.id = 0;
+    target.texture.width = width;
+    target.texture.height = height;
+    target.texture.format = UNCOMPRESSED_R8G8B8;
+    target.texture.mipmaps = 1;
+    
+    target.depth.id = 0;
+    target.depth.width = width;
+    target.depth.height = height;
+    target.depth.format = 19;       //DEPTH_COMPONENT_16BIT
+    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);
+    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, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+#define USE_DEPTH_RENDERBUFFER
+#if defined(USE_DEPTH_RENDERBUFFER)
+    // Create the renderbuffer that will serve as the depth attachment for the framebuffer.
+    glGenRenderbuffers(1, &target.depth.id);
+    glBindRenderbuffer(GL_RENDERBUFFER, target.depth.id);
+    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
+    
+#elif defined(USE_DEPTH_TEXTURE)
+    // NOTE: We can also use a texture for depth buffer (GL_ARB_depth_texture/GL_OES_depth_texture extension required)
+    // A renderbuffer is simpler than a texture and could offer better performance on embedded devices
+    glGenTextures(1, &target.depth.id);
+    glBindTexture(GL_TEXTURE_2D, target.depth.id);
+    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, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 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
+
+    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+    if (status != GL_FRAMEBUFFER_COMPLETE)
+    {
+        TraceLog(WARNING, "Framebuffer object could not be created...");
+        
+        switch(status)
+        {
+            case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(WARNING, "Framebuffer is unsupported"); break;
+            case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete attachment"); break;
+#if defined(GRAPHICS_API_OPENGL_ES2)
+            case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: TraceLog(WARNING, "Framebuffer incomplete dimensions"); break;
+#endif
+            case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete missing attachment"); break;
+            default: break;
+        }
+        
+        glDeleteTextures(1, &target.texture.id);
+        glDeleteTextures(1, &target.depth.id);
+        glDeleteFramebuffers(1, &target.id);
+    }
+    else TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", target.id);
+    
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+#endif
+
+    return target; 
+}
+
+// Update already loaded texture in GPU with new data
 void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data)
 {
     glBindTexture(GL_TEXTURE_2D, id);

+ 11 - 0
src/rlgl.h

@@ -183,6 +183,13 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion;
         int format;             // Data format (TextureFormat)
     } Texture2D;
     
+    // RenderTexture2D type, for texture rendering
+    typedef struct RenderTexture2D {
+        unsigned int id;        // Render texture (fbo) id
+        Texture2D texture;      // Color buffer attachment texture
+        Texture2D depth;        // Depth buffer attachment texture
+    } RenderTexture2D;
+    
     // Material type
     typedef struct Material {
         Shader shader;
@@ -248,9 +255,12 @@ void rlColor4f(float x, float y, float z, float w); // Define one vertex (color)
 //------------------------------------------------------------------------------------
 void rlEnableTexture(unsigned int id);          // Enable texture usage
 void rlDisableTexture(void);                    // Disable texture usage
+void rlEnableRenderTexture(unsigned int id);    // Enable render texture (fbo)
+void rlDisableRenderTexture(void);              // Disable render texture (fbo), return to default framebuffer
 void rlEnableDepthTest(void);                   // Enable depth test
 void rlDisableDepthTest(void);                  // Disable depth test
 void rlDeleteTextures(unsigned int id);         // Delete OpenGL texture from GPU
+void rlDeleteRenderTextures(RenderTexture2D target);    // Delete render textures (fbo) from GPU
 void rlDeleteShader(unsigned int id);           // Delete OpenGL shader program from GPU
 void rlDeleteVertexArrays(unsigned int id);     // Unload vertex data (VAO) from GPU memory
 void rlDeleteBuffers(unsigned int id);          // Unload vertex data (VBO) from GPU memory
@@ -268,6 +278,7 @@ void rlglDraw(void);                            // Draw VAO/VBO
 void rlglInitGraphics(int offsetX, int offsetY, int width, int height);  // Initialize Graphics (OpenGL stuff)
 
 unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount);    // Load texture in GPU
+RenderTexture2D rlglLoadRenderTexture(int width, int height);   // Load a texture to be used for rendering (fbo with color and depth attachments)
 void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data);         // Update GPU texture with new data
 void rlglGenerateMipmaps(Texture2D texture);                             // Generate mipmap data for selected texture
 

+ 19 - 0
src/textures.c

@@ -389,6 +389,14 @@ Texture2D LoadTextureFromImage(Image image)
     return texture;
 }
 
+// Load a texture to be used for rendering
+RenderTexture2D LoadRenderTexture(int width, int height)
+{
+    RenderTexture2D target = rlglLoadRenderTexture(width, height);
+    
+    return target;
+}
+
 // Unload image from CPU memory (RAM)
 void UnloadImage(Image image)
 {
@@ -409,6 +417,17 @@ void UnloadTexture(Texture2D texture)
     }
 }
 
+// Unload render texture from GPU memory
+void UnloadRenderTexture(RenderTexture2D target)
+{
+    if (target.id != 0)
+    {
+        rlDeleteRenderTextures(target);
+        
+        TraceLog(INFO, "[FBO ID %i] Unloaded render texture data from VRAM (GPU)", target.id);
+    }
+}
+
 // Get pixel data from image in the form of Color struct array
 Color *GetImageData(Image image)
 {