181 lines
5.1 KiB
C
181 lines
5.1 KiB
C
|
/* 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 <malloc.h>
|
||
|
|
||
|
//========================================================================================//
|
||
|
//== 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;
|
||
|
}
|