/* KallistiGL for KallistiOS ##version## libgl/gl-framebuffer.c Copyright (C) 2014 Josh Pearson This file implements Open GL Frame Buffer Object (FBO) functionality, with what the DC's PVR can directly implement. Basically, Render-To-Texture using GL_RGB565 is the only native feature of the PVR, so if you are looking for a depth-buffer, bad news. This implementation uses a dynamic linked list to implement the data structures needed. */ #include "gl.h" #include "glext.h" #include "gl-api.h" #include //========================================================================================// //== Internal KOS Open GL API FBO Structures / Global Variables ==// static GL_FRAMEBUFFER_OBJECT *FRAMEBUF_OBJ = NULL; static GLsizei FRAMEBUF_OBJECT = 0; //========================================================================================// //== Internal KOS Open GL API FBO Functionality ==// void _glKosInitFrameBuffers() { FRAMEBUF_OBJ = malloc(sizeof(GL_FRAMEBUFFER_OBJECT)); FRAMEBUF_OBJ->index = 0; FRAMEBUF_OBJ->texID = 0; FRAMEBUF_OBJ->data = NULL; FRAMEBUF_OBJ->link = NULL; } static void _glKosInsertFramebufferObj(GL_FRAMEBUFFER_OBJECT *obj) { GL_FRAMEBUFFER_OBJECT *ptr = FRAMEBUF_OBJ; while(ptr->link != NULL) ptr = (GL_FRAMEBUFFER_OBJECT *)ptr->link; ptr->link = obj; } static GLsizei _glKosGetLastFrameBufferIndex() { GL_FRAMEBUFFER_OBJECT *ptr = FRAMEBUF_OBJ; while(ptr->link != NULL) ptr = (GL_FRAMEBUFFER_OBJECT *)ptr->link; return ptr->index; } static GL_FRAMEBUFFER_OBJECT *_glKosGetFrameBufferObj(GLuint index) { GL_FRAMEBUFFER_OBJECT *ptr = FRAMEBUF_OBJ; while(ptr->index != index && ptr->link != NULL) ptr = (GL_FRAMEBUFFER_OBJECT *)ptr->link; return ptr; } GLsizei _glKosGetFBO() { return FRAMEBUF_OBJECT; } GLuint _glKosGetFBOWidth(GLsizei fbi) { GL_FRAMEBUFFER_OBJECT *fbo = _glKosGetFrameBufferObj(fbi); return _glKosTextureWidth(fbo->texID); } GLuint _glKosGetFBOHeight(GLsizei fbi) { GL_FRAMEBUFFER_OBJECT *fbo = _glKosGetFrameBufferObj(fbi); return _glKosTextureHeight(fbo->texID); } GLvoid *_glKosGetFBOData(GLsizei fbi) { GL_FRAMEBUFFER_OBJECT *fbo = _glKosGetFrameBufferObj(fbi); return fbo->data; } //========================================================================================// //== Public KOS Open GL API FBO Functionality ==// GLAPI void APIENTRY glGenFramebuffers(GLsizei n, GLuint *framebuffers) { GLsizei index = _glKosGetLastFrameBufferIndex(); while(n--) { GL_FRAMEBUFFER_OBJECT *obj = malloc(sizeof(GL_FRAMEBUFFER_OBJECT)); obj->index = ++index; obj->texID = 0; obj->data = NULL; obj->link = NULL; _glKosInsertFramebufferObj(obj); *framebuffers++ = obj->index; } } GLAPI void APIENTRY glDeleteFramebuffers(GLsizei n, GLuint *framebuffers) { while(n--) { GL_FRAMEBUFFER_OBJECT *ptr = FRAMEBUF_OBJ->link, * lptr = FRAMEBUF_OBJ; while(ptr != NULL) { if(ptr->index == *framebuffers) { GL_FRAMEBUFFER_OBJECT *cur_node = ptr; lptr->link = ptr->link; ptr = (GL_FRAMEBUFFER_OBJECT *)ptr->link; free(cur_node); if(*framebuffers == FRAMEBUF_OBJECT) FRAMEBUF_OBJECT = 0; break; } else ptr = (GL_FRAMEBUFFER_OBJECT *)ptr->link; } ++framebuffers; } } GLAPI void APIENTRY glBindFramebuffer(GLenum target, GLuint framebuffer) { if(target != GL_FRAMEBUFFER) { _glKosThrowError(GL_INVALID_ENUM, "glBindFramebuffer"); _glKosPrintError(); return; } FRAMEBUF_OBJECT = framebuffer; } GLAPI void APIENTRY glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { if(target != GL_FRAMEBUFFER) _glKosThrowError(GL_INVALID_ENUM, "glFramebufferTexture2D"); if(attachment != GL_COLOR_ATTACHMENT0) _glKosThrowError(GL_INVALID_OPERATION, "glFramebufferTexture2D"); if(textarget != GL_TEXTURE_2D) _glKosThrowError(GL_INVALID_OPERATION, "glFramebufferTexture2D"); if(level) _glKosThrowError(GL_INVALID_ENUM, "glFramebufferTexture2D"); if(!FRAMEBUF_OBJECT) _glKosThrowError(GL_INVALID_OPERATION, "glFramebufferTexture2D"); if(_glKosGetError()) { _glKosPrintError(); return; } GL_FRAMEBUFFER_OBJECT *fbo = _glKosGetFrameBufferObj(FRAMEBUF_OBJECT); fbo->texID = texture; fbo->data = _glKosTextureData(texture); } GLAPI GLenum APIENTRY glCheckFramebufferStatus(GLenum target) { if(target != GL_FRAMEBUFFER) { _glKosThrowError(GL_INVALID_ENUM, "glCheckFramebufferStatus"); _glKosPrintError(); return 0; } if(!FRAMEBUF_OBJECT) return GL_FRAMEBUFFER_COMPLETE; GL_FRAMEBUFFER_OBJECT *fbo = _glKosGetFrameBufferObj(FRAMEBUF_OBJECT); if(!fbo->texID) return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; return GL_FRAMEBUFFER_COMPLETE; }