diff --git a/gl-api.c b/gl-api.c new file mode 100755 index 0000000..c50fc69 --- /dev/null +++ b/gl-api.c @@ -0,0 +1,1358 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl.h + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + Some functionality adapted from the original KOS libgl: + Copyright (C) 2001 Dan Potter + Copyright (C) 2002 Benoit Miller + + This API implements much but not all of the OpenGL 1.1 for KallistiOS. +*/ + +#include +#include +#include + +#include "gl.h" +#include "glu.h" +#include "gl-api.h" +#include "gl-sh4.h" +#include "gl-pvr.h" + +/* Texture Submission Functions ************************************************************************/ +/* The texutre sumbission uses a fixed-size buffer, that defaults to 1024 textures. + That means that you must manage your texture submission by calling glDelTextures(...) + when you are done using a texture that was created by glGenTextures(...). + The size of the texture buffer can be controlled by setting GL_MAX_TEXTURES on gl-pvr.h. + + glTexImage2D(..) is used for loading texture data to OpenGL that is located in Main RAM: + OpenGL will allocate VRAM for the texture, and copy the texture data from Main RAM to VRAM. + + glKosTexImage2D(...) is used for loading texture data to OpenGL that is already in VRAM: + This mode must be used for a render-to-texture if you are using glutSwapBuffersToTexture(). +*/ + +typedef struct { + GLenum target; + GLint level; + GLint border; + GLenum format; + GLenum type; + GLint filter, env; + GLuint width, height; + GLuint internalFormat; + GLvoid *data; +} glTexCxt; + +static glTexCxt GL_TEX_LIST[GL_MAX_TEXTURES]; +static GLint GL_BOUND_TEX = -1, GL_LAST_BOUND_TEX = -1, + GL_BOUND_TEX1 = -1, GL_LAST_BOUND_TEX1 = -1; + +static GLubyte BLEND_SRC = PVR_BLEND_ONE; +static GLubyte BLEND_DST = PVR_BLEND_ZERO; + +static GLubyte GL_SHADE_FUNC = PVR_SHADE_GOURAUD; + +static GLubyte GL_CULL_FUNC = PVR_CULLING_NONE; + +static GLubyte GL_DEPTH_CMP = PVR_DEPTHCMP_GEQUAL; +static GLubyte GL_DEPTH_ENABLE = PVR_DEPTHWRITE_ENABLE; + +static GLubyte GL_TEX_ENV = PVR_TXRENV_MODULATEALPHA; + +static GLubyte GL_ENABLE_CLIPZ = 0; +static GLubyte GL_ENABLE_LIGHTING = 0; +static GLubyte GL_ENABLE_SCISSOR = 0; +static GLubyte GL_ENABLE_FOG = 0; +static GLubyte GL_ENABLE_CULLING = 0; +static GLubyte GL_ENABLE_DEPTH_TEST = 0; +static GLubyte GL_ENABLE_SUPERSAMP = 0; + +static GLubyte GL_FACE_FRONT = 0; +static GLubyte GL_CLAMP_ST = 0; + +#define GL_CLAMP_U 0x0F +#define GL_CLAMP_V 0xF0 +#define GL_CLAMP_UV 0xFF + +#define GL_TEXTURE_0 1<<0 +#define GL_TEXTURE_1 1<<1 + +static GLuint GL_TEXTURE_ENABLED = 0; +static GLuint GL_CUR_ACTIVE_TEX = 0; + +void glActiveTexture(GLenum texture) { + if(texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + GL_MAX_TEXTURE_UNITS) + return; + + GL_CUR_ACTIVE_TEX = ((texture & 0xFF) - (GL_TEXTURE0 & 0xFF)); +} + +void glBindTexture(GLenum target, GLuint texture) { + if(target == GL_TEXTURE_2D) { + switch(GL_CUR_ACTIVE_TEX) { + case 0: + GL_BOUND_TEX = texture; + GL_LAST_BOUND_TEX = GL_BOUND_TEX; + break; + + case 1: + GL_BOUND_TEX1 = texture; + GL_LAST_BOUND_TEX1 = GL_BOUND_TEX1; + break; + } + } +} + +void glGetIntegerv(GLenum pname, GLint *params) { + switch(pname) { + case GL_ACTIVE_TEXTURE: + *params = GL_CUR_ACTIVE_TEX; + break; + + case GL_BLEND: + *params = _glKosList(); + break; + + case GL_BLEND_DST: + *params = BLEND_SRC; + break; + + case GL_BLEND_SRC: + *params = BLEND_DST; + break; + + case GL_CULL_FACE: + *params = GL_ENABLE_CULLING; + break; + + case GL_CULL_FACE_MODE: + *params = GL_CULL_FUNC; + break; + + case GL_DEPTH_FUNC: + *params = GL_DEPTH_CMP; + break; + + case GL_DEPTH_TEST: + *params = GL_ENABLE_DEPTH_TEST; + break; + + case GL_DEPTH_WRITEMASK: + *params = GL_DEPTH_ENABLE; + break; + + case GL_FRONT_FACE: + *params = GL_FACE_FRONT; + break; + + case GL_SCISSOR_TEST: + *params = GL_ENABLE_SCISSOR; + break; + + default: + *params = -1; // Indicate invalid parameter // + break; + } +} + +static void _glKosInitTextures() { + GLuint i; + + for(i = 0; i < GL_MAX_TEXTURES; i++) + GL_TEX_LIST[i].data = NULL; +} + +static GLuint _glKosNextTexture() { + GLint i; + + for(i = 0; i < GL_MAX_TEXTURES; i++) + if(GL_TEX_LIST[i].data == NULL) + return i; + + return 0; /* Invalid Texture! */ +} + +GLuint glKosMipMapTexSize(GLuint width, GLuint height) { + GLuint b = 0; + + while(width >= 1 && height >= 1) { + b += width * height * 2; + + if(width >= 1) + width /= 2; + + if(height >= 1) + height /= 2; + } + + return b; +} + +void glGenTextures(GLsizei n, GLuint *textures) { + while(n--) + *textures++ = _glKosNextTexture(); +} + +void glDelTextures(GLsizei n, GLuint *textures) { + while(n--) { + if(GL_TEX_LIST[*textures].data != NULL) { + pvr_mem_free(GL_TEX_LIST[*textures].data); + GL_TEX_LIST[*textures].data = NULL; + } + + textures++; + } +} + +void glTexImage2D(GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, GLvoid *data) { + if(target != GL_TEXTURE_2D) return; + + GL_TEX_LIST[GL_BOUND_TEX].target = target; + GL_TEX_LIST[GL_BOUND_TEX].level = level; + GL_TEX_LIST[GL_BOUND_TEX].border = border; + GL_TEX_LIST[GL_BOUND_TEX].format = format; + GL_TEX_LIST[GL_BOUND_TEX].type = type; + + GLuint bytes; + + if(!level) + bytes = width * height * 2; + else + bytes = glKosMipMapTexSize(width, height); + + if(format == PVR_TXRFMT_VQ_ENABLE) + bytes /= 4; + + GL_TEX_LIST[GL_BOUND_TEX].data = pvr_mem_malloc(bytes); + + GL_TEX_LIST[GL_BOUND_TEX].width = width; + GL_TEX_LIST[GL_BOUND_TEX].height = height; + GL_TEX_LIST[GL_BOUND_TEX].internalFormat = internalFormat; + + GL_TEX_LIST[GL_BOUND_TEX].filter = PVR_FILTER_NONE; + + sq_cpy(GL_TEX_LIST[GL_BOUND_TEX].data, data, bytes); +} + +void glKosTexImage2D(GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, GLvoid *data) { + if(target != GL_TEXTURE_2D) return; + + GL_TEX_LIST[GL_BOUND_TEX].target = target; + GL_TEX_LIST[GL_BOUND_TEX].level = level; + GL_TEX_LIST[GL_BOUND_TEX].border = border; + GL_TEX_LIST[GL_BOUND_TEX].format = format; + GL_TEX_LIST[GL_BOUND_TEX].type = type; + + GL_TEX_LIST[GL_BOUND_TEX].data = data; + + GL_TEX_LIST[GL_BOUND_TEX].width = width; + GL_TEX_LIST[GL_BOUND_TEX].height = height; + GL_TEX_LIST[GL_BOUND_TEX].internalFormat = internalFormat; + + GL_TEX_LIST[GL_BOUND_TEX].filter = PVR_FILTER_NONE; +} + +void glTexParameteri(GLenum target, GLenum pname, GLint param) { + if(target == GL_TEXTURE_2D) { + switch(pname) { + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_MIN_FILTER: + switch(param) { + case GL_LINEAR: + GL_TEX_LIST[GL_BOUND_TEX].filter = PVR_FILTER_BILINEAR; + break; + + case GL_NEAREST: + GL_TEX_LIST[GL_BOUND_TEX].filter = PVR_FILTER_NEAREST; + break; + + case GL_FILTER_NONE: /* Compatabile with deprecated kgl */ + GL_TEX_LIST[GL_BOUND_TEX].filter = PVR_FILTER_NONE; + break; + + case GL_FILTER_BILINEAR: /* Compatabile with deprecated kgl */ + GL_TEX_LIST[GL_BOUND_TEX].filter = PVR_FILTER_BILINEAR; + break; + + case GL_NEAREST_MIPMAP_NEAREST: + GL_TEX_LIST[GL_BOUND_TEX].level = PVR_MIPMAP_ENABLE; + break; + + default: + break; + } + + break; + + case GL_TEXTURE_WRAP_S: + switch(param) { + case GL_CLAMP: + GL_CLAMP_ST |= GL_CLAMP_U; + break; + + case GL_REPEAT: + GL_CLAMP_ST ^= GL_CLAMP_U; + break; + } + + break; + + case GL_TEXTURE_WRAP_T: + switch(param) { + case GL_CLAMP: + GL_CLAMP_ST |= GL_CLAMP_V; + break; + + case GL_REPEAT: + GL_CLAMP_ST ^= GL_CLAMP_V; + break; + } + + break; + } + } +} + +void glTexEnvi(GLenum target, GLenum pname, GLint param) { + if(target == GL_TEXTURE_ENV) + if(pname == GL_TEXTURE_ENV_MODE) + if(param >= PVR_TXRENV_REPLACE && param <= PVR_TXRENV_MODULATEALPHA) + GL_TEX_ENV = param; +} + +void glTexEnvf(GLenum target, GLenum pname, GLfloat param) { + /* GL_TEXTURE_LOD_BIAS Not Implemented */ + glTexEnvi(target, pname, param); +} + +GLint gluBuild2DBiMipmaps(GLenum target, GLint internalFormat, GLsizei width, + GLsizei height, GLenum format, GLenum type, const void *data) { + if(target != GL_TEXTURE_2D) + return -1; + + if(width < 1 || height < 1) + return 0; + + uint32 i = 0; + uint16 x , y; + + uint16 *src = (uint16 *)data; + uint16 *dst = (uint16 *)data + (width * height); + + for(y = 0; y < height; y += 2) { + for(x = 0; x < width; x += 2) { + switch(type) { + case GL_UNSIGNED_SHORT_5_6_5: + dst[i++] = __glKosAverageBiPixelRGB565(*src, *(src + 1)); + break; + + case GL_UNSIGNED_SHORT_4_4_4_4: + dst[i++] = __glKosAverageBiPixelARGB4444(*src, *(src + 1)); + break; + + case GL_UNSIGNED_SHORT_1_5_5_5: + dst[i++] = __glKosAverageBiPixelARGB1555(*src, *(src + 1)); + break; + } + + src += 2; + } + + src += width; + } + + return gluBuild2DBiMipmaps(target, internalFormat, width / 2, height / 2, + format, type, (uint16 *)data + (width * height)); +} + +GLint gluBuild2DMipmaps(GLenum target, GLint internalFormat, GLsizei width, + GLsizei height, GLenum format, GLenum type, const void *data) { + if(target != GL_TEXTURE_2D) + return -1; + + if(width < 1 || height < 1) + return 0; + + if(width == 1 || height == 1) + return gluBuild2DBiMipmaps(target, internalFormat, width, height, format, type, data); + + uint32 i = 0; + uint16 x, y; + + uint16 *src = (uint16 *)data; + uint16 *dst = (uint16 *)data + (width * height); + + for(y = 0; y < height; y += 2) { + for(x = 0; x < width; x += 2) { + switch(type) { + case GL_UNSIGNED_SHORT_5_6_5: + dst[i++] = __glKosAverageQuadPixelRGB565(*src, *(src + 1), *(src + width), *(src + width + 1)); + break; + + case GL_UNSIGNED_SHORT_4_4_4_4: + dst[i++] = __glKosAverageQuadPixelARGB4444(*src, *(src + 1), *(src + width), *(src + width + 1)); + break; + + case GL_UNSIGNED_SHORT_1_5_5_5: + dst[i++] = __glKosAverageQuadPixelARGB1555(*src, *(src + 1), *(src + width), *(src + width + 1)); + break; + } + + src += 2; + } + + src += width; + } + + return gluBuild2DMipmaps(target, internalFormat, width / 2, height / 2, + format, type, (uint16 *)data + (width * height)); +} + +/* Blending / Shading functions ********************************************************/ + +void glShadeModel(GLenum mode) { + switch(mode) { + case GL_FLAT: + GL_SHADE_FUNC = PVR_SHADE_FLAT; + break; + + case GL_SMOOTH: + GL_SHADE_FUNC = PVR_SHADE_GOURAUD; + break; + } +} + +void glBlendFunc(GLenum sfactor, GLenum dfactor) { + switch(sfactor) { + case GL_ONE: + BLEND_SRC = PVR_BLEND_ONE; + break; + + case GL_ZERO: + BLEND_SRC = PVR_BLEND_ZERO; + break; + + case GL_SRC_COLOR: + BLEND_SRC = PVR_BLEND_SRCALPHA; + break; + + case GL_DST_COLOR: + BLEND_SRC = PVR_BLEND_DESTCOLOR; + break; + + case GL_SRC_ALPHA: + BLEND_SRC = PVR_BLEND_SRCALPHA; + break; + + case GL_DST_ALPHA: + BLEND_SRC = PVR_BLEND_DESTALPHA; + break; + + case GL_ONE_MINUS_SRC_ALPHA: + BLEND_SRC = PVR_BLEND_INVSRCALPHA; + break; + + case GL_ONE_MINUS_DST_ALPHA: + BLEND_SRC = PVR_BLEND_INVDESTALPHA; + break; + + case GL_ONE_MINUS_DST_COLOR: + BLEND_SRC = PVR_BLEND_INVDESTCOLOR; + break; + } + + switch(dfactor) { + case GL_ONE: + BLEND_DST = PVR_BLEND_ONE; + break; + + case GL_ZERO: + BLEND_DST = PVR_BLEND_ZERO; + break; + + case GL_SRC_COLOR: + BLEND_DST = PVR_BLEND_SRCALPHA; + break; + + case GL_DST_COLOR: + BLEND_DST = PVR_BLEND_DESTCOLOR; + break; + + case GL_SRC_ALPHA: + BLEND_DST = PVR_BLEND_SRCALPHA; + break; + + case GL_DST_ALPHA: + BLEND_DST = PVR_BLEND_DESTALPHA; + break; + + case GL_ONE_MINUS_SRC_ALPHA: + BLEND_DST = PVR_BLEND_INVSRCALPHA; + break; + + case GL_ONE_MINUS_DST_ALPHA: + BLEND_DST = PVR_BLEND_INVDESTALPHA; + break; + + case GL_ONE_MINUS_DST_COLOR: + BLEND_DST = PVR_BLEND_INVDESTCOLOR; + break; + } +} + +/* Depth / Clear functions */ +static GLfloat GL_DEPTH_CLEAR = 1.0f, + GL_COLOR_CLEAR[3] = { 0, 0, 0 }; + +void glClear(GLuint mode) { + if(mode & GL_COLOR_BUFFER_BIT) + pvr_set_bg_color(GL_COLOR_CLEAR[0], GL_COLOR_CLEAR[1], GL_COLOR_CLEAR[2]); +} + +void glClearColor(float r, float g, float b, float a) { + if(r > 1) r = 1; + + if(g > 1) g = 1; + + if(b > 1) b = 1; + + if(a > 1) a = 1; + + GL_COLOR_CLEAR[0] = r * a; + GL_COLOR_CLEAR[1] = g * a; + GL_COLOR_CLEAR[2] = b * a; +} + +void glClearDepthf(GLfloat depth) { + GL_DEPTH_CLEAR = depth; +} + +void glDepthFunc(GLenum func) { + switch(func) { + case GL_LESS: + GL_DEPTH_CMP = PVR_DEPTHCMP_GEQUAL; + break; + + case GL_LEQUAL: + GL_DEPTH_CMP = PVR_DEPTHCMP_GREATER; + break; + + case GL_GREATER: + GL_DEPTH_CMP = PVR_DEPTHCMP_LEQUAL; + break; + + case GL_GEQUAL: + GL_DEPTH_CMP = PVR_DEPTHCMP_LESS; + break; + + default: + GL_DEPTH_CMP = func & 0xF; + } +} + +void glDepthMask(GLboolean flag) { + flag ? (GL_DEPTH_ENABLE = PVR_DEPTHWRITE_ENABLE) : + (GL_DEPTH_ENABLE = PVR_DEPTHWRITE_DISABLE); +} + +void glFrontFace(GLenum mode) { + switch(mode) { + case GL_CW: + case GL_CCW: + GL_FACE_FRONT = mode; + break; + } +} + +void glCullFace(GLenum mode) { + switch(mode) { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + GL_CULL_FUNC = mode; + break; + } +} + +/* glEnable / glDisable ****************************************************************/ + +void glEnable(GLenum cap) { + if(cap >= GL_LIGHT0 && cap <= GL_LIGHT7) return _glKosEnableLight(cap); + + switch(cap) { + case GL_TEXTURE_2D: + GL_TEXTURE_ENABLED |= (1 << GL_CUR_ACTIVE_TEX); + break; + + case GL_BLEND: + _glKosVertexBufSwitchTR(); + break; + + case GL_DEPTH_TEST: + GL_ENABLE_DEPTH_TEST = 1; + break; + + case GL_LIGHTING: + GL_ENABLE_LIGHTING = 1; + break; + + case GL_KOS_NEARZ_CLIPPING: + GL_ENABLE_CLIPZ = 1; + break; + + case GL_SCISSOR_TEST: + GL_ENABLE_SCISSOR = 1; + break; + + case GL_FOG: + GL_ENABLE_FOG = 1; + break; + + case GL_CULL_FACE: + GL_ENABLE_CULLING = 1; + break; + } +} + +void glDisable(GLenum cap) { + if(cap >= GL_LIGHT0 && cap <= GL_LIGHT7) return _glKosDisableLight(cap); + + switch(cap) { + case GL_TEXTURE_2D: + GL_TEXTURE_ENABLED &= ~(1 << GL_CUR_ACTIVE_TEX); + break; + + case GL_BLEND: + _glKosVertexBufSwitchOP(); + break; + + case GL_DEPTH_TEST: + GL_ENABLE_DEPTH_TEST = 0; + break; + + case GL_LIGHTING: + GL_ENABLE_LIGHTING = 0; + break; + + case GL_KOS_NEARZ_CLIPPING: + GL_ENABLE_CLIPZ = 0; + break; + + case GL_SCISSOR_TEST: + GL_ENABLE_SCISSOR = 0; + break; + + case GL_FOG: + GL_ENABLE_FOG = 0; + break; + + case GL_CULL_FACE: + GL_ENABLE_CULLING = 0; + break; + } +} + +/* Vertex Submission Functions *************************************************************************/ +static GLuint GL_VERTICES = 0, + GL_VERTEX_MODE = GL_TRIANGLES; +static GLuint GL_VERTEX_COLOR = 0xFFFFFFFF; +//static GLuint GL_VERTEX_SPECULAR = 0xFF000000; +static GLfloat GL_VERTEX_UV[2] = {0, 0}; + +typedef struct { + GLfloat u; + GLfloat v; +} TexCoord; + +static TexCoord GL_MULTI_UV[GL_MAX_VERTS]; + +static pvr_poly_cxt_t GL_POLY_CXT; + +void glKosInit() { + _glKosInitPVR(); + + _glKosInitTextures(); + + _glKosInitMatrix(); + + _glKosInitLighting(); +} + +void _glKosCompileHdr() { + pvr_poly_hdr_t *hdr = _glKosVertexBufPointer(); + + /* Non-textured pvr poly header */ + pvr_poly_cxt_col(&GL_POLY_CXT, _glKosList() * 2); + + GL_POLY_CXT.gen.shading = GL_SHADE_FUNC; + + if(GL_ENABLE_DEPTH_TEST) + GL_POLY_CXT.depth.comparison = GL_DEPTH_CMP; + else + GL_POLY_CXT.depth.comparison = PVR_DEPTHCMP_ALWAYS; + + GL_POLY_CXT.depth.write = GL_DEPTH_ENABLE; + + if(GL_ENABLE_SCISSOR) + GL_POLY_CXT.gen.clip_mode = PVR_USERCLIP_INSIDE; + + if(GL_ENABLE_FOG) + GL_POLY_CXT.gen.fog_type = PVR_FOG_TABLE; + + if(GL_ENABLE_CULLING) { + if(GL_CULL_FUNC == GL_BACK) { + if(GL_FACE_FRONT == GL_CW) + GL_POLY_CXT.gen.culling = PVR_CULLING_CCW; + else + GL_POLY_CXT.gen.culling = PVR_CULLING_CW; + } + else if(GL_CULL_FUNC == GL_FRONT) { + if(GL_FACE_FRONT == GL_CCW) + GL_POLY_CXT.gen.culling = PVR_CULLING_CCW; + else + GL_POLY_CXT.gen.culling = PVR_CULLING_CW; + } + } + else + GL_POLY_CXT.gen.culling = PVR_CULLING_NONE; + + pvr_poly_compile(hdr, &GL_POLY_CXT); + + if(GL_ENABLE_SUPERSAMP) + hdr->mode2 |= GL_PVR_SAMPLE_SUPER << PVR_TA_SUPER_SAMPLE_SHIFT; + + _glKosVertexBufIncrement(); +} + +void _glKosCompileHdrTx() { + pvr_poly_hdr_t *hdr = _glKosVertexBufPointer(); + + pvr_poly_cxt_txr(&GL_POLY_CXT, _glKosList() * 2, + GL_TEX_LIST[GL_BOUND_TEX].format | + GL_TEX_LIST[GL_BOUND_TEX].type, + GL_TEX_LIST[GL_BOUND_TEX].width, + GL_TEX_LIST[GL_BOUND_TEX].height, + GL_TEX_LIST[GL_BOUND_TEX].data, + GL_TEX_LIST[GL_BOUND_TEX].filter); + + GL_POLY_CXT.gen.shading = GL_SHADE_FUNC; + + if(GL_ENABLE_DEPTH_TEST) + GL_POLY_CXT.depth.comparison = GL_DEPTH_CMP; + else + GL_POLY_CXT.depth.comparison = PVR_DEPTHCMP_ALWAYS; + + GL_POLY_CXT.depth.write = GL_DEPTH_ENABLE; + + if(GL_ENABLE_SCISSOR) + GL_POLY_CXT.gen.clip_mode = PVR_USERCLIP_INSIDE; + + if(GL_ENABLE_FOG) + GL_POLY_CXT.gen.fog_type = PVR_FOG_TABLE; + + if(GL_ENABLE_CULLING) { + if(GL_CULL_FUNC == GL_BACK) { + if(GL_FACE_FRONT == GL_CW) + GL_POLY_CXT.gen.culling = PVR_CULLING_CCW; + else + GL_POLY_CXT.gen.culling = PVR_CULLING_CW; + } + else if(GL_CULL_FUNC == GL_FRONT) { + if(GL_FACE_FRONT == GL_CCW) + GL_POLY_CXT.gen.culling = PVR_CULLING_CCW; + else + GL_POLY_CXT.gen.culling = PVR_CULLING_CW; + } + } + else + GL_POLY_CXT.gen.culling = PVR_CULLING_NONE; + + if(GL_CLAMP_ST == GL_CLAMP_UV) + GL_POLY_CXT.txr.uv_clamp = PVR_UVCLAMP_UV; + else if(GL_CLAMP_ST & GL_CLAMP_U) + GL_POLY_CXT.txr.uv_clamp = PVR_UVCLAMP_U; + else if(GL_CLAMP_ST & GL_CLAMP_V) + GL_POLY_CXT.txr.uv_clamp = PVR_UVCLAMP_V; + + GL_POLY_CXT.txr.mipmap = GL_TEX_LIST[GL_BOUND_TEX].level; + GL_POLY_CXT.txr.mipmap_bias = PVR_MIPBIAS_NORMAL; + + if(_glKosList()) { + GL_POLY_CXT.txr.env = GL_TEX_ENV; + GL_POLY_CXT.blend.src = BLEND_SRC; + GL_POLY_CXT.blend.dst = BLEND_DST; + } + + pvr_poly_compile(hdr, &GL_POLY_CXT); + + if(GL_ENABLE_SUPERSAMP) + hdr->mode2 |= GL_PVR_SAMPLE_SUPER << PVR_TA_SUPER_SAMPLE_SHIFT; + + _glKosVertexBufIncrement(); +} + + +void _glKosCompileHdrTx2() { + pvr_poly_hdr_t *hdr = _glKosTRVertexBufPointer(); + + pvr_poly_cxt_txr(&GL_POLY_CXT, 2, + GL_TEX_LIST[GL_BOUND_TEX1].format | + GL_TEX_LIST[GL_BOUND_TEX1].type, + GL_TEX_LIST[GL_BOUND_TEX1].width, + GL_TEX_LIST[GL_BOUND_TEX1].height, + GL_TEX_LIST[GL_BOUND_TEX1].data, + GL_TEX_LIST[GL_BOUND_TEX1].filter); + + GL_POLY_CXT.gen.shading = GL_SHADE_FUNC; + + if(GL_ENABLE_DEPTH_TEST) + GL_POLY_CXT.depth.comparison = GL_DEPTH_CMP; + else + GL_POLY_CXT.depth.comparison = PVR_DEPTHCMP_ALWAYS; + + GL_POLY_CXT.depth.write = GL_DEPTH_ENABLE; + + if(GL_ENABLE_SCISSOR) + GL_POLY_CXT.gen.clip_mode = PVR_USERCLIP_INSIDE; + + if(GL_ENABLE_FOG) + GL_POLY_CXT.gen.fog_type = PVR_FOG_TABLE; + + if(GL_ENABLE_CULLING) { + if(GL_CULL_FUNC == GL_BACK) { + if(GL_FACE_FRONT == GL_CW) + GL_POLY_CXT.gen.culling = PVR_CULLING_CCW; + else + GL_POLY_CXT.gen.culling = PVR_CULLING_CW; + } + else if(GL_CULL_FUNC == GL_FRONT) { + if(GL_FACE_FRONT == GL_CCW) + GL_POLY_CXT.gen.culling = PVR_CULLING_CCW; + else + GL_POLY_CXT.gen.culling = PVR_CULLING_CW; + } + } + else + GL_POLY_CXT.gen.culling = PVR_CULLING_NONE; + + if(GL_CLAMP_ST == GL_CLAMP_UV) + GL_POLY_CXT.txr.uv_clamp = PVR_UVCLAMP_UV; + else if(GL_CLAMP_ST & GL_CLAMP_U) + GL_POLY_CXT.txr.uv_clamp = PVR_UVCLAMP_U; + else if(GL_CLAMP_ST & GL_CLAMP_V) + GL_POLY_CXT.txr.uv_clamp = PVR_UVCLAMP_V; + + GL_POLY_CXT.txr.mipmap = GL_TEX_LIST[GL_BOUND_TEX1].level; + GL_POLY_CXT.txr.mipmap_bias = PVR_MIPBIAS_NORMAL; + + GL_POLY_CXT.txr.env = GL_TEX_ENV; + GL_POLY_CXT.blend.src = BLEND_SRC; + GL_POLY_CXT.blend.dst = BLEND_DST; + + pvr_poly_compile(hdr, &GL_POLY_CXT); + + if(GL_ENABLE_SUPERSAMP) + hdr->mode2 |= GL_PVR_SAMPLE_SUPER << PVR_TA_SUPER_SAMPLE_SHIFT; + + _glKosTRVertexBufIncrement(); +} + +/* Vertex Color Submission */ + +void glColor1ui(GLuint argb) { + GL_VERTEX_COLOR = argb; +} + +void glColor4ub(GLubyte r, GLubyte g, GLubyte b, GLubyte a) { + GL_VERTEX_COLOR = a << 24 | r << 16 | g << 8 | b; +} + +void glColor3f(float r, float g, float b) { + GL_VERTEX_COLOR = PVR_PACK_COLOR(1.0f, r, g, b); +} + +void glColor3fv(float *rgb) { + GL_VERTEX_COLOR = PVR_PACK_COLOR(1.0f, rgb[0], rgb[1], rgb[2]); +} + +void glColor4f(float r, float g, float b, float a) { + GL_VERTEX_COLOR = PVR_PACK_COLOR(a, r, g, b); +} + +void glColor4fv(float *rgba) { + GL_VERTEX_COLOR = PVR_PACK_COLOR(rgba[3], rgba[0], rgba[1], rgba[2]); +} + +/* Texture Coordinate Submission */ + +void glTexCoord2f(GLfloat u, GLfloat v) { + GL_VERTEX_UV[0] = u; + GL_VERTEX_UV[1] = v; +} + +void glTexCoord2fv(GLfloat *uv) { + GL_VERTEX_UV[0] = uv[0]; + GL_VERTEX_UV[1] = uv[1]; +} + +void glMultiTexCoord2f(GLenum target, GLfloat s, GLfloat t) { + switch(target) { + case GL_TEXTURE0: + GL_VERTEX_UV[0] = s; + GL_VERTEX_UV[1] = t; + break; + + case GL_TEXTURE1: + GL_MULTI_UV[GL_VERTICES].u = s; + GL_MULTI_UV[GL_VERTICES].v = t; + break; + } +} + +void glMultiTexCoord2fv(GLenum target, const GLfloat *v) { + switch(target) { + case GL_TEXTURE0: + GL_VERTEX_UV[0] = v[0]; + GL_VERTEX_UV[1] = v[1]; + break; + + case GL_TEXTURE1: + GL_MULTI_UV[GL_VERTICES].u = v[0]; + GL_MULTI_UV[GL_VERTICES].v = v[1]; + break; + } +} + +static inline void _glKosMultiTexCoord(pvr_vertex_t *v, GLuint count) { + GLuint i; + + for(i = 0; i < count; i++) { + v[i].u = GL_MULTI_UV[i].u; + v[i].v = GL_MULTI_UV[i].v; + } +} + +static inline void _glKosMultiTexCoordQuads(pvr_vertex_t *v, GLuint count) { + GLuint i; + + for(i = 0; i < count / 4; i += 4) { + v[i + 0].u = GL_MULTI_UV[i + 0].u; + v[i + 0].v = GL_MULTI_UV[i + 0].v; + v[i + 1].u = GL_MULTI_UV[i + 1].u; + v[i + 1].v = GL_MULTI_UV[i + 1].v; + v[i + 2].u = GL_MULTI_UV[i + 3].u; + v[i + 2].v = GL_MULTI_UV[i + 3].v; + v[i + 3].u = GL_MULTI_UV[i + 2].u; + v[i + 3].v = GL_MULTI_UV[i + 2].v; + } +} + +/* Vertex Submission */ + +static inline void _glKosVertexSwap(pvr_vertex_t *v1, pvr_vertex_t *v2) { + pvr_vertex_t tmp = *v1; + *v1 = *v2; + *v2 = * &tmp; +} + +static inline void _glKosFlagsSetQuad() { + pvr_vertex_t *v = (pvr_vertex_t *)_glKosVertexBufPointer() - GL_VERTICES; + GLuint i; + + for(i = 0; i < GL_VERTICES; i += 4) { + _glKosVertexSwap(v + 2, v + 3); + v->flags = (v + 1)->flags = (v + 2)->flags = PVR_CMD_VERTEX; + (v + 3)->flags = PVR_CMD_VERTEX_EOL; + v += 4; + } +} + +static inline void _glKosFlagsSetTriangle() { + pvr_vertex_t *v = (pvr_vertex_t *)_glKosVertexBufPointer() - GL_VERTICES; + GLuint i; + + for(i = 0; i < GL_VERTICES; i += 3) { + v->flags = (v + 1)->flags = PVR_CMD_VERTEX; + (v + 2)->flags = PVR_CMD_VERTEX_EOL; + v += 3; + } +} + +static inline void _glKosFlagsSetTriangleStrip() { + pvr_vertex_t *v = (pvr_vertex_t *)_glKosVertexBufPointer() - GL_VERTICES; + GLuint i; + + for(i = 0; i < GL_VERTICES - 1; i++) { + v->flags = PVR_CMD_VERTEX; + v++; + } + + v->flags = PVR_CMD_VERTEX_EOL; +} + +void glBegin(unsigned int mode) { + _glKosMatrixApplyRender(); /* Apply the Render Matrix Stack */ + + _glKosArrayBufReset(); /* Make sure arrays buffer is reset */ + + GL_VERTEX_MODE = mode; + + GL_BOUND_TEX < 0 ? _glKosCompileHdr() : _glKosCompileHdrTx(); + + if(GL_TEXTURE_ENABLED & GL_TEXTURE_1) + _glKosCompileHdrTx2(); + + GL_VERTICES = 0; + + if(mode == GL_POINTS) { + glVertex3f = _glKosVertex3fp; + glVertex3fv = _glKosVertex3fpv; + } + else if(GL_ENABLE_CLIPZ && GL_ENABLE_LIGHTING) { + glVertex3f = _glKosVertex3flc; + glVertex3fv = _glKosVertex3flcv; + } + else if(GL_ENABLE_LIGHTING) { + glVertex3f = _glKosVertex3fl; + glVertex3fv = _glKosVertex3flv; + } + else if(GL_ENABLE_CLIPZ) { + glVertex3f = _glKosVertex3fc; + glVertex3fv = _glKosVertex3fcv; + } + else { + glVertex3f = _glKosVertex3ft; + glVertex3fv = _glKosVertex3ftv; + } + + glVertex2f = _glKosVertex2ft; + glVertex2fv = _glKosVertex2ftv; +} + +void _glKosTransformClipBuf(pvr_vertex_t *v, GLuint verts) { + register float __x __asm__("fr12"); + register float __y __asm__("fr13"); + register float __z __asm__("fr14"); + + while(verts--) { + __x = v->x; + __y = v->y; + __z = v->z; + + mat_trans_fv12(); + + v->x = __x; + v->y = __y; + v->z = __z; + ++v; + } +} + +static inline void _glKosCopyMultiTexture(pvr_vertex_t *v, GLuint count) { + if(GL_TEXTURE_ENABLED & GL_TEXTURE_1) { + _glKosVertexBufCopy(_glKosTRVertexBufPointer(), v, count); + + if(GL_VERTEX_MODE == GL_QUADS) + _glKosMultiTexCoordQuads(_glKosTRVertexBufPointer(), count); + else + _glKosMultiTexCoord(_glKosTRVertexBufPointer(), count); + + _glKosTRVertexBufAdd(count); + } +} + +void glEnd() { + if(GL_ENABLE_CLIPZ) { /* Z-Clipping Enabled */ + if(GL_ENABLE_LIGHTING) { + _glKosVertexComputeLighting(_glKosClipBufAddress(), GL_VERTICES); + + _glKosMatrixLoadRender(); + } + + GLuint cverts; + pvr_vertex_t *v = _glKosVertexBufPointer(); + + switch(GL_VERTEX_MODE) { + case GL_TRIANGLES: + cverts = _glKosClipTriangles(_glKosClipBufAddress(), v, GL_VERTICES); + _glKosTransformClipBuf(v, cverts); + _glKosCopyMultiTexture(v, cverts); + _glKosVertexBufAdd(cverts); + break; + + case GL_TRIANGLE_STRIP: + cverts = _glKosClipTriangleStrip(_glKosClipBufAddress(), v, GL_VERTICES); + _glKosTransformClipBuf(v, cverts); + _glKosCopyMultiTexture(v, cverts); + _glKosVertexBufAdd(cverts); + break; + + case GL_QUADS: + cverts = _glKosClipQuads(_glKosClipBufAddress(), v, GL_VERTICES); + _glKosTransformClipBuf(v, cverts); + _glKosCopyMultiTexture(v, cverts); + _glKosVertexBufAdd(cverts); + break; + } + + _glKosClipBufReset(); + } + else { /* No Z-Clipping Enabled */ + if(GL_ENABLE_LIGHTING) + _glKosVertexComputeLighting((pvr_vertex_t *)_glKosVertexBufPointer() - GL_VERTICES, GL_VERTICES); + + switch(GL_VERTEX_MODE) { + case GL_TRIANGLES: + _glKosFlagsSetTriangle(); + break; + + case GL_TRIANGLE_STRIP: + _glKosFlagsSetTriangleStrip(); + break; + + case GL_QUADS: + _glKosFlagsSetQuad(); + break; + } + + _glKosCopyMultiTexture((pvr_vertex_t *)_glKosVertexBufPointer() - GL_VERTICES, GL_VERTICES); + } +} + +void _glKosVertex2ft(float x, float y) { + pvr_vertex_t *v = _glKosVertexBufPointer(); + + v->x = x; + v->y = y; + v->z = 10; + v->u = GL_VERTEX_UV[0]; + v->v = GL_VERTEX_UV[1]; + v->argb = GL_VERTEX_COLOR; + //v->oargb = GL_VERTEX_SPECULAR; + + _glKosVertexBufIncrement(); + + ++GL_VERTICES; +} + +void _glKosVertex2ftv(float *xy) { + pvr_vertex_t *v = _glKosVertexBufPointer(); + + v->x = xy[0]; + v->y = xy[1]; + v->z = 10; + v->u = GL_VERTEX_UV[0]; + v->v = GL_VERTEX_UV[1]; + v->argb = GL_VERTEX_COLOR; + //v->oargb = GL_VERTEX_SPECULAR; + + _glKosVertexBufIncrement(); + + ++GL_VERTICES; +} + +void _glKosVertex3fs(float x, float y, float z) { + pvr_vertex_t *v = _glKosVertexBufPointer(); + + mat_trans_single3_nomod(x, y, z, v->x, v->y, v->z); + + v->u = GL_VERTEX_UV[0]; + v->v = GL_VERTEX_UV[1]; + //v->oargb = GL_VERTEX_SPECULAR; + + _glKosVertexBufIncrement(); + + ++GL_VERTICES; +} + +void _glKosVertex3fsv(float *xyz) { + pvr_vertex_t *v = _glKosVertexBufPointer(); + + mat_trans_single3_nomod(xyz[0], xyz[1], xyz[2], v->x, v->y, v->z); + + v->u = GL_VERTEX_UV[0]; + v->v = GL_VERTEX_UV[1]; + //v->oargb = GL_VERTEX_SPECULAR; + + _glKosVertexBufIncrement(); + + ++GL_VERTICES; +} + +void _glKosVertex3ft(float x, float y, float z) { + pvr_vertex_t *v = _glKosVertexBufPointer(); + + mat_trans_single3_nomod(x, y, z, v->x, v->y, v->z); + + v->u = GL_VERTEX_UV[0]; + v->v = GL_VERTEX_UV[1]; + v->argb = GL_VERTEX_COLOR; + //v->oargb = GL_VERTEX_SPECULAR; + + _glKosVertexBufIncrement(); + + ++GL_VERTICES; +} + +void _glKosVertex3ftv(float *xyz) { + pvr_vertex_t *v = _glKosVertexBufPointer(); + + mat_trans_single3_nomod(xyz[0], xyz[1], xyz[2], v->x, v->y, v->z); + + v->u = GL_VERTEX_UV[0]; + v->v = GL_VERTEX_UV[1]; + v->argb = GL_VERTEX_COLOR; + //v->oargb = GL_VERTEX_SPECULAR; + + _glKosVertexBufIncrement(); + + ++GL_VERTICES; +} + +void _glKosVertex3fc(float x, float y, float z) { + pvr_vertex_t *v = _glKosClipBufPointer(); + + v->x = x; + v->y = y; + v->z = z; + v->u = GL_VERTEX_UV[0]; + v->v = GL_VERTEX_UV[1]; + v->argb = GL_VERTEX_COLOR; + //v->oargb = GL_VERTEX_SPECULAR; + + _glKosClipBufIncrement(); + + ++GL_VERTICES; +} + +void _glKosVertex3fcv(float *xyz) { + pvr_vertex_t *v = _glKosClipBufPointer(); + + v->x = xyz[0]; + v->y = xyz[1]; + v->z = xyz[2]; + v->u = GL_VERTEX_UV[0]; + v->v = GL_VERTEX_UV[1]; + v->argb = GL_VERTEX_COLOR; + //v->oargb = GL_VERTEX_SPECULAR; + + _glKosClipBufIncrement(); + + ++GL_VERTICES; +} + +/* GL_POINTS */ +static float GL_POINT_SIZE = 0.02; + +inline void _glKosVertex3fpa(float x, float y, float z) { + pvr_vertex_t *v = _glKosVertexBufPointer(); + + mat_trans_single3_nomod(x, y, z, v->x, v->y, v->z); + + v->argb = GL_VERTEX_COLOR; + //v->oargb = GL_VERTEX_SPECULAR; + v->flags = PVR_CMD_VERTEX; + + _glKosVertexBufIncrement(); +} + +inline void _glKosVertex3fpb(float x, float y, float z) { + pvr_vertex_t *v = _glKosVertexBufPointer(); + + mat_trans_single3_nomod(x, y, z, v->x, v->y, v->z); + + v->argb = GL_VERTEX_COLOR; + //v->oargb = GL_VERTEX_SPECULAR; + v->flags = PVR_CMD_VERTEX_EOL; + + _glKosVertexBufIncrement(); +} + +void _glKosVertex3fp(float x, float y, float z) { + _glKosVertex3fpa(x - GL_POINT_SIZE, y - GL_POINT_SIZE, z); + _glKosVertex3fpa(x + GL_POINT_SIZE, y - GL_POINT_SIZE, z); + _glKosVertex3fpa(x - GL_POINT_SIZE, y + GL_POINT_SIZE, z); + _glKosVertex3fpb(x + GL_POINT_SIZE, y + GL_POINT_SIZE, z); +} + +void _glKosVertex3fpv(float *xyz) { + _glKosVertex3fpa(xyz[0] - GL_POINT_SIZE, xyz[1] - GL_POINT_SIZE, xyz[2]); + _glKosVertex3fpa(xyz[0] + GL_POINT_SIZE, xyz[1] - GL_POINT_SIZE, xyz[2]); + _glKosVertex3fpa(xyz[0] - GL_POINT_SIZE, xyz[1] + GL_POINT_SIZE, xyz[2]); + _glKosVertex3fpb(xyz[0] + GL_POINT_SIZE, xyz[1] + GL_POINT_SIZE, xyz[2]); +} + +/* Misc. functions */ + +/* Clamp X to [MIN,MAX]: */ +#define CLAMP( X, MIN, MAX ) ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) ) + +/* Setup the hardware user clip rectangle. + + The minimum clip rectangle is a 32x32 area which is dependent on the tile + size use by the tile accelerator. The PVR swithes off rendering to tiles + outside or inside the defined rectangle dependant upon the 'clipmode' + bits in the polygon header. + + Clip rectangles therefore must have a size that is some multiple of 32. + + glScissor(0, 0, 32, 32) allows only the 'tile' in the lower left + hand corner of the screen to be modified and glScissor(0, 0, 0, 0) + disallows modification to all 'tiles' on the screen. +*/ +void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) { + pvr_cmd_tclip_t *c = _glKosVertexBufPointer(); + + GLint miny, maxx, maxy; + GLsizei gl_scissor_width = CLAMP(width, 0, vid_mode->width); + GLsizei gl_scissor_height = CLAMP(height, 0, vid_mode->height); + + /* force the origin to the lower left-hand corner of the screen */ + miny = (vid_mode->height - gl_scissor_height) - y; + maxx = (gl_scissor_width + x); + maxy = (gl_scissor_height + miny); + + /* load command structure while mapping screen coords to TA tiles */ + c->flags = PVR_CMD_USERCLIP; + c->d1 = c->d2 = c->d3 = 0; + c->sx = CLAMP(x / 32, 0, vid_mode->width / 32); + c->sy = CLAMP(miny / 32, 0, vid_mode->height / 32); + c->ex = CLAMP((maxx / 32) - 1, 0, vid_mode->width / 32); + c->ey = CLAMP((maxy / 32) - 1, 0, vid_mode->height / 32); + + _glKosVertexBufIncrement(); +} + +void glHint(GLenum target, GLenum mode) { + switch(target) { + case GL_PERSPECTIVE_CORRECTION_HINT: + if(mode == GL_NICEST) + GL_ENABLE_SUPERSAMP = 1; + else + GL_ENABLE_SUPERSAMP = 0; + + break; + } +} + +GLint _glKosEnabledTexture2D() { + return GL_TEXTURE_ENABLED; +} + +GLubyte _glKosEnabledNearZClip() { + return GL_ENABLE_CLIPZ; +} + +GLubyte _glKosEnabledLighting() { + return GL_ENABLE_LIGHTING; +} + +inline void _glKosResetEnabledTex() { + GL_TEXTURE_ENABLED = GL_CUR_ACTIVE_TEX = 0; +} diff --git a/gl-api.h b/gl-api.h new file mode 100755 index 0000000..e6d83f6 --- /dev/null +++ b/gl-api.h @@ -0,0 +1,116 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-api.h + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + The functions defined in this header are for internal use by the API, + and not for use externally. +*/ + +#ifndef GL_API_H +#define GL_API_H + +typedef struct { + float pos[3]; + float norm[3]; +} glVertex; /* Simple Vertex used for Dynamic Vertex Lighting */ + +typedef unsigned short uint16; +typedef unsigned char uint8; + +/* Vertex Main Buffer Internal Functions */ +inline void _glKosVertexBufSwitchOP(); +inline void _glKosVertexBufSwitchTR(); +inline void *_glKosVertexBufAddress(unsigned char list); +inline void *_glKosVertexBufPointer(); +inline void *_glKosTRVertexBufPointer(); +inline void _glKosVertexBufIncrement(); +inline void _glKosTRVertexBufIncrement(); +inline void _glKosVertexBufAdd(unsigned int count); +inline void _glKosTRVertexBufAdd(unsigned int count); +inline void _glKosVertexBufDecrement(); +inline void _glKosVertexBufReset(); +inline unsigned int _glKosVertexBufCount(unsigned char list); +unsigned char _glKosList(); +inline void _glKosVertexBufCopy(void *src, void *dst, GLuint count); +inline void _glKosResetEnabledTex(); + +/* Vertex Clip Buffer Internal Functions */ +inline void *_glKosClipBufAddress(); +inline void *_glKosClipBufPointer(); +inline void _glKosClipBufIncrement(); +inline void _glKosClipBufReset(); + +/* Vertex Array Buffer Internal Functions */ +inline void _glKosArrayBufIncrement(); +inline void _glKosArrayBufReset(); +inline glVertex *_glKosArrayBufAddr(); +inline glVertex *_glKosArrayBufPtr(); + +/* Initialize the OpenGL PVR Pipeline */ +int _glKosInitPVR(); + +/* Compile the current Polygon Header for the PVR */ +void _glKosCompileHdr(); +void _glKosCompileHdrTx(); +void _glKosCompileHdrTx2(); + +/* Clipping Internal Functions */ +void _glKosTransformClipBuf(pvr_vertex_t *v, GLuint verts); +unsigned int _glKosClipTriangleStrip(pvr_vertex_t *vin, pvr_vertex_t *vout, unsigned int vertices); +unsigned int _glKosClipTriangles(pvr_vertex_t *vin, pvr_vertex_t *vout, unsigned int vertices); +unsigned int _glKosClipQuads(pvr_vertex_t *vin, pvr_vertex_t *vout, unsigned int vertices); + +unsigned int _glKosClipTrianglesTransformed(pvr_vertex_t *src, float *w, pvr_vertex_t *dst, GLuint count); +unsigned char _glKosClipTriTransformed(pvr_vertex_t *vin, float *w, pvr_vertex_t *vout); +unsigned int _glKosClipQuadsTransformed(pvr_vertex_t *vin, float *w, pvr_vertex_t *vout, unsigned int vertices); +unsigned int _glKosClipTriangleStripTransformed(pvr_vertex_t *src, float *w, pvr_vertex_t *dst, GLuint count); + +/* Lighting Internal Functions */ +void _glKosInitLighting(); +void _glKosEnableLight(const GLuint light); +void _glKosDisableLight(const GLuint light); +void _glKosSetEyePosition(GLfloat *position); +void _glKosVertexComputeLighting(pvr_vertex_t *v, int verts); +void _glKosVertexLight(glVertex *P, pvr_vertex_t *v); +unsigned int _glKosVertexLightColor(glVertex *P); +void _glKosVertexLights(glVertex *P, pvr_vertex_t *v, GLuint count); + +/* Vertex Position Submission Internal Functions */ +void _glKosVertex2ft(GLfloat x, GLfloat y); +void _glKosVertex2ftv(GLfloat *xy); +void _glKosVertex3ft(GLfloat x, GLfloat y, GLfloat z); +void _glKosVertex3ftv(GLfloat *xyz); +void _glKosVertex3fc(GLfloat x, GLfloat y, GLfloat z); +void _glKosVertex3fcv(GLfloat *xyz); +void _glKosVertex3fp(GLfloat x, GLfloat y, GLfloat z); +void _glKosVertex3fpv(GLfloat *xyz); +void _glKosVertex3fl(GLfloat x, GLfloat y, GLfloat z); +void _glKosVertex3flv(GLfloat *xyz); +void _glKosVertex3flc(GLfloat x, GLfloat y, GLfloat z); +void _glKosVertex3flcv(GLfloat *xyz); +void _glKosVertex3fs(GLfloat x, GLfloat y, GLfloat z); +void _glKosVertex3fsv(GLfloat *xyz); + +/* Matrix Internal Functions */ +void _glKosInitMatrix(); +void _glKosMatrixLoadModelView(); +void _glKosMatrixLoadModelRot(); +void _glKosMatrixApplyScreenSpace(); +void _glKosMatrixApplyRender(); +void _glKosMatrixLoadRender(); + +/* API Enabled Capabilities Internal Functions */ +GLint _glKosEnabledTexture2D(); +GLubyte _glKosEnabledNearZClip(); +GLubyte _glKosEnabledLighting(); + +/* RGB Pixel Colorspace Internal Functions */ +uint16 __glKosAverageQuadPixelRGB565(uint16 p1, uint16 p2, uint16 p3, uint16 p4); +uint16 __glKosAverageQuadPixelARGB1555(uint16 p1, uint16 p2, uint16 p3, uint16 p4); +uint16 __glKosAverageQuadPixelARGB4444(uint16 p1, uint16 p2, uint16 p3, uint16 p4); +uint16 __glKosAverageBiPixelRGB565(uint16 p1, uint16 p2); +uint16 __glKosAverageBiPixelARGB1555(uint16 p1, uint16 p2); +uint16 __glKosAverageBiPixelARGB4444(uint16 p1, uint16 p2); + +#endif diff --git a/gl-arrays.c b/gl-arrays.c new file mode 100755 index 0000000..c7d2158 --- /dev/null +++ b/gl-arrays.c @@ -0,0 +1,1039 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-arrays.c + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + Arrays Input Primitive Types Supported: + -GL_TRIANGLES + -GL_TRIANGLE_STRIPS + -GL_QUADS + + Here, it is not necessary to enable or disable client states; + the API is aware of what pointers have been submitted, and will + render accordingly. If you submit a normal pointer, dynamic + vertex lighting will be applied even if you submit a color + pointer, so only submit one or the other. +*/ + +#include +#include + +#include "gl.h" +#include "gl-api.h" +#include "gl-arrays.h" +#include "gl-rgb.h" +#include "gl-sh4.h" + +//========================================================================================// +//== Local Variables ==// + +#define GL_MAX_ARRAY_VERTICES 1024*32 /* Maximum Number of Vertices in the Array Buffer */ +static glVertex GL_ARRAY_BUF[GL_MAX_ARRAY_VERTICES]; +static GLfloat GL_ARRAY_BUFW[GL_MAX_ARRAY_VERTICES]; +static GLfloat GL_ARRAY_DSTW[GL_MAX_ARRAY_VERTICES]; +static glVertex *GL_ARRAY_BUF_PTR; +static GLuint GL_VERTEX_PTR_MODE = 0; + +//========================================================================================// +//== Multi-Texture Extensions ==// + +#define GL_TEXTURE_0 1<<0 +#define GL_TEXTURE_1 1<<1 + +static GLuint GL_ARRAY_TEXTURE_ENABLED = 0; +static GLuint GL_ARRAY_ACTIVE_TEXTURE = 0; + +void glClientActiveTexture(GLenum texture) { + if(texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + GL_MAX_TEXTURE_UNITS) + return; + + GL_ARRAY_ACTIVE_TEXTURE = ((texture & 0xFF) - (GL_TEXTURE0 & 0xFF)); + + return glActiveTexture(texture); +} + +static inline void _glKosArrayCopyMultiTexture(GLuint count) { + if(GL_ARRAY_TEXTURE_ENABLED == 3) { + pvr_vertex_t *dst = _glKosTRVertexBufPointer(); + pvr_vertex_t *src = _glKosVertexBufPointer(); + GLuint i; + + for(i = 0; i < count; i++) { + dst[i].x = src[i].x; + dst[i].y = src[i].y; + dst[i].z = src[i].z; + dst[i].argb = src[i].argb; + dst[i].flags = src[i].flags; + + dst[i].u = GL_TEXCOORD2_POINTER[0]; + dst[i].v = GL_TEXCOORD2_POINTER[1]; + GL_TEXCOORD2_POINTER += GL_TEXCOORD2_STRIDE; + } + + _glKosTRVertexBufAdd(count); + } +} + +static inline void _glKosArrayCopyMultiTextureQuads(GLuint count) { + if(GL_ARRAY_TEXTURE_ENABLED == 3) { + pvr_vertex_t *dst = _glKosTRVertexBufPointer(); + pvr_vertex_t *src = _glKosVertexBufPointer(); + GLuint i; + + for(i = 0; i < count; i += 4) { + /* 1st Vertex */ + dst[i].x = src[i].x; + dst[i].y = src[i].y; + dst[i].z = src[i].z; + dst[i].argb = src[i].argb; + dst[i].flags = src[i].flags; + + dst[i].u = GL_TEXCOORD2_POINTER[0]; + dst[i].v = GL_TEXCOORD2_POINTER[1]; + GL_TEXCOORD2_POINTER += GL_TEXCOORD2_STRIDE; + + /* 2nd Vertex */ + dst[i + 1].x = src[i + 1].x; + dst[i + 1].y = src[i + 1].y; + dst[i + 1].z = src[i + 1].z; + dst[i + 1].argb = src[i + 1].argb; + dst[i + 1].flags = src[i + 1].flags; + + dst[i + 1].u = GL_TEXCOORD2_POINTER[0]; + dst[i + 1].v = GL_TEXCOORD2_POINTER[1]; + GL_TEXCOORD2_POINTER += GL_TEXCOORD2_STRIDE; + + /* 3rd Vertex */ + dst[i + 2].x = src[i + 2].x; + dst[i + 2].y = src[i + 2].y; + dst[i + 2].z = src[i + 2].z; + dst[i + 2].argb = src[i + 2].argb; + dst[i + 2].flags = src[i + 2].flags; + + dst[i + 3].u = GL_TEXCOORD2_POINTER[0]; + dst[i + 3].v = GL_TEXCOORD2_POINTER[1]; + GL_TEXCOORD2_POINTER += GL_TEXCOORD2_STRIDE; + + /* 4th Vertex */ + dst[i + 3].x = src[i + 3].x; + dst[i + 3].y = src[i + 3].y; + dst[i + 3].z = src[i + 3].z; + dst[i + 3].argb = src[i + 3].argb; + dst[i + 3].flags = src[i + 3].flags; + + dst[i + 2].u = GL_TEXCOORD2_POINTER[0]; + dst[i + 2].v = GL_TEXCOORD2_POINTER[1]; + GL_TEXCOORD2_POINTER += GL_TEXCOORD2_STRIDE; + } + + _glKosTRVertexBufAdd(count); + } +} + +//========================================================================================// +//== Local Function Definitions ==// + +static inline void _glKosArraysTransformNormals(GLfloat *normal, GLuint count); +static inline void _glKosArraysTransformPositions(GLfloat *position, GLuint count); + +//========================================================================================// +//== Open GL API Public Functions ==// + +/* Submit a Vertex Position Pointer */ +void glVertexPointer(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer) { + if(size != 3) return; /* Expect 3D X,Y,Z vertex... could do 2d X,Y later */ + + if(type != GL_FLOAT) return; /* Expect Floating point vertices */ + + (stride) ? (GL_VERTEX_STRIDE = stride / 4) : (GL_VERTEX_STRIDE = 3); + + GL_VERTEX_POINTER = (float *)pointer; + + GL_VERTEX_PTR_MODE |= GL_USE_ARRAY; +} + +/* Submit a Vertex Normal Pointer */ +void glNormalPointer(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer) { + if(size != 3) return; + + if(type != GL_FLOAT) return; /* Expect Floating point vertices */ + + (stride) ? (GL_NORMAL_STRIDE = stride / 4) : (GL_NORMAL_STRIDE = 3); + + GL_NORMAL_POINTER = (float *)pointer; + + GL_VERTEX_PTR_MODE |= GL_USE_NORMAL; +} + +/* Submit a Texture Coordinate Pointer */ +void glTexCoordPointer(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer) { + if(size != 2) return; /* Expect u and v */ + + if(type != GL_FLOAT) return; /* Expect Floating point vertices */ + + if(GL_ARRAY_ACTIVE_TEXTURE == 0) { + (stride) ? (GL_TEXCOORD_STRIDE = stride / 4) : (GL_TEXCOORD_STRIDE = 2); + + GL_TEXCOORD_POINTER = (float *)pointer; + + GL_VERTEX_PTR_MODE |= GL_USE_TEXTURE; + + GL_ARRAY_TEXTURE_ENABLED |= GL_TEXTURE_0; + } + else if(GL_ARRAY_ACTIVE_TEXTURE == 1) { + (stride) ? (GL_TEXCOORD2_STRIDE = stride / 4) : (GL_TEXCOORD2_STRIDE = 2); + + GL_TEXCOORD2_POINTER = (float *)pointer; + + GL_ARRAY_TEXTURE_ENABLED |= GL_TEXTURE_1; + } +} + +/* Submit a Color Pointer */ +void glColorPointer(GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer) { + if((type == GL_UNSIGNED_INT) && (size == 1)) { + GL_COLOR_COMPONENTS = 1; + GL_COLOR_POINTER = (GLvoid *)pointer; + GL_COLOR_TYPE = type; + } + else if((type == GL_UNSIGNED_BYTE) && (size == 4)) { + GL_COLOR_COMPONENTS = 4; + GL_COLOR_POINTER = (GLvoid *)pointer; + GL_COLOR_TYPE = type; + } + else if((type == GL_FLOAT) && (size == 3)) { + GL_COLOR_COMPONENTS = 3; + GL_COLOR_POINTER = (GLfloat *)pointer; + GL_COLOR_TYPE = type; + } + else if((type == GL_FLOAT) && (size == 4)) { + GL_COLOR_COMPONENTS = 4; + GL_COLOR_POINTER = (GLfloat *)pointer; + GL_COLOR_TYPE = type; + } + else + return; + + (stride) ? (GL_COLOR_STRIDE = stride / 4) : (GL_COLOR_STRIDE = size); + + GL_VERTEX_PTR_MODE |= GL_USE_COLOR; +} +//========================================================================================// +//== Vertex Pointer Internal API ==// + +inline void _glKosArrayBufIncrement() { + ++GL_ARRAY_BUF_PTR; +} + +inline void _glKosArrayBufReset() { + GL_ARRAY_BUF_PTR = &GL_ARRAY_BUF[0]; +} + +inline glVertex *_glKosArrayBufAddr() { + return &GL_ARRAY_BUF[0]; +} + +inline glVertex *_glKosArrayBufPtr() { + return GL_ARRAY_BUF_PTR; +} + +static inline void _glKosArraysTransformNormals(GLfloat *normal, GLuint count) { + glVertex *v = &GL_ARRAY_BUF[0]; + GLfloat *N = normal; + + _glKosMatrixLoadModelRot(); + + while(count--) { + mat_trans_normal3_nomod(N[0], N[1], N[2], v->norm[0], v->norm[1], v->norm[2]); + N += 3; + ++v; + } +} + +static inline void _glKosArraysTransformPositions(GLfloat *position, GLuint count) { + glVertex *v = &GL_ARRAY_BUF[0]; + GLfloat *P = position; + + _glKosMatrixLoadModelView(); + + while(count--) { + mat_trans_single3_nodiv_nomod(P[0], P[1], P[2], v->pos[0], v->pos[1], v->pos[2]); + P += 3; + ++v; + } +} + +//========================================================================================// +//== Arrays Vertex Transform ==/ + +static void _glKosArraysTransform(GLuint count) { + GLfloat *src = GL_VERTEX_POINTER; + pvr_vertex_t *dst = _glKosVertexBufPointer(); + + register float __x __asm__("fr12"); + register float __y __asm__("fr13"); + register float __z __asm__("fr14"); + + while(count--) { + __x = *src++; + __y = *src++; + __z = *src++; + + mat_trans_fv12() + + dst->x = __x; + dst->y = __y; + dst->z = __z; + + ++dst; + } +} + +static void _glKosArraysTransformClip(GLuint count) { + GLfloat *src = GL_VERTEX_POINTER; + GLfloat *W = GL_ARRAY_DSTW; + pvr_vertex_t *dst = _glKosClipBufAddress(); + + register float __x __asm__("fr12"); + register float __y __asm__("fr13"); + register float __z __asm__("fr14"); + register float __w __asm__("fr15"); + + while(count--) { + __x = *src++; + __y = *src++; + __z = *src++; + + mat_trans_fv12_nodivw() + + dst->x = __x; + dst->y = __y; + dst->z = __z; + *W++ = __w; + ++dst; + } +} + +static void _glKosArraysTransformElements(GLuint count) { + GLfloat *src = GL_VERTEX_POINTER; + GLuint i = 0; + + register float __x __asm__("fr12"); + register float __y __asm__("fr13"); + register float __z __asm__("fr14"); + + printf("Transform Elements()\n"); + + for(i = 0; i < count; i++) { + __x = src[0]; + __y = src[1]; + __z = src[2]; + + mat_trans_fv12() + + GL_ARRAY_BUF[i].pos[0] = __x; + GL_ARRAY_BUF[i].pos[1] = __y; + GL_ARRAY_BUF[i].pos[2] = __z; + + src += GL_VERTEX_STRIDE; + } +} + +static void _glKosArraysTransformClipElements(GLuint count) { + GLfloat *src = GL_VERTEX_POINTER; + GLuint i; + + register float __x __asm__("fr12"); + register float __y __asm__("fr13"); + register float __z __asm__("fr14"); + register float __w __asm__("fr15"); + + for(i = 0; i < count; i++) { + __x = src[0]; + __y = src[1]; + __z = src[2]; + + mat_trans_fv12_nodivw() + + GL_ARRAY_BUF[i].pos[0] = __x; + GL_ARRAY_BUF[i].pos[1] = __y; + GL_ARRAY_BUF[i].pos[2] = __z; + GL_ARRAY_BUFW[i] = __w; + + src += GL_VERTEX_STRIDE; + } +} + +//========================================================================================// +//== Element Attribute Functions ==// + +//== Color ==// + +static inline void _glKosElementColor0(pvr_vertex_t *dst, GLuint count) { + GLuint i; + + for(i = 0; i < count; i++) + dst[i].argb = 0xFFFFFFFF; +} + +static inline void _glKosElementColor1uiU8(pvr_vertex_t *dst, GLuint count) { + GLuint i; + GLuint *src = (GLuint *)GL_COLOR_POINTER; + + for(i = 0; i < count; i++) + dst[i].argb = src[GL_INDEX_POINTER_U8[i] * GL_COLOR_STRIDE]; +} + +static inline void _glKosElementColor1uiU16(pvr_vertex_t *dst, GLuint count) { + GLuint i; + GLuint *color = (GLuint *)GL_COLOR_POINTER; + + for(i = 0; i < count; i++) + dst[i].argb = color[GL_INDEX_POINTER_U16[i] * GL_COLOR_STRIDE]; +} + +static inline void _glKosElementColor4ubU8(pvr_vertex_t *dst, GLuint count) { + GLuint i, *color = (GLuint *)GL_COLOR_POINTER; + + for(i = 0; i < count; i++) + dst[i].argb = RGBA32_2_ARGB32(color[GL_INDEX_POINTER_U8[i]] * GL_COLOR_STRIDE); +} + +static inline void _glKosElementColor4ubU16(pvr_vertex_t *dst, GLuint count) { + GLuint i, *color = (GLuint *)GL_COLOR_POINTER; + + for(i = 0; i < count; i++) + dst[i].argb = RGBA32_2_ARGB32(color[GL_INDEX_POINTER_U16[i] * GL_COLOR_STRIDE]); +} + +static inline void _glKosElementColor3fU8(pvr_vertex_t *dst, GLuint count) { + GLuint i, index; + GLrgb3f *color = (GLrgb3f *)GL_COLOR_POINTER; + + for(i = 0; i < count; i++) { + index = GL_INDEX_POINTER_U8[i] * GL_COLOR_STRIDE; + dst[i].argb = (0xFF000000 | ((GLubyte)color[index][0] * 0xFF) << 16 + | ((GLubyte)color[index][1] * 0xFF) << 8 + | ((GLubyte)color[index][2] * 0xFF)); + } +} + +static inline void _glKosElementColor3fU16(pvr_vertex_t *dst, GLuint count) { + GLuint i, index; + GLrgb3f *color = (GLrgb3f *)GL_COLOR_POINTER; + + for(i = 0; i < count; i++) { + index = GL_INDEX_POINTER_U16[i] * GL_COLOR_STRIDE; + dst[i].argb = (0xFF000000 | ((GLubyte)color[index][0] * 0xFF) << 16 + | ((GLubyte)color[index][1] * 0xFF) << 8 + | ((GLubyte)color[index][2] * 0xFF)); + } +} + +static inline void _glKosElementColor4fU8(pvr_vertex_t *dst, GLuint count) { + GLuint i, index; + GLrgba4f *color = (GLrgba4f *)GL_COLOR_POINTER; + + for(i = 0; i < count; i++) { + index = GL_INDEX_POINTER_U8[i] * GL_COLOR_STRIDE; + dst[i].argb = (((GLubyte)color[index][3] * 0xFF) << 24 + | ((GLubyte)color[index][0] * 0xFF) << 16 + | ((GLubyte)color[index][1] * 0xFF) << 8 + | ((GLubyte)color[index][2] * 0xFF)); + } +} + +static inline void _glKosElementColor4fU16(pvr_vertex_t *dst, GLuint count) { + GLuint i, index; + GLrgba4f *color = (GLrgba4f *)GL_COLOR_POINTER; + + for(i = 0; i < count; i++) { + index = GL_INDEX_POINTER_U16[i] * GL_COLOR_STRIDE; + dst[i].argb = (((GLubyte)color[index][3] * 0xFF) << 24 + | ((GLubyte)color[index][0] * 0xFF) << 16 + | ((GLubyte)color[index][1] * 0xFF) << 8 + | ((GLubyte)color[index][2] * 0xFF)); + } +} + +//== Texture Coordinates ==// + +static inline void _glKosElementTexCoord2fU16(pvr_vertex_t *dst, GLuint count) { + GLuint i, index; + GLfloat *t = GL_TEXCOORD_POINTER; + + for(i = 0; i < count; i++) { + index = GL_INDEX_POINTER_U16[i] * GL_TEXCOORD_STRIDE; + dst[i].u = t[index]; + dst[i].v = t[index + 1]; + } +} + +static inline void _glKosElementTexCoord2fU8(pvr_vertex_t *dst, GLuint count) { + GLuint i, index; + GLfloat *t = GL_TEXCOORD_POINTER; + + for(i = 0; i < count; i++) { + index = GL_INDEX_POINTER_U8[i] * GL_TEXCOORD_STRIDE; + dst[i].u = t[index]; + dst[i].v = t[index + 1]; + } +} + +//========================================================================================// +//== Element Unpacking ==// + +static inline void _glKosArraysUnpackElementsS16(pvr_vertex_t *dst, GLuint count) { + glVertex *vert = GL_ARRAY_BUF; + GLuint i; + + for(i = 0; i < count; i++) { + dst[i].x = vert[GL_INDEX_POINTER_U16[i]].pos[0]; + dst[i].y = vert[GL_INDEX_POINTER_U16[i]].pos[1]; + dst[i].z = vert[GL_INDEX_POINTER_U16[i]].pos[2]; + } +} + +static inline void _glKosArraysUnpackElementsS8(pvr_vertex_t *dst, GLuint count) { + glVertex *vert = GL_ARRAY_BUF; + GLuint i; + + for(i = 0; i < count; i++) { + dst[i].x = vert[GL_INDEX_POINTER_U8[i]].pos[0]; + dst[i].y = vert[GL_INDEX_POINTER_U8[i]].pos[1]; + dst[i].z = vert[GL_INDEX_POINTER_U8[i]].pos[2]; + } +} + +static inline void _glKosArraysUnpackClipElementsS16(pvr_vertex_t *dst, GLuint count) { + glVertex *vert = GL_ARRAY_BUF; + GLuint i; + + for(i = 0; i < count; i++) { + dst[i].x = vert[GL_INDEX_POINTER_U16[i]].pos[0]; + dst[i].y = vert[GL_INDEX_POINTER_U16[i]].pos[1]; + dst[i].z = vert[GL_INDEX_POINTER_U16[i]].pos[2]; + GL_ARRAY_DSTW[i] = GL_ARRAY_BUFW[GL_INDEX_POINTER_U16[i]]; + } +} + +static inline void _glKosArraysUnpackClipElementsS8(pvr_vertex_t *dst, GLuint count) { + glVertex *vert = GL_ARRAY_BUF; + GLuint i; + + for(i = 0; i < count; i++) { + dst[i].x = vert[GL_INDEX_POINTER_U8[i]].pos[0]; + dst[i].y = vert[GL_INDEX_POINTER_U8[i]].pos[1]; + dst[i].z = vert[GL_INDEX_POINTER_U8[i]].pos[2]; + GL_ARRAY_DSTW[i] = GL_ARRAY_BUFW[GL_INDEX_POINTER_U8[i]]; + } +} + +//========================================================================================// +//== Misc Utils ==// + +static inline void _glKosVertexSwizzle(pvr_vertex_t *v1, pvr_vertex_t *v2) { + pvr_vertex_t tmp = *v1; + *v1 = *v2; + *v2 = * &tmp; +} + +static inline void _glKosArraysResetState() { + GL_VERTEX_PTR_MODE = 0; + + if(GL_ARRAY_TEXTURE_ENABLED == 3) + _glKosResetEnabledTex(); + + GL_ARRAY_TEXTURE_ENABLED = GL_ARRAY_ACTIVE_TEXTURE = 0; +} + +//========================================================================================// +//== Vertex Flag Settings for the PVR2DC hardware ==// + +static inline void _glKosArrayFlagsSetQuad(pvr_vertex_t *dst, GLuint count) { + GLuint i; + + for(i = 0; i < count; i += 4) { + _glKosVertexSwizzle(&dst[2], &dst[3]); + dst[i + 0].flags = dst[i + 1].flags = dst[i + 2].flags = PVR_CMD_VERTEX; + dst[i + 3].flags = PVR_CMD_VERTEX_EOL; + } +} + +static inline void _glKosArrayFlagsSetTriangle(pvr_vertex_t *dst, GLuint count) { + GLuint i; + + for(i = 0; i < count; i += 3) { + dst[i + 0].flags = dst[i + 1].flags = PVR_CMD_VERTEX; + dst[i + 2].flags = PVR_CMD_VERTEX_EOL; + } +} + +static inline void _glKosArrayFlagsSetTriangleStrip(pvr_vertex_t *dst, GLuint count) { + GLuint i; + + for(i = 0; i < count - 1; i++) + dst[i].flags = PVR_CMD_VERTEX; + + dst[i].flags = PVR_CMD_VERTEX_EOL; +} + +//========================================================================================// +//== OpenGL Error Code Genration ==// + +static GLuint _glKosArraysVerifyParameter(GLenum mode, GLsizei count, GLenum type, GLubyte element) { + GLuint GL_ERROR_CODE = 0; + + if(mode != GL_QUADS) + if(mode != GL_TRIANGLES) + if(mode != GL_TRIANGLE_STRIP) + GL_ERROR_CODE |= GL_INVALID_ENUM; + + if(count < 0) + GL_ERROR_CODE |= GL_INVALID_VALUE; + + if(!(GL_VERTEX_PTR_MODE & GL_USE_ARRAY)) + GL_ERROR_CODE |= GL_INVALID_OPERATION; + + if(count > GL_MAX_ARRAY_VERTICES) + GL_ERROR_CODE |= GL_OUT_OF_MEMORY; + + if(element) { + switch(type) { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT: + break; + + default: + GL_ERROR_CODE |= GL_INVALID_ENUM; + } + } + else if(type > count) + GL_ERROR_CODE |= GL_INVALID_VALUE; + + return GL_ERROR_CODE; +} + +void _glKosPrintErrorString(GLuint error) { + if(error) { + printf("GL_ERROR_CODE GENERATED:\n"); + + if(error & GL_INVALID_ENUM) + printf("\tGL_INVALID_ENUM\n"); + + if(error & GL_INVALID_VALUE) + printf("\tGL_INVALID_VALUE\n"); + + if(error & GL_INVALID_OPERATION) + printf("\tGL_INVALID__OPERATION\n"); + + if(error & GL_OUT_OF_MEMORY) + printf("\tGL_OUT_OF_MEMORY\n"); + } +} + +//========================================================================================// +//== OpenGL Elemental Array Submission ==// + +void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) { + /* Before we process the vertex data, ensure all parameters are valid */ + GLuint error = _glKosArraysVerifyParameter(mode, count, type, 1); + + if(error) { + _glKosPrintErrorString(error); + + _glKosArraysResetState(); + + return; + } + + switch(type) { + case GL_UNSIGNED_BYTE: + GL_INDEX_POINTER_U8 = (GLubyte *)indices; + break; + + case GL_UNSIGNED_SHORT: + GL_INDEX_POINTER_U16 = (GLushort *)indices; + break; + } + + /* Compile the PVR polygon context with the currently enabled flags */ + if((GL_VERTEX_PTR_MODE & GL_USE_TEXTURE)) + _glKosCompileHdrTx(); + else + _glKosCompileHdr(); + + if(GL_ARRAY_TEXTURE_ENABLED == 3) /* Multi-Texture! */ + _glKosCompileHdrTx2(); + + pvr_vertex_t *dst; /* Destination of Output Vertex Array */ + + if(_glKosEnabledNearZClip()) + dst = _glKosClipBufAddress(); + else + dst = _glKosVertexBufPointer(); + + /* Check if Vertex Lighting is enabled. Else, check for Color Submission */ + if((GL_VERTEX_PTR_MODE & GL_USE_NORMAL) && _glKosEnabledLighting()) { + _glKosArraysTransformNormals(GL_NORMAL_POINTER, count); + _glKosArraysTransformPositions(GL_VERTEX_POINTER, count); + _glKosVertexLights(GL_ARRAY_BUF, dst, count); + } + else if(GL_VERTEX_PTR_MODE & GL_USE_COLOR) { + switch(GL_COLOR_TYPE) { + case GL_FLOAT: + switch(GL_COLOR_COMPONENTS) { + case 3: + switch(type) { + case GL_UNSIGNED_BYTE: + _glKosElementColor3fU8(dst, count); + break; + + case GL_UNSIGNED_SHORT: + _glKosElementColor3fU16(dst, count); + break; + } + + break; + + case 4: + switch(type) { + case GL_UNSIGNED_BYTE: + _glKosElementColor4fU8(dst, count); + break; + + case GL_UNSIGNED_SHORT: + _glKosElementColor4fU16(dst, count); + break; + } + + break; + } + + break; + + case GL_UNSIGNED_INT: + if(GL_COLOR_COMPONENTS == 1) + switch(type) { + case GL_UNSIGNED_BYTE: + _glKosElementColor1uiU8(dst, count); + break; + + case GL_UNSIGNED_SHORT: + _glKosElementColor1uiU16(dst, count); + break; + } + + break; + + case GL_UNSIGNED_BYTE: + if(GL_COLOR_COMPONENTS == 4) + switch(type) { + case GL_UNSIGNED_BYTE: + _glKosElementColor4ubU8(dst, count); + break; + + case GL_UNSIGNED_SHORT: + _glKosElementColor4ubU16(dst, count); + break; + } + + break; + } + } + else + _glKosElementColor0(dst, count); /* No colors bound, color white */ + + /* Check if Texture Coordinates are enabled */ + if((GL_VERTEX_PTR_MODE & GL_USE_TEXTURE) && (_glKosEnabledTexture2D() >= 0)) + switch(type) { + case GL_UNSIGNED_BYTE: + _glKosElementTexCoord2fU8(dst, count); + break; + + case GL_UNSIGNED_SHORT: + _glKosElementTexCoord2fU16(dst, count); + break; + } + + _glKosMatrixApplyRender(); /* Apply the Render Matrix Stack */ + + if(!(_glKosEnabledNearZClip())) {/* Transform the element vertices */ + /* Transform vertices with perspective divde */ + _glKosArraysTransformElements(count); + + /* Unpack the indexed positions into primitives for rasterization */ + switch(type) { + case GL_UNSIGNED_BYTE: + _glKosArraysUnpackElementsS8(dst, count); + break; + + case GL_UNSIGNED_SHORT: + _glKosArraysUnpackElementsS16(dst, count); + break; + } + + /* Set the vertex flags for use with the PVR */ + switch(mode) { + case GL_QUADS: + _glKosArrayFlagsSetQuad(dst, count); + break; + + case GL_TRIANGLES: + _glKosArrayFlagsSetTriangle(dst, count); + break; + + case GL_TRIANGLE_STRIP: + _glKosArrayFlagsSetTriangleStrip(dst, count); + break; + } + + if(mode == GL_QUADS) + _glKosArrayCopyMultiTextureQuads(count); + else + _glKosArrayCopyMultiTexture(count); + } + else { + /* Transform vertices with no perspective divde, store w component */ + _glKosArraysTransformClipElements(count); + + /* Unpack the indexed positions into primitives for rasterization */ + switch(type) { + case GL_UNSIGNED_BYTE: + _glKosArraysUnpackClipElementsS8(dst, count); + break; + + case GL_UNSIGNED_SHORT: + _glKosArraysUnpackClipElementsS16(dst, count); + break; + } + + /* Finally, clip the input vertex data into the output vertex buffer */ + switch(mode) { + case GL_TRIANGLES: + count = _glKosClipTrianglesTransformed(dst, GL_ARRAY_DSTW, + (pvr_vertex_t *)_glKosVertexBufPointer(), count); + break; + + case GL_QUADS: + count = _glKosClipQuadsTransformed(dst, GL_ARRAY_DSTW, + (pvr_vertex_t *)_glKosVertexBufPointer(), count); + + break; + + case GL_TRIANGLE_STRIP: + count = _glKosClipTriangleStripTransformed(dst, GL_ARRAY_DSTW, + (pvr_vertex_t *)_glKosVertexBufPointer(), count); + break; + } + } + + _glKosVertexBufAdd(count); + + _glKosArraysResetState(); +} + + + +//========================================================================================// +//== Array Attribute Functions ==// + +//== Color ==// + +static inline void _glKosArrayColor0(pvr_vertex_t *dst, GLuint count) { + GLuint i; + + for(i = 0; i < count; i++) + dst[i].argb = 0xFFFFFFFF; +} + +static inline void _glKosArrayColor1ui(pvr_vertex_t *dst, GLuint count) { + GLuint i; + GLuint *color = (GLuint *)GL_COLOR_POINTER; + + for(i = 0; i < count; i++) { + dst[i].argb = *color; + color += GL_COLOR_STRIDE; + } +} + +static inline void _glKosArrayColor4ub(pvr_vertex_t *dst, GLuint count) { + GLuint i, *color = (GLuint *)GL_COLOR_POINTER; + + for(i = 0; i < count; i++) { + dst[i].argb = RGBA32_2_ARGB32(*color); + color += GL_COLOR_STRIDE; + } +} + +static inline void _glKosArrayColor3f(pvr_vertex_t *dst, GLuint count) { + GLuint i; + GLfloat *color = (GLfloat *)GL_COLOR_POINTER; + + for(i = 0; i < count; i++) { + dst[i].argb = (0xFF000000 | ((GLubyte)(color[0] * 0xFF)) << 16 + | ((GLubyte)(color[1] * 0xFF)) << 8 + | ((GLubyte)(color[2] * 0xFF))); + color += GL_COLOR_STRIDE; + } +} + +static inline void _glKosArrayColor4f(pvr_vertex_t *dst, GLuint count) { + GLuint i; + GLfloat *color = (GLfloat *)GL_COLOR_POINTER; + + for(i = 0; i < count; i++) { + dst[i].argb = (((GLubyte)(color[3] * 0xFF)) << 24 + | ((GLubyte)(color[0] * 0xFF)) << 16 + | ((GLubyte)(color[1] * 0xFF)) << 8 + | ((GLubyte)(color[2] * 0xFF))); + color += GL_COLOR_STRIDE; + } +} + +//== Texture Coordinates ==// + +static inline void _glKosArrayTexCoord2f(pvr_vertex_t *dst, GLuint count) { + GLuint i; + GLfloat *uv = GL_TEXCOORD_POINTER; + + for(i = 0; i < count; i++) { + dst[i].u = uv[0]; + dst[i].v = uv[1]; + uv += GL_TEXCOORD_STRIDE; + } +} + +//========================================================================================// +//== Openg GL Draw Arrays ==// + +void glDrawArrays(GLenum mode, GLint first, GLsizei count) { + /* Before we process the vertex data, ensure all parameters are valid */ + GLuint error = _glKosArraysVerifyParameter(mode, count, first, 0); + + if(error) { + _glKosPrintErrorString(error); + + return _glKosArraysResetState(); + } + + GL_VERTEX_POINTER += first; /* Add Pointer Offset */ + GL_TEXCOORD_POINTER += first; + GL_COLOR_POINTER += first; + GL_NORMAL_POINTER += first; + + /* Compile the PVR polygon context with the currently enabled flags */ + if((GL_VERTEX_PTR_MODE & GL_USE_TEXTURE)) + _glKosCompileHdrTx(); + else + _glKosCompileHdr(); + + if(GL_ARRAY_TEXTURE_ENABLED == 3) /* Multi-Texture! */ + _glKosCompileHdrTx2(); + + pvr_vertex_t *dst; /* Destination of Output Vertex Array */ + + if(_glKosEnabledNearZClip()) + dst = _glKosClipBufAddress(); + else + dst = _glKosVertexBufPointer(); + + /* Check if Vertex Lighting is enabled. Else, check for Color Submission */ + if((GL_VERTEX_PTR_MODE & GL_USE_NORMAL) && _glKosEnabledLighting()) { + _glKosArraysTransformNormals(GL_NORMAL_POINTER, count); + _glKosArraysTransformPositions(GL_VERTEX_POINTER, count); + _glKosVertexLights(GL_ARRAY_BUF, dst, count); + } + else if(GL_VERTEX_PTR_MODE & GL_USE_COLOR) { + switch(GL_COLOR_TYPE) { + case GL_FLOAT: + switch(GL_COLOR_COMPONENTS) { + case 3: + _glKosArrayColor3f(dst, count); + break; + + case 4: + _glKosArrayColor4f(dst, count); + break; + } + + break; + + case GL_UNSIGNED_INT: + if(GL_COLOR_COMPONENTS == 1) + _glKosArrayColor1ui(dst, count); + + break; + + case GL_UNSIGNED_BYTE: + if(GL_COLOR_COMPONENTS == 4) + _glKosArrayColor4ub(dst, count); + + break; + } + } + else + _glKosArrayColor0(dst, count); /* No colors bound, color white */ + + /* Check if Texture Coordinates are enabled */ + if((GL_VERTEX_PTR_MODE & GL_USE_TEXTURE) && (_glKosEnabledTexture2D() >= 0)) + _glKosArrayTexCoord2f(dst, count); + + _glKosMatrixApplyRender(); /* Apply the Render Matrix Stack */ + + if(!_glKosEnabledNearZClip()) { + /* Transform Vertex Positions */ + _glKosArraysTransform(count); + + /* Set the vertex flags for use with the PVR */ + switch(mode) { + case GL_QUADS: + _glKosArrayFlagsSetQuad(dst, count); + break; + + case GL_TRIANGLES: + _glKosArrayFlagsSetTriangle(dst, count); + break; + + case GL_TRIANGLE_STRIP: + _glKosArrayFlagsSetTriangleStrip(dst, count); + break; + } + + if(mode == GL_QUADS) + _glKosArrayCopyMultiTextureQuads(count); + else + _glKosArrayCopyMultiTexture(count); + } + else { + /* Transform vertices with no perspective divde, store w component */ + _glKosArraysTransformClip(count); + + /* Finally, clip the input vertex data into the output vertex buffer */ + switch(mode) { + case GL_TRIANGLES: + count = _glKosClipTrianglesTransformed(dst, GL_ARRAY_DSTW, + (pvr_vertex_t *)_glKosVertexBufPointer(), count); + break; + + case GL_QUADS: + count = _glKosClipQuadsTransformed(dst, GL_ARRAY_DSTW, + (pvr_vertex_t *)_glKosVertexBufPointer(), count); + + break; + + case GL_TRIANGLE_STRIP: + count = _glKosClipTriangleStripTransformed(dst, GL_ARRAY_DSTW, + (pvr_vertex_t *)_glKosVertexBufPointer(), count); + break; + } + } + + _glKosVertexBufAdd(count); + + _glKosArraysResetState(); +} \ No newline at end of file diff --git a/gl-arrays.h b/gl-arrays.h new file mode 100755 index 0000000..d514169 --- /dev/null +++ b/gl-arrays.h @@ -0,0 +1,58 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-arrays.h + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + Arrays Input Primitive Types Supported: + -GL_TRIANGLES + -GL_TRIANGLE_STRIPS + -GL_QUADS + + Here, it is not necessary to enable or disable client states; + the API is aware of what arrays have been submitted, and will + render accordingly. If you submit a normal pointer, dynamic + vertex lighting will be applied even if you submit a color + pointer, so only submit one or the other. + + ToDo: glDrawElements() is not yet implemented. +*/ + +#ifndef GL_ARRAYS_H +#define GL_ARRAYS_H + +#include "gl.h" + +#define GL_USE_ARRAY 0x0001 +#define GL_USE_TEXTURE 0x0010 +#define GL_USE_COLOR 0x0100 +#define GL_USE_NORMAL 0x1000 +#define GL_USE_TEXTURE_COLOR 0x0111 +#define GL_USE_TEXTURE_LIT 0x1011 + +void (*_glKosArrayTexCoordFunc)(pvr_vertex_t *); +void (*_glKosArrayColorFunc)(pvr_vertex_t *); + +void (*_glKosElementTexCoordFunc)(pvr_vertex_t *, GLuint); +void (*_glKosElementColorFunc)(pvr_vertex_t *, GLuint); + +static GLfloat *GL_VERTEX_POINTER = NULL; +static GLushort GL_VERTEX_STRIDE = 0; + +static GLfloat *GL_NORMAL_POINTER = NULL; +static GLushort GL_NORMAL_STRIDE = 0; + +static GLfloat *GL_TEXCOORD_POINTER = NULL; +static GLushort GL_TEXCOORD_STRIDE = 0; + +static GLfloat *GL_TEXCOORD2_POINTER = NULL; +static GLushort GL_TEXCOORD2_STRIDE = 0; + +static GLfloat *GL_COLOR_POINTER = NULL; +static GLushort GL_COLOR_STRIDE = 0; +static GLubyte GL_COLOR_COMPONENTS = 0; +static GLenum GL_COLOR_TYPE = 0; + +static GLubyte *GL_INDEX_POINTER_U8 = NULL; +static GLushort *GL_INDEX_POINTER_U16 = NULL; + +#endif diff --git a/gl-clip.c b/gl-clip.c new file mode 100755 index 0000000..b1a704a --- /dev/null +++ b/gl-clip.c @@ -0,0 +1,745 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-clip.c + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + Near-Z Clipping Algorithm (C) 2013-2014 Josh PH3NOM Pearson + Input Primitive Types Supported: + -GL_TRIANGLES + -GL_TRIANGLE_STRIPS + -GL_QUADS + Outputs a mix of Triangles and Triangle Strips for use with the PVR +*/ + +#include +#include + +#include "gl-clip.h" + +static float3 CLIP_BUF[1024 * 32]; + +static inline void glVertexCopy3f(float3 *src, float3 *dst) { + *dst = *src; +} + +static inline void glVertexCopyPVR(pvr_vertex_t *src, pvr_vertex_t *dst) { + *dst = *src; +} + +static inline void _glKosVertexCopyPVR(pvr_vertex_t *src, pvr_vertex_t *dst) { + *dst = *src; +} + +static inline float ZclipMag(float3 *v1, float3 *v2) { + return ((CLIP_NEARZ - v1->z) / (v2->z - v1->z)); +} + +static inline void glVertexClipZNear(pvr_vertex_t *v1, pvr_vertex_t *v2, float MAG) { + colorui *c1 = (colorui *)&v1->argb; + colorui *c2 = (colorui *)&v2->argb; + + v1->x += (v2->x - v1->x) * MAG; + v1->y += (v2->y - v1->y) * MAG; + v1->z += (v2->z - v1->z) * MAG; + v1->u += (v2->u - v1->u) * MAG; + v1->v += (v2->v - v1->v) * MAG; + c1->a += (c2->a - c1->a) * MAG; + c1->r += (c2->r - c1->r) * MAG; + c1->g += (c2->g - c1->g) * MAG; + c1->b += (c2->b - c1->b) * MAG; +} + +static inline void _glKosVertexClipZNear3(pvr_vertex_t *v1, pvr_vertex_t *v2, float *w1, float *w2) { + float MAG = ((CLIP_NEARZ - v1->z) / (v2->z - v1->z)); + + colorui *c1 = (colorui *)&v1->argb; + colorui *c2 = (colorui *)&v2->argb; + + v1->x += (v2->x - v1->x) * MAG; + v1->y += (v2->y - v1->y) * MAG; + v1->z += (v2->z - v1->z) * MAG; + v1->u += (v2->u - v1->u) * MAG; + v1->v += (v2->v - v1->v) * MAG; + c1->a += (c2->a - c1->a) * MAG; + c1->r += (c2->r - c1->r) * MAG; + c1->g += (c2->g - c1->g) * MAG; + c1->b += (c2->b - c1->b) * MAG; + + *w1 += (*w2 - *w1) * MAG; +} + +static GLuint glTransformClip(pvr_vertex_t *v, int count) { + pvr_vertex_t *V = v; + float3 *C = CLIP_BUF; + GLuint in = 0; + + while(count--) { + mat_trans_single3_nodiv_nomod(V->x, V->y, V->z, C->x, C->y, C->z); + + if(C->z < CLIP_NEARZ) ++in; + + ++C; + ++V; + } + + return in; +} + +GLuint _glKosClipTriangleStrip(pvr_vertex_t *vin, pvr_vertex_t *vout, unsigned int vertices) { + GLuint i, v = 0, in = glTransformClip(vin, vertices); + float3 *C = CLIP_BUF; + + if(in == vertices) { + memcpy(vout, vin, vertices * 0x20); + pvr_vertex_t *v = vout; + + while(--in) { + v->flags = PVR_CMD_VERTEX; + ++v; + } + + v->flags = PVR_CMD_VERTEX_EOL; + + return vertices; + } + else if(in == 0) + return 0; + + /* Iterate all Triangles of the Strip - Hence looping vertices-2 times */ + for(i = 0; i < ((vertices) - 2); i++) { + unsigned short int clip = 0; /* Clip Code for current Triangle */ + unsigned char verts_in = 0; /* # of Verteices inside clip plane for current Triangle */ + + C->z >= CLIP_NEARZ ? clip |= FIRST : ++verts_in; + (C + 1)->z >= CLIP_NEARZ ? clip |= SECOND : ++verts_in; + (C + 2)->z >= CLIP_NEARZ ? clip |= THIRD : ++verts_in; + + switch(verts_in) { /* Start by examining # of vertices inside clip plane */ + case 0: /* All Vertices of Triangle are outside of clip plne */ + break; + + case 3: /* All Vertices of Triangle are inside of clip plne */ + memcpy(&vout[v], &vin[i], 96); + + vout[v].flags = vout[v + 1].flags = PVR_CMD_VERTEX; + vout[v + 2].flags = PVR_CMD_VERTEX_EOL; + + v += 3; + break; + + case 1:/* 1 Vertex of Triangle is inside of clip plane = output 1 Triangle */ + memcpy(&vout[v], &vin[i], 96); + + switch(clip) { + case FIRST_TWO_OUT: + glVertexClipZNear(&vout[v], &vout[v + 2], ZclipMag(&CLIP_BUF[i], &CLIP_BUF[i + 2])); + glVertexClipZNear(&vout[v + 1], &vout[v + 2], ZclipMag(&CLIP_BUF[i + 1], &CLIP_BUF[i + 2])); + + break; + + case FIRST_AND_LAST_OUT: + glVertexClipZNear(&vout[v], &vout[v + 1], ZclipMag(&CLIP_BUF[i], &CLIP_BUF[i + 1])); + glVertexClipZNear(&vout[v + 2], &vout[v + 1], ZclipMag(&CLIP_BUF[i + 2], &CLIP_BUF[i + 1])); + + break; + + case LAST_TWO_OUT: + glVertexClipZNear(&vout[v + 1], &vout[v], ZclipMag(&CLIP_BUF[i + 1], &CLIP_BUF[i + 0])); + glVertexClipZNear(&vout[v + 2], &vout[v], ZclipMag(&CLIP_BUF[i + 2], &CLIP_BUF[i + 0])); + + break; + } + + vout[v].flags = vout[v + 1].flags = PVR_CMD_VERTEX; + vout[v + 2].flags = PVR_CMD_VERTEX_EOL; + v += 3; + + break; + + case 2:/* 2 Vertices of Triangle are inside of clip plane = output 2 Triangles */ + switch(clip) { + case FIRST: + glVertexCopyPVR(&vin[i + 0], &vout[v + 0]); + glVertexCopyPVR(&vin[i + 1], &vout[v + 1]); + glVertexCopyPVR(&vin[i + 0], &vout[v + 2]); + glVertexCopyPVR(&vin[i + 2], &vout[v + 3]); + glVertexClipZNear(&vout[v + 0], &vout[v + 1], ZclipMag(&CLIP_BUF[i], &CLIP_BUF[i + 1])); + glVertexClipZNear(&vout[v + 2], &vout[v + 3], ZclipMag(&CLIP_BUF[i], &CLIP_BUF[i + 2])); + break; + + case SECOND: + glVertexCopyPVR(&vin[i + 1], &vout[v + 0]); + glVertexCopyPVR(&vin[i + 0], &vout[v + 1]); + glVertexCopyPVR(&vin[i + 1], &vout[v + 2]); + glVertexCopyPVR(&vin[i + 2], &vout[v + 3]); + glVertexClipZNear(&vout[v + 0], &vout[v + 1], ZclipMag(&CLIP_BUF[i + 1], &CLIP_BUF[i + 0])); + glVertexClipZNear(&vout[v + 2], &vout[v + 3], ZclipMag(&CLIP_BUF[i + 1], &CLIP_BUF[i + 2])); + break; + + case THIRD: + glVertexCopyPVR(&vin[i + 2], &vout[v + 0]); + glVertexCopyPVR(&vin[i + 0], &vout[v + 1]); + glVertexCopyPVR(&vin[i + 2], &vout[v + 2]); + glVertexCopyPVR(&vin[i + 1], &vout[v + 3]); + glVertexClipZNear(&vout[v + 0], &vout[v + 1], ZclipMag(&CLIP_BUF[i + 2], &CLIP_BUF[i])); + glVertexClipZNear(&vout[v + 2], &vout[v + 3], ZclipMag(&CLIP_BUF[i + 2], &CLIP_BUF[i + 1])); + break; + } + + vout[v + 0].flags = vout[v + 1].flags = vout[v + 2].flags = PVR_CMD_VERTEX; + vout[v + 3].flags = PVR_CMD_VERTEX_EOL; + v += 4; + + break; + } + + C++; + } + + return v; +} + +static inline unsigned char _glKosClipTri(pvr_vertex_t *vin, pvr_vertex_t *vout) { + unsigned short int clip = 0; /* Clip Code for current Triangle */ + unsigned char verts_in = 0; /* # of Vertices inside clip plane for current Triangle */ + float3 clip_buf[3]; /* Store the Vertices for each Triangle Translated into Clip Space */ + + /* Transform all 3 Vertices of Triangle */ + { + register float __x __asm__("fr12") = vin->x; + register float __y __asm__("fr13") = vin->y; + register float __z __asm__("fr14") = vin->z; + + mat_trans_fv12_nodiv(); + + clip_buf[0].x = __x; + clip_buf[0].y = __y; + clip_buf[0].z = __z; + + __x = (vin + 1)->x; + __y = (vin + 1)->y; + __z = (vin + 1)->z; + + mat_trans_fv12_nodiv(); + + clip_buf[1].x = __x; + clip_buf[1].y = __y; + clip_buf[1].z = __z; + + __x = (vin + 2)->x; + __y = (vin + 2)->y; + __z = (vin + 2)->z; + + mat_trans_fv12_nodiv(); + + clip_buf[2].x = __x; + clip_buf[2].y = __y; + clip_buf[2].z = __z; + + /* Compute Clip Code for Triangle */ + (clip_buf[0].z >= CLIP_NEARZ) ? clip |= FIRST : ++verts_in; + (clip_buf[1].z >= CLIP_NEARZ) ? clip |= SECOND : ++verts_in; + (clip_buf[2].z >= CLIP_NEARZ) ? clip |= THIRD : ++verts_in; + } + + switch(verts_in) { /* Start by examining # of vertices inside clip plane */ + case 0: /* All Vertices of Triangle are Outside of clip plne */ + return 0; + + case 3: /* All Vertices of Triangle are inside of clip plne */ + memcpy(vout, vin, 96); + + vout->flags = (vout + 1)->flags = PVR_CMD_VERTEX; + (vout + 2)->flags = PVR_CMD_VERTEX_EOL; + + return 3; + + case 1:/* 1 Vertex of Triangle is inside of clip plane = output 1 Triangle */ + memcpy(vout, vin, 96); + + switch(clip) { + case FIRST_TWO_OUT: + glVertexClipZNear(vout, vout + 2, ZclipMag(&clip_buf[0], &clip_buf[2])); + glVertexClipZNear(vout + 1, vout + 2, ZclipMag(&clip_buf[1], &clip_buf[2])); + + break; + + case FIRST_AND_LAST_OUT: + glVertexClipZNear(vout, vout + 1, ZclipMag(&clip_buf[0], &clip_buf[1])); + glVertexClipZNear(vout + 2, vout + 1, ZclipMag(&clip_buf[2], &clip_buf[1])); + + break; + + case LAST_TWO_OUT: + glVertexClipZNear(vout + 1, vout, ZclipMag(&clip_buf[1], &clip_buf[0])); + glVertexClipZNear(vout + 2, vout, ZclipMag(&clip_buf[2], &clip_buf[0])); + + break; + } + + vout->flags = (vout + 1)->flags = PVR_CMD_VERTEX; + (vout + 2)->flags = PVR_CMD_VERTEX_EOL; + + return 3; + + case 2:/* 2 Vertices of Triangle are inside of clip plane = output 2 Triangles */ + switch(clip) { + case FIRST: + memcpy(vout, vin, 64); + glVertexCopyPVR(vin, vout + 2); + glVertexCopyPVR(vin + 2, vout + 3); + glVertexClipZNear(vout, vout + 1, ZclipMag(&clip_buf[0], &clip_buf[1])); + glVertexClipZNear(vout + 2, vout + 3, ZclipMag(&clip_buf[0], &clip_buf[2])); + break; + + case SECOND: + glVertexCopyPVR(vin + 1, vout); + glVertexCopyPVR(vin, vout + 1); + memcpy(vout + 2, vin + 1, 64); + glVertexClipZNear(vout, vout + 1, ZclipMag(&clip_buf[1], &clip_buf[0])); + glVertexClipZNear(vout + 2, vout + 3, ZclipMag(&clip_buf[1], &clip_buf[2])); + break; + + case THIRD: + glVertexCopyPVR(vin + 2, vout); + glVertexCopyPVR(vin, vout + 1); + glVertexCopyPVR(vin + 2, vout + 2); + glVertexCopyPVR(vin + 1, vout + 3); + glVertexClipZNear(vout, vout + 1, ZclipMag(&clip_buf[2], &clip_buf[0])); + glVertexClipZNear(vout + 2, vout + 3, ZclipMag(&clip_buf[2], &clip_buf[1])); + break; + } + + vout->flags = (vout + 1)->flags = (vout + 2)->flags = PVR_CMD_VERTEX; + (vout + 3)->flags = PVR_CMD_VERTEX_EOL; + + return 4; + } + + return 0; +} + +unsigned int _glKosClipTriangles(pvr_vertex_t *vin, pvr_vertex_t *vout, unsigned int vertices) { + unsigned int i, v = 0; + + for(i = 0; i < vertices; i += 3) /* Iterate all Triangles */ + v += _glKosClipTri(vin + i, vout + v); + + return v; +} + +unsigned int _glKosClipQuads(pvr_vertex_t *vin, pvr_vertex_t *vout, unsigned int vertices) { + unsigned int i, v = 0; + pvr_vertex_t qv; + + for(i = 0; i < vertices; i += 4) { /* Iterate all Quads, Rearranging into Triangle Strips */ + glVertexCopyPVR(vin + i + 3, &qv); + glVertexCopyPVR(vin + i + 2, vin + i + 3); + glVertexCopyPVR(&qv, vin + i + 2); + v += _glKosClipTriangleStrip(vin + i, vout + v, 4); + } + + return v; +} + +static inline void _glKosVertexPerspectiveDivide(pvr_vertex_t *dst, float w) { + dst->z = 1.0f / w; + dst->x *= dst->z; + dst->y *= dst->z; +} + +GLuint _glKosClipTrianglesTransformed(pvr_vertex_t *src, float *w, pvr_vertex_t *dst, GLuint count) { + pvr_vertex_t *vin = src; + pvr_vertex_t *vout = dst; + unsigned short int clip; + unsigned char verts_in = 0; + GLuint verts_out = 0; + GLuint i; + + for(i = 0; i < count; i += 3) { + clip = 0; /* Clip Code for current Triangle */ + verts_in = 0; /* # of Vertices inside clip plane for current Triangle */ + float W[4] = { w[i], w[i + 1], w[i + 2] }; /* W Component for Perspective Divide */ + + (vin[0].z >= CLIP_NEARZ) ? clip |= FIRST : ++verts_in; + (vin[1].z >= CLIP_NEARZ) ? clip |= SECOND : ++verts_in; + (vin[2].z >= CLIP_NEARZ) ? clip |= THIRD : ++verts_in; + + switch(verts_in) { /* Start by examining # of vertices inside clip plane */ + case 0: /* All Vertices of Triangle are Outside of clip plne */ + break; + + case 3: /* All Vertices of Triangle are inside of clip plne */ + _glKosVertexCopyPVR(&vin[0], &vout[0]); + _glKosVertexCopyPVR(&vin[1], &vout[1]); + _glKosVertexCopyPVR(&vin[2], &vout[2]); + + _glKosVertexPerspectiveDivide(&vout[0], W[0]); + _glKosVertexPerspectiveDivide(&vout[1], W[1]); + _glKosVertexPerspectiveDivide(&vout[2], W[2]); + + vout[0].flags = vout[1].flags = PVR_CMD_VERTEX; + vout[2].flags = PVR_CMD_VERTEX_EOL; + + vout += 3; + verts_out += 3; + break; + + case 1:/* 1 Vertex of Triangle is inside of clip plane = output 1 Triangle */ + _glKosVertexCopyPVR(&vin[0], &vout[0]); + _glKosVertexCopyPVR(&vin[1], &vout[1]); + _glKosVertexCopyPVR(&vin[2], &vout[2]); + + switch(clip) { + case FIRST_TWO_OUT: + _glKosVertexClipZNear3(&vout[0], &vout[2], &W[0], &W[2]); + _glKosVertexClipZNear3(&vout[1], &vout[2], &W[1], &W[2]); + + break; + + case FIRST_AND_LAST_OUT: + _glKosVertexClipZNear3(&vout[0], &vout[1], &W[0], &W[1]); + _glKosVertexClipZNear3(&vout[2], &vout[1], &W[2], &W[1]); + + break; + + case LAST_TWO_OUT: + _glKosVertexClipZNear3(&vout[1], &vout[0], &W[1], &W[0]); + _glKosVertexClipZNear3(&vout[2], &vout[0], &W[2], &W[0]); + + break; + } + + _glKosVertexPerspectiveDivide(&vout[0], W[0]); + _glKosVertexPerspectiveDivide(&vout[1], W[1]); + _glKosVertexPerspectiveDivide(&vout[2], W[2]); + + vout[0].flags = vout[1].flags = PVR_CMD_VERTEX; + vout[2].flags = PVR_CMD_VERTEX_EOL; + + vout += 3; + verts_out += 3; + break; + + case 2:/* 2 Vertices of Triangle are inside of clip plane = output 2 Triangles */ + switch(clip) { + case FIRST: + _glKosVertexCopyPVR(&vin[0], &vout[0]); + _glKosVertexCopyPVR(&vin[1], &vout[1]); + _glKosVertexCopyPVR(&vin[0], &vout[2]); + _glKosVertexCopyPVR(&vin[2], &vout[3]); + W[3] = W[2]; + W[2] = W[0]; + + break; + + case SECOND: + _glKosVertexCopyPVR(&vin[1], &vout[0]); + _glKosVertexCopyPVR(&vin[2], &vout[1]); + _glKosVertexCopyPVR(&vin[1], &vout[2]); + _glKosVertexCopyPVR(&vin[0], &vout[3]); + W[3] = W[0]; + W[0] = W[1]; + W[1] = W[2]; + W[2] = W[0]; + + break; + + case THIRD: + _glKosVertexCopyPVR(&vin[2], &vout[0]); + _glKosVertexCopyPVR(&vin[0], &vout[1]); + _glKosVertexCopyPVR(&vin[2], &vout[2]); + _glKosVertexCopyPVR(&vin[1], &vout[3]); + W[3] = W[1]; + W[1] = W[0]; + W[0] = W[2]; + + break; + } + + _glKosVertexClipZNear3(&vout[0], &vout[1], &W[0], &W[1]); + _glKosVertexClipZNear3(&vout[2], &vout[3], &W[2], &W[3]); + + _glKosVertexPerspectiveDivide(&vout[0], W[0]); + _glKosVertexPerspectiveDivide(&vout[1], W[1]); + _glKosVertexPerspectiveDivide(&vout[2], W[2]); + _glKosVertexPerspectiveDivide(&vout[3], W[3]); + + vout[0].flags = vout[1].flags = vout[2].flags = PVR_CMD_VERTEX; + vout[3].flags = PVR_CMD_VERTEX_EOL; + + vout += 4; + verts_out += 4; + break; + } + + vin += 3; + } + + return verts_out; +} + +GLuint _glKosClipTriangleStripTransformed(pvr_vertex_t *src, float *w, pvr_vertex_t *dst, GLuint count) { + pvr_vertex_t *vin = src; + pvr_vertex_t *vout = dst; + unsigned short int clip; + unsigned char verts_in = 0; + GLuint verts_out = 0; + GLuint i; + + for(i = 0; i < (count - 2); i ++) { + clip = 0; /* Clip Code for current Triangle */ + verts_in = 0; /* # of Vertices inside clip plane for current Triangle */ + float W[4] = { w[i], w[i + 1], w[i + 2] }; /* W Component for Perspective Divide */ + + (vin[0].z >= CLIP_NEARZ) ? clip |= FIRST : ++verts_in; + (vin[1].z >= CLIP_NEARZ) ? clip |= SECOND : ++verts_in; + (vin[2].z >= CLIP_NEARZ) ? clip |= THIRD : ++verts_in; + + switch(verts_in) { /* Start by examining # of vertices inside clip plane */ + case 0: /* All Vertices of Triangle are Outside of clip plne */ + break; + + case 3: /* All Vertices of Triangle are inside of clip plne */ + _glKosVertexCopyPVR(&vin[0], &vout[0]); + _glKosVertexCopyPVR(&vin[1], &vout[1]); + _glKosVertexCopyPVR(&vin[2], &vout[2]); + + _glKosVertexPerspectiveDivide(&vout[0], W[0]); + _glKosVertexPerspectiveDivide(&vout[1], W[1]); + _glKosVertexPerspectiveDivide(&vout[2], W[2]); + + vout[0].flags = vout[1].flags = PVR_CMD_VERTEX; + vout[2].flags = PVR_CMD_VERTEX_EOL; + + vout += 3; + verts_out += 3; + break; + + case 1:/* 1 Vertex of Triangle is inside of clip plane = output 1 Triangle */ + _glKosVertexCopyPVR(&vin[0], &vout[0]); + _glKosVertexCopyPVR(&vin[1], &vout[1]); + _glKosVertexCopyPVR(&vin[2], &vout[2]); + + switch(clip) { + case FIRST_TWO_OUT: + _glKosVertexClipZNear3(&vout[0], &vout[2], &W[0], &W[2]); + _glKosVertexClipZNear3(&vout[1], &vout[2], &W[1], &W[2]); + + break; + + case FIRST_AND_LAST_OUT: + _glKosVertexClipZNear3(&vout[0], &vout[1], &W[0], &W[1]); + _glKosVertexClipZNear3(&vout[2], &vout[1], &W[2], &W[1]); + + break; + + case LAST_TWO_OUT: + _glKosVertexClipZNear3(&vout[1], &vout[0], &W[1], &W[0]); + _glKosVertexClipZNear3(&vout[2], &vout[0], &W[2], &W[0]); + + break; + } + + _glKosVertexPerspectiveDivide(&vout[0], W[0]); + _glKosVertexPerspectiveDivide(&vout[1], W[1]); + _glKosVertexPerspectiveDivide(&vout[2], W[2]); + + vout[0].flags = vout[1].flags = PVR_CMD_VERTEX; + vout[2].flags = PVR_CMD_VERTEX_EOL; + + vout += 3; + verts_out += 3; + break; + + case 2:/* 2 Vertices of Triangle are inside of clip plane = output 2 Triangles */ + switch(clip) { + case FIRST: + _glKosVertexCopyPVR(&vin[0], &vout[0]); + _glKosVertexCopyPVR(&vin[1], &vout[1]); + _glKosVertexCopyPVR(&vin[0], &vout[2]); + _glKosVertexCopyPVR(&vin[2], &vout[3]); + W[3] = W[2]; + W[2] = W[0]; + + break; + + case SECOND: + _glKosVertexCopyPVR(&vin[1], &vout[0]); + _glKosVertexCopyPVR(&vin[2], &vout[1]); + _glKosVertexCopyPVR(&vin[1], &vout[2]); + _glKosVertexCopyPVR(&vin[0], &vout[3]); + W[3] = W[0]; + W[0] = W[1]; + W[1] = W[2]; + W[2] = W[0]; + + break; + + case THIRD: + _glKosVertexCopyPVR(&vin[2], &vout[0]); + _glKosVertexCopyPVR(&vin[0], &vout[1]); + _glKosVertexCopyPVR(&vin[2], &vout[2]); + _glKosVertexCopyPVR(&vin[1], &vout[3]); + W[3] = W[1]; + W[1] = W[0]; + W[0] = W[2]; + + break; + } + + _glKosVertexClipZNear3(&vout[0], &vout[1], &W[0], &W[1]); + _glKosVertexClipZNear3(&vout[2], &vout[3], &W[2], &W[3]); + + _glKosVertexPerspectiveDivide(&vout[0], W[0]); + _glKosVertexPerspectiveDivide(&vout[1], W[1]); + _glKosVertexPerspectiveDivide(&vout[2], W[2]); + _glKosVertexPerspectiveDivide(&vout[3], W[3]); + + vout[0].flags = vout[1].flags = vout[2].flags = PVR_CMD_VERTEX; + vout[3].flags = PVR_CMD_VERTEX_EOL; + + vout += 4; + verts_out += 4; + break; + } + + ++vin; + } + + return verts_out; +} + +GLubyte _glKosClipTriTransformed(pvr_vertex_t *vin, float *w, pvr_vertex_t *vout) { + unsigned short int clip = 0; /* Clip Code for current Triangle */ + unsigned char verts_in = 0; /* # of Vertices inside clip plane for current Triangle */ + float W[4] = { w[0], w[1], w[2] }; /* W Component for Perspective Divide */ + + (vin[0].z >= CLIP_NEARZ) ? clip |= FIRST : ++verts_in; + (vin[1].z >= CLIP_NEARZ) ? clip |= SECOND : ++verts_in; + (vin[2].z >= CLIP_NEARZ) ? clip |= THIRD : ++verts_in; + + switch(verts_in) { /* Start by examining # of vertices inside clip plane */ + case 0: /* All Vertices of Triangle are Outside of clip plne */ + return 0; + + case 3: /* All Vertices of Triangle are inside of clip plne */ + _glKosVertexCopyPVR(&vin[0], &vout[0]); + _glKosVertexCopyPVR(&vin[1], &vout[1]); + _glKosVertexCopyPVR(&vin[2], &vout[2]); + + _glKosVertexPerspectiveDivide(&vout[0], W[0]); + _glKosVertexPerspectiveDivide(&vout[1], W[1]); + _glKosVertexPerspectiveDivide(&vout[2], W[2]); + + vout[0].flags = vout[1].flags = PVR_CMD_VERTEX; + vout[2].flags = PVR_CMD_VERTEX_EOL; + + return 3; + + case 1:/* 1 Vertex of Triangle is inside of clip plane = output 1 Triangle */ + _glKosVertexCopyPVR(&vin[0], &vout[0]); + _glKosVertexCopyPVR(&vin[1], &vout[1]); + _glKosVertexCopyPVR(&vin[2], &vout[2]); + + switch(clip) { + case FIRST_TWO_OUT: + _glKosVertexClipZNear3(&vout[0], &vout[2], &W[0], &W[2]); + _glKosVertexClipZNear3(&vout[1], &vout[2], &W[1], &W[2]); + + break; + + case FIRST_AND_LAST_OUT: + _glKosVertexClipZNear3(&vout[0], &vout[1], &W[0], &W[1]); + _glKosVertexClipZNear3(&vout[2], &vout[1], &W[2], &W[1]); + + break; + + case LAST_TWO_OUT: + _glKosVertexClipZNear3(&vout[1], &vout[0], &W[1], &W[0]); + _glKosVertexClipZNear3(&vout[2], &vout[0], &W[2], &W[0]); + + break; + } + + _glKosVertexPerspectiveDivide(&vout[0], W[0]); + _glKosVertexPerspectiveDivide(&vout[1], W[1]); + _glKosVertexPerspectiveDivide(&vout[2], W[2]); + + vout[0].flags = vout[1].flags = PVR_CMD_VERTEX; + vout[2].flags = PVR_CMD_VERTEX_EOL; + + return 3; + + case 2:/* 2 Vertices of Triangle are inside of clip plane = output 2 Triangles */ + switch(clip) { + case FIRST: + _glKosVertexCopyPVR(&vin[0], &vout[0]); + _glKosVertexCopyPVR(&vin[1], &vout[1]); + _glKosVertexCopyPVR(&vin[0], &vout[2]); + _glKosVertexCopyPVR(&vin[2], &vout[3]); + W[3] = W[2]; + W[2] = W[0]; + + break; + + case SECOND: + _glKosVertexCopyPVR(&vin[1], &vout[0]); + _glKosVertexCopyPVR(&vin[2], &vout[1]); + _glKosVertexCopyPVR(&vin[1], &vout[2]); + _glKosVertexCopyPVR(&vin[0], &vout[3]); + W[3] = W[0]; + W[0] = W[1]; + W[1] = W[2]; + W[2] = W[0]; + + break; + + case THIRD: + _glKosVertexCopyPVR(&vin[2], &vout[0]); + _glKosVertexCopyPVR(&vin[0], &vout[1]); + _glKosVertexCopyPVR(&vin[2], &vout[2]); + _glKosVertexCopyPVR(&vin[1], &vout[3]); + W[3] = W[1]; + W[1] = W[0]; + W[0] = W[2]; + + break; + } + + _glKosVertexClipZNear3(&vout[0], &vout[1], &W[0], &W[1]); + _glKosVertexClipZNear3(&vout[2], &vout[3], &W[2], &W[3]); + + _glKosVertexPerspectiveDivide(&vout[0], W[0]); + _glKosVertexPerspectiveDivide(&vout[1], W[1]); + _glKosVertexPerspectiveDivide(&vout[2], W[2]); + _glKosVertexPerspectiveDivide(&vout[3], W[3]); + + vout[0].flags = vout[1].flags = vout[2].flags = PVR_CMD_VERTEX; + vout[3].flags = PVR_CMD_VERTEX_EOL; + + return 4; + } + + return 0; +} + +unsigned int _glKosClipQuadsTransformed(pvr_vertex_t *vin, float *w, pvr_vertex_t *vout, unsigned int vertices) { + unsigned int i, v = 0; + pvr_vertex_t qv[3]; + float W[3]; + + for(i = 0; i < vertices; i += 4) { /* Iterate all Quads, Rearranging into Triangle Strips */ + _glKosVertexCopyPVR(&vin[i + 0], &qv[0]); + _glKosVertexCopyPVR(&vin[i + 2], &qv[1]); + _glKosVertexCopyPVR(&vin[i + 3], &qv[2]); + W[0] = w[0]; + W[1] = w[2]; + W[2] = w[3]; + + v += _glKosClipTriTransformed(&vin[i], &w[i], &vout[v]); + v += _glKosClipTriTransformed(&qv[i], &W[i], &vout[v]); + } + + return v; +} diff --git a/gl-clip.h b/gl-clip.h new file mode 100755 index 0000000..64ed34b --- /dev/null +++ b/gl-clip.h @@ -0,0 +1,44 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-clip.h + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + Near-Z Clipping Algorithm (C) 2013-2014 Josh PH3NOM Pearson + Input Primitive Types Supported: + -GL_TRIANGLES + -GL_TRIANGLE_STRIPS + -GL_QUADS + Outputs a mix of Triangles and Triangle Strips for use with the PVR +*/ + +#ifndef GL_CLIP_H +#define GL_CLIP_H + +#include "gl.h" +#include "gl-sh4.h" + +#define NONE 0x0000 /* Clip Codes */ +#define FIRST 0x0001 +#define SECOND 0x0010 +#define THIRD 0x0100 +#define ALL 0x0111 +#define FIRST_TWO_OUT 0x0011 +#define FIRST_AND_LAST_OUT 0x0101 +#define LAST_TWO_OUT 0x0110 + +#define ALPHA 0xFF000000 /* Color Components using PVR's Packed 32bit int */ +#define RED 0x00FF0000 +#define GREEN 0x0000FF00 +#define BLUE 0x000000FF + +#define CLIP_NEARZ -0.5f /* Clip Threshold */ + +typedef struct { + float x, y, z; +} float3; + +typedef struct { + unsigned char b, g, r, a; +} colorui; + +#endif diff --git a/gl-fog.c b/gl-fog.c new file mode 100755 index 0000000..99c1ecb --- /dev/null +++ b/gl-fog.c @@ -0,0 +1,102 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-fog.c + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + Functionality adapted from the original KOS libgl fog code: + Copyright (C) 2002 Benoit Miller + + OpenGL Fog - Wrapper for the PowerVR fog functions in KOS. +*/ + +#include "gl.h" + +static GLuint FOG_MODE = GL_EXP; /* GL_LINEAR, GL_EXP, or GL_EXP2 FOG */ +static GLfloat FOG_DENSITY = 1.0f, /* Density - GL_EXP, or GL_EXP2 FOG */ + FOG_START = 0.0f, /* Linear FOG */ + FOG_END = 1.0f; /* Linear FOG */ + +void glFogi(GLenum pname, GLint param) { + switch(pname) { + case GL_FOG_MODE: + switch(param) { + case GL_LINEAR: + return pvr_fog_table_linear(FOG_START, FOG_END); + + case GL_EXP: + return pvr_fog_table_exp(FOG_DENSITY); + + case GL_EXP2: + return pvr_fog_table_exp2(FOG_DENSITY); + + default: + return; + } + + default: + return; + } +} + +void glFogf(GLenum pname, GLfloat param) { + switch(pname) { + case GL_FOG_START: + FOG_START = param; + + if(FOG_MODE == GL_LINEAR) + return pvr_fog_table_linear(FOG_START, FOG_END); + + return; + + case GL_FOG_END: + FOG_END = param; + + if(FOG_MODE == GL_LINEAR) + return pvr_fog_table_linear(FOG_START, FOG_END); + + return; + + case GL_FOG_DENSITY: + FOG_DENSITY = param; + + if(FOG_MODE == GL_EXP) + return pvr_fog_table_exp(FOG_DENSITY); + + if(FOG_MODE == GL_EXP2) + return pvr_fog_table_exp2(FOG_DENSITY); + + return; + + default: + return; + } +} + +void glFogfv(GLenum pname, const GLfloat *params) { + switch(pname) { + case GL_FOG_MODE: + return glFogi(pname, (GLint) * params); + + case GL_FOG_DENSITY: + FOG_DENSITY = *params; + + if(FOG_MODE == GL_EXP) + return pvr_fog_table_exp(FOG_DENSITY); + + if(FOG_MODE == GL_EXP2) + return pvr_fog_table_exp2(FOG_DENSITY); + + return; + + case GL_FOG_START: + case GL_FOG_END: + return glFogf(pname, *params); + + case GL_FOG_COLOR: + return pvr_fog_table_color(params[3], params[0], params[1], params[2]); + + case GL_FOG_INDEX: + default: + return; + } +} diff --git a/gl-light.c b/gl-light.c new file mode 100755 index 0000000..3c57991 --- /dev/null +++ b/gl-light.c @@ -0,0 +1,562 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-light.c + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + Dynamic Vertex Lighting Model: + vertexColor = emissive + ambient + ( diffuse + specular * attenuation ) + + The only difference here from real OpenGL is that only 1 ambient light + source is used, as opposed to each light containing its own abmient value. + Abmient light is set by the glKosLightAbmient..(..) functions below. + + By default, the specular lighting term is enabled. + For now, specular can be disabled by setting GL_ENABLE_SPECULAR on + gl-light.h when you build the library. +*/ + +#include +#include +#include + +#include "gl.h" +#include "gl-api.h" +#include "gl-clip.h" +#include "gl-light.h" + +static GLfloat GL_GLOBAL_AMBIENT[4] = { 0, 0, 0, 0 }; /* RGBA Global Ambient Light */ +static GLfloat GL_VERTEX_NORMAL[3] = {0, 0, 0}; /* Current Vertex Normal */ +static GLuint GL_LIGHT_ENABLED = 0; /* Client State for Enabling Lighting */ + +static glLight GL_LIGHTS[GL_MAX_LIGHTS], +GL_DEFAULT_LIGHT = { { 0.0, 0.0, 1.0, 0.0 }, /* Position */ + { 0.0, 0.0, -1.0 }, /* Spot Direction */ + -1.0f, /* Spot Cutoff */ + 1.0f, 0.0f, 0.0f, /* Attenuation Factors */ + 0.0f, /* Spot Exponent */ + { 1.0, 1.0, 1.0, 1.0 }, /* Diffuse */ + { 1.0, 1.0, 1.0, 1.0 }, /* Specular */ + { 0.0, 0.0, 0.0, 1.0 } /* Ambient */ +}; + +static glMaterial GL_MATERIAL, +GL_DEFAULT_MATERIAL = { { 0.0, 0.0, 0.0, 1.0 }, /* Emissive Color */ + { 0.2, 0.2, 0.2, 1.0 }, /* Ambient Reflectance */ + { 0.8, 0.8, 0.8, 1.0 }, /* Diffuse Reflectance */ + { 0.0, 0.0, 0.0, 1.0 }, /* Specular Reflectance */ + 0.0 /* Shininess */ +}; + +static GLfloat GL_EYE_POSITION[3] = { 0, 0, 0 }; /* Eye Position for Specular Factor */ + +void _glKosSetEyePosition(GLfloat *position) { /* Called internally by glhLookAtf() */ + GL_EYE_POSITION[0] = position[0]; + GL_EYE_POSITION[1] = position[1]; + GL_EYE_POSITION[2] = position[2]; +} + +void _glKosInitLighting() { /* Called internally by glInit() */ + unsigned char i; + + for(i = 0; i < GL_MAX_LIGHTS; i++) + memcpy(&GL_LIGHTS[i], &GL_DEFAULT_LIGHT, sizeof(glLight)); + + memcpy(&GL_MATERIAL, &GL_DEFAULT_MATERIAL, sizeof(glMaterial)); +} + +/* Enable a light - GL_LIGHT0->GL_LIGHT7 */ +void _glKosEnableLight(const GLuint light) { + if(light < GL_LIGHT0 || light > GL_LIGHT7) return; + + GL_LIGHT_ENABLED |= (1 << (light & 0xF)); +} + +/* Disable a light - GL_LIGHT0->GL_LIGHT7 */ +void _glKosDisableLight(const GLuint light) { + if(light < GL_LIGHT0 || light > GL_LIGHT7) return; + + GL_LIGHT_ENABLED &= ~(1 << (light & 0xF)); +} + +/* Vertex Normal Submission */ +void glNormal3f(float x, float y, float z) { + GL_VERTEX_NORMAL[0] = x; + GL_VERTEX_NORMAL[1] = y; + GL_VERTEX_NORMAL[2] = z; +} + +void glNormal3fv(float *xyz) { + GL_VERTEX_NORMAL[0] = xyz[0]; + GL_VERTEX_NORMAL[1] = xyz[1]; + GL_VERTEX_NORMAL[2] = xyz[2]; +} + +/* Global Ambient Light Parameters */ +void glKosLightAmbient4fv(float *rgba) { + GL_GLOBAL_AMBIENT[0] = rgba[0]; + GL_GLOBAL_AMBIENT[1] = rgba[1]; + GL_GLOBAL_AMBIENT[2] = rgba[2]; + GL_GLOBAL_AMBIENT[3] = rgba[3]; +} + +void glKosLightAmbient4f(float r, float g, float b, float a) { + GL_GLOBAL_AMBIENT[0] = r; + GL_GLOBAL_AMBIENT[1] = g; + GL_GLOBAL_AMBIENT[2] = b; + GL_GLOBAL_AMBIENT[3] = a; +} + +void glKosLightAmbient3fv(float *rgb) { + GL_GLOBAL_AMBIENT[0] = rgb[0]; + GL_GLOBAL_AMBIENT[1] = rgb[1]; + GL_GLOBAL_AMBIENT[2] = rgb[2]; + GL_GLOBAL_AMBIENT[3] = 1.0f; +} + +void glKosLightAmbient3f(float r, float g, float b) { + GL_GLOBAL_AMBIENT[0] = r; + GL_GLOBAL_AMBIENT[1] = g; + GL_GLOBAL_AMBIENT[2] = b; + GL_GLOBAL_AMBIENT[3] = 1.0f; +} + +/* Misc Lighting Functions ************************************/ +static inline void glCopyRGBA(rgba *src, rgba *dst) { + *dst = *src; +} + +static inline void glCopy4f(const float *src, float *dst) { + memcpy(dst, src, 0x10); +} + +static inline void glCopy3f(const float *src, float *dst) { + memcpy(dst, src, 0xC); +} + +/* GL Light Parameters ******************************************************/ + +void glLightfv(GLenum light, GLenum pname, const GLfloat *params) { + if(light < GL_LIGHT0 || light > GL_LIGHT7) return; + + switch(pname) { + case GL_AMBIENT: + glCopyRGBA((rgba *)params, (rgba *)&GL_LIGHTS[light & 0xF].Ka); + break; + + case GL_DIFFUSE: + glCopyRGBA((rgba *)params, (rgba *)&GL_LIGHTS[light & 0xF].Kd); + break; + + case GL_SPECULAR: + glCopyRGBA((rgba *)params, (rgba *)&GL_LIGHTS[light & 0xF].Ks); + break; + + case GL_POSITION: + glCopy4f(params, &GL_LIGHTS[light & 0xF].Pos[0]); + break; + + case GL_SPOT_DIRECTION: + glCopy3f(params, &GL_LIGHTS[light & 0xF].Dir[0]); + break; + + case GL_SPOT_EXPONENT: + GL_LIGHTS[light & 0xF].Exponent = *params; + break; + + case GL_SPOT_CUTOFF: + if(*params >= 0.0f && *params <= 180.0f) + GL_LIGHTS[light & 0xF].CutOff = LCOS(*params); + + break; + + case GL_CONSTANT_ATTENUATION: + if(*params >= 0) + GL_LIGHTS[light & 0xF].Kc = *params; + else + GL_LIGHTS[light & 0xF].Kc = 0; + + break; + + case GL_LINEAR_ATTENUATION: + if(*params >= 0) + GL_LIGHTS[light & 0xF].Kl = *params; + else + GL_LIGHTS[light & 0xF].Kl = 0; + + break; + + case GL_QUADRATIC_ATTENUATION: + if(*params >= 0) + GL_LIGHTS[light & 0xF].Kq = *params; + else + GL_LIGHTS[light & 0xF].Kq = 0; + + break; + + case GL_AMBIENT_AND_DIFFUSE: + glCopyRGBA((rgba *)params, (rgba *)&GL_LIGHTS[light & 0xF].Ka); + glCopyRGBA((rgba *)params, (rgba *)&GL_LIGHTS[light & 0xF].Kd); + break; + } +} + +void glLightf(GLenum light, GLenum pname, GLfloat param) { + if(light < GL_LIGHT0 || light > GL_LIGHT7) return; + + switch(pname) { + case GL_CONSTANT_ATTENUATION: + if(param >= 0) + GL_LIGHTS[light & 0xF].Kc = param; + else + GL_LIGHTS[light & 0xF].Kc = 0; + + break; + + case GL_LINEAR_ATTENUATION: + if(param >= 0) + GL_LIGHTS[light & 0xF].Kl = param; + else + GL_LIGHTS[light & 0xF].Kl = 0; + + break; + + case GL_QUADRATIC_ATTENUATION: + if(param >= 0) + GL_LIGHTS[light & 0xF].Kq = param; + else + GL_LIGHTS[light & 0xF].Kq = 0; + + break; + + case GL_SPOT_CUTOFF: + if(param >= 0.0f && param <= 180.0f) + GL_LIGHTS[light & 0xF].CutOff = LCOS(param); + + break; + + case GL_SPOT_EXPONENT: + GL_LIGHTS[light & 0xF].Exponent = param; + break; + } +} + +/* GL Material Parameters **************************************************/ + +void glMateriali(GLenum face, GLenum pname, const GLint param) { + //if(face!=GL_FRONT_AND_BACK) return; + + if(pname == GL_SHININESS) { + if(param < 0) + GL_MATERIAL.Shine = 0; + else if(param > 128) + GL_MATERIAL.Shine = 128; + else + GL_MATERIAL.Shine = param; + } +} + +void glMaterialf(GLenum face, GLenum pname, const GLfloat param) { + //if(face!=GL_FRONT_AND_BACK) return; + + if(pname == GL_SHININESS) { + if(param < 0) + GL_MATERIAL.Shine = 0; + else if(param > 128.0) + GL_MATERIAL.Shine = 128.0; + else + GL_MATERIAL.Shine = param; + } +} + +void glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) { + //if(face!=GL_FRONT_AND_BACK) return; + + switch(pname) { + case GL_AMBIENT: + glCopyRGBA((rgba *)params, (rgba *)&GL_MATERIAL.Ka[0]); + break; + + case GL_DIFFUSE: + glCopyRGBA((rgba *)params, (rgba *)&GL_MATERIAL.Kd[0]); + break; + + case GL_SPECULAR: + glCopyRGBA((rgba *)params, (rgba *)&GL_MATERIAL.Ks[0]); + break; + + case GL_EMISSION: + glCopyRGBA((rgba *)params, (rgba *)&GL_MATERIAL.Ke[0]); + break; + + case GL_SHININESS: + glMaterialf(GL_FRONT_AND_BACK, pname, *params); + break; + + case GL_AMBIENT_AND_DIFFUSE: + glCopyRGBA((rgba *)params, (rgba *)&GL_MATERIAL.Ka[0]); + glCopyRGBA((rgba *)params, (rgba *)&GL_MATERIAL.Kd[0]); + break; + } + +} + +/* Vertex Lighting **********************************************************/ + +/* Fast POW Implementation - Less accurate, but much faster than math.h */ +#define EXP_A 184 +#define EXP_C 16249 + +float FEXP(float y) { + union { + float d; + struct { + short j, i; + } n; + } eco; + eco.n.i = EXP_A * (y) + (EXP_C); + eco.n.j = 0; + return eco.d; +} + +float FLOG(float y) { + int *nTemp = (int *)&y; + y = (*nTemp) >> 16; + return (y - EXP_C) / EXP_A; +} + +float FPOW(float b, float p) { + return FEXP(FLOG(b) * p); +} + +/* End FPOW Implementation */ + +void _glKosVertex3flv(GLfloat *xyz) { + glVertex *v = _glKosArrayBufPtr(); + + v->pos[0] = xyz[0]; + v->pos[1] = xyz[1]; + v->pos[2] = xyz[2]; + v->norm[0] = GL_VERTEX_NORMAL[0]; + v->norm[1] = GL_VERTEX_NORMAL[1]; + v->norm[2] = GL_VERTEX_NORMAL[2]; + + _glKosArrayBufIncrement(); + + _glKosVertex3fsv(xyz); +} + +void _glKosVertex3fl(GLfloat x, GLfloat y, GLfloat z) { + glVertex *v = _glKosArrayBufPtr(); + + v->pos[0] = x; + v->pos[1] = y; + v->pos[2] = z; + v->norm[0] = GL_VERTEX_NORMAL[0]; + v->norm[1] = GL_VERTEX_NORMAL[1]; + v->norm[2] = GL_VERTEX_NORMAL[2]; + + _glKosArrayBufIncrement(); + + _glKosVertex3fs(x, y, z); +} + +void _glKosVertex3flcv(GLfloat *xyz) { + glVertex *v = _glKosArrayBufPtr(); + + v->pos[0] = xyz[0]; + v->pos[1] = xyz[1]; + v->pos[2] = xyz[2]; + v->norm[0] = GL_VERTEX_NORMAL[0]; + v->norm[1] = GL_VERTEX_NORMAL[1]; + v->norm[2] = GL_VERTEX_NORMAL[2]; + + _glKosArrayBufIncrement(); + + _glKosVertex3fcv(xyz); +} + +void _glKosVertex3flc(GLfloat x, GLfloat y, GLfloat z) { + glVertex *v = _glKosArrayBufPtr(); + + v->pos[0] = x; + v->pos[1] = y; + v->pos[2] = z; + v->norm[0] = GL_VERTEX_NORMAL[0]; + v->norm[1] = GL_VERTEX_NORMAL[1]; + v->norm[2] = GL_VERTEX_NORMAL[2]; + + _glKosArrayBufIncrement(); + + _glKosVertex3fc(x, y, z); +} + +/**** Compute Vertex Light Color ***/ +void _glKosVertexLights(glVertex *P, pvr_vertex_t *v, GLuint count) { +#ifdef GL_ENABLE_SPECULAR + float S; +#endif + unsigned char i; + float L[4]; + float C[3] = { 0, 0, 0 }; + + colorui *color = (colorui *)&v->argb; + + /* Compute Global Ambient */ + float A[3] = { GL_MATERIAL.Ke[0] + GL_MATERIAL.Ka[0] *GL_GLOBAL_AMBIENT[0], + GL_MATERIAL.Ke[1] + GL_MATERIAL.Ka[1] *GL_GLOBAL_AMBIENT[1], + GL_MATERIAL.Ke[2] + GL_MATERIAL.Ka[2] *GL_GLOBAL_AMBIENT[2] + }; + + while(count--) { + for(i = 0; i < GL_MAX_LIGHTS; i++) + if(GL_LIGHT_ENABLED & 1 << i) + if(_glKosSpotlight(&GL_LIGHTS[i], P, L)) { /* Compute Spot / Diffuse */ + C[0] = A[0] + (GL_MATERIAL.Kd[0] * GL_LIGHTS[i].Kd[0] * L[3]); + C[1] = A[1] + (GL_MATERIAL.Kd[1] * GL_LIGHTS[i].Kd[1] * L[3]); + C[2] = A[2] + (GL_MATERIAL.Kd[2] * GL_LIGHTS[i].Kd[2] * L[3]); + +#ifdef GL_ENABLE_SPECULAR + S = _glKosSpecular(P, GL_EYE_POSITION, L); /* Compute Specular */ + + if(S > 0) { +#ifdef GL_ENABLE_FAST_POW + S = FPOW(S, GL_MATERIAL.Shine); +#else + S = pow(S, GL_MATERIAL.Shine); +#endif + C[0] += (GL_MATERIAL.Ks[0] * GL_LIGHTS[i].Ks[0] * S); + C[1] += (GL_MATERIAL.Ks[1] * GL_LIGHTS[i].Ks[1] * S); + C[2] += (GL_MATERIAL.Ks[2] * GL_LIGHTS[i].Ks[2] * S); + } + +#endif + } + + color->a = 0xFF; /* Clamp / Pack Floating Point Colors to 32bit int */ + (C[0] > 1.0f) ? (color->r = 0xFF) : (color->r = (unsigned char)(255 * C[0])); + (C[1] > 1.0f) ? (color->g = 0xFF) : (color->g = (unsigned char)(255 * C[1])); + (C[2] > 1.0f) ? (color->b = 0xFF) : (color->b = (unsigned char)(255 * C[2])); + color += 8; /* pvr_vertex_t color stride */ + ++P; + } +} + +void _glKosVertexLight(glVertex *P, pvr_vertex_t *v) { +#ifdef GL_ENABLE_SPECULAR + float S; +#endif + unsigned char i; + float L[4]; + + /* Compute Ambient */ + float C[3] = { GL_MATERIAL.Ke[0] + GL_MATERIAL.Ka[0] *GL_GLOBAL_AMBIENT[0], + GL_MATERIAL.Ke[1] + GL_MATERIAL.Ka[1] *GL_GLOBAL_AMBIENT[1], + GL_MATERIAL.Ke[2] + GL_MATERIAL.Ka[2] *GL_GLOBAL_AMBIENT[2] + }; + + for(i = 0; i < GL_MAX_LIGHTS; i++) + if(GL_LIGHT_ENABLED & 1 << i) + if(_glKosSpotlight(&GL_LIGHTS[i], P, L)) { /* Compute Spot / Diffuse */ + C[0] += (GL_MATERIAL.Kd[0] * GL_LIGHTS[i].Kd[0] * L[3]); + C[1] += (GL_MATERIAL.Kd[1] * GL_LIGHTS[i].Kd[1] * L[3]); + C[2] += (GL_MATERIAL.Kd[2] * GL_LIGHTS[i].Kd[2] * L[3]); + +#ifdef GL_ENABLE_SPECULAR + S = _glKosSpecular(P, GL_EYE_POSITION, L); /* Compute Specular */ + + if(S > 0) { +#ifdef GL_ENABLE_FAST_POW + S = FPOW(S, GL_MATERIAL.Shine); +#else + S = pow(S, GL_MATERIAL.Shine); +#endif + C[0] += (GL_MATERIAL.Ks[0] * GL_LIGHTS[i].Ks[0] * S); + C[1] += (GL_MATERIAL.Ks[1] * GL_LIGHTS[i].Ks[1] * S); + C[2] += (GL_MATERIAL.Ks[2] * GL_LIGHTS[i].Ks[2] * S); + } + +#endif + } + + colorui *col = (colorui *)&v->argb; /* Clamp / Pack floats to a 32bit int */ + col->a = 0xFF; + (C[0] > 1.0f) ? (col->r = 0xFF) : (col->r = (unsigned char)(255 * C[0])); + (C[1] > 1.0f) ? (col->g = 0xFF) : (col->g = (unsigned char)(255 * C[1])); + (C[2] > 1.0f) ? (col->b = 0xFF) : (col->b = (unsigned char)(255 * C[2])); +} + +GLuint _glKosVertexLightColor(glVertex *P) { +#ifdef GL_ENABLE_SPECULAR + float S; +#endif + GLuint color; + GLubyte i; + float L[4]; + + /* Compute Ambient */ + float C[3] = { GL_MATERIAL.Ke[0] + GL_MATERIAL.Ka[0] *GL_GLOBAL_AMBIENT[0], + GL_MATERIAL.Ke[1] + GL_MATERIAL.Ka[1] *GL_GLOBAL_AMBIENT[1], + GL_MATERIAL.Ke[2] + GL_MATERIAL.Ka[2] *GL_GLOBAL_AMBIENT[2] + }; + + for(i = 0; i < GL_MAX_LIGHTS; i++) + if(GL_LIGHT_ENABLED & 1 << i) + if(_glKosSpotlight(&GL_LIGHTS[i], P, L)) { /* Compute Spot / Diffuse */ + C[0] += (GL_MATERIAL.Kd[0] * GL_LIGHTS[i].Kd[0] * L[3]); + C[1] += (GL_MATERIAL.Kd[1] * GL_LIGHTS[i].Kd[1] * L[3]); + C[2] += (GL_MATERIAL.Kd[2] * GL_LIGHTS[i].Kd[2] * L[3]); + +#ifdef GL_ENABLE_SPECULAR + S = _glKosSpecular(P, GL_EYE_POSITION, L); /* Compute Specular */ + + if(S > 0) { +#ifdef GL_ENABLE_FAST_POW + S = FPOW(S, GL_MATERIAL.Shine); +#else + S = pow(S, GL_MATERIAL.Shine); +#endif + C[0] += (GL_MATERIAL.Ks[0] * GL_LIGHTS[i].Ks[0] * S); + C[1] += (GL_MATERIAL.Ks[1] * GL_LIGHTS[i].Ks[1] * S); + C[2] += (GL_MATERIAL.Ks[2] * GL_LIGHTS[i].Ks[2] * S); + } + +#endif + } + + colorui *col = (colorui *)&color; /* Clamp / Pack floats to a 32bit int */ + col->a = 0xFF; + (C[0] > 1.0f) ? (col->r = 0xFF) : (col->r = (unsigned char)(255 * C[0])); + (C[1] > 1.0f) ? (col->g = 0xFF) : (col->g = (unsigned char)(255 * C[1])); + (C[2] > 1.0f) ? (col->b = 0xFF) : (col->b = (unsigned char)(255 * C[2])); + + return color; +} + +/** Iterate vertices submitted and compute vertex lighting **/ + +void _glKosVertexComputeLighting(pvr_vertex_t *v, int verts) { + unsigned int i; + glVertex *s = _glKosArrayBufAddr(); + + _glKosMatrixLoadModelView(); + + for(i = 0; i < verts; i++) { + mat_trans_single3_nodiv(s->pos[0], s->pos[1], s->pos[2]); + ++s; + } + + s = _glKosArrayBufAddr(); + + _glKosMatrixLoadModelRot(); + + for(i = 0; i < verts; i++) { + mat_trans_normal3(s->norm[0], s->norm[1], s->norm[2]); + _glKosVertexLight(s++, v++); + } +} + +void _glKosLightTransformScreenSpace(float *xyz) { + _glKosMatrixApplyScreenSpace(); + mat_trans_single(xyz[0], xyz[1], xyz[2]); + _glKosMatrixLoadRender(); +} diff --git a/gl-light.h b/gl-light.h new file mode 100755 index 0000000..005f7a4 --- /dev/null +++ b/gl-light.h @@ -0,0 +1,51 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-light.h + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + Dynamic Vertex Lighting. + + By default, specular lighting is enabled. + For now, specular can be disabled by setting GL_ENABLE_SPECULAR + below when you build the library. + By default, specular lighting uses a fast POW implementation, at + sacrifice of accuracy. Change GL_ENABLE_FAST_POW to suit your needs. +*/ + +#ifndef GL_LIGHT_H +#define GL_LIGHT_H + +#include "gl-sh4.h" + +#define GL_ENABLE_SPECULAR 1 +#define GL_ENABLE_FAST_POW 1 + +int _glKosSpotlight(void *glLight, void *vertex6f, void *Lvectorout); +float _glKosSpecular(void *vertex6f, void *eyepos, void *Lvectorin); + +typedef struct { + float r, g, b, a; +} rgba; + +typedef struct { + float Ke[4]; /* RGBA material emissive color # 0.0, 0.0, 0.0, 1.0 */ + float Ka[4]; /* RGBA material ambient reflectance # 0.2, 0.2, 0.2, 1.0 */ + float Kd[4]; /* RGBA material diffuse reflectance # 0.8, 0.8, 0.8, 1.0 */ + float Ks[4]; /* RGBA material diffuse reflectance # 0.0, 0.0, 0.0, 1.0 */ + float Shine; /* Material Specular Shine # 0.0f */ +} glMaterial; + +typedef struct { + float Pos[4]; /* XYZW Position of Light # 0.0, 0.0, 1.0, 0.0 */ + float Dir[3]; /* Spot Light Direction # 0.0, 0.0, -1.0 */ + float CutOff; /* Spot Light CutOff #-1.0f */ + float Kc, /* Constant Attenuation # 1.0f */ + Kl, /* Linear Attenuation # 0.0f */ + Kq; /* Quadratic Attenuation # 0.0f */ + float Exponent; /* Spot Light Exponent # 0.0f */ + float Kd[4]; /* RGBA Diffuse Light Contribution # 1.0, 1.0, 1.0, 1.0 */ + float Ks[4]; /* RGBA Specular Light Contribution # 1.0, 1.0, 1.0, 1.0 */ + float Ka[4]; /* RGBA Ambient Light Contribution # 0.0, 0.0, 0.0, 1.0 */ +} glLight; + +#endif diff --git a/gl-matrix.c b/gl-matrix.c new file mode 100755 index 0000000..383ff91 --- /dev/null +++ b/gl-matrix.c @@ -0,0 +1,395 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-matrix.c + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + Some functionality adapted from the original KOS libgl: + Copyright (C) 2001 Dan Potter + + The GL matrix operations use the KOS SH4 matrix operations. + Basically, we keep two seperate matrix stacks: + 1.) Internal GL API Matrix Stack ( screenview, modelview, etc. ) ( fixed stack size ) + 2.) External Matrix Stack for client to push / pop ( size of each stack is determined by MAX_MATRICES ) +*/ + +#include + +#include "gl.h" +#include "glu.h" +#include "gl-api.h" +#include "gl-sh4.h" + +/* This Matrix contains the GL Base Stack */ +static matrix4f Matrix[GL_MATRIX_COUNT] __attribute__((aligned(32))); +static GLsizei MatrixMode = 0; + +/* This Matrix contains the GL Push/Pop Stack ( fixed size per mode, 32 matrices )*/ +static const GLsizei MAX_MATRICES = 32; +static matrix4f MatrixStack[GL_MATRIX_COUNT][32] __attribute__((aligned(32))); +static GLsizei MatrixStackPos[GL_MATRIX_COUNT]; + +/* Viewport mapping */ +static GLfloat gl_viewport_scale[3], gl_viewport_offset[3]; + +/* Depth range */ +static GLclampf gl_depthrange_near, gl_depthrange_far; + +/* Viewport size */ +static GLint gl_viewport_x1, gl_viewport_y1, gl_viewport_width, gl_viewport_height; + +/* Frustum attributes */ +typedef struct { + float left, right, bottom, top, znear, zfar; +} gl_frustum_t; + +static gl_frustum_t gl_frustum; + +/* Frustum Matrix */ +static matrix4f FrustumMatrix __attribute__((aligned(32))) = { + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, -1.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f } +}; + +/* Ortho Matrix */ +static matrix4f OrthoMatrix __attribute__((aligned(32))) = { + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f } +}; + +/* Matrix for user to submit externally, ensure 32byte allignment */ +static matrix4f ml __attribute__((aligned(32))); + +/* Look-At Matrix */ +static matrix4f MatrixLookAt __attribute__((aligned(32))) = { + { 1.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f } +}; + +/* Modelview Rotation Matrix - Applied to Vertex Normal when Lighting is Enabled */ +static matrix4f MatrixMdlRot __attribute__((aligned(32))) = { + { 1.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f } +}; + +void glMatrixMode(GLenum mode) { + if(mode >= GL_SCREENVIEW && mode <= GL_IDENTITY) + MatrixMode = mode; +} + +void glPushMatrix() { + if(MatrixStackPos[MatrixMode] < MAX_MATRICES - 1) { + mat_load(Matrix + MatrixMode); + mat_store(&MatrixStack[MatrixMode][MatrixStackPos[MatrixMode]]); + ++MatrixStackPos[MatrixMode]; + } +} + +void glPopMatrix() { + if(MatrixStackPos[MatrixMode]) { + --MatrixStackPos[MatrixMode]; + mat_load(&MatrixStack[MatrixMode][MatrixStackPos[MatrixMode]]); + mat_store(Matrix + MatrixMode); + } +} + +void glLoadIdentity() { + mat_load(Matrix + GL_IDENTITY); + mat_store(Matrix + MatrixMode); + + if(MatrixMode == GL_MODELVIEW) + mat_store(&MatrixMdlRot); +} + +void glTranslatef(GLfloat x, GLfloat y, GLfloat z) { + mat_load(Matrix + MatrixMode); + mat_translate(x, y, z); + mat_store(Matrix + MatrixMode); +} + +void glScalef(GLfloat x, GLfloat y, GLfloat z) { + mat_load(Matrix + MatrixMode); + mat_scale(x, y, z); + mat_store(Matrix + MatrixMode); +} + +void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { + float r = DEG2RAD * angle; + mat_load(Matrix + MatrixMode); + mat_rotate(r * x, r * y, r * z); + mat_store(Matrix + MatrixMode); + + if(MatrixMode == GL_MODELVIEW) { + mat_load(&MatrixMdlRot); + mat_rotate(r * x, r * y, r * z); + mat_store(&MatrixMdlRot); + } +} + +/* Load an arbitrary matrix */ +void glLoadMatrixf(const GLfloat *m) { + memcpy(ml, m, sizeof(matrix4f)); + mat_load(&ml); + mat_store(Matrix + MatrixMode); +} + +/* Load an arbitrary transposed matrix */ +void glLoadTransposeMatrixf(const GLfloat *m) { + ml[0][0] = m[0]; + ml[0][1] = m[4]; + ml[0][2] = m[8]; + ml[0][3] = m[12]; + ml[1][0] = m[1]; + ml[1][1] = m[5]; + ml[1][2] = m[9]; + ml[1][3] = m[13]; + ml[2][0] = m[2]; + ml[2][1] = m[6]; + ml[2][2] = m[10]; + ml[2][3] = m[14]; + ml[3][0] = m[3]; + ml[3][1] = m[7]; + ml[3][2] = m[11]; + ml[3][3] = m[15]; + + mat_load(&ml); + mat_store(Matrix + MatrixMode); +} + +/* Multiply the current matrix by an arbitrary matrix */ +void glMultMatrixf(const GLfloat *m) { + memcpy(ml, m, sizeof(matrix4f)); + mat_load(Matrix + MatrixMode); + mat_apply(&ml); + mat_store(Matrix + MatrixMode); +} + +/* Multiply the current matrix by an arbitrary transposed matrix */ +void glMultTransposeMatrixf(const GLfloat *m) { + ml[0][0] = m[0]; + ml[0][1] = m[4]; + ml[0][2] = m[8]; + ml[0][3] = m[12]; + ml[1][0] = m[1]; + ml[1][1] = m[5]; + ml[1][2] = m[9]; + ml[1][3] = m[13]; + ml[2][0] = m[2]; + ml[2][1] = m[6]; + ml[2][2] = m[10]; + ml[2][3] = m[14]; + ml[3][0] = m[3]; + ml[3][1] = m[7]; + ml[3][2] = m[11]; + ml[3][3] = m[15]; + + mat_load(Matrix + MatrixMode); + mat_apply(&ml); + mat_store(Matrix + MatrixMode); +} + +/* Set the depth range */ +void glDepthRange(GLclampf n, GLclampf f) { + /* clamp the values... */ + if(n < 0.0f) n = 0.0f; + else if(n > 1.0f) n = 1.0f; + + if(f < 0.0f) f = 0.0f; + else if(f > 1.0f) f = 1.0f; + + gl_depthrange_near = n; + gl_depthrange_far = f; + + /* Adjust the viewport scale and offset for Z */ + gl_viewport_scale[2] = ((f - n) / 2.0f); + gl_viewport_offset[2] = (n + f) / 2.0f; +} + +/* Set the GL viewport */ +void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { + gl_viewport_x1 = x; + gl_viewport_y1 = y; + gl_viewport_width = width; + gl_viewport_height = height; + + /* Calculate the viewport scale and offset */ + gl_viewport_scale[0] = (GLfloat)width / 2.0f; + gl_viewport_offset[0] = gl_viewport_scale[0] + (GLfloat)x; + gl_viewport_scale[1] = (GLfloat)height / 2.0f; + gl_viewport_offset[1] = gl_viewport_scale[1] + (GLfloat)y; + gl_viewport_scale[2] = (gl_depthrange_far - gl_depthrange_near) / 2.0f; + gl_viewport_offset[2] = (gl_depthrange_near + gl_depthrange_far) / 2.0f; + + gl_viewport_offset[2] += 0.0001f; + + /* Set the Screenview Matrix based on the viewport */ + Matrix[GL_SCREENVIEW][0][0] = gl_viewport_scale[0]; + Matrix[GL_SCREENVIEW][1][1] = -gl_viewport_scale[1]; + Matrix[GL_SCREENVIEW][2][2] = 1; + Matrix[GL_SCREENVIEW][3][0] = gl_viewport_offset[0]; + Matrix[GL_SCREENVIEW][3][1] = vid_mode->height - gl_viewport_offset[1]; +} + +/* Set the GL frustum */ +void glFrustum(GLfloat left, GLfloat right, + GLfloat bottom, GLfloat top, + GLfloat znear, GLfloat zfar) { + gl_frustum.left = left; + gl_frustum.right = right; + gl_frustum.bottom = bottom; + gl_frustum.top = top; + gl_frustum.znear = znear; + gl_frustum.zfar = zfar; + + FrustumMatrix[0][0] = (2.0f * znear) / (right - left); + FrustumMatrix[2][0] = (right + left) / (right - left); + FrustumMatrix[1][1] = (2.0f * znear) / (top - bottom); + FrustumMatrix[2][1] = (top + bottom) / (top - bottom); + FrustumMatrix[2][2] = zfar / (zfar - znear); + FrustumMatrix[3][2] = -(zfar * znear) / (zfar - znear); + + mat_load(Matrix + MatrixMode); + mat_apply(&FrustumMatrix); + mat_store(Matrix + MatrixMode); +} + +/* Ortho */ +void glOrtho(GLfloat left, GLfloat right, + GLfloat bottom, GLfloat top, + GLfloat znear, GLfloat zfar) { + OrthoMatrix[0][0] = 2.0f / (right - left); + OrthoMatrix[1][1] = 2.0f / (top - bottom); + OrthoMatrix[2][2] = -2.0f / (zfar - znear); + OrthoMatrix[3][0] = -(right + left) / (right - left);; + OrthoMatrix[3][1] = -(top + bottom) / (top - bottom); + OrthoMatrix[3][2] = -(zfar + znear) / (zfar - znear); + + mat_load(Matrix + MatrixMode); + mat_apply(&OrthoMatrix); + mat_store(Matrix + MatrixMode); +} + +/* Set the Perspective */ +void gluPerspective(GLfloat angle, GLfloat aspect, + GLfloat znear, GLfloat zfar) { + GLfloat xmin, xmax, ymin, ymax; + + ymax = znear * ftan(angle * F_PI / 360.0f); + ymin = -ymax; + xmin = ymin * aspect; + xmax = ymax * aspect; + + glFrustum(xmin, xmax, ymin, ymax, znear, zfar); +} + +/* Vector Cross Product - Used by glhLookAtf2 */ +void vec3f_cross(vector3f v1, vector3f v2, vector3f result) { + result[0] = v1[1] * v2[2] - v1[2] * v2[1]; + result[1] = v1[2] * v2[0] - v1[0] * v2[2]; + result[2] = v1[0] * v2[1] - v1[1] * v2[0]; +} + +/* glhLookAtf2 adapted from http://www.opengl.org/wiki/GluLookAt_code */ +void glhLookAtf2(vector3f eyePosition3D, + vector3f center3D, + vector3f upVector3D) { + vector3f forward, side, up; + + _glKosSetEyePosition(eyePosition3D); + + vec3f_sub_normalize(center3D[0], center3D[1], center3D[2], + eyePosition3D[0], eyePosition3D[1], eyePosition3D[2], + forward[0], forward[1], forward[2]); + + //Side = forward x up + vec3f_cross(forward, upVector3D, side); + vec3f_normalize(side[0], side[1], side[2]); + + //Recompute up as: up = side x forward + vec3f_cross(side, forward, up); + + MatrixLookAt[0][0] = side[0]; + MatrixLookAt[1][0] = side[1]; + MatrixLookAt[2][0] = side[2]; + MatrixLookAt[3][0] = 0; + + MatrixLookAt[0][1] = up[0]; + MatrixLookAt[1][1] = up[1]; + MatrixLookAt[2][1] = up[2]; + MatrixLookAt[3][1] = 0; + + MatrixLookAt[0][2] = -forward[0]; + MatrixLookAt[1][2] = -forward[1]; + MatrixLookAt[2][2] = -forward[2]; + MatrixLookAt[3][2] = 0; + + MatrixLookAt[0][3] = + MatrixLookAt[1][3] = + MatrixLookAt[2][3] = 0; + MatrixLookAt[3][3] = 1; + + // Does not modify internal Modelview matrix + mat_load(&MatrixLookAt); + mat_translate(-eyePosition3D[0], -eyePosition3D[1], -eyePosition3D[2]); + mat_store(&MatrixLookAt); +} + +void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx, + GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy, + GLfloat upz) { + vector3f eye = { eyex, eyey, eyez }; + vector3f point = { centerx, centery, centerz }; + vector3f up = { upx, upy, upz }; + glhLookAtf2(eye, point, up); +} + +void _glKosMatrixApplyRender() { + mat_load(Matrix + GL_SCREENVIEW); + mat_apply(Matrix + GL_PROJECTION); + mat_apply(&MatrixLookAt); + mat_apply(Matrix + GL_MODELVIEW); + mat_store(Matrix + GL_RENDER); +} + +void _glKosMatrixLoadRender() { + mat_load(Matrix + GL_RENDER); +} + +void _glKosMatrixLoadModelView() { + mat_load(Matrix + GL_MODELVIEW); +} + +void _glKosMatrixLoadModelRot() { + mat_load(&MatrixMdlRot); +} + +void _glKosMatrixApplyScreenSpace() { + mat_load(Matrix + GL_SCREENVIEW); + mat_apply(Matrix + GL_PROJECTION); + mat_apply(&MatrixLookAt); +} + +void _glKosInitMatrix() { + mat_identity(); + mat_store(Matrix + GL_SCREENVIEW); + mat_store(Matrix + GL_PROJECTION); + mat_store(Matrix + GL_MODELVIEW); + mat_store(Matrix + GL_TEXTURE); + mat_store(Matrix + GL_IDENTITY); + mat_store(Matrix + GL_RENDER); + + int i; + + for(i = 0; i < GL_MATRIX_COUNT; i++) + MatrixStackPos[i] = 0; + + glDepthRange(0.0f, 1.0f); + glViewport(0, 0, vid_mode->width, vid_mode->height); +} diff --git a/gl-pvr.c b/gl-pvr.c new file mode 100755 index 0000000..7c53dd0 --- /dev/null +++ b/gl-pvr.c @@ -0,0 +1,215 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-pvr.c + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + Vertex Buffer Routines for interfacing the Dreamcast's SH4 CPU and PowerVR GPU. + + What we are doing here is using a Vertex Buffer in main RAM to store the + submitted data, untill the user finishes the scene by either calling + glSwapBuffer() to submit the buffer to the PVR for render to the screen OR + glSwapBufferToTexture() to submit the buffer to the PVR for render to texture. + + This solution means the client can switch between transparent and opaque polygon + sumbission at any time, in no particular order, with no penalty in speed. + + The size of the Vertex Buffer can be controlled by setting some params on gl-pvr.h: + GL_PVR_VERTEX_BUF_SIZE controls size of Vertex Buffer in the PVR VRAM + GL_MAX_VERTS conrols the number of vertices per list in the Vertex Buffer in SH4 RAM +*/ + +#include +#include +#include +#include + +#include "gl.h" +#include "gl-sh4.h" +#include "gl-pvr.h" + +/* Vertex Buffer Functions *************************************************************************/ + +#ifdef GL_USE_MALLOC +static pvr_cmd_t *GL_VBUF[2] __attribute__((aligned(32))); /* Dynamic Vertex Buffer */ +static pvr_cmd_t *GL_CBUF; /* Dynamic Clip Buffer */ +#else +static pvr_cmd_t GL_VBUF[2][GL_MAX_VERTS] __attribute__((aligned(32))); /* Static Vertex Buffer */ +static pvr_cmd_t GL_CBUF[GL_MAX_VERTS / 2]; /* Static Clip Buffer */ +#endif + +static unsigned int GL_VERTS[2] = {0, 0}, + GL_CVERTS = 0, + GL_LIST = GL_LIST_OP; + +/* Custom version of sq_cpy from KOS for copying vertex data to the PVR */ +static inline void pvr_list_submit(void *src, int n) { + unsigned int *d = TA_SQ_ADDR; + unsigned int *s = src; + + /* fill/write queues as many times necessary */ + while(n--) { + asm("pref @%0" : : "r"(s + 8)); /* prefetch 32 bytes for next loop */ + d[0] = *(s++); + d[1] = *(s++); + d[2] = *(s++); + d[3] = *(s++); + d[4] = *(s++); + d[5] = *(s++); + d[6] = *(s++); + d[7] = *(s++); + asm("pref @%0" : : "r"(d)); + d += 8; + } + + /* Wait for both store queues to complete */ + d = (unsigned int *)0xe0000000; + d[0] = d[8] = 0; +} + +inline void *_glKosClipBufAddress() { + return &GL_CBUF[0]; +} + +inline void *_glKosClipBufPointer() { + return &GL_CBUF[GL_CVERTS]; +} + +inline void _glKosClipBufIncrement() { + ++GL_CVERTS; +} + +inline void _glKosClipBufAdd(unsigned int count) { + GL_CVERTS += count; +} + +inline void _glKosClipBufReset() { + GL_CVERTS = 0; +} + +inline void _glKosVertexBufSwitchOP() { + GL_LIST = GL_LIST_OP; +} + +inline void _glKosVertexBufSwitchTR() { + GL_LIST = GL_LIST_TR; +} + +inline void *_glKosVertexBufAddress(unsigned char list) { + return &GL_VBUF[list][0]; +} + +inline void *_glKosVertexBufPointer() { + return &GL_VBUF[GL_LIST][GL_VERTS[GL_LIST]]; +} + +inline void _glKosVertexBufIncrement() { + ++GL_VERTS[GL_LIST]; +} + +inline void *_glKosTRVertexBufPointer() { + return &GL_VBUF[GL_LIST_TR][GL_VERTS[GL_LIST_TR]]; +} + +inline void _glKosTRVertexBufIncrement() { + ++GL_VERTS[GL_LIST_TR]; +} + +inline void _glKosVertexBufAdd(unsigned int count) { + GL_VERTS[GL_LIST] += count; +} + +inline void _glKosTRVertexBufAdd(unsigned int count) { + GL_VERTS[GL_LIST_TR] += count; +} + +inline void _glKosVertexBufDecrement() { + --GL_VERTS[GL_LIST]; +} + +inline void _glKosVertexBufReset() { + GL_VERTS[0] = GL_VERTS[1] = 0; +} + +inline unsigned int _glKosVertexBufCount(unsigned char list) { + return GL_VERTS[list]; +} + +unsigned char _glKosList() { + return GL_LIST; +} + +inline void _glKosVertexBufCopy(void *dst, void *src, GLuint count) { + memcpy(dst, src, count * 0x20); +} + +static inline void glutSwapBuffer() { + pvr_list_begin(PVR_LIST_OP_POLY); + + pvr_list_submit(_glKosVertexBufAddress(GL_LIST_OP), _glKosVertexBufCount(GL_LIST_OP)); + + pvr_list_finish(); + + pvr_list_begin(PVR_LIST_TR_POLY); + + pvr_list_submit(_glKosVertexBufAddress(GL_LIST_TR), _glKosVertexBufCount(GL_LIST_TR)); + + pvr_list_finish(); + + pvr_scene_finish(); +} + +void glutSwapBuffers() { + pvr_wait_ready(); + + pvr_scene_begin(); + + glutSwapBuffer(); + + _glKosVertexBufReset(); +} + +void glutSwapBuffersToTexture(void *dst, GLsizei *x, GLsizei *y) { + pvr_wait_ready(); + + pvr_scene_begin_txr(dst, x, y); + + glutSwapBuffer(); + + _glKosVertexBufReset(); +} + +void glutCopyBufferToTexture(void *dst, GLsizei *x, GLsizei *y) { + pvr_wait_ready(); + + pvr_scene_begin_txr(dst, x, y); + + glutSwapBuffer(); +} + +int _glKosInitPVR() { + pvr_init_params_t params = { + + /* Enable opaque and translucent polygons with size 32 and 32 */ + { PVR_BINSIZE_32, PVR_BINSIZE_0, PVR_BINSIZE_32, PVR_BINSIZE_0, PVR_BINSIZE_0 }, + + GL_PVR_VERTEX_BUF_SIZE, /* Vertex buffer size */ + + 0, /* No DMA */ + + + 0 /* No FSAA */ + }; + + pvr_init(¶ms); +#ifdef GL_USE_DMA + pvr_dma_init(); +#endif + +#ifdef GL_USE_MALLOC + GL_VBUF[0] = memalign(0x20, GL_MAX_VERTS * sizeof(pvr_cmd_t)); + GL_VBUF[1] = memalign(0x20, GL_MAX_VERTS * sizeof(pvr_cmd_t)); + GL_CBUF = malloc((GL_MAX_VERTS / 2) * sizeof(pvr_cmd_t)); +#endif + + return 1; +} diff --git a/gl-pvr.h b/gl-pvr.h new file mode 100755 index 0000000..f80b0c9 --- /dev/null +++ b/gl-pvr.h @@ -0,0 +1,54 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-pvr.h + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + Vertex Buffer Routines for interfacing the Dreamcast's SH4 CPU and PowerVR GPU. +*/ + +#ifndef GL_PVR_H +#define GL_PVR_H + +/* GL->PVR Commands */ +typedef struct { + unsigned int cmd[8]; +} pvr_cmd_t; /* Generic 32byte command for the pvr */ + +typedef struct { + unsigned int flags; /* Constant PVR_CMD_USERCLIP */ + unsigned int d1, d2, d3; /* Ignored for this type */ + unsigned int sx, /* Start x */ + sy, /* Start y */ + ex, /* End x */ + ey; /* End y */ +} pvr_cmd_tclip_t; /* Tile Clip command for the pvr */ + +#define GL_PVR_VERTEX_BUF_SIZE 2560 * 256 /* PVR Vertex buffer size */ +#define GL_MAX_VERTS 1024*64 /* SH4 Vertex Count */ +#define GL_MAX_TEXTURES 1024 /* Textures in Buffer */ + +#define GL_USE_MALLOC 1 /* Use Dynamic Vertex Array */ +//#define GL_USE_FLOAT 0 /* Use PVR's floating-point color Vertex Type (64bit) *NoOp* */ +//#define GL_USE_DMA 0 /* Use PVR DMA for vertex data transfer *NoOp* */ +#define GL_LIST_OP 0 +#define GL_LIST_TR 1 + +/* Misc SH4->PVR Commands */ +#define TA_SQ_ADDR (unsigned int *)(void *) \ + (0xe0000000 | (((unsigned long)0x10000000) & 0x03ffffe0)) + +#define QACRTA ((((unsigned int)0x10000000)>>26)<<2)&0x1c + +#define PVR_TA_TXR_FILTER_SHIFT 14 + +#define GL_PVR_FILTER_POINT 0x00 +#define GL_PVR_FILTER_BILINEAR 0x01 +#define GL_PVR_FILTER_TRILINEAR_A 0x10 +#define GL_PVR_FILTER_TRILINEAR_B 0x11 + +#define PVR_TA_SUPER_SAMPLE_SHIFT 12 + +#define GL_PVR_SAMPLE_POINT 0x0 +#define GL_PVR_SAMPLE_SUPER 0x1 + +#endif diff --git a/gl-rgb.c b/gl-rgb.c new file mode 100755 index 0000000..c8ee319 --- /dev/null +++ b/gl-rgb.c @@ -0,0 +1,116 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-rgb.c + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + A set of functions for working with ARGB pixel data, used by gluBuild2DMipmaps(...). +*/ + +#include "gl.h" +#include "gl-rgb.h" + +//===================================================================================================// +//== ARGB Bit Masks ==// + +static unsigned char ARGB1555_ALPHA(unsigned short c) { + return (c & ARGB1555_ALPHA_MASK) >> ARGB1555_ALPHA_SHIFT; +} + +static unsigned char ARGB1555_RED(unsigned short c) { + return (c & ARGB1555_RED_MASK) >> ARGB1555_RED_SHIFT; +} + +static unsigned char ARGB1555_GREEN(unsigned short c) { + return (c & ARGB1555_GREEN_MASK) >> ARGB1555_GREEN_SHIFT; +} + +static unsigned char ARGB1555_BLUE(unsigned short c) { + return (c & ARGB1555_BLUE_MASK) >> ARGB1555_BLUE_SHIFT; +} + +static unsigned char ARGB4444_ALPHA(unsigned short c) { + return (c & ARGB4444_ALPHA_MASK) >> ARGB4444_ALPHA_SHIFT; +} + +static unsigned char ARGB4444_RED(unsigned short c) { + return (c & ARGB4444_RED_MASK) >> ARGB4444_RED_SHIFT; +} + +static unsigned char ARGB4444_GREEN(unsigned short c) { + return (c & ARGB4444_GREEN_MASK) >> ARGB4444_GREEN_SHIFT; +} + +static unsigned char ARGB4444_BLUE(unsigned short c) { + return (c & ARGB4444_BLUE_MASK) >> ARGB4444_BLUE_SHIFT; +} + +static unsigned char RGB565_RED(unsigned short c) { + return (c & RGB565_RED_MASK) >> RGB565_RED_SHIFT; +} + +static unsigned char RGB565_GREEN(unsigned short c) { + return (c & RGB565_GREEN_MASK) >> RGB565_GREEN_SHIFT; +} + +static unsigned char RGB565_BLUE(unsigned short c) { + return c & RGB565_BLUE_MASK; +} + +//===================================================================================================// +//== Block Compression ==// + +uint16 __glKosAverageQuadPixelRGB565(uint16 p1, uint16 p2, uint16 p3, uint16 p4) { + uint8 R = (RGB565_RED(p1) + RGB565_RED(p2) + RGB565_RED(p3) + RGB565_RED(p4)) / 4; + uint8 G = (RGB565_GREEN(p1) + RGB565_GREEN(p2) + RGB565_GREEN(p3) + RGB565_GREEN(p4)) / 4; + uint8 B = (RGB565_BLUE(p1) + RGB565_BLUE(p2) + RGB565_BLUE(p3) + RGB565_BLUE(p4)) / 4; + + return R << RGB565_RED_SHIFT | G << RGB565_GREEN_SHIFT | B; +} + +uint16 __glKosAverageQuadPixelARGB1555(uint16 p1, uint16 p2, uint16 p3, uint16 p4) { + uint8 A = (ARGB1555_ALPHA(p1) + ARGB1555_ALPHA(p2) + ARGB1555_ALPHA(p3) + ARGB1555_ALPHA(p4)) / 4; + uint8 R = (ARGB1555_RED(p1) + ARGB1555_RED(p2) + ARGB1555_RED(p3) + ARGB1555_RED(p4)) / 4; + uint8 G = (ARGB1555_GREEN(p1) + ARGB1555_GREEN(p2) + ARGB1555_GREEN(p3) + ARGB1555_GREEN(p4)) / 4; + uint8 B = (ARGB1555_BLUE(p1) + ARGB1555_BLUE(p2) + ARGB1555_BLUE(p3) + ARGB1555_BLUE(p4)) / 4; + + return ((A & RGB1_MAX) << ARGB1555_ALPHA_SHIFT) | ((R & RGB5_MAX) << ARGB1555_RED_SHIFT) + | ((G & RGB5_MAX) << ARGB1555_GREEN_SHIFT) | (B & RGB5_MAX); +} + +uint16 __glKosAverageQuadPixelARGB4444(uint16 p1, uint16 p2, uint16 p3, uint16 p4) { + uint8 A = (ARGB4444_ALPHA(p1) + ARGB4444_ALPHA(p2) + ARGB4444_ALPHA(p3) + ARGB4444_ALPHA(p4)) / 4; + uint8 R = (ARGB4444_RED(p1) + ARGB4444_RED(p2) + ARGB4444_RED(p3) + ARGB4444_RED(p4)) / 4; + uint8 G = (ARGB4444_GREEN(p1) + ARGB4444_GREEN(p2) + ARGB4444_GREEN(p3) + ARGB4444_GREEN(p4)) / 4; + uint8 B = (ARGB4444_BLUE(p1) + ARGB4444_BLUE(p2) + ARGB4444_BLUE(p3) + ARGB4444_BLUE(p4)) / 4; + + return ((A & RGB4_MAX) << ARGB4444_ALPHA_SHIFT) | ((R & RGB4_MAX) << ARGB4444_RED_SHIFT) + | ((G & RGB4_MAX) << ARGB4444_GREEN_SHIFT) | (B & RGB4_MAX); +} + +uint16 __glKosAverageBiPixelRGB565(uint16 p1, uint16 p2) { + uint8 R = (RGB565_RED(p1) + RGB565_RED(p2)) / 2; + uint8 G = (RGB565_GREEN(p1) + RGB565_GREEN(p2)) / 2; + uint8 B = (RGB565_BLUE(p1) + RGB565_BLUE(p2)) / 2; + + return R << RGB565_RED_SHIFT | G << RGB565_GREEN_SHIFT | B; +} + +uint16 __glKosAverageBiPixelARGB1555(uint16 p1, uint16 p2) { + uint8 A = (ARGB1555_ALPHA(p1) + ARGB1555_ALPHA(p2)) / 4; + uint8 R = (ARGB1555_RED(p1) + ARGB1555_RED(p2)) / 4; + uint8 G = (ARGB1555_GREEN(p1) + ARGB1555_GREEN(p2)) / 4; + uint8 B = (ARGB1555_BLUE(p1) + ARGB1555_BLUE(p2)) / 4; + + return ((A & RGB1_MAX) << ARGB1555_ALPHA_SHIFT) | ((R & RGB5_MAX) << ARGB1555_RED_SHIFT) + | ((G & RGB5_MAX) << ARGB1555_GREEN_SHIFT) | (B & RGB5_MAX); +} + +uint16 __glKosAverageBiPixelARGB4444(uint16 p1, uint16 p2) { + uint8 A = (ARGB4444_ALPHA(p1) + ARGB4444_ALPHA(p2)) / 4; + uint8 R = (ARGB4444_RED(p1) + ARGB4444_RED(p2)) / 4; + uint8 G = (ARGB4444_GREEN(p1) + ARGB4444_GREEN(p2)) / 4; + uint8 B = (ARGB4444_BLUE(p1) + ARGB4444_BLUE(p2)) / 4; + + return ((A & RGB4_MAX) << ARGB4444_ALPHA_SHIFT) | ((R & RGB4_MAX) << ARGB4444_RED_SHIFT) + | ((G & RGB4_MAX) << ARGB4444_GREEN_SHIFT) | (B & RGB4_MAX); +} diff --git a/gl-rgb.h b/gl-rgb.h new file mode 100755 index 0000000..f212cf5 --- /dev/null +++ b/gl-rgb.h @@ -0,0 +1,63 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-rgb.h + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + A set of functions for working with ARGB pixel data. +*/ + +#ifndef GL_RGB_H +#define GL_RGB_H + +typedef GLubyte GLrgb3ub[3]; +typedef GLubyte GLrgba4ub[3]; +typedef GLfloat GLrgb3f[3]; +typedef GLfloat GLrgba4f[4]; + +#define RGB565_RED_MASK 0xF800 +#define RGB565_GREEN_MASK 0x7E0 +#define RGB565_BLUE_MASK 0x1F + +#define RGB565_RED_SHIFT 0xB +#define RGB565_GREEN_SHIFT 0x5 +#define RGB565_BLUE_SHIFT 0x0 + +#define ARGB4444_ALPHA_MASK 0xF000 +#define ARGB4444_RED_MASK 0x0F00 +#define ARGB4444_GREEN_MASK 0x00F0 +#define ARGB4444_BLUE_MASK 0x000F + +#define ARGB4444_ALPHA_SHIFT 0xC +#define ARGB4444_RED_SHIFT 0x8 +#define ARGB4444_GREEN_SHIFT 0x4 +#define ARGB4444_BLUE_SHIFT 0x0 + +#define ARGB1555_ALPHA_MASK 0x8000 +#define ARGB1555_RED_MASK 0x7C00 +#define ARGB1555_GREEN_MASK 0x3E0 +#define ARGB1555_BLUE_MASK 0x1F + +#define ARGB1555_ALPHA_SHIFT 0xF +#define ARGB1555_RED_SHIFT 0xA +#define ARGB1555_GREEN_SHIFT 0x5 +#define ARGB1555_BLUE_SHIFT 0x0 + +#define ARGB32_ALPHA_MASK 0xFF000000 +#define ARGB32_RGB_MASK 0xFFFFFF +#define ARGB32_RED_SHIFT 0x8 + +#define RGBA32_APLHA_MASK 0xFF +#define RGBA32_RGB_MASK 0xFFFFFF00 + +#define RGB1_MAX 0x1 +#define RGB4_MAX 0xF +#define RGB5_MAX 0x1F +#define RGB6_MAX 0x3F +#define RGB8_MAX 0xFF + +#define RGBA32_2_ARGB32(n) (((n & ARGB32_RGB_MASK) << ARGB32_RED_SHIFT) | (n & ARGB32_ALPHA_MASK)) + +#define ARGB_PACK_RGBF(r,g,b) (0xFF000000 | ((r*0xFF) << 16) | ((g*0xFF)<<8) | (b*0xFF)) +#define ARGB_PACK_ARGBF(a,r,g,b) (((a*0xFF) << 24) | ((r*0xFF) << 16) | ((g*0xFF)<<8) | (b*0xFF)) + +#endif diff --git a/gl-sh4-light.S b/gl-sh4-light.S new file mode 100755 index 0000000..67e6a86 --- /dev/null +++ b/gl-sh4-light.S @@ -0,0 +1,232 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-sh4-light.S + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + Dynamic Vertex Lighting + + This Assembly file contains 2 functions: + _glKosSpotLight - This function computes diffuse / spotlight / attenuation + _glKosSpecular - This functions computes the Specular Term +*/ + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +!float _glKosSpecular( void * vertex6f, void * eyepos, void * Lvectorin ); +.globl __glKosSpecular + +!r4 = [arg][void*] = vertex +!r5 = [arg][void*] = eyepos +!r6 = [arg][void*] = L vector + +!fr0 = return value +!fv0 = vertex position (P)(N) +!fv4 = eye position (E) +!fv8 = L vector (L) + +__glKosSpecular: + + fmov @r4+, fr0 ! load vertex x to fv0 + fmov @r4+, fr1 ! load vertex y to fv0 + fmov @r4+, fr2 ! load vertex z to fv0 + + fmov @r5+, fr4 ! load eye pos x to fv4 + fmov @r5+, fr5 ! load eye pos y to fv4 + fmov @r5+, fr6 ! load eye pos z to fv4 + + fmov @r6+, fr8 ! load L vector x to fv8 + fmov @r6+, fr9 ! load L vector y to fv8 + fmov @r6+, fr10 ! load L vector z to fv8 + + fsub fr0, fr4 ! fv4 = V = normalize ( E - P ) + fsub fr1, fr5 + fsub fr2, fr6 + fldi0 fr3 ! load 0 for P w + fldi0 fr7 ! load 0 for E w + + fipr fv4, fv4 ! Normalize V vector + fsqrt fr7 + + fcmp/gt fr3, fr7 ! V w <=0 = skip ndiv + bf .SKIPVndiv + + fdiv fr7, fr4 + fdiv fr7, fr5 + fdiv fr7, fr6 + +.SKIPVndiv: + + fadd fr4, fr8 ! fv8 = H = normalize( L + V ) + fadd fr5, fr9 + fadd fr6, fr10 + fldi0 fr11 ! load 0 for H w + + fipr fv8, fv8 ! Normalize H vector + fsqrt fr11 + + fcmp/gt fr3, fr11 ! H w <=0 = skip ndiv + bf .SKIPHndiv + + fdiv fr11, fr8 + fdiv fr11, fr9 + fdiv fr11, fr10 + +.SKIPHndiv: + fmov @r4+, fr0 ! load N to fv0 + fmov @r4+, fr1 + fmov @r4+, fr2 + + fipr fv0, fv8 ! N dot H for specular term + + rts + fmov fr11, fr0 ! move N dot H to fr0 for return + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +!int _glKosSpotlight( void * glLight, void * vertex6f, void * Lvectorout ); +.globl __glKosSpotlight + +!r0 = return value | true or false +!r1 = boolean flag +!r2 = boolean false +!r4 = [arg] = light +!r5 = [arg] = vertex +!r6 = [arg] = output + +!fv0 = vertex position +!fv4 = light position | L vector | normalize(light pos - vertex pos) | w = attenuation distance +!fv8 = light direction | N vector = Vertex Normal +!fv12 = Spot vector | normalize(vertex pos - light pos) + +__glKosSpotlight: + + mov #0, r1 ! load 0 for boolean flag + mov #0, r2 ! load 0 for boolean false + + fmov @r4+, fr4 ! load light position x to fv4 + fmov @r4+, fr5 ! load light position y to fv4 + fmov @r4+, fr6 ! load light position z to fv4 + fmov @r4+, fr7 ! load light position w to fv4 + + fmov @r4+, fr8 ! load light direction x to fv8 + fmov @r4+, fr9 ! load light direction y to fv8 + fmov @r4+, fr10 ! load light direction z to fv8 + + fmov @r5+, fr0 ! load vertex position x to fv0 + fmov @r5+, fr1 ! load vertex position y to fv0 + fmov @r5+, fr2 ! load vertex position z to fv0 + + fldi0 fr11 ! load 0 for light dir w + fcmp/gt fr11, fr7 ! light pos w component set = spot light + bf .VERTEXLIGHT0 ! light not a spot light - branch to vertex lighting + + fschg + fmov dr0, dr12 ! copy vertex x,y to fv12 + fschg + fmov fr2, fr14 ! copy vertex z to fv12 + + fsub fr4, fr12 ! fv12 = ( vertex position - light position) + fsub fr5, fr13 + fsub fr6, fr14 + fldi0 fr15 ! set fv12 w component to 0 + + fipr fv12, fv12 ! Normalize vector + fsqrt fr15 + + fcmp/gt fr11, fr15 ! Check for Normalization division + bf .SPOTcosdir ! If w < 0, skip division + + fdiv fr12, fr15 + fdiv fr13, fr15 + fdiv fr14, fr15 + +.SPOTcosdir: + + fldi0 fr15 ! set fv12 w component to 0 + fipr fv12, fv8 ! fr11 now holds light cosDir + + fmov @r4+, fr15 ! load light cutOff to fr15 + mov #1, r1 ! load 1 for boolean flag = indicate light cutOff was read + + fcmp/gt fr15, fr11 ! cosDir > cutOff ? 0 : 1 + bt .RET0spot ! vertex outside of spotlight = return 0 + +.VERTEXLIGHT0: + + fsub fr0, fr4 ! fv4 = L vector = ( light position - vertex position) + fsub fr1, fr5 + fsub fr2, fr6 + fldi0 fr7 ! load 0 for L w + fldi0 fr11 ! load 0 for N w + + fipr fv4, fv4 ! Normalize L vector + fsqrt fr7 + + fcmp/gt fr11, fr7 ! Normalization division if w component > 0 + bf .SDIVlv + + fdiv fr7, fr4 + fdiv fr7, fr5 + fdiv fr7, fr6 ! fv4 = Normalized L Vector + +.SDIVlv: + + fmov fr7, fr3 ! copy L w to fr3 + + fldi0 fr7 ! load 0 for L w + + fcmp/gt fr7, fr3 + bf .RET0spot ! if L w < 0, return 0 now to avoid pointless computations + + fmov @r5+, fr8 ! load normal to fv8 + fmov @r5+, fr9 ! load normal to fv8 + fmov @r5+, fr10 ! load normal to fv8 + + fipr fv8, fv4 ! N dot L + + fcmp/gt fr11, fr7 ! L w < = 0 ? L w = 0 + bf .RET0spot: ! if L w < 0, return 0 now to avoid pointless computations + +.WRITEDi: + + fschg + fmov dr4, @r6 ! write L vector x to output + fschg + add #8, r6 + fmov fr6, @r6 ! write L vector z to output + add #4, r6 + + cmp/gt r2, r1 + bt .READattenf + + add #4, r4 + +.READattenf: + + fmov @r4+, fr8 ! vertex normal gets overwritten by atten factors + fmov @r4+, fr9 + fmov @r4+, fr10 + fldi1 fr11 + + fmul fr3, fr9 ! calculate attenuation + fmul fr3, fr10 + fmul fr3, fr10 + fadd fr9, fr8 + fadd fr10, fr8 + fdiv fr8, fr11 ! fr11 = A + + fmul fr7, fr11 ! D * A + + fmov fr11, @r6 ! write D*A to output + +.RET1spot: + + rts + mov #1, r0 + +.RET0spot: + + rts + mov #0, r0 + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/gl-sh4.h b/gl-sh4.h new file mode 100755 index 0000000..4aad810 --- /dev/null +++ b/gl-sh4.h @@ -0,0 +1,52 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/gl-sh4.h + Copyright (C) 2013-2014 Josh "PH3NOM" Pearson + + Macros for utilizing the Dreamcast's SH4 CPU vector / matrix math functions. +*/ + +#ifndef GL_SH4_H +#define GL_SH4_H + +typedef float vector3f[3]; /* 3 float vector */ +typedef float matrix4f[4][4]; /* 4x4 float matrix */ + +/* DEG2RAD - convert Degrees to Radians = PI / 180.0f */ +#define DEG2RAD (0.01745329251994329576923690768489) + +/* Calculate Spot Light Angle Cosine = (PI / 180.0f) * (n / 2) */ +#define LCOS(n) fcos(n*0.00872664625997164788461845384244) + +/* Internal GL API macro */ +#define mat_trans_fv12() { \ + __asm__ __volatile__( \ + "fldi1 fr15\n" \ + "ftrv xmtrx, fv12\n" \ + "fldi1 fr14\n" \ + "fdiv fr15, fr14\n" \ + "fmul fr14, fr12\n" \ + "fmul fr14, fr13\n" \ + : "=f" (__x), "=f" (__y), "=f" (__z) \ + : "0" (__x), "1" (__y), "2" (__z) \ + : "fr15" ); \ + } + +/* Internal GL API macro */ +#define mat_trans_fv12_nodiv() { \ + __asm__ __volatile__( \ + "fldi1 fr15\n" \ + "ftrv xmtrx, fv12\n" \ + : "=f" (__x), "=f" (__y), "=f" (__z) \ + : "0" (__x), "1" (__y), "2" (__z) ); \ + } + +#define mat_trans_fv12_nodivw() { \ + __asm__ __volatile__( \ + "fldi1 fr15\n" \ + "ftrv xmtrx, fv12\n" \ + : "=f" (__x), "=f" (__y), "=f" (__z), "=f" (__w) \ + : "0" (__x), "1" (__y), "2" (__z), "3" (__w) ); \ + } + +#endif diff --git a/include/._gl.h b/include/._gl.h new file mode 100755 index 0000000..abd5f9b Binary files /dev/null and b/include/._gl.h differ diff --git a/include/glut.h b/include/glut.h new file mode 100755 index 0000000..4284b04 --- /dev/null +++ b/include/glut.h @@ -0,0 +1,25 @@ +/* KallistiGL for KallistiOS ##version## + + libgl/glut.h + Copyright (C) 2014 Josh Pearson + Copyright (C) 2014 Lawrence Sebald + +*/ + +#ifndef __GL_GLUT_H +#define __GL_GLUT_H + +#include + +/* Flush the Submitted Primitive Data to the GPU for render to screen */ +GLAPI void APIENTRY glutSwapBuffers(); + +/* Flush the Submitted Primitive Data to the GPU for render to texture */ +GLAPI void APIENTRY glutSwapBuffersToTexture(void *dst, GLsizei *x, GLsizei *y); + +/* Copy the Submitted Primitive Data to the GPU for render to texture */ +/* This will leave the Vertex Data in the Main Buffer to be Flushed on the + next frame rendered */ +GLAPI void APIENTRY glutCopyBufferToTexture(void *dst, GLsizei *x, GLsizei *y); + +#endif /* !__GL_GLUT_H */