diff --git a/src/core.c b/src/core.c index 2c5bad74..efff6206 100644 --- a/src/core.c +++ b/src/core.c @@ -153,8 +153,7 @@ static int gamepadStream = -1; // Gamepad device file descripto #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) static EGLDisplay display; // Native display device (physical screen connection) static EGLSurface surface; // Surface to draw on, framebuffers (connected to context) -static EGLContext context; // Graphic context, mode in which drawing can be done - +static EGLContext context; // Graphic context, mode in which drawing can be done static uint64_t baseTime; // Base time measure for hi-res timer static bool windowShouldClose = false; // Flag to set window for closing #endif @@ -207,6 +206,12 @@ static double targetTime = 0.0; // Desired time for one frame, if 0 static char configFlags = 0; static bool showLogo = false; +static bool customCamera = true; +//static int cameraMode = CUSTOM; // FREE, FIRST_PERSON, THIRD_PERSON + +static bool enabledPostpro = false; +static unsigned int fboShader = 0; + //---------------------------------------------------------------------------------- // Other Modules Functions Declaration (required by core) //---------------------------------------------------------------------------------- @@ -264,7 +269,7 @@ static void CommandCallback(struct android_app *app, int32_t cmd); // void InitWindow(int width, int height, const char *title) { TraceLog(INFO, "Initializing raylib (v1.2.2)"); - + // Store window title (could be useful...) windowTitle = title; @@ -303,7 +308,7 @@ void InitWindow(int width, int height, const char *title) void InitWindow(int width, int height, struct android_app *state) { TraceLog(INFO, "Initializing raylib (v1.2.2)"); - + app_dummy(); screenWidth = width; @@ -399,7 +404,7 @@ void CloseWindow(void) // Detect if KEY_ESCAPE pressed or Close icon pressed bool WindowShouldClose(void) -{ +{ #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // While window minimized, stop loop execution while (windowMinimized) glfwPollEvents(); @@ -434,7 +439,7 @@ void SetCustomCursor(const char *cursorImage) cursor = LoadTexture(cursorImage); #if defined(PLATFORM_DESKTOP) - // NOTE: emscripten not implemented + // NOTE: emscripten not implemented glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); #endif customCursor = true; @@ -473,6 +478,8 @@ void BeginDrawing(void) currentTime = GetTime(); // Number of elapsed seconds since InitTimer() was called updateTime = currentTime - previousTime; previousTime = currentTime; + + if (enabledPostpro) rlEnableFBO(); rlClearScreenBuffers(); @@ -480,14 +487,17 @@ void BeginDrawing(void) rlMultMatrixf(GetMatrixVector(downscaleView)); // If downscale required, apply it here -// rlTranslatef(0.375, 0.375, 0); // HACK to have 2D pixel-perfect drawing on OpenGL 1.1 + //rlTranslatef(0.375, 0.375, 0); // HACK to have 2D pixel-perfect drawing on OpenGL 1.1 // NOTE: Not required with OpenGL 3.3+ } // End canvas drawing and Swap Buffers (Double Buffering) void EndDrawing(void) { - rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) + rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) + + // TODO: Set postprocessing shader to be passed: SetPostproShader()? + if (enabledPostpro) rlglDrawPostpro(fboShader); // Draw postprocessing effect (shader) SwapBuffers(); // Copy back buffer to front buffer PollInputEvents(); // Poll user events @@ -515,7 +525,7 @@ void EndDrawing(void) // Initializes 3D mode for drawing (Camera setup) void Begin3dMode(Camera camera) { - rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) + rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) rlMatrixMode(RL_PROJECTION); // Switch to projection matrix @@ -533,14 +543,21 @@ void Begin3dMode(Camera camera) rlLoadIdentity(); // Reset current matrix (MODELVIEW) // Setup Camera view - Matrix matLookAt = MatrixLookAt(camera.position, camera.target, camera.up); - rlMultMatrixf(GetMatrixVector(matLookAt)); // Multiply MODELVIEW matrix by view matrix (camera) + if (customCamera) + { + Matrix matLookAt = MatrixLookAt(camera.position, camera.target, camera.up); + rlMultMatrixf(GetMatrixVector(matLookAt)); // Multiply MODELVIEW matrix by view matrix (camera) + } + else + { + // TODO: Add support for multiple automatic camera modes + } } // Ends 3D mode and returns to default 2D orthographic mode void End3dMode(void) { - rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) + rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) rlMatrixMode(RL_PROJECTION); // Switch to projection matrix rlPopMatrix(); // Restore previous matrix (PROJECTION) from matrix stack @@ -738,7 +755,7 @@ void SetMousePosition(Vector2 position) { mousePosition = position; #if defined(PLATFORM_DESKTOP) - // NOTE: emscripten not implemented + // NOTE: emscripten not implemented glfwSetCursorPos(window, position.x, position.y); #endif } @@ -900,7 +917,7 @@ Vector2 GetTouchPosition(void) //eventDrag int32_t iIndex = FindIndex( eventDrag, vec_pointers_[0] ); - + if (iIndex == -1) return false; float x = AMotionEvent_getX(eventDrag, iIndex); @@ -951,7 +968,7 @@ static void InitDisplay(int width, int height) displayWidth = screenWidth; displayHeight = screenHeight; #endif - + glfwDefaultWindowHints(); // Set default windows hints glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable @@ -961,7 +978,7 @@ static void InitDisplay(int width, int height) //glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); // Default OpenGL API to use. Alternative: GLFW_OPENGL_ES_API //glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers - // NOTE: When asking for an OpenGL context version, most drivers provide highest supported version + // NOTE: When asking for an OpenGL context version, most drivers provide highest supported version // with forward compatibility to older OpenGL versions. // For example, if using OpenGL 1.1, driver can provide a 3.3 context fordward compatible. @@ -972,7 +989,7 @@ static void InitDisplay(int width, int height) glfwWindowHint(GLFW_SAMPLES, 4); // Enables multisampling x4 (MSAA), default is 0 TraceLog(INFO, "Enabled MSAA x4"); } - + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint) glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint) glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.2 and above! @@ -1188,6 +1205,18 @@ void InitGraphics(void) #endif } +void InitPostShader(void) +{ + rlglInitPostpro(); + + enabledPostpro = true; +} + +void SetPostShader(unsigned int shader) +{ + fboShader = shader; +} + #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // GLFW3 Error Callback, runs on GLFW3 error static void ErrorCallback(int error, const char *description) @@ -1233,7 +1262,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int static void CharCallback(GLFWwindow *window, unsigned int key) { lastKeyPressed = key; - + //TraceLog(INFO, "Char Callback Key pressed: %i\n", key); } @@ -1267,14 +1296,14 @@ static void WindowIconifyCallback(GLFWwindow* window, int iconified) { // The window was iconified PauseMusicStream(); - + windowMinimized = true; } else { // The window was restored ResumeMusicStream(); - + windowMinimized = false; } } @@ -1353,7 +1382,7 @@ static int32_t InputCallback(struct android_app *app, AInputEvent *event) //size_t pointerCount = AMotionEvent_getPointerCount(event); //float AMotionEvent_getPressure(const AInputEvent *motion_event, size_t pointer_index); // 0 to 1 //float AMotionEvent_getSize(const AInputEvent *motion_event, size_t pointer_index); // Pressed area - + // Detect DOUBLE TAP event bool tapDetected = touchTap; @@ -1362,19 +1391,19 @@ static int32_t InputCallback(struct android_app *app, AInputEvent *event) case AMOTION_EVENT_ACTION_DOWN: { int64_t eventTime = AMotionEvent_getEventTime(event); - + if (eventTime - lastTapTime <= DOUBLE_TAP_TIMEOUT) { float x = AMotionEvent_getX(event, 0) - lastTapX; float y = AMotionEvent_getY(event, 0) - lastTapY; - + float densityFactor = 1.0f; - + if ((x*x + y*y) < (DOUBLE_TAP_SLOP*DOUBLE_TAP_SLOP*densityFactor)) { // Doubletap detected doubleTap = true; - + } } } break; @@ -1385,12 +1414,12 @@ static int32_t InputCallback(struct android_app *app, AInputEvent *event) lastTapTime = AMotionEvent_getEventTime(event); lastTapX = AMotionEvent_getX(event, 0); lastTapY = AMotionEvent_getY(event, 0); - + } } break; } - - + + // Detect DRAG event //int32_t action = AMotionEvent_getAction(event); @@ -1407,7 +1436,7 @@ static int32_t InputCallback(struct android_app *app, AInputEvent *event) stdVector[indexPosition] = AMotionEvent_getPointerId(event, 0); indexPosition++; TraceLog(INFO, "ACTION_DOWN"); - + //ret = GESTURE_STATE_START; } break; case AMOTION_EVENT_ACTION_POINTER_DOWN: @@ -1415,7 +1444,7 @@ static int32_t InputCallback(struct android_app *app, AInputEvent *event) stdVector[indexPosition] = AMotionEvent_getPointerId(event, index); indexPosition++; TraceLog(INFO, "ACTION_POINTER_DOWN"); - + } break; case AMOTION_EVENT_ACTION_UP: { @@ -1423,12 +1452,12 @@ static int32_t InputCallback(struct android_app *app, AInputEvent *event) indexPosition--; //ret = GESTURE_STATE_END; TraceLog(INFO, "ACTION_UP"); - + } break; case AMOTION_EVENT_ACTION_POINTER_UP: { int32_t releasedPointerId = AMotionEvent_getPointerId(event, index); - + int i = 0; for (i = 0; i < MAX_TOUCH_POINTS; i++) { @@ -1438,27 +1467,27 @@ static int32_t InputCallback(struct android_app *app, AInputEvent *event) { stdVector[k] = stdVector[k + 1]; } - + //indexPosition--; indexPosition = 0; break; } } - + if (i <= 1) { // Reset pinch or drag //if (count == 2) //ret = GESTURE_STATE_START; } TraceLog(INFO, "ACTION_POINTER_UP"); - + } break; case AMOTION_EVENT_ACTION_MOVE: { if (count == 1) { //TraceLog(INFO, "DRAG gesture detected"); - + drag = true; //ret = GESTURE_STATE_MOVE; } else break; @@ -1470,7 +1499,7 @@ static int32_t InputCallback(struct android_app *app, AInputEvent *event) } //-------------------------------------------------------------------- - + return 1; } else if (type == AINPUT_EVENT_TYPE_KEY) @@ -1672,13 +1701,13 @@ static void PollInputEvents(void) // Keyboard polling // Automatically managed by GLFW3 through callback lastKeyPressed = -1; - + // Register previous keys states for (int i = 0; i < 512; i++) previousKeyState[i] = currentKeyState[i]; - + // Register previous mouse states for (int i = 0; i < 3; i++) previousMouseState[i] = currentMouseState[i]; - + glfwPollEvents(); // Register keyboard/mouse events... and window events! #elif defined(PLATFORM_ANDROID) @@ -1702,8 +1731,8 @@ static void PollInputEvents(void) { // NOTE: Never close window, native activity is controlled by the system! //TraceLog(INFO, "Closing Window..."); - //windowShouldClose = true; - + //windowShouldClose = true; + //ANativeActivity_finish(app->activity); } } diff --git a/src/raylib.h b/src/raylib.h index ef487a30..3c849bdd 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -92,7 +92,7 @@ #define FLAG_MSAA_4X_HINT 16 #define FLAG_VSYNC_HINT 32 -// Keyboard Function Keys +// Keyboard Function Keys #define KEY_SPACE 32 #define KEY_ESCAPE 256 #define KEY_ENTER 257 @@ -268,9 +268,15 @@ typedef struct Model { unsigned int vaoId; unsigned int vboId[4]; unsigned int textureId; + unsigned int shaderId; //Matrix transform; } Model; +// Shader type +typedef struct Shader { + unsigned int id; +} Shader; + // Sound source type typedef struct Sound { unsigned int source; @@ -334,6 +340,9 @@ Color Fade(Color color, float alpha); // Color fade-in or void SetupFlags(char flags); // Enable some window configurations void ShowLogo(void); // Activates raylib logo at startup (can be done with flags) +void InitPostShader(void); +void SetPostShader(unsigned int shader); + //------------------------------------------------------------------------------------ // Input Handling Functions (Module: core) //------------------------------------------------------------------------------------ @@ -449,7 +458,7 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires -void DrawQuad(Vector3 vertices[4], Vector2 textcoords[4], Vector3 normals[4], Color colors[4]); // Draw a quad +void DrawQuad(Vector3 vertices[4], Vector2 textcoords[4], Vector3 normals[4], Color colors[4]); // Draw a quad void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color); // Draw a plane void DrawPlaneEx(Vector3 centerPos, Vector2 size, Vector3 rotation, int slicesX, int slicesZ, Color color); // Draw a plane with divisions void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) @@ -466,6 +475,7 @@ Model LoadHeightmap(Image heightmap, float maxHeight); Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based) void UnloadModel(Model model); // Unload 3d model from memory void SetModelTexture(Model *model, Texture2D texture); // Link a texture to a model +void SetModelShader(Model *model, unsigned int shader); void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) void DrawModelEx(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color tint); // Draw a model with extended parameters @@ -474,6 +484,8 @@ void DrawModelWires(Model model, Vector3 position, float scale, Color color); void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec +unsigned int LoadCustomShader(char *vsFileName, char *fsFileName); // Load a custom shader (vertex shader + fragment shader) + //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) //------------------------------------------------------------------------------------ diff --git a/src/rlgl.c b/src/rlgl.c index 7977ea84..67ef0a48 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -32,20 +32,20 @@ #include // Declares malloc() and free() for memory management, rand() #if defined(GRAPHICS_API_OPENGL_11) - #ifdef __APPLE__ // OpenGL include for OSX - #include - #else - #include // Basic OpenGL include - #endif + #ifdef __APPLE__ // OpenGL include for OSX + #include + #else + #include // Basic OpenGL include + #endif #endif #if defined(GRAPHICS_API_OPENGL_33) #define GLEW_STATIC - #ifdef __APPLE__ // OpenGL include for OSX + #ifdef __APPLE__ // OpenGL include for OSX #include - #else - #include // Extensions loading lib - //#include "glad.h" // TODO: Other extensions loading lib? --> REVIEW + #else + #include // Extensions loading lib + //#include "glad.h" // TODO: Other extensions loading lib? --> REVIEW #endif #endif @@ -164,6 +164,12 @@ static GLuint simpleVertexLoc, simpleTexcoordLoc, simpleNormalLoc, simpleColorLo static GLuint simpleProjectionMatrixLoc, simpleModelviewMatrixLoc; static GLuint simpleTextureLoc; +// Custom Shader program attibutes binding locations +static GLuint customVertexLoc, customTexcoordLoc, customNormalLoc, customColorLoc; +static GLuint customProjectionMatrixLoc, customModelviewMatrixLoc; +static GLuint customTextureLoc; +static bool customShader = false; + // Vertex Array Objects (VAO) static GLuint vaoLines, vaoTriangles, vaoQuads; @@ -182,6 +188,9 @@ static bool useTempBuffer = false; // Support for VAOs (OpenGL ES2 could not support VAO extensions) static bool vaoSupported = false; + +// Framebuffer object and texture +static GLuint fbo, fboColorTexture, fboDepthTexture, fboShader = 0; #endif #if defined(GRAPHICS_API_OPENGL_ES2) @@ -208,7 +217,6 @@ static void InitializeBuffersGPU(void); static void UpdateBuffers(void); // Custom shader files loading (external) -static GLuint LoadCustomShader(char *vertexFileName, char *fragmentFileName); static char *TextFileRead(char *fn); #endif @@ -313,21 +321,21 @@ void rlRotatef(float angleDeg, float x, float y, float z) // TODO: Support rotation in multiple axes Matrix rot = MatrixIdentity(); - // OPTION 1: It works... + // OPTION 1: It works... if (x == 1) rot = MatrixRotateX(angleDeg*DEG2RAD); else if (y == 1) rot = MatrixRotateY(angleDeg*DEG2RAD); else if (z == 1) rot = MatrixRotateZ(angleDeg*DEG2RAD); - - // OPTION 2: Requires review... - //Vector3 vec = (Vector3){ 0, 1, 0 }; + + // OPTION 2: Requires review... + //Vector3 vec = (Vector3){ 0, 1, 0 }; //VectorNormalize(&vec); //rot = MatrixFromAxisAngle(vec, angleDeg*DEG2RAD); // Working? - + // OPTION 3: TODO: Review, it doesn't work! //Vector3 vec = (Vector3){ x, y, z }; //VectorNormalize(&vec); //rot = MatrixRotate(angleDeg*vec.x, angleDeg*vec.x, angleDeg*vec.x); - + MatrixTranspose(&rot); *currentMatrix = MatrixMultiply(*currentMatrix, rot); @@ -696,6 +704,17 @@ void rlDeleteTextures(unsigned int id) glDeleteTextures(1, &id); } +// Unload shader from GPU memory +void rlDeleteShader(unsigned int id) +{ + glDeleteProgram(id); +} + +void rlEnableFBO(void) +{ + glBindFramebuffer(GL_FRAMEBUFFER, fbo); +} + // Unload vertex data (VAO) from GPU memory void rlDeleteVertexArrays(unsigned int id) { @@ -786,7 +805,7 @@ void rlglInit(void) #endif #if defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: emscripten does not support VAOs natively, it uses emulation and it reduces overall performance... + // NOTE: emscripten does not support VAOs natively, it uses emulation and it reduces overall performance... #if !defined(PLATFORM_WEB) glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES"); glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES"); @@ -851,7 +870,8 @@ void rlglInit(void) // Init default Shader (GLSL 110) -> Common for GL 3.3+ and ES2 defaultShaderProgram = LoadDefaultShader(); simpleShaderProgram = LoadSimpleShader(); - //customShaderProgram = LoadShaders("simple150.vert", "simple150.frag"); + //simpleShaderProgram = LoadCustomShader("custom.vs", "custom.fs"); // Works ok + //customShaderProgram = LoadCustomShader("simple150.vert", "simple150.frag"); // Get handles to GLSL input vars locations for defaultShaderProgram //------------------------------------------------------------------- @@ -866,7 +886,7 @@ void rlglInit(void) // Get handles to GLSL uniform vars locations (fragment-shader) defaultTextureLoc = glGetUniformLocation(defaultShaderProgram, "texture0"); //-------------------------------------------------------------------- - + // Get handles to GLSL input vars locations for simpleShaderProgram //------------------------------------------------------------------- simpleVertexLoc = glGetAttribLocation(simpleShaderProgram, "vertexPosition"); @@ -908,10 +928,53 @@ void rlglInit(void) } drawsCounter = 1; - draws[drawsCounter - 1].textureId = whiteTexture; + draws[drawsCounter - 1].textureId = whiteTexture; #endif } +// Init postpro system +void rlglInitPostpro(void) +{ + // Create the texture that will serve as the color attachment for the framebuffer + glGenTextures(1, &fboColorTexture); + glBindTexture(GL_TEXTURE_2D, fboColorTexture); + 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_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GetScreenWidth(), GetScreenHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + // Create the texture that will serve as the depth attachment for the framebuffer. + glGenTextures(1, &fboDepthTexture); + glBindTexture(GL_TEXTURE_2D, fboDepthTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GetScreenWidth(), GetScreenHeight(), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + // Create the framebuffer object + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + // Attach colort texture and depth texture to FBO + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboColorTexture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fboDepthTexture, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) TraceLog(WARNING, "Framebuffer object could not be created..."); + else TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", fbo); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + fboShader = 0; + + // TODO: Init simple quad VAO and data here? +} + // Vertex Buffer Object deinitialization (memory free) void rlglClose(void) { @@ -950,6 +1013,7 @@ void rlglClose(void) //glDeleteShader(v); //glDeleteShader(f); glDeleteProgram(defaultShaderProgram); + glDeleteProgram(simpleShaderProgram); // Free vertex arrays memory free(lines.vertices); @@ -965,6 +1029,8 @@ void rlglClose(void) // Free GPU texture glDeleteTextures(1, &whiteTexture); + + if (fbo != 0) glDeleteFramebuffers(1, &fbo); free(draws); #endif @@ -977,13 +1043,16 @@ void rlglDraw(void) if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) { - glUseProgram(defaultShaderProgram); // Use our shader + if (fbo == 0) glUseProgram(defaultShaderProgram); // Use our default shader + else glUseProgram(fboShader); // Use our postpro shader + glUseProgram(defaultShaderProgram); + glUniformMatrix4fv(defaultProjectionMatrixLoc, 1, false, GetMatrixVector(projection)); glUniformMatrix4fv(defaultModelviewMatrixLoc, 1, false, GetMatrixVector(modelview)); glUniform1i(defaultTextureLoc, 0); } - + // NOTE: We draw in this order: triangle shapes, textured quads and lines if (triangles.vCounter > 0) @@ -1116,6 +1185,67 @@ void rlglDraw(void) #endif } +void rlglDrawPostpro(unsigned int shaderId) +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // TODO: Draw screen quad with texture +/* + const float quadPositions[] = { 1.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0, -1.0, 0.0, + -1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0 }; + const float quadTexcoords[] = { 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0 }; + + glBindBuffer(GL_ARRAY_BUFFER, quadVbo); + + glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), quadPositions); + glVertexAttribPointer(ATTRIB_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), quadTexcoords); + + glEnableVertexAttribArray(ATTRIB_VERTEX); + glEnableVertexAttribArray(ATTRIB_TEXCOORD0); + + glBindTexture(GL_TEXTURE_2D, fboColorTexture); + + glDrawArrays(GL_TRIANGLES, 0, 2*3); + + // Quad render using triangle strip + glBindBuffer(GL_ARRAY_BUFFER, uiVBO[1]); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + glUseProgram(0); +*/ + rlEnableTexture(fboColorTexture); + + rlPushMatrix(); + rlBegin(RL_QUADS); + rlColor4ub(255, 255, 255, 255); + rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer + + // Bottom-left corner for texture and quad + rlTexCoord2f(0.0f, 1.0f); + rlVertex2f(0.0f, 0.0f); + + // Bottom-right corner for texture and quad + rlTexCoord2f(0.0f, 0.0f); + rlVertex2f(0.0f, GetScreenHeight()); + + // Top-right corner for texture and quad + rlTexCoord2f(1.0f, 0.0f); + rlVertex2f(GetScreenWidth(), GetScreenHeight()); + + // Top-left corner for texture and quad + rlTexCoord2f(1.0f, 1.0f); + rlVertex2f(GetScreenWidth(), 0.0f); + rlEnd(); + rlPopMatrix(); + + fboShader = shaderId; + + rlglDraw(); +} + // Draw a 3d model void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color color, bool wires) { @@ -1159,23 +1289,35 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scal #endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glUseProgram(simpleShaderProgram); // Use our simple shader + if (customShader) glUseProgram(model.shaderId); + else glUseProgram(simpleShaderProgram); // Use our simple shader VectorScale(&rotation, DEG2RAD); - + // Get transform matrix (rotation -> scale -> translation) Matrix transform = MatrixTransform(position, rotation, scale); Matrix modelviewworld = MatrixMultiply(transform, modelview); // NOTE: Drawing in OpenGL 3.3+, transform is passed to shader - glUniformMatrix4fv(simpleProjectionMatrixLoc, 1, false, GetMatrixVector(projection)); - glUniformMatrix4fv(simpleModelviewMatrixLoc, 1, false, GetMatrixVector(modelviewworld)); - glUniform1i(simpleTextureLoc, 0); + if (customShader) + { + glUniformMatrix4fv(customProjectionMatrixLoc, 1, false, GetMatrixVector(projection)); + glUniformMatrix4fv(customModelviewMatrixLoc, 1, false, GetMatrixVector(modelviewworld)); + glUniform1i(customTextureLoc, 0); + } + else + { + glUniformMatrix4fv(simpleProjectionMatrixLoc, 1, false, GetMatrixVector(projection)); + glUniformMatrix4fv(simpleModelviewMatrixLoc, 1, false, GetMatrixVector(modelviewworld)); + glUniform1i(simpleTextureLoc, 0); + } // Apply color tinting to model // NOTE: Just update one uniform on fragment shader float vColor[4] = { (float)color.r/255, (float)color.g/255, (float)color.b/255, (float)color.a/255 }; - glUniform4fv(simpleColorLoc, 1, vColor); + + if (customShader) glUniform4fv(customColorLoc, 1, vColor); + else glUniform4fv(simpleColorLoc, 1, vColor); if (vaoSupported) { @@ -1206,7 +1348,7 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scal if (vaoSupported) glBindVertexArray(0); // Unbind VAO else glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBOs - + glUseProgram(0); #endif @@ -1376,7 +1518,7 @@ Model rlglLoadModel(VertexData mesh) model.vboId[2] = 0; // Normals VBO #elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - model.textureId = 1; // Default whiteTexture + model.textureId = whiteTexture; // Default whiteTexture GLuint vaoModel = 0; // Vertex Array Objects (VAO) GLuint vertexBuffer[3]; // Vertex Buffer Objects (VBO) @@ -1412,7 +1554,7 @@ Model rlglLoadModel(VertexData mesh) model.vboId[0] = vertexBuffer[0]; // Vertex position VBO model.vboId[1] = vertexBuffer[1]; // Texcoords VBO model.vboId[2] = vertexBuffer[2]; // Normals VBO - + if (vaoSupported) { if (vaoModel > 0) @@ -1510,6 +1652,102 @@ unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int heigh return id; } +// Load a shader (vertex shader + fragment shader) from text data +unsigned int rlglLoadShader(char *vShaderStr, char *fShaderStr) +{ + unsigned int program; + GLuint vertexShader; + GLuint fragmentShader; + + vertexShader = glCreateShader(GL_VERTEX_SHADER); + fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + + const char *pvs = vShaderStr; + const char *pfs = fShaderStr; + + glShaderSource(vertexShader, 1, &pvs, NULL); + glShaderSource(fragmentShader, 1, &pfs, NULL); + + GLint success = 0; + + glCompileShader(vertexShader); + + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); + + if (success != GL_TRUE) + { + TraceLog(WARNING, "[VSHDR ID %i] Failed to compile vertex shader...", vertexShader); + + int maxLength = 0; + int length; + + glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &maxLength); + + char log[maxLength]; + + glGetShaderInfoLog(vertexShader, maxLength, &length, log); + + TraceLog(INFO, "%s", log); + } + else TraceLog(INFO, "[VSHDR ID %i] Vertex shader compiled successfully", vertexShader); + + glCompileShader(fragmentShader); + + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); + + if (success != GL_TRUE) + { + TraceLog(WARNING, "[FSHDR ID %i] Failed to compile fragment shader...", fragmentShader); + + int maxLength = 0; + int length; + + glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &maxLength); + + char log[maxLength]; + + glGetShaderInfoLog(fragmentShader, maxLength, &length, log); + + TraceLog(INFO, "%s", log); + } + else TraceLog(INFO, "[FSHDR ID %i] Fragment shader compiled successfully", fragmentShader); + + program = glCreateProgram(); + + glAttachShader(program, vertexShader); + glAttachShader(program, fragmentShader); + + glLinkProgram(program); + + glGetProgramiv(program, GL_LINK_STATUS, &success); + + if (success == GL_FALSE) + { + TraceLog(WARNING, "[SHDR ID %i] Failed to link shader program...", program); + + int maxLength = 0; + int length; + + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); + + char log[maxLength]; + + glGetProgramInfoLog(program, maxLength, &length, log); + + TraceLog(INFO, "%s", log); + + glDeleteProgram(program); + + program = 0; + } + else TraceLog(INFO, "[SHDR ID %i] Shader program loaded successfully", program); + + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + + return program; +} + // Read screen pixel data (color buffer) unsigned char *rlglReadScreenPixels(int width, int height) { @@ -1534,6 +1772,66 @@ unsigned char *rlglReadScreenPixels(int width, int height) return imgData; // NOTE: image data should be freed } +unsigned int LoadCustomShader(char *vsFileName, char *fsFileName) +{ + // Shaders loading from external text file + char *vShaderStr = TextFileRead(vsFileName); + char *fShaderStr = TextFileRead(fsFileName); + + unsigned int shaderId = rlglLoadShader(vShaderStr, fShaderStr); + + if (shaderId != 0) TraceLog(INFO, "[SHDR ID %i] Custom shader loaded successfully", shaderId); + else TraceLog(WARNING, "[SHDR ID %i] Custom shader could not be loaded", shaderId); + + return shaderId; + + // Shader strings must be freed + free(vShaderStr); + free(fShaderStr); + + return shaderId; +} + +// Link shader to model +void SetModelShader(Model *model, unsigned int shader) +{ + // Get handles to GLSL input vars locations for simpleShaderProgram + customVertexLoc = glGetAttribLocation(shader, "vertexPosition"); + customTexcoordLoc = glGetAttribLocation(shader, "vertexTexCoord"); + customNormalLoc = glGetAttribLocation(shader, "vertexNormal"); + + // Get handles to GLSL uniform vars locations (vertex-shader) + customModelviewMatrixLoc = glGetUniformLocation(shader, "modelviewMatrix"); + customProjectionMatrixLoc = glGetUniformLocation(shader, "projectionMatrix"); + + // Get handles to GLSL uniform vars locations (fragment-shader) + customTextureLoc = glGetUniformLocation(shader, "texture0"); + customColorLoc = glGetUniformLocation(shader, "fragColor"); + + if (vaoSupported) glBindVertexArray(model->vaoId); + + // Enable vertex attributes: position + glBindBuffer(GL_ARRAY_BUFFER, model->vboId[0]); + glEnableVertexAttribArray(customVertexLoc); + glVertexAttribPointer(customVertexLoc, 3, GL_FLOAT, 0, 0, 0); + + // Enable vertex attributes: texcoords + glBindBuffer(GL_ARRAY_BUFFER, model->vboId[1]); + glEnableVertexAttribArray(customTexcoordLoc); + glVertexAttribPointer(customTexcoordLoc, 2, GL_FLOAT, 0, 0, 0); + + // Enable vertex attributes: normals + glBindBuffer(GL_ARRAY_BUFFER, model->vboId[2]); + glEnableVertexAttribArray(customNormalLoc); + glVertexAttribPointer(customNormalLoc, 3, GL_FLOAT, 0, 0, 0); + + if (vaoSupported) glBindVertexArray(0); // Unbind VAO + + model->shaderId = shader; + + customShader = true; +} + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) void PrintProjectionMatrix() @@ -1559,10 +1857,12 @@ void PrintModelviewMatrix() static GLuint LoadDefaultShader(void) { // NOTE: Shaders are written using GLSL 110 (desktop), that is equivalent to GLSL 100 on ES2 + // NOTE: Detected an error on ATI cards if defined #version 110 while OpenGL 3.3+ + // Just defined #version 330 despite shader is #version 110 // Vertex shader directly defined, no external file required #if defined(GRAPHICS_API_OPENGL_33) - char vShaderStr[] = " #version 110 \n" // NOTE: Equivalent to version 100 on ES2 + char vShaderStr[] = " #version 330 \n" // NOTE: Actually, #version 110 (quivalent to #version 100 on ES2) #elif defined(GRAPHICS_API_OPENGL_ES2) char vShaderStr[] = " #version 100 \n" // NOTE: Must be defined this way! 110 doesn't work! #endif @@ -1582,7 +1882,7 @@ static GLuint LoadDefaultShader(void) // Fragment shader directly defined, no external file required #if defined(GRAPHICS_API_OPENGL_33) - char fShaderStr[] = " #version 110 \n" // NOTE: Equivalent to version 100 on ES2 + char fShaderStr[] = " #version 330 \n" // NOTE: Actually, #version 110 (quivalent to #version 100 on ES2) #elif defined(GRAPHICS_API_OPENGL_ES2) char fShaderStr[] = " #version 100 \n" // NOTE: Must be defined this way! 110 doesn't work! "precision mediump float; \n" // WebGL, required for emscripten @@ -1595,63 +1895,12 @@ static GLuint LoadDefaultShader(void) " gl_FragColor = texture2D(texture0, fragTexCoord) * fragColor; \n" "} \n"; - GLuint program; - GLuint vertexShader; - GLuint fragmentShader; + unsigned int shaderId = rlglLoadShader(vShaderStr, fShaderStr); - vertexShader = glCreateShader(GL_VERTEX_SHADER); - fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + if (shaderId != 0) TraceLog(INFO, "[SHDR ID %i] Default shader loaded successfully", shaderId); + else TraceLog(WARNING, "[SHDR ID %i] Default shader could not be loaded", shaderId); - const char *pvs = vShaderStr; - const char *pfs = fShaderStr; - - glShaderSource(vertexShader, 1, &pvs, NULL); - glShaderSource(fragmentShader, 1, &pfs, NULL); - - GLint success = 0; - - glCompileShader(vertexShader); - - glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); - - if (success != GL_TRUE) TraceLog(WARNING, "[VSHDR ID %i] Failed to compile default vertex shader...", vertexShader); - else TraceLog(INFO, "[VSHDR ID %i] Default vertex shader compiled successfully", vertexShader); - - glCompileShader(fragmentShader); - - glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); - - if (success != GL_TRUE) TraceLog(WARNING, "[FSHDR ID %i] Failed to compile default fragment shader...", fragmentShader); - else TraceLog(INFO, "[FSHDR ID %i] Default fragment shader compiled successfully", fragmentShader); - - program = glCreateProgram(); - - glAttachShader(program, vertexShader); - glAttachShader(program, fragmentShader); - - glLinkProgram(program); - - glGetProgramiv(program, GL_LINK_STATUS, &success); - - if (success == GL_FALSE) - { - int maxLength; - int length; - - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); - - char log[maxLength]; - - glGetProgramInfoLog(program, maxLength, &length, log); - - TraceLog(INFO, "Shader program fail log: %s", log); - } - else TraceLog(INFO, "[SHDR ID %i] Default shader program loaded successfully", program); - - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - - return program; + return shaderId; } // Load Simple Shader (Vertex and Fragment) @@ -1659,10 +1908,12 @@ static GLuint LoadDefaultShader(void) static GLuint LoadSimpleShader(void) { // NOTE: Shaders are written using GLSL 110 (desktop), that is equivalent to GLSL 100 on ES2 + // NOTE: Detected an error on ATI cards if defined #version 110 while OpenGL 3.3+ + // Just defined #version 330 despite shader is #version 110 // Vertex shader directly defined, no external file required #if defined(GRAPHICS_API_OPENGL_33) - char vShaderStr[] = " #version 110 \n" // NOTE: Equivalent to version 100 on ES2 + char vShaderStr[] = " #version 330 \n" // NOTE: Actually, #version 110 (quivalent to #version 100 on ES2) #elif defined(GRAPHICS_API_OPENGL_ES2) char vShaderStr[] = " #version 100 \n" // NOTE: Must be defined this way! 110 doesn't work! #endif @@ -1680,7 +1931,7 @@ static GLuint LoadSimpleShader(void) // Fragment shader directly defined, no external file required #if defined(GRAPHICS_API_OPENGL_33) - char fShaderStr[] = " #version 110 \n" // NOTE: Equivalent to version 100 on ES2 + char fShaderStr[] = " #version 330 \n" // NOTE: Actually, #version 110 (quivalent to #version 100 on ES2) #elif defined(GRAPHICS_API_OPENGL_ES2) char fShaderStr[] = " #version 100 \n" // NOTE: Must be defined this way! 110 doesn't work! "precision mediump float; \n" // precision required for OpenGL ES2 (WebGL) @@ -1693,117 +1944,22 @@ static GLuint LoadSimpleShader(void) " gl_FragColor = texture2D(texture0, fragTexCoord) * fragColor; \n" "} \n"; - GLuint program; - GLuint vertexShader; - GLuint fragmentShader; + unsigned int shaderId = rlglLoadShader(vShaderStr, fShaderStr); - vertexShader = glCreateShader(GL_VERTEX_SHADER); - fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + if (shaderId != 0) TraceLog(INFO, "[SHDR ID %i] Simple shader loaded successfully", shaderId); + else TraceLog(WARNING, "[SHDR ID %i] Simple shader could not be loaded", shaderId); - const char *pvs = vShaderStr; - const char *pfs = fShaderStr; - - glShaderSource(vertexShader, 1, &pvs, NULL); - glShaderSource(fragmentShader, 1, &pfs, NULL); - - GLint success = 0; - - glCompileShader(vertexShader); - - glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); - - if (success != GL_TRUE) TraceLog(WARNING, "[VSHDR ID %i] Failed to compile simple vertex shader...", vertexShader); - else TraceLog(INFO, "[VSHDR ID %i] Simple vertex shader compiled successfully", vertexShader); - - glCompileShader(fragmentShader); - - glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); - - if (success != GL_TRUE) TraceLog(WARNING, "[FSHDR ID %i] Failed to compile simple fragment shader...", fragmentShader); - else TraceLog(INFO, "[FSHDR ID %i] Simple fragment shader compiled successfully", fragmentShader); - - program = glCreateProgram(); - - glAttachShader(program, vertexShader); - glAttachShader(program, fragmentShader); - - glLinkProgram(program); - - glGetProgramiv(program, GL_LINK_STATUS, &success); - - if (success == GL_FALSE) - { - int maxLength; - int length; - - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); - - char log[maxLength]; - - glGetProgramInfoLog(program, maxLength, &length, log); - - TraceLog(INFO, "Shader program fail log: %s", log); - } - else TraceLog(INFO, "[SHDR ID %i] Simple shader program loaded successfully", program); - - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - - return program; + return shaderId; } -// Load shaders from text files -static GLuint LoadCustomShader(char *vertexFileName, char *fragmentFileName) -{ - // Shaders loading from external text file - char *vShaderStr = TextFileRead(vertexFileName); - char *fShaderStr = TextFileRead(fragmentFileName); - - GLuint program; - GLuint vertexShader; - GLuint fragmentShader; - - vertexShader = glCreateShader(GL_VERTEX_SHADER); - fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - - const char *pvs = vShaderStr; - const char *pfs = fShaderStr; - - glShaderSource(vertexShader, 1, &pvs, NULL); - glShaderSource(fragmentShader, 1, &pfs, NULL); - - glCompileShader(vertexShader); - glCompileShader(fragmentShader); - - TraceLog(INFO, "[VSHDR ID %i] Vertex shader compiled successfully", vertexShader); - TraceLog(INFO, "[FSHDR ID %i] Fragment shader compiled successfully", fragmentShader); - - program = glCreateProgram(); - - glAttachShader(program, vertexShader); - glAttachShader(program, fragmentShader); - - glLinkProgram(program); - - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - - free(vShaderStr); - free(fShaderStr); - - TraceLog(INFO, "[SHDR ID %i] Shader program loaded successfully", program); - - return program; -} - -// Read shader text file +// Read text file // NOTE: text chars array should be freed manually static char *TextFileRead(char *fileName) { FILE *textFile; char *text = NULL; - int count=0; + int count = 0; if (fileName != NULL) { @@ -1817,7 +1973,7 @@ static char *TextFileRead(char *fileName) if (count > 0) { - text = (char *)malloc(sizeof(char) * (count+1)); + text = (char *)malloc(sizeof(char) * (count + 1)); count = fread(text, sizeof(char), count, textFile); text[count] = '\0'; } @@ -1826,7 +1982,7 @@ static char *TextFileRead(char *fileName) } else TraceLog(WARNING, "[%s] Text file could not be opened", fileName); } - + return text; } @@ -1925,7 +2081,7 @@ static void InitializeBuffersGPU(void) glGenVertexArrays(1, &vaoTriangles); glBindVertexArray(vaoTriangles); } - + // Create buffers for our vertex data glGenBuffers(2, trianglesBuffer); @@ -1950,7 +2106,7 @@ static void InitializeBuffersGPU(void) glGenVertexArrays(1, &vaoQuads); glBindVertexArray(vaoQuads); } - + // Create buffers for our vertex data glGenBuffers(4, quadsBuffer); @@ -1994,7 +2150,7 @@ static void UpdateBuffers(void) { // Activate Lines VAO if (vaoSupported) glBindVertexArray(vaoLines); - + // Lines - vertex positions buffer glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]); //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*2*MAX_LINES_BATCH, lines.vertices, GL_DYNAMIC_DRAW); @@ -2011,7 +2167,7 @@ static void UpdateBuffers(void) { // Activate Triangles VAO if (vaoSupported) glBindVertexArray(vaoTriangles); - + // Triangles - vertex positions buffer glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]); //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*3*MAX_TRIANGLES_BATCH, triangles.vertices, GL_DYNAMIC_DRAW); diff --git a/src/rlgl.h b/src/rlgl.h index b42b388b..94cf6072 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -145,22 +145,27 @@ 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 rlDeleteTextures(unsigned int id); // Delete OpenGL texture 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 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); //------------------------------------------------------------------------------------ // Functions Declaration - rlgl functionality //------------------------------------------------------------------------------------ void rlglInit(void); // Initialize rlgl (shaders, VAO, VBO...) +void rlglInitPostpro(void); // Initialize postprocessing system void rlglClose(void); // De-init rlgl void rlglDraw(void); // Draw VAO/VBO +void rlglDrawPostpro(unsigned int shaderId); // Draw with postpro shader void rlglInitGraphics(int offsetX, int offsetY, int width, int height); // Initialize Graphics (OpenGL stuff) unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool genMipmaps); // Load in GPU OpenGL texture unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int format); +unsigned int rlglLoadShader(char *vShaderStr, char *fShaderStr); // Load a shader from text data Model rlglLoadModel(VertexData mesh); // Upload vertex data into GPU and provided VAO/VBO ids void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color color, bool wires);