commit cbe2111cd852db838d71c5a77f6a979286fb6679 Author: Dan Potter Date: Mon Oct 13 00:41:10 2003 +0000 Updated changelog/relnotes, moved most addons into their own tree diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..df733bc --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +# KallistiOS ##version## +# +# addons/libgl Makefile +# (c)2001 Dan Potter +# +# $Id: Makefile,v 1.5 2003/02/27 04:25:39 bardtx Exp $ + +TARGET = libgl.a +OBJS = gldepth.o gldraw.o glkos.o gllight.o glmisc.o +OBJS += gltex.o gltrans.o glvars.o glblend.o glfog.o glmodifier.o glnzclip.o +SUBDIRS = + +include ../Makefile.prefab + + diff --git a/glblend.c b/glblend.c new file mode 100644 index 0000000..5a0908d --- /dev/null +++ b/glblend.c @@ -0,0 +1,79 @@ +/* KallistiGL for KOS ##version## + + glblend.c + (c)2002 Benoit Miller +*/ + +#include +#include +#include "glinternal.h" +#include "glmacros.h" + +#include + +CVSID("$Id: glblend.c,v 1.3 2002/04/03 03:33:38 axlen Exp $"); + +/* Blending */ +void glBlendFunc(GLenum sfactor, GLenum dfactor) { + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + switch(sfactor) { + case GL_ZERO: + gl_blend_src = PVR_BLEND_ZERO; + break; + case GL_ONE: + gl_blend_src = PVR_BLEND_ONE; + break; + case GL_DST_COLOR: + gl_blend_src = PVR_BLEND_DESTCOLOR; + break; + case GL_ONE_MINUS_DST_COLOR: + gl_blend_src = PVR_BLEND_INVDESTCOLOR; + break; + case GL_SRC_ALPHA: + gl_blend_src = PVR_BLEND_SRCALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + gl_blend_src = PVR_BLEND_INVSRCALPHA; + break; + case GL_DST_ALPHA: + gl_blend_src = PVR_BLEND_DESTALPHA; + break; + case GL_ONE_MINUS_DST_ALPHA: + gl_blend_src = PVR_BLEND_INVDESTALPHA; + break; + default: + assert_msg(0, "Invalid source blending function."); + } + + switch(dfactor) { + case GL_ZERO: + gl_blend_dst = PVR_BLEND_ZERO; + break; + case GL_ONE: + gl_blend_dst = PVR_BLEND_ONE; + break; + case GL_SRC_COLOR: + gl_blend_dst = PVR_BLEND_DESTCOLOR; + break; + case GL_ONE_MINUS_SRC_COLOR: + gl_blend_dst = PVR_BLEND_INVDESTCOLOR; + break; + case GL_SRC_ALPHA: + gl_blend_dst = PVR_BLEND_SRCALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + gl_blend_dst = PVR_BLEND_INVSRCALPHA; + break; + case GL_DST_ALPHA: + gl_blend_dst = PVR_BLEND_DESTALPHA; + break; + case GL_ONE_MINUS_DST_ALPHA: + gl_blend_dst = PVR_BLEND_INVDESTALPHA; + break; + default: + assert_msg(0, "Invalid destination blending function"); + } + + gl_pbuf_submitted = GL_FALSE; +} diff --git a/glclip.h b/glclip.h new file mode 100644 index 0000000..a71e321 --- /dev/null +++ b/glclip.h @@ -0,0 +1,97 @@ +/* KallistiGL for KOS ##version## + + Near Z Clipper + (c) Trilinear + Trilinear@hotmail.com + + $Id: glclip.h,v 1.2 2002/06/28 04:47:02 axlen Exp $ +*/ + +#ifndef __GLCLIP_H +#define __GLCLIP_H + +#include +#include "glinternal.h" + +#define MAXZ 0.0001f /* if z is negative, it is behind the camera */ + +inline void CopyV(gl_vertex_t *vertold, gl_vertex_t *vertnew) { + +/* memcpy(vertnew, vertold, sizeof(gl_vertex_t)); */ + + vertnew->flags = vertold->flags; + vertnew->x = vertold->x; + vertnew->y = vertold->y; + vertnew->z = vertold->z; + vertnew->w = vertold->w; + vertnew->u = vertold->u; + vertnew->v = vertold->v; + vertnew->argb = vertold->argb; + vertnew->oargb = vertold->oargb; + +} + +inline void FindZ(gl_vertex_t *vertnew, gl_vertex_t *vert1, gl_vertex_t *vert2) { + + float diffz; + /* z is indp variable because we know it changes, thus no div 0 error */ + vertnew->z = gl_frustum.znear; + vertnew->w = vert1->w + (gl_frustum.znear-vert1->z)*(vert1->w - vert2->w)/(vert1->z - vert2->z); + vertnew->x = vert1->x + (gl_frustum.znear-vert1->z)*(vert1->x - vert2->x)/(vert1->z - vert2->z); + vertnew->y = vert1->y + (gl_frustum.znear-vert1->z)*(vert1->y - vert2->y)/(vert1->z - vert2->z); + + diffz = (vert1->z-vertnew->z)/(vert1->z-vert2->z); + vertnew->u = (diffz)*vert2->u + (1.0f-diffz)*vert1->u; + vertnew->v = (diffz)*vert2->v + (1.0f-diffz)*vert1->v; +} + +inline int ZClipTex(gl_vertex_t *vert) + /* returns 0 for full clip, 3 for triangle output and 4 for quad output + based on sutherland-hodgeman clip algorithm */ +{ + int i,j; + gl_vertex_t tempvert[4]; + + if (vert[0].z < gl_frustum.znear || vert[1].z < gl_frustum.znear || vert[2].z < gl_frustum.znear) {/* one or more parts behind camera */ + j=0; + CopyV(&vert[0],&vert[3]);/* copy first to next after last to make cyclic */ + for(i=0; i<3; i++) { + if (vert[i].z >= gl_frustum.znear && vert[i+1].z >= gl_frustum.znear) { /* both in */ + CopyV(&vert[i],&tempvert[j]); + j++; + }else if (vert[i].z < gl_frustum.znear && vert[i+1].z >= gl_frustum.znear) {/* this out, next in */ + CopyV(&vert[i],&tempvert[j]); + FindZ(&tempvert[j],&vert[i],&vert[i+1]); + j++; + }else if (vert[i].z >= gl_frustum.znear && vert[i+1].z < gl_frustum.znear) {/* this in, next out */ + CopyV(&vert[i],&tempvert[j]); + CopyV(&vert[i+1],&tempvert[j+1]); + FindZ(&tempvert[j+1],&vert[i],&vert[i+1]); + j+=2; + }/* both out, ignore */ + } + + + switch (j) { + case 3: + CopyV(&tempvert[0],&vert[0]); + CopyV(&tempvert[1],&vert[1]); + CopyV(&tempvert[2],&vert[2]); + return 3; + case 4: + CopyV(&tempvert[0],&vert[0]); + CopyV(&tempvert[1],&vert[1]); + CopyV(&tempvert[2],&vert[3]); + CopyV(&tempvert[3],&vert[2]); + return 4; + }/* if j==0 we return 0 which we are about to do anyway */ + + }else{/* is all in front of camera */ + return 3; + } + + return 0;/* if it isn't one of the above it is an invalid poly or completely behind camera */ +} + +#endif /* __GLCLIP_H */ + diff --git a/gldepth.c b/gldepth.c new file mode 100644 index 0000000..684a229 --- /dev/null +++ b/gldepth.c @@ -0,0 +1,74 @@ +/* KallistiGL for KOS ##version## + + gldepth.c + (c)2001 Dan Potter +*/ + +#include +#include +#include "glinternal.h" +#include "glmacros.h" + +#include +#include + +CVSID("$Id: gldepth.c,v 1.7 2002/04/03 03:34:22 axlen Exp $"); + +/* Depth buffer (non-functional, just stubs) */ +void glClearDepth(GLclampd depth) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); +} + +void glDepthFunc(GLenum func) { + /* Note regarding the mapping of OpenGL depth stuff to the PVR2DC: + + The depth compare modes should be "conceptually" the same except + for two points: + 1) You have a floating point "Depth buffer" and + 2) DC uses 1/W to compare so 1 (or higher if your clipping + is off!) = near and 0=infinity. + Therefore > or >= is probably what you want for closer objects to be visible. - Simon Fenney + */ + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + switch(func) + { + case GL_ALWAYS: + gl_poly_cxt.depth.comparison = PVR_DEPTHCMP_ALWAYS; + break; + case GL_LESS: + gl_poly_cxt.depth.comparison = PVR_DEPTHCMP_GEQUAL; + break; + case GL_NOTEQUAL: + gl_poly_cxt.depth.comparison = PVR_DEPTHCMP_NOTEQUAL; + break; + case GL_LEQUAL: + gl_poly_cxt.depth.comparison = PVR_DEPTHCMP_GREATER; + break; + case GL_GREATER: + gl_poly_cxt.depth.comparison = PVR_DEPTHCMP_LEQUAL; + break; + case GL_EQUAL: + gl_poly_cxt.depth.comparison = PVR_DEPTHCMP_EQUAL; + break; + case GL_GEQUAL: + gl_poly_cxt.depth.comparison = PVR_DEPTHCMP_LESS; + break; + case GL_NEVER: + gl_poly_cxt.depth.comparison = PVR_DEPTHCMP_NEVER; + break; + default: + assert_msg(0, "Invalid depth comparison function."); + } + + gl_pbuf_submitted = GL_FALSE; +} + +void glDepthMask(GLboolean flag) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + if (flag) { + gl_poly_cxt.depth.write = PVR_DEPTHWRITE_ENABLE; + } else { + gl_poly_cxt.depth.write = PVR_DEPTHWRITE_DISABLE; + } + gl_pbuf_submitted = GL_FALSE; +} diff --git a/gldraw.c b/gldraw.c new file mode 100644 index 0000000..d2fe3e5 --- /dev/null +++ b/gldraw.c @@ -0,0 +1,595 @@ +/* KallistiGL for KOS ##version## + + gldraw.c + (c)2001 Dan Potter +*/ + +#include +#include +#include "glinternal.h" +#include "glmacros.h" + +#include +#include +#include +#include + +CVSID("$Id: gldraw.c,v 1.23 2002/09/05 07:36:23 bardtx Exp $"); + +/* internal prototypes */ +static void send_user_clip(); + +/* Drawing functions */ + +/* This portion of the pipeline will change drastically */ + +/* Current vertex attributes (move to global?) */ +static GLuint vert_rgba = 0xffffffff; +static GLfloat vert_u = 0.0f, vert_v = 0.0f; + +/* Make sure the proper matrices are in the matrix registers */ +static void fix_matrices() { + if (gl_matrix_dirty) { + mat_identity(); + glKosMatrixApply(GL_KOS_SCREENVIEW); + glKosMatrixApply(GL_PROJECTION); + glKosMatrixApply(GL_MODELVIEW); + + gl_matrix_dirty = GL_FALSE; + } +} + +/* Negative 1/w values annoy the pvr, so check for them */ +static inline int check_w(gl_vertex_t *vert, int n) { + int i; + + for(i=0; i= 1, "Need at least one point."); + + /* create a point using a quad */ + memcpy(&gl_vbuf[1], &gl_vbuf[0], sizeof(gl_vertex_t)); + memcpy(&gl_vbuf[2], &gl_vbuf[0], sizeof(gl_vertex_t)); + memcpy(&gl_vbuf[3], &gl_vbuf[0], sizeof(gl_vertex_t)); + + gl_vbuf[3].flags = PVR_CMD_VERTEX_EOL; + mat_transform((vector_t*)&gl_vbuf[0].x, (vector_t*)&gl_xbuf[0].x, 4, sizeof(gl_vertex_t)); + + gl_xbuf[0].x += size1; + gl_xbuf[0].y += size2; + gl_xbuf[1].x += size1; + gl_xbuf[1].y -= size2; + gl_xbuf[2].x -= size1; + gl_xbuf[2].y += size2; + gl_xbuf[3].x -= size1; + gl_xbuf[3].y -= size2; + + /* Throw it all to the TA using direct render */ + if (check_w(gl_xbuf, 4)) + for (i=0; i<4; i++) { + vert = pvr_dr_target(dr_state); + vert->flags = gl_vbuf[i].flags; + vert->x = gl_xbuf[i].x; + vert->y = gl_xbuf[i].y; + vert->z = gl_xbuf[i].z; + vert->u = gl_vbuf[i].u; + vert->v = gl_vbuf[i].v; + vert->argb = gl_vbuf[i].argb; + vert->oargb = gl_vbuf[i].oargb; + pvr_dr_commit(vert); + } +} + +static void end_triangles() { + int i; + volatile pvr_vertex_t *vert; + pvr_dr_state_t dr_state; + + pvr_dr_init(dr_state); + + /* Should be three points in the buffer */ + assert_msg(gl_vbuf_top == 3, "Wrong number of vertices."); + + gl_vbuf[2].flags = PVR_CMD_VERTEX_EOL; + /* mat_transform((vector_t*)&gl_vbuf[0].x, (vector_t*)&gl_xbuf[0].x, 3, +sizeof(gl_vertex_t)); */ + + for (i=0; iflags = gl_vbuf[i].flags; + vert->x = gl_xbuf[i].x; + vert->y = gl_xbuf[i].y; + vert->z = gl_xbuf[i].z; + vert->u = gl_vbuf[i].u; + vert->v = gl_vbuf[i].v; + vert->argb = gl_vbuf[i].argb; + vert->oargb = gl_vbuf[i].oargb; + pvr_dr_commit(vert); + } +} + +static void end_triangle_strip() { + int i; + volatile pvr_vertex_t *vert; + pvr_dr_state_t dr_state; + + pvr_dr_init(dr_state); + + /* Should be at least 3 points in the buffer */ + assert_msg(gl_vbuf_top >= 3, "Need at least three vertices."); + + gl_vbuf[gl_vbuf_top-1].flags = PVR_CMD_VERTEX_EOL; + /* mat_transform((vector_t*)&gl_vbuf[0].x, (vector_t*)&gl_xbuf[0].x, +gl_vbuf_top, sizeof(gl_vertex_t)); */ + + for (i=0; iflags = gl_vbuf[i].flags; + vert->x = gl_xbuf[i].x; + vert->y = gl_xbuf[i].y; + vert->z = gl_xbuf[i].z; + vert->u = gl_vbuf[i].u; + vert->v = gl_vbuf[i].v; + vert->argb = gl_vbuf[i].argb; + vert->oargb = gl_vbuf[i].oargb; + pvr_dr_commit(vert); + } +} + +static void end_quads() { + int i, j, order[4] = {3, 0, 2, 1}; + volatile pvr_vertex_t *vert; + pvr_dr_state_t dr_state; + + pvr_dr_init(dr_state); + + /* Should be four points in the buffer */ + assert_msg(gl_vbuf_top == 4, "Wrong number of vertices."); + + gl_vbuf[order[3]].flags = PVR_CMD_VERTEX_EOL; + /* mat_transform((vector_t*)&gl_vbuf[0].x, (vector_t*)&gl_xbuf[0].x, 4, +sizeof(gl_vertex_t)); */ + + for (i=0; iflags = gl_vbuf[j].flags; + vert->x = gl_xbuf[j].x; + vert->y = gl_xbuf[j].y; + vert->z = gl_xbuf[j].z; + vert->u = gl_vbuf[j].u; + vert->v = gl_vbuf[j].v; + vert->argb = gl_vbuf[j].argb; + vert->oargb = gl_vbuf[j].oargb; + pvr_dr_commit(vert); + } +} + +static void end_quad_strip() { + int i; + volatile pvr_vertex_t *vert; + pvr_dr_state_t dr_state; + + pvr_dr_init(dr_state); + + /* Should be at least 4 points in the buffer */ + assert_msg(gl_vbuf_top >= 4, "Need at least four vertices."); + + /* OpenGL specs that any dangling vertex be chopped, which + we have to do since we're rendering as a tri-strip. */ + if(gl_vbuf_top & 0x0001) + gl_vbuf_top--; + + gl_vbuf[gl_vbuf_top-1].flags = PVR_CMD_VERTEX_EOL; + + for (i=0; iflags = gl_vbuf[i].flags; + vert->x = gl_xbuf[i].x; + vert->y = gl_xbuf[i].y; + vert->z = gl_xbuf[i].z; + vert->u = gl_vbuf[i].u; + vert->v = gl_vbuf[i].v; + vert->argb = gl_vbuf[i].argb; + vert->oargb = gl_vbuf[i].oargb; + pvr_dr_commit(vert); + } +} + +static void end_polygon() { + int i, j_frn, j_bck; + volatile pvr_vertex_t *vert; + gl_vertex_t *gl_tvbuf; + pvr_dr_state_t dr_state; + + pvr_dr_init(dr_state); + + /* Should be at least 3 points in the buffer */ + assert_msg(gl_vbuf_top >= 3, "Need at least three vertices."); + + /* Have to alter linear vertex order to staggered Triangle strip order + performance will suffer, but it does on all cards. */ + + gl_tvbuf = malloc(sizeof(gl_vertex_t) * (gl_vbuf_top)); + assert_msg(gl_tvbuf != NULL, "Not enough memory for GL_POLYGON"); + + gl_tvbuf[0] = gl_vbuf[0]; + gl_tvbuf[1] = gl_vbuf[1]; + + i = 2; /* the first 2 vertices are in proper order. */ + j_frn = i; + j_bck = gl_vbuf_top - 1; + + do { + gl_tvbuf[i++] = gl_vbuf[j_bck]; /* move data */ + if (i < gl_vbuf_top) { + gl_tvbuf[i++] = gl_vbuf[j_frn]; + j_frn++; + j_bck--; + } + } while (i < gl_vbuf_top); + + memcpy(gl_vbuf, gl_tvbuf, sizeof(gl_vertex_t) * gl_vbuf_top); + free(gl_tvbuf); + + gl_vbuf[gl_vbuf_top-1].flags = PVR_CMD_VERTEX_EOL; + + for (i=0; iflags = gl_vbuf[i].flags; + vert->x = gl_xbuf[i].x; + vert->y = gl_xbuf[i].y; + vert->z = gl_xbuf[i].z; + vert->u = gl_vbuf[i].u; + vert->v = gl_vbuf[i].v; + vert->argb = gl_vbuf[i].argb; + vert->oargb = gl_vbuf[i].oargb; + pvr_dr_commit(vert); + } +} + +static void check_end() { + /* What type of primitive was it? */ + switch(gl_prim_type) { + case GL_POINTS: + end_points(); + gl_vbuf_top = 0; + break; + case GL_TRIANGLES: + if (gl_vbuf_top == 3) { + end_triangles(); + gl_vbuf_top = 0; + } + break; + case GL_TRIANGLE_STRIP: + break; + case GL_QUADS: + if (gl_vbuf_top == 4) { + end_quads(); + gl_vbuf_top = 0; + } + break; + case GL_QUAD_STRIP: + break; + case GL_POLYGON: + break; + default: + assert_msg(0, "gl_prim_type: Unknown primitive type."); + } +} + +static pvr_poly_hdr_t polyhdr; + +void send_poly_hdr(void) { + + if (TXR_ENABLED) { + memcpy(&gl_poly_cxt.txr, &gl_cur_texture->txr, sizeof(gl_poly_cxt.txr)); + } + + switch(gl_active_list) { + case GL_LIST_OPAQUE_POLY: + gl_poly_cxt.gen.alpha = PVR_ALPHA_DISABLE; + gl_poly_cxt.txr.alpha = PVR_TXRALPHA_ENABLE; + gl_poly_cxt.blend.src = PVR_BLEND_ONE; + gl_poly_cxt.blend.dst = PVR_BLEND_ZERO; + break; + case GL_LIST_OPAQUE_MOD: + break; + case GL_LIST_TRANS_POLY: + case GL_LIST_PUNCHTHRU: + gl_poly_cxt.gen.alpha = PVR_ALPHA_ENABLE; + gl_poly_cxt.txr.alpha = PVR_TXRALPHA_ENABLE; + gl_poly_cxt.blend.src = gl_blend_src; + gl_poly_cxt.blend.dst = gl_blend_dst; + break; + case GL_LIST_TRANS_MOD: + break; + } + /* Set states that we couldn't before */ + if (gl_cull_face) + { + if (gl_cull_mode == GL_BACK) + if (gl_front_face == GL_CW) + gl_poly_cxt.gen.culling = PVR_CULLING_CCW; + else + gl_poly_cxt.gen.culling = PVR_CULLING_CW; + else + if (gl_front_face == 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(&polyhdr, &gl_poly_cxt); + pvr_prim(&polyhdr, sizeof(pvr_poly_hdr_t)); +} + +/* This can be used for KGL Direct Rendering */ +void glKosPolyHdrSend() { + send_poly_hdr(); +} + +void glBegin(GLenum mode) { + /* Submit the user clip rectangle (if necessary) */ + if (gl_scissor_dirty) { + send_user_clip(); + gl_scissor_dirty = GL_FALSE; + } + + /* Submit the poly buffer (if necessary) */ + if (!gl_pbuf_submitted) { + send_poly_hdr(); + gl_pbuf_submitted = GL_TRUE; + } + if (ZCLIP_ENABLED || LIGHTING_ENABLED) + fix_vfzclip_matrices(); + else + fix_matrices(); + + gl_prim_type = mode; + gl_vbuf_top = 0; +} + +void glEnd(void) { + if (MODIFIER_ENABLED) { + modifier_end(); + return; + } else if (ZCLIP_ENABLED || LIGHTING_ENABLED) { + vfzclip_end(); + return; + } + + /* What type of primitive was it? */ + switch(gl_prim_type) { + case GL_POINTS: + break; + case GL_TRIANGLES: + break; + case GL_TRIANGLE_STRIP: + end_triangle_strip(); + break; + case GL_QUADS: + break; + case GL_QUAD_STRIP: + end_quad_strip(); + break; + case GL_POLYGON: + end_polygon(); + break; + default: + assert_msg(0, "gl_prim_type: Unknown primitive type."); + } + gl_prim_type = 0; +} + +static float autouv[4][2] = { + {0.0f, 0.0f}, + {1.0f, 0.0f}, + {1.0f, 1.0f}, + {0.0f, 1.0f} +}; + +void glVertex3f(GLfloat x, GLfloat y, GLfloat z) { + gl_vbuf[gl_vbuf_top].flags = PVR_CMD_VERTEX; + + gl_vbuf[gl_vbuf_top].x = x; + gl_vbuf[gl_vbuf_top].y = y; + gl_vbuf[gl_vbuf_top].z = z; + gl_vbuf[gl_vbuf_top].w = 1.0f; + if (AUTOUV_ENABLED) { + vert_u = autouv[gl_vbuf_top][0]; + vert_v = autouv[gl_vbuf_top][1]; + } + gl_vbuf[gl_vbuf_top].u = vert_u; + gl_vbuf[gl_vbuf_top].v = vert_v; + gl_vbuf[gl_vbuf_top].argb = vert_rgba; + gl_vbuf[gl_vbuf_top].oargb = 0xff000000; + + gl_vbuf_top++; + assert_msg(gl_vbuf_top < VBUF_SIZE, "Vertex buffer overflow"); + + if (MODIFIER_ENABLED) + modifier_check_end(); + else if (ZCLIP_ENABLED || LIGHTING_ENABLED) + vfzclip_check_end(); + else + check_end(); +} + +void glVertex3fv(GLfloat *v) { + glVertex3f(*v, *(v+1), *(v+2)); +} + +void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) { +} + +void glColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) { + vert_rgba = (alpha << 24) | (red << 16) | (green << 8) | blue; +} + +void glColor3f(GLfloat red, GLfloat green, GLfloat blue) { + vert_rgba = (0xff << 24) | + ((uint32)(red * 0xff) << 16) | + ((uint32)(green * 0xff) << 8) | + ((uint32)(blue * 0xff)); +} + +void glColor3fv(GLfloat *v) { + glColor3f(*v, *(v+1), *(v+2)); +} + +void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { + vert_rgba = ((uint32)(alpha * 0xff) << 24) | + ((uint32)(red * 0xff) << 16) | + ((uint32)(green * 0xff) << 8) | + ((uint32)(blue * 0xff)); +} + +void glColor4fv(GLfloat *v) { + glColor4f(*v, *(v+1), *(v+2), *(v+3)); +} + +void glTexCoord2f(GLfloat s, GLfloat t) { + vert_u = s; + vert_v = t; +} + +void glTexCoord2fv(GLfloat *v) { + vert_u = *v; + vert_v = *(v+1); +} + +static pvr_poly_hdr_t user_clip = { + PVR_CMD_USERCLIP, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +static void send_user_clip() { + pvr_prim(&user_clip, sizeof(pvr_poly_hdr_t)); +} +/* Setup the hardware user clip rectangle. It will be sent during glBegin. + + 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) { + GLint minx, miny, maxx, maxy; + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + assert((width >= 0) && (height >= 0)); + gl_scissor_x = x; + gl_scissor_y = y; + gl_scissor_width = CLAMP(width, 0, gl_screen_width); + gl_scissor_height = CLAMP(height, 0, gl_screen_height); + + minx = gl_scissor_x; + /* force the origin to the lower left-hand corner of the screen */ + miny = /**/(gl_screen_height - gl_scissor_height) - /**/ gl_scissor_y; + maxx = (gl_scissor_width + minx); + maxy = (gl_scissor_height + miny); + + /* load command structure while mapping screen coords to TA tiles */ + user_clip.d1 = CLAMP(minx/32, 0, gl_screen_width/32); + user_clip.d2 = CLAMP(miny/32, 0, gl_screen_height/32); + user_clip.d3 = CLAMP((maxx/32)-1, 0, gl_screen_width/32); + user_clip.d4 = CLAMP((maxy/32)-1, 0, gl_screen_height/32); + + gl_scissor_dirty = GL_TRUE; + gl_pbuf_submitted = GL_FALSE; +} + diff --git a/glfog.c b/glfog.c new file mode 100644 index 0000000..338cd0d --- /dev/null +++ b/glfog.c @@ -0,0 +1,180 @@ +/* KallistiGL for KOS ##version## + + glfog.c + (c)2002 Paul Boese +*/ + + +#include +#include +#include "glinternal.h" + +#include +#include + +CVSID("$Id: glfog.c,v 1.2 2002/04/03 03:36:15 axlen Exp $"); + +#define TEST_EQ_4V(a,b) ((a)[0] == (b)[0] && \ + (a)[1] == (b)[1] && \ + (a)[2] == (b)[2] && \ + (a)[3] == (b)[3]) + +/* Convert GLint in [-2147483648,2147483647] to GLfloat in [-1.0,1.0] */ +#define INT_TO_FLOAT(I) ((2.0F * (I) + 1.0F) * (1.0F/4294967294.0F)) + + +/* prototypes */ +void Fogfv( GLenum pname, const GLfloat *params ); +void DCFogfv( GLenum pname, const GLfloat *params ); + + +/* functions */ +void glFogf(GLenum pname, GLfloat param) +{ + glFogfv(pname, ¶m); +} + + +void glFogi(GLenum pname, GLint param ) +{ + GLfloat fparam = (GLfloat) param; + glFogfv(pname, &fparam); +} + + +void glFogiv(GLenum pname, const GLint *params ) +{ + GLfloat p[4]; + switch (pname) { + case GL_FOG_MODE: + case GL_FOG_DENSITY: + case GL_FOG_START: + case GL_FOG_END: + case GL_FOG_INDEX: + p[0] = (GLfloat) *params; + break; + case GL_FOG_COLOR: + p[0] = INT_TO_FLOAT( params[0] ); + p[1] = INT_TO_FLOAT( params[1] ); + p[2] = INT_TO_FLOAT( params[2] ); + p[3] = INT_TO_FLOAT( params[3] ); + break; + default: + /* Error will be caught later in Fogfv */ + ; + } + glFogfv(pname, p); +} + + +void glFogfv( GLenum pname, const GLfloat *params ) +{ + GLenum m; + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + switch (pname) { + case GL_FOG_MODE: + m = (GLenum) (GLint) *params; + switch (m) { + case GL_LINEAR: + case GL_EXP: + case GL_EXP2: + break; + default: + assert_msg(0, "Unknown fog mode."); + return; + } + if (gl_fog_mode == m) + return; + /* flush vertices here */ + gl_fog_mode = m; + break; + case GL_FOG_DENSITY: + if (*params<0.0) { + assert_msg(0, "Invalid value - fog density < zero."); + return; + } + if (gl_fog_density == *params) + return; + /* flush vertices here */ + gl_fog_density = *params; + break; + case GL_FOG_START: + if (gl_fog_start == *params) + return; + /* flush vertices here */ + gl_fog_start = *params; + break; + case GL_FOG_END: + if (gl_fog_end == *params) + return; + /* flush vertices here */ + gl_fog_end = *params; + break; + case GL_FOG_INDEX: + if (gl_fog_index == *params) + return; + /* flush vertices here */ + gl_fog_index = *params; + break; + case GL_FOG_COLOR: + if (TEST_EQ_4V(gl_fog_color, params)) + return; + /* flush vertices here */ + gl_fog_color[0] = params[0]; + gl_fog_color[1] = params[1]; + gl_fog_color[2] = params[2]; + gl_fog_color[3] = params[3]; + break; + default: + assert_msg(0, "Invalid parameter."); + return; + } + DCFogfv( pname, params ); +} + +/* DC specific interface for fog */ + +void fog_table_color4fv(GLfloat *v) { + pvr_fog_table_color(*(v+3), *v, *(v+1), *(v+2)); +} + +/* void fog_set_vertex_color4fv(GLfloat *v) { + pvr_fog_vertex_color(*(v+3), *v, *(v+1), *(v+2)); +} */ + +void DCFogfv( GLenum pname, const GLfloat *params ) { + + /* Just drop thru here and setup DC registers using dcutils fog. + ** + ** Future Note: + ** We should have a GL_KOS_FOG_TYPE enum that will give the user + ** a choice of GL_KOS_FOG_TABLE, GL_KOS_FOG_VERTEX, and maybe + ** GL_KOS_FOG_TABLE2 + */ + switch (pname) { + case GL_FOG_START: + case GL_FOG_END: + pvr_fog_far_depth(gl_fog_end); + case GL_FOG_INDEX: + case GL_FOG_DENSITY: + case GL_FOG_COLOR: + fog_table_color4fv(gl_fog_color); + /* fog_set_vertex_color4fv(gl_fog_color); */ + case GL_FOG_MODE: + switch (gl_fog_mode) { + case GL_EXP: + pvr_fog_table_exp(gl_fog_density); + break; + case GL_EXP2: + pvr_fog_table_exp2(gl_fog_density); + break; + case GL_LINEAR: + pvr_fog_table_linear(gl_fog_start, gl_fog_end); + break; + } + default: + ; + } +} + diff --git a/glinternal.h b/glinternal.h new file mode 100644 index 0000000..924f612 --- /dev/null +++ b/glinternal.h @@ -0,0 +1,166 @@ +/* KallistiGL for KOS ##version## + + glinternal.c + (c)2001 Dan Potter + + $Id: glinternal.h,v 1.13 2002/09/05 07:36:23 bardtx Exp $ +*/ + +#ifndef __GL_GLINTERNAL_H +#define __GL_GLINTERNAL_H + +/* Implementation details; not to be used externally */ +#include +#include +#include + +/* AFAIK, the PowerVR simulates a 32bit depth buffer */ +#define DEPTHBUFFER_MAX ((GLfloat)0xffffffff) + +/* "Clear color" -- really the background plane color */ +extern GLfloat gl_clear_color[4]; + +/* Capability mask (for glEnable() and glDisable()) */ +extern GLbitfield gl_capabilities; + +/* Enabled lists (PVR specific) */ +extern GLbitfield gl_enabled_lists; + +/* Current primitive type (GL_TRIANGLES, etc) */ +extern GLenum gl_prim_type; + +/* Current polygon context */ +extern pvr_poly_cxt_t gl_poly_cxt; + +/* Poly header buffer submitted? */ +extern GLboolean gl_pbuf_submitted; + +/* Current Blend functions */ +extern GLint gl_blend_src; +extern GLint gl_blend_dst; + +/* Currently selected texture header */ +extern pvr_poly_cxt_t *gl_cur_texture; + +/* a "null" texture header for colored polys */ +extern pvr_poly_cxt_t gl_null_texture; + +/* Depth range */ +extern GLclampf gl_depthrange_near; +extern GLclampf gl_depthrange_far; + +/* Screen size */ +extern GLsizei gl_screen_width; +extern GLsizei gl_screen_height; + +/* Viewport size */ +extern GLint gl_viewport_x1, gl_viewport_y1, + gl_viewport_width, gl_viewport_height; + +/* Viewport mapping */ +extern GLfloat gl_viewport_scale[3]; +extern GLfloat gl_viewport_offset[3]; + +/* Scissor clipping */ +extern GLint gl_scissor_x; +extern GLint gl_scissor_y; +extern GLsizei gl_scissor_width; +extern GLsizei gl_scissor_height; +extern GLboolean gl_scissor_dirty; + +/* Transformation matrices; possibilities are: + GL_MODELVIEW + GL_PROJECTION + GL_TEXTURE +*/ +extern matrix_t gl_trans_mats[GL_MATRIX_COUNT] __attribute__((aligned(32))); +extern int gl_matrix_mode; +extern GLboolean gl_matrix_dirty; + +/* Frustum attributes */ +typedef struct { + float left, right, bottom, top, znear, zfar; +} gl_frustum_t; + +extern gl_frustum_t gl_frustum; + +/* Some happy macros */ +#define TXR_ENABLED (gl_capabilities & GL_TEXTURE_2D) +#define AUTOUV_ENABLED (gl_capabilities & GL_KOS_AUTO_UV) +#define FOG_ENABLED (gl_capabilities & GL_FOG) +#define BLEND_ENABLED (gl_capabilities & GL_BLEND) +#define SCISSOR_ENABLED (gl_capabilities & GL_SCISSOR_TEST) +#define USERCLIP_OUTSIDE_ENABLED (gl_capabilities & GL_KOS_USERCLIP_OUTSIDE) +#define MODIFIER_ENABLED (gl_capabilities & GL_KOS_MODIFIER) +#define CHEAP_SHADOW_ENABLED (gl_capabilities & GL_KOS_CHEAP_SHADOW) +#define ZCLIP_ENABLED (gl_capabilities & GL_KOS_NEARZ_CLIPPING) +#define LIGHTING_ENABLED (gl_capabilities & GL_LIGHT0) + +/* Currently active list */ +extern GLbitfield gl_active_list; + +/* Face culling enabled/disabled */ +extern GLboolean gl_cull_face; + +/* Front face */ +extern GLenum gl_front_face; + +/* Culling mode */ +extern GLenum gl_cull_mode; + +/* Fog Attributes */ +extern GLfloat gl_fog_color[4]; +extern GLfloat gl_fog_density; +extern GLfloat gl_fog_start; +extern GLfloat gl_fog_end; +extern GLfloat gl_fog_index; /* unused */ +extern GLenum gl_fog_mode; + +/* Point size */ +extern GLfloat gl_point_size; + +/* Vertex buffers + + It is important to align the vertex buffers for use with the + the direct render API. I found 8192 gave the best results, but 32, + 64, and 1024 also worked well. To see cache thrashing in action try + setting the alignment to 16384 or 32768. The polys per second will + drop by about half. + + mat_transform seems to work best when the source and destination buffers + are seperate. Therefore we have a pre and post transform vertex buffer + + I'm quite aware of how wasteful this is. It's a simple matter that this + is how you have to treat the PVR to get decent poly drawing rates. + + What's needed is a way to collect long vertex [Strips, Fans, Polygons] + and blast them to the store queue every 16 to 32 verts all the while + maintaining the proper PVR_CMD_VERTEX and ...EOL requirements. One + way might be to keep a copy of the last vertex submitted and toss + it to the PVR in the glEnd statement. You will have to keep track of + verts whose z values go < 0 and either clip them to the view frustum or + cull them entirely. But you'll have to do this carefully because the PVR + does not like degenerate triangles or strips. */ + +typedef struct { + uint32 flags; + float x, y, z, w; + float u, v; + uint32 argb, oargb; +} gl_vertex_t; + +#define VBUF_SIZE 128 +/* Pre-xformed vertex buffer */ +extern gl_vertex_t gl_vbuf[VBUF_SIZE] __attribute__((aligned(8192))); +/* Post-xformed vertex buffer */ +extern gl_vertex_t gl_xbuf[VBUF_SIZE] __attribute__((aligned(8192))); +extern int gl_vbuf_top; + +/* some internal prototypes */ +extern void modifier_check_end(); +extern void modifier_end(); +extern void fix_vfzclip_matrices(); +extern void vfzclip_check_end(); +extern void vfzclip_end(); +#endif /* __GL_GLINTERNAL_H */ + diff --git a/glkos.c b/glkos.c new file mode 100644 index 0000000..6f8aa6a --- /dev/null +++ b/glkos.c @@ -0,0 +1,212 @@ +/* KallistiGL for KOS ##version## + + glkos.c + (c)2001 Dan Potter +*/ + +#include +#include +#include + +#include +#include +#include "glinternal.h" +#include "glmacros.h" + +CVSID("$Id: glkos.c,v 1.14 2002/09/05 07:36:23 bardtx Exp $"); + +/* KOS-specific APIs */ + +int glKosInit() { + GLfloat w, h; + static pvr_stats_t pvr_stats; + + if (pvr_get_stats(&pvr_stats)) { + dbglog(DBG_ERROR, "gl: glKosInit - No PVR lists enabled!"); + return -1; + } + + /* Pre-initialize all the globals */ + gl_clear_color[0] = + gl_clear_color[1] = + gl_clear_color[2] = + gl_clear_color[3] = 0.0f; + gl_capabilities = 0; + gl_prim_type = 0; + gl_pbuf_submitted = GL_FALSE; + + gl_enabled_lists = pvr_stats.enabled_list_mask | GL_LIST_END; + gl_active_list = GL_LIST_NONE; + + /* Reset all matrices */ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + /* Setup the basic polygon context */ + pvr_poly_cxt_col(&gl_poly_cxt, PVR_LIST_OP_POLY); + /* Adjust context for GL conformance */ + gl_poly_cxt.gen.culling = PVR_CULLING_NONE; + + /* Make a NULL Texture */ + pvr_poly_cxt_col(&gl_null_texture, PVR_LIST_OP_POLY); + gl_cur_texture = &gl_null_texture; + + glKosGetScreenSize(&w, &h); + /* The screen w & h is used internally by some functions */ + gl_screen_width = (GLsizei)w; gl_screen_height = (GLsizei)h; + + /* Initialize the viewport */ + glDepthRange(0.0f, 1.0f); + glViewport(0, 0, (GLsizei)w, (GLsizei)h); + + /* Initialize the scissor test rectangle */ + glScissor(0, 0, (GLsizei)w, (GLsizei)h); + + /* Initialize fog */ + glFogi(GL_FOG_MODE, GL_EXP); + + return 0; +} + +void glKosShutdown() { +} + +void glKosGetScreenSize(GLfloat *w, GLfloat *h) { + *w = vid_mode->width; + *h = vid_mode->height; +} + +static void _gl_list_begin(uint32 list) { + pvr_list_begin(list); + gl_poly_cxt.list_type = list; +} + +void glKosBeginFrame() { + uint32 tmp_list; + + pvr_wait_ready(); + pvr_scene_begin(); + gl_pbuf_submitted = GL_FALSE; + gl_active_list = GL_LIST_FIRST; + + /* we can't assume GL_LIST_OPAQUE_POLY is the first enabled list + anymore! Advance to the first enabled list if opaque list is + not first already. */ + tmp_list = gl_active_list; + if (!(gl_active_list&gl_enabled_lists)) { + do { + tmp_list = gl_active_list = (gl_active_list << 1); + tmp_list &= gl_enabled_lists; + } while(tmp_list==0); + } + + switch(gl_active_list) { + case GL_LIST_OPAQUE_POLY: + _gl_list_begin(PVR_LIST_OP_POLY); + break; + case GL_LIST_OPAQUE_MOD: + _gl_list_begin(PVR_LIST_OP_MOD); + break; + case GL_LIST_TRANS_POLY: + _gl_list_begin(PVR_LIST_TR_POLY); + break; + case GL_LIST_TRANS_MOD: + _gl_list_begin(PVR_LIST_TR_MOD); + break; + case GL_LIST_PUNCHTHRU: + _gl_list_begin(PVR_LIST_PT_POLY); + break; + case GL_LIST_END: + /* no lists were enabled!?! */ + dbglog(DBG_ERROR, "gl: no lists enabled in glKosBeginFrame!"); + /* this is probably a bailout condition! */ + break; + } +} + +void glKosFinishFrame() { + while (gl_active_list != GL_LIST_NONE) + glKosFinishList(); + pvr_scene_finish(); +} + +void glKosFinishList() { + uint32 tmp_list; + + if (gl_active_list == GL_LIST_NONE) + return; + + pvr_list_finish(); + + /* Advance to the next list */ + tmp_list = gl_active_list; + do { + tmp_list = gl_active_list = (gl_active_list << 1); + tmp_list &= gl_enabled_lists; + } while(tmp_list==0); + + switch(gl_active_list) { + case GL_LIST_OPAQUE_MOD: + _gl_list_begin(PVR_LIST_OP_MOD); + break; + case GL_LIST_TRANS_POLY: + _gl_list_begin(PVR_LIST_TR_POLY); + break; + case GL_LIST_TRANS_MOD: + _gl_list_begin(PVR_LIST_TR_MOD); + break; + case GL_LIST_PUNCHTHRU: + _gl_list_begin(PVR_LIST_PT_POLY); + break; + case GL_LIST_END: + gl_active_list = GL_LIST_NONE; + } + + /* We haven't submitted the new poly headers */ + gl_pbuf_submitted = GL_FALSE; +} + +/* This can be used for KGL Direct Rendering: applies one of the GL + matrices to the matrix registers and lets you do whatever you + want after that. */ +static matrix_t msv __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 glKosMatrixApply(GLenum mode) { + gl_matrix_dirty = GL_TRUE; + if (mode < GL_KOS_SCREENVIEW) { + mat_apply(gl_trans_mats + mode); + } else { + msv[0][0] = gl_viewport_scale[0]; + msv[1][1] = -gl_viewport_scale[1]; + msv[3][0] = gl_viewport_offset[0]; + msv[3][1] = gl_screen_height - gl_viewport_offset[1]; + mat_apply(&msv); + } +} + +/* A matrix clear function, for completeness */ +void glKosMatrixIdent() { + gl_matrix_dirty = GL_TRUE; + mat_identity(); +} + +/* Tell KGL that the poly header is dirty again (i.e., you did something + manually that it doesn't know about) */ +void glKosPolyHdrDirty() { + gl_pbuf_submitted = GL_FALSE; +} + +/* Tell KGL that the matrix registers are dirty (i.e., you did something + manually that it doesn't know about). Note that this does not include + the above functions because those already take this step. */ +void glKosMatrixDirty() { + gl_matrix_dirty = GL_TRUE; +} diff --git a/gllight.c b/gllight.c new file mode 100644 index 0000000..742e84d --- /dev/null +++ b/gllight.c @@ -0,0 +1,29 @@ +/* KallistiGL for KOS ##version## + + gllight.c + (c)2001 Dan Potter +*/ + +#include +#include +#include "glinternal.h" +#include "glmacros.h" + +#include "assert.h" + +CVSID("$Id: gllight.c,v 1.5 2002/04/03 03:36:53 axlen Exp $"); + +/* Lighting */ +void glShadeModel(GLenum mode) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + switch(mode) + { + case GL_FLAT: + gl_poly_cxt.gen.shading = PVR_SHADE_FLAT; + break; + case GL_SMOOTH: + gl_poly_cxt.gen.shading = PVR_SHADE_GOURAUD; + break; + } +} + diff --git a/glmacros.h b/glmacros.h new file mode 100644 index 0000000..7ebab82 --- /dev/null +++ b/glmacros.h @@ -0,0 +1,20 @@ +/* GL for KOS ##version## + + glmacros.c + (c)2001 Paul Boese + + $Id: glmacros.h,v 1.5 2002/06/28 04:57:31 axlen Exp $ +*/ + +#ifndef __GL_GLMACROS_H +#define __GL_GLMACROS_H + + +#define ABS(n) ( (n)<(0.0f) ? (-n):(n) ) +#define NEG(n) ( (n)>(0.0f) ? (-n):(n) ) +#define CLAMP01(x) ( (x)<(0.0f) ? ((0.0f)) : ((x)>(1.0f) ? ((1.0f)) : (x)) ) + +/* Clamp X to [MIN,MAX]: */ +#define CLAMP( X, MIN, MAX ) ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) ) + +#endif /* __GL_GLMACROS_H */ diff --git a/glmisc.c b/glmisc.c new file mode 100644 index 0000000..3df3d59 --- /dev/null +++ b/glmisc.c @@ -0,0 +1,232 @@ +/* KallistiGL for KOS ##version## + + glmisc.c + (c)2001 Dan Potter +*/ + +#include +#include +#include "glinternal.h" +#include "glmacros.h" + +#include +#include +#include + +CVSID("$Id: glmisc.c,v 1.17 2002/07/08 05:28:28 axlen Exp $"); + +/* Miscellaneous APIs */ + +/* Set the background clear color */ +void glClearColor(GLclampf red, + GLclampf green, + GLclampf blue, + GLclampf alpha) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + gl_clear_color[0] = CLAMP01(red); + gl_clear_color[1] = CLAMP01(green); + gl_clear_color[2] = CLAMP01(blue); + gl_clear_color[3] = CLAMP01(alpha); + pvr_set_bg_color(gl_clear_color[0]*gl_clear_color[3], + gl_clear_color[1]*gl_clear_color[3], + gl_clear_color[2]*gl_clear_color[3]); +} + +/* NOP: there's nothing to clear on the PVR2 */ +void glClear(GLbitfield mask) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); +} + +/* Set front face */ +void glFrontFace(GLenum mode) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + switch(mode) { + case GL_CW: + case GL_CCW: + gl_front_face = mode; + gl_pbuf_submitted = GL_FALSE; + break; + } +} + +/* Set face culling mode */ +void glCullFace(GLenum mode) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + switch(mode) { + case GL_FRONT: + case GL_BACK: + gl_cull_mode = mode; + gl_pbuf_submitted = GL_FALSE; + break; + } +} + +/* Enable / disable capabilities */ +void glEnable(GLenum cap) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + switch(cap) { + case GL_TEXTURE_2D: + gl_pbuf_submitted = GL_FALSE; + gl_poly_cxt.txr.enable = PVR_TEXTURE_ENABLE; + break; + case GL_BLEND: + if (gl_active_list != GL_LIST_TRANS_POLY) { + dbglog(DBG_ERROR, "gl: invalid list to enable GL_BLEND inside"); + return; + } + break; + case GL_CULL_FACE: + gl_pbuf_submitted = GL_FALSE; + gl_cull_face = GL_TRUE; + break; + case GL_FOG: + gl_pbuf_submitted = GL_FALSE; + gl_poly_cxt.gen.fog_type = PVR_FOG_TABLE; + break; + case GL_SCISSOR_TEST: + gl_pbuf_submitted = GL_FALSE; + gl_poly_cxt.gen.clip_mode = PVR_USERCLIP_INSIDE; + if (USERCLIP_OUTSIDE_ENABLED) + gl_capabilities &= ~((GLbitfield)GL_KOS_USERCLIP_OUTSIDE); + break; + case GL_KOS_USERCLIP_OUTSIDE: + gl_pbuf_submitted = GL_FALSE; + gl_poly_cxt.gen.clip_mode = PVR_USERCLIP_OUTSIDE; + if (SCISSOR_ENABLED) + gl_capabilities &= ~((GLbitfield)GL_SCISSOR_TEST); + break; + case GL_KOS_MODIFIER: + assert_msg(0, "GL_KOS_MODIFER not implemented"); + gl_pbuf_submitted = GL_FALSE; + gl_poly_cxt.fmt.modifier = PVR_MODIFIER_ENABLE; + break; + case GL_KOS_CHEAP_SHADOW: + assert_msg(0, "GL_KOS_CHEAP_SHADOW not implemented"); + gl_pbuf_submitted = GL_FALSE; + gl_poly_cxt.gen.modifier_mode = PVR_MODIFIER_CHEAP_SHADOW; + break; + case GL_KOS_NEARZ_CLIPPING: + gl_matrix_dirty = GL_TRUE; + break; + case GL_LIGHT0: + assert_msg(0, "GL_LIGHTi not implemented"); + break; + } + + gl_capabilities |= (GLbitfield)cap; +} + +void glDisable(GLenum cap) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + switch(cap) { + case GL_TEXTURE_2D: + gl_pbuf_submitted = GL_FALSE; + gl_poly_cxt.txr.enable = PVR_TEXTURE_DISABLE; + break; + case GL_BLEND: + if (gl_active_list == GL_LIST_TRANS_POLY) { + dbglog(DBG_ERROR, "gl: invalid list to disable GL_BLEND inside"); + return; + } + break; + case GL_CULL_FACE: + gl_pbuf_submitted = GL_FALSE; + gl_cull_face = GL_FALSE; + break; + case GL_FOG: + gl_pbuf_submitted = GL_FALSE; + gl_poly_cxt.gen.fog_type = PVR_FOG_DISABLE; + break; + case GL_SCISSOR_TEST: + gl_pbuf_submitted = GL_FALSE; + gl_poly_cxt.gen.clip_mode = PVR_USERCLIP_DISABLE; + if (USERCLIP_OUTSIDE_ENABLED) + gl_capabilities &= ~((GLbitfield)GL_KOS_USERCLIP_OUTSIDE); + break; + case GL_KOS_USERCLIP_OUTSIDE: + gl_pbuf_submitted = GL_FALSE; + gl_poly_cxt.gen.clip_mode = PVR_USERCLIP_DISABLE; + if (SCISSOR_ENABLED) + gl_capabilities &= ~((GLbitfield)GL_SCISSOR_TEST); + break; + case GL_KOS_MODIFIER: + assert_msg(0, "GL_KOS_MODIFER not implemented"); + gl_pbuf_submitted = GL_FALSE; + gl_poly_cxt.fmt.modifier = PVR_MODIFIER_DISABLE; + break; + case GL_KOS_CHEAP_SHADOW: + assert_msg(0, "GL_KOS_CHEAP_SHADOW not implemented"); + gl_pbuf_submitted = GL_FALSE; + gl_poly_cxt.gen.modifier_mode = PVR_MODIFIER_NORMAL; + break; + case GL_KOS_NEARZ_CLIPPING: + gl_matrix_dirty = GL_TRUE; + break; + case GL_LIGHT0: + assert_msg(0, "GL_LIGHTi not implemented"); + break; + } + + gl_capabilities &= ~((GLbitfield)cap); +} + +/* We have no rendering pipeline yet, so this is a NOP */ +void glFlush() { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); +} + +/* There aren't any useful hints to set yet, so this is a NOP */ +void glHint(GLenum target, GLenum mode) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); +} + +void glPointSize(GLfloat size) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + gl_point_size = CLAMP(size, 0.0f, 100.0f); +} + +/* These strings should go somewhere else */ +const GLubyte *glGetString(GLenum name) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + switch(name) { + case GL_VENDOR: + return "Cryptic Allusions"; + + case GL_RENDERER: + return "KallistiOS"; + + case GL_VERSION: + return "1.1"; + + case GL_EXTENSIONS: + return "GL_ARB_transpose_matrix "; + } + + return ""; +} + +/* A limited view into the guts of KGL - This will change! */ +void glGetFloatv(GLenum pname, GLfloat *params) { + int i, j; + matrix_t *pmat = (matrix_t*)params; + + switch(pname) { + case GL_MODELVIEW_MATRIX: + for (i=0; i<4; i++) + for (j=0; j<4; j++) + (*pmat)[i][j] = gl_trans_mats[GL_MODELVIEW][i][j]; + break; + case GL_PROJECTION_MATRIX: + for (i=0; i<4; i++) + for (j=0; j<4; j++) + (*pmat)[i][j] = gl_trans_mats[GL_PROJECTION][i][j]; + break; + case GL_TEXTURE_MATRIX: + for (i=0; i<4; i++) + for (j=0; j<4; j++) + (*pmat)[i][j] = gl_trans_mats[GL_TEXTURE][i][j]; + break; + default: + assert_msg(0, "not glGet param not implemented"); + } +} diff --git a/glmodifier.c b/glmodifier.c new file mode 100644 index 0000000..867f78d --- /dev/null +++ b/glmodifier.c @@ -0,0 +1,214 @@ +/* KallistiGL for KOS ##version## + + glmodifier.c + (c)2002 Paul Boese + + NOTE: This module is experimental, incomplete, and non-working +*/ + +#include +#include +#include "glinternal.h" +#include "glmacros.h" + +#include +#include +#include +#include +#include + +CVSID("$Id"); + +volatile pvr_modifier_vol_t *volume; +static pvr_modifier_vol_t vol_vbuf, vol_xbuf; +pvr_dr_state_t dr_state; +static GLint mod_type = -1; + +/* local buffer for textured, packed-color, affected by modifier vertex */ +pvr_vertex_tpcm_t vert_xbuf = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +/* Negative 1/w values annoy the pvr, so check for them */ +static inline int check_w(pvr_vertex_t *vert, int n) { + int i; + + for(i=0; i +#include +#include +#include "glinternal.h" +#include "glmacros.h" +#include "glclip.h" /* Trilinear's inline near z clipper code */ + +#include +#include +#include + +CVSID("$Id:"); + +/* Some local tranform stuff. It is generally faster to clip and + light verts in view-space. The transform has been broken into + two pieces to make that possibe. */ +static matrix_t mvp __attribute__((aligned(32))); + +/* Make sure the proper matrices are in the matrix registers */ +void fix_vfzclip_matrices() { + if (gl_matrix_dirty) { + mat_load(gl_trans_mats + GL_PROJECTION); + mat_apply(gl_trans_mats + GL_MODELVIEW); + mat_store(&mvp); + + gl_matrix_dirty = GL_FALSE; + } +} + +static uint32 frms = 0; +/* translate verts from model-space to view-space */ +static void xltmodel(gl_vertex_t *invert, gl_vertex_t *outvert, int num) { + int i; + gl_vertex_t *ip, *op; + + for (i=0; ix = (mvp[0][0] * ip->x) + (mvp[1][0] * ip->y) + (mvp[2][0] * ip->z) + (mvp[3][0] * ip->w); + op->y = (mvp[0][1] * ip->x) + (mvp[1][1] * ip->y) + (mvp[2][1] * ip->z) + (mvp[3][1] * ip->w); + op->z = (mvp[0][2] * ip->x) + (mvp[1][2] * ip->y) + (mvp[2][2] * ip->z) + (mvp[3][2] * ip->w); + op->w = (mvp[0][3] * ip->x) + (mvp[1][3] * ip->y) + (mvp[2][3] * ip->z) + (mvp[3][3] * ip->w); + + /* copy other attributes */ + op->flags = ip->flags; + op->u = ip->u; + op->v = ip->v; + op->argb = ip->argb; + op->oargb = ip ->oargb; + + if ((frms++)%20000 == 0) + printf("z=%03.3f, w=%03.3f\n", op->z, op->w); + } +} + +/* translate verts from view-space to the screen */ +static void xltview(gl_vertex_t *invert, gl_vertex_t *outvert, int num) { + int i; + gl_vertex_t *ip, *op; + + for (i=0; ix = (ip->x /= ip->w); + op->y = (ip->y /= ip->w); + op->z = (ip->z /= ip->w); + + /* Perform viewport mapping (note: this implicitly flips the y-axis) */ + op->x = (gl_viewport_scale[0] * op->x) + gl_viewport_offset[0]; + op->y = gl_screen_height - ((gl_viewport_scale[1] * op->y) + gl_viewport_offset[1]); + op->z = (ip->w == 1.0) ? (gl_viewport_scale[2] * op->z) + gl_viewport_offset[2] : 1.0f / ip->w; + } +} + +static void end_triangles() { + int i, rslt; + volatile pvr_vertex_t *vert; + pvr_dr_state_t dr_state; + + pvr_dr_init(dr_state); + + /* Should be three points in the buffer */ + assert_msg(gl_vbuf_top == 3, "Wrong number of vertices."); + + xltmodel(gl_vbuf, gl_xbuf, 3); + rslt = ZClipTex(gl_xbuf); + xltview(gl_xbuf, gl_xbuf, rslt); + + /* Throw it all to the TA using direct render */ + if (rslt!=0) { + gl_xbuf[rslt-1].flags = PVR_CMD_VERTEX_EOL; + for (i=0; iflags = gl_xbuf[i].flags; + vert->x = gl_xbuf[i].x; + vert->y = gl_xbuf[i].y; + vert->z = gl_xbuf[i].z; + vert->u = gl_xbuf[i].u; + vert->v = gl_xbuf[i].v; + vert->argb = gl_xbuf[i].argb; + vert->oargb = gl_xbuf[i].oargb; + pvr_dr_commit(vert); + } + } +} + +void vfzclip_check_end() { + /* What type of primitive was it? */ + switch(gl_prim_type) { + case GL_POINTS: + //end_points(); + assert_msg(0, "GL_POINTS not supported"); + gl_vbuf_top = 0; + break; + case GL_TRIANGLES: + if (gl_vbuf_top == 3) { + end_triangles(); + gl_vbuf_top = 0; + } + break; + case GL_TRIANGLE_STRIP: + assert_msg(0, "GL_TRIANGE_STRIP not supported"); + break; + case GL_QUADS: + assert_msg(0, "GL_QUADS not supported"); + if (gl_vbuf_top == 4) { + //end_quads(); + gl_vbuf_top = 0; + } + break; + case GL_QUAD_STRIP: + assert_msg(0, "GL_QUAD_STRIP not supported"); + break; + case GL_POLYGON: + assert_msg(0, "GL_POLYGON not supported"); + break; + default: + assert_msg(0, "gl_prim_type: Unknown primitive type."); + } +} + +void vfzclip_end(void) { + /* What type of primitive was it? */ + switch(gl_prim_type) { + case GL_POINTS: + break; + case GL_TRIANGLES: + break; + case GL_TRIANGLE_STRIP: + //end_triangle_strip(); + break; + case GL_QUADS: + break; + case GL_QUAD_STRIP: + //end_quad_strip(); + break; + case GL_POLYGON: + //end_polygon(); + break; + default: + assert_msg(0, "gl_prim_type: Unknown primitive type."); + } + gl_prim_type = 0; +} + diff --git a/gltex.c b/gltex.c new file mode 100644 index 0000000..5d7ed28 --- /dev/null +++ b/gltex.c @@ -0,0 +1,190 @@ +/* KallistiGL for KOS ##version## + + gltex.c + (c)2001 Dan Potter +*/ + +#include +#include +#include "glinternal.h" +#include "glmacros.h" + +#include +#include +#include + +CVSID("$Id: gltex.c,v 1.11 2002/09/05 07:36:23 bardtx Exp $"); + +/* Texture handling */ + +/* Allocate "texture structures" (really poly context structs) */ +void glGenTextures(GLsizei n, GLuint *textures) { + int i; + pvr_poly_cxt_t *p; + for (i=0; itxr.env = PVR_TXRENV_MODULATE; + p->txr.enable = PVR_TEXTURE_ENABLE; + p->txr.filter = PVR_FILTER_NONE; + p->txr.alpha = PVR_TXRALPHA_DISABLE; + p->txr.mipmap = PVR_MIPMAP_DISABLE; + p->txr.mipmap_bias = PVR_MIPBIAS_NORMAL; + p->txr.uv_flip = PVR_UVFLIP_NONE; + p->txr.uv_clamp = PVR_UVCLAMP_NONE; + p->txr.format = PVR_TXRFMT_NONE; + p->txr.base = NULL; + p->txr.width = -1; + p->txr.height = -1; + + textures[i] = (GLuint)p; + } +} + +/* Delete textures from VRAM */ +void glDeleteTextures(GLsizei n, const GLuint *textures) { + int i; + + for (i=0; itxr.base); + free((void*)textures[i]); + } +} + +/* Bind a texture */ +void glBindTexture(GLenum type, GLuint texture) { + assert(type == GL_TEXTURE_2D); + + gl_cur_texture = (pvr_poly_cxt_t *)texture; + gl_pbuf_submitted = GL_FALSE; +} + +/* Load a texture from a 2D image */ +void glTexImage2D(GLenum target, GLint level, + GLint internal_fmt, + GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, + const GLvoid *pixels) { + pvr_ptr_t txr; + + assert_msg(border == 0 && level == 0, "Borders and levels not supported."); + assert_msg((internal_fmt & ~1) == (format & ~1), "Pixel conversion not supported."); + + /* Allocate space for it */ + txr = pvr_mem_malloc(width * height * 2); + + /* Load the texture data */ + if ((internal_fmt & 1) != (format & 1)) + pvr_txr_load_ex((GLvoid *)pixels, txr, width, height, PVR_TXRLOAD_16BPP); + else + pvr_txr_load((GLvoid *)pixels, txr, width * height * 2); + + /* Store texture state in context */ + gl_cur_texture->txr.width = width; + gl_cur_texture->txr.height = height; + gl_cur_texture->txr.format = internal_fmt; + gl_cur_texture->txr.base = txr; + + gl_pbuf_submitted = GL_FALSE; +} + +/* KOS shortcut function (if you loaded your own texture) */ +void glKosTex2D(GLint internal_fmt, GLsizei width, GLsizei height, + pvr_ptr_t txr_address) { + + /* Store texture state in context */ + gl_cur_texture->txr.width = width; + gl_cur_texture->txr.height = height; + gl_cur_texture->txr.format = internal_fmt; + gl_cur_texture->txr.base = txr_address; + + gl_pbuf_submitted = GL_FALSE; +} + +/* Texture environment */ +void glTexEnvi(GLenum target, GLenum pname, GLint param) { + assert(target == GL_TEXTURE_2D); + assert(pname == GL_TEXTURE_ENV_MODE); + + switch(param) { + case GL_REPLACE: + gl_cur_texture->txr.env = PVR_TXRENV_REPLACE; + break; + case GL_MODULATE: + gl_cur_texture->txr.env = PVR_TXRENV_MODULATE; + break; + case GL_DECAL: + gl_cur_texture->txr.env = PVR_TXRENV_DECAL; + break; + case GL_MODULATEALPHA: + gl_cur_texture->txr.env = PVR_TXRENV_MODULATEALPHA; + break; + } + gl_pbuf_submitted = GL_FALSE; +} + +/* Texture parameter */ +void glTexParameteri(GLenum target, GLenum pname, GLint param) { + assert(target == GL_TEXTURE_2D); + + switch(pname) { + case GL_TEXTURE_FILTER: + switch(param) { + case GL_FILTER_NONE: + gl_cur_texture->txr.filter = PVR_FILTER_NONE; + break; + case GL_FILTER_BILINEAR: + gl_cur_texture->txr.filter = PVR_FILTER_BILINEAR; + break; + default: + assert_msg(0, "Unknown texture filter."); + break; + } + break; + case GL_TEXTURE_WRAP_S: /* adjust state of UVCLAMP_U */ + switch(param) { + case GL_REPEAT: + if (gl_cur_texture->txr.uv_clamp == PVR_UVCLAMP_UV) + gl_cur_texture->txr.uv_clamp = PVR_UVCLAMP_V; + else if (gl_cur_texture->txr.uv_clamp == PVR_UVCLAMP_U) + gl_cur_texture->txr.uv_clamp = PVR_UVCLAMP_NONE; + break; + case GL_CLAMP: + if (gl_cur_texture->txr.uv_clamp == PVR_UVCLAMP_NONE) + gl_cur_texture->txr.uv_clamp = PVR_UVCLAMP_U; + else if (gl_cur_texture->txr.uv_clamp == PVR_UVCLAMP_V) + gl_cur_texture->txr.uv_clamp = PVR_UVCLAMP_UV; + break; + default: + assert_msg(0, "Unknown texture wrap mode."); + break; + } + break; + case GL_TEXTURE_WRAP_T: /* adjust state of UVCLAMP_V */ + switch(param) { + case GL_REPEAT: + if (gl_cur_texture->txr.uv_clamp == PVR_UVCLAMP_UV) + gl_cur_texture->txr.uv_clamp = PVR_UVCLAMP_U; + else if (gl_cur_texture->txr.uv_clamp == PVR_UVCLAMP_V) + gl_cur_texture->txr.uv_clamp = PVR_UVCLAMP_NONE; + break; + case GL_CLAMP: + if (gl_cur_texture->txr.uv_clamp == PVR_UVCLAMP_NONE) + gl_cur_texture->txr.uv_clamp = PVR_UVCLAMP_V; + else if (gl_cur_texture->txr.uv_clamp == PVR_UVCLAMP_U) + gl_cur_texture->txr.uv_clamp = PVR_UVCLAMP_UV; + break; + default: + assert_msg(0, "Unknown texture wrap mode."); + break; + } + break; + default: + assert_msg(0, "Unknown parameter name (pname)."); + break; + + } + gl_pbuf_submitted = GL_FALSE; +} + diff --git a/gltrans.c b/gltrans.c new file mode 100644 index 0000000..590529c --- /dev/null +++ b/gltrans.c @@ -0,0 +1,520 @@ +/* KallistiGL for KOS ##version## + + gltrans.c + (c)2001 Dan Potter +*/ + +#include +#include +#include "glinternal.h" + +#include +#include +#include +#include + +CVSID("$Id: gltrans.c,v 1.13 2002/09/05 07:36:23 bardtx Exp $"); + +/* Transformation APIs */ + +/* Modus operandi, as it were + +The transformation API will store N matrices, representing the various +GL matrix modes (projection, modelview, texture) and gl_matrix_mode will +point to the currently selected on. All matrix operations will load the matrix +from its array position, perform the math on that matrix, and store it back +into the array. + +When gldraw() uses the matrices, it will pull the matrices it needs and +multiply them out in registers before applying them to vectors. + +*/ + +#define DEG2RAD (F_PI / 180.0f) +#define RAD2DEG (180.0f / F_PI) + +/* Matrix stacks (move to global?) */ +#define MAT_MV_STACK_CNT 32 +#define MAT_P_STACK_CNT 2 +#define MAT_T_STACK_CNT 2 +static matrix_t gl_mat_mv_stack[MAT_MV_STACK_CNT] __attribute__((aligned(32))); +static int gl_mat_mv_stack_top = 0; +static matrix_t gl_mat_p_stack[MAT_P_STACK_CNT] __attribute__((aligned(32))); +static int gl_mat_p_stack_top = 0; +static matrix_t gl_mat_t_stack[MAT_T_STACK_CNT] __attribute__((aligned(32))); +static int gl_mat_t_stack_top = 0; + +/* Frustum stack */ +static gl_frustum_t gl_frustum_stack[MAT_P_STACK_CNT]; +static int gl_frustum_stack_top = 0; + +/* Set which matrix we are working on */ +void glMatrixMode(GLenum mode) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + gl_matrix_mode = mode; + gl_matrix_dirty = GL_TRUE; +} + +/* Load the identitiy matrix */ +void glLoadIdentity(void) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + mat_identity(); + mat_store(gl_trans_mats + gl_matrix_mode); + gl_matrix_dirty = GL_TRUE; +} + +static matrix_t ml __attribute__((aligned(32))); + +/* Load an arbitrary matrix */ +void glLoadMatrixf(const GLfloat *m) { + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + memcpy(ml, m, sizeof(matrix_t)); + + mat_load(&ml); + mat_store(gl_trans_mats + gl_matrix_mode); + + gl_matrix_dirty = GL_TRUE; +} + +/* Load an arbitrary transposed matrix */ +void glLoadTransposeMatrixf(const GLfloat *m) { + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + 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(gl_trans_mats + gl_matrix_mode); + + gl_matrix_dirty = GL_TRUE; +} + +/* Multiply the current matrix by an arbitrary matrix */ +void glMultMatrixf(const GLfloat *m) { + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + memcpy(ml, m, sizeof(matrix_t)); + + mat_load(gl_trans_mats + gl_matrix_mode); + mat_apply(&ml); + mat_store(gl_trans_mats + gl_matrix_mode); + + gl_matrix_dirty = GL_TRUE; +} + +/* Multiply the current matrix by an arbitrary transposed matrix */ +void glMultTransposeMatrixf(const GLfloat *m) { + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + 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(gl_trans_mats + gl_matrix_mode); + mat_apply(&ml); + mat_store(gl_trans_mats + gl_matrix_mode); + + gl_matrix_dirty = GL_TRUE; +} + +/* Set the depth range */ +void glDepthRange(GLclampf n, GLclampf f) { + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + /* clamp the values... */ + if (n < 0.0f) n = 0.0f; + if (n > 1.0f) n = 1.0f; + if (f < 0.0f) f = 0.0f; + 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) { + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + 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; + + /* Flip the Y-axis */ + //gl_viewport_scale[1] *= -1.0f; + + /* FIXME: Why does the depth value need some nudging? + * This makes polys with Z=0 work. + */ + gl_viewport_offset[2] += 0.0001f; +} + +/* Located here for now */ +void gluPerspective(GLfloat angle, GLfloat aspect, + GLfloat znear, GLfloat zfar) { + + GLfloat xmin, xmax, ymin, ymax; + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + ymax = znear * ftan(angle * F_PI / 360.0f); + ymin = -ymax; + xmin = ymin * aspect; + xmax = ymax * aspect; + + glFrustum(xmin, xmax, ymin, ymax, znear, zfar); +} + +static matrix_t mf __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 } +}; + +void glFrustum(GLfloat left, GLfloat right, + GLfloat bottom, GLfloat top, + GLfloat znear, GLfloat zfar) { + + GLfloat x, y, a, b, c, d; + + gl_frustum.left = left; + gl_frustum.right = right; + gl_frustum.bottom = bottom; + gl_frustum.top = top; + gl_frustum.znear = znear; + gl_frustum.zfar = zfar; + + assert(znear > 0.0f); + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + x = (2.0f * znear) / (right - left); + y = (2.0f * znear) / (top - bottom); + a = (right + left) / (right - left); + b = (top + bottom) / (top - bottom); + c = -(zfar + znear) / (zfar - znear); + d = -(2.0f * zfar * znear) / (zfar - znear); + + mf[0][0] = x; + mf[2][0] = a; + mf[1][1] = y; + mf[2][1] = b; + mf[2][2] = c; + mf[3][2] = d; + + mat_load(gl_trans_mats + gl_matrix_mode); + mat_apply(&mf); + mat_store(gl_trans_mats + gl_matrix_mode); + + gl_matrix_dirty = GL_TRUE; +} + +static matrix_t mo __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 } +}; + +void glOrtho(GLfloat left, GLfloat right, + GLfloat bottom, GLfloat top, + GLfloat znear, GLfloat zfar) { + + GLfloat x, y, z; + GLfloat tx, ty, tz; + + gl_frustum.znear = 0.001; + gl_frustum.zfar = 100; + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + x = 2.0f / (right - left); + y = 2.0f / (top - bottom); + z = -2.0f / (zfar - znear); + tx = -(right + left) / (right - left); + ty = -(top + bottom) / (top - bottom); + tz = -(zfar + znear) / (zfar - znear); + + mo[0][0] = x; + mo[1][1] = y; + mo[2][2] = z; + mo[3][0] = tx; + mo[3][1] = ty; + mo[3][2] = tz; + + mat_load(gl_trans_mats + gl_matrix_mode); + mat_apply(&mo); + mat_store(gl_trans_mats + gl_matrix_mode); + + gl_matrix_dirty = GL_TRUE; +} + +void glPushMatrix(void) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + switch (gl_matrix_mode) + { + case GL_MODELVIEW: + assert_msg(gl_mat_mv_stack_top < MAT_MV_STACK_CNT, "Modelview stack overflow."); + memcpy(gl_mat_mv_stack + gl_mat_mv_stack_top, + gl_trans_mats + gl_matrix_mode, + sizeof(matrix_t)); + gl_mat_mv_stack_top++; + break; + case GL_PROJECTION: + assert_msg(gl_mat_p_stack_top < MAT_P_STACK_CNT, "Projection stack overflow."); + memcpy(gl_mat_p_stack + gl_mat_p_stack_top, + gl_trans_mats + gl_matrix_mode, + sizeof(matrix_t)); + gl_mat_p_stack_top++; + memcpy(gl_frustum_stack + gl_frustum_stack_top, + &gl_frustum, + sizeof(gl_frustum_t)); + gl_frustum_stack_top++; + break; + case GL_TEXTURE: + assert_msg(gl_mat_t_stack_top < MAT_T_STACK_CNT, "Texture stack overflow."); + memcpy(gl_mat_t_stack + gl_mat_t_stack_top, + gl_trans_mats + gl_matrix_mode, + sizeof(matrix_t)); + gl_mat_t_stack_top++; + break; + } +} + +void glPopMatrix(void) { + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + switch(gl_matrix_mode) + { + case GL_MODELVIEW: + assert_msg(gl_mat_mv_stack_top > 0, "Modelview stack underflow."); + gl_mat_mv_stack_top--; + memcpy(gl_trans_mats + gl_matrix_mode, + gl_mat_mv_stack + gl_mat_mv_stack_top, + sizeof(matrix_t)); + break; + case GL_PROJECTION: + assert_msg(gl_mat_p_stack_top > 0, "Projection stack underflow."); + gl_mat_p_stack_top--; + memcpy(gl_trans_mats + gl_matrix_mode, + gl_mat_p_stack + gl_mat_p_stack_top, + sizeof(matrix_t)); + gl_frustum_stack_top--; + memcpy(&gl_frustum, + gl_frustum_stack + gl_frustum_stack_top, + sizeof(gl_frustum_t)); + break; + case GL_TEXTURE: + assert_msg(gl_mat_t_stack_top > 0, "Texture stack underflow."); + gl_mat_t_stack_top--; + memcpy(gl_trans_mats + gl_matrix_mode, + gl_mat_t_stack + gl_mat_t_stack_top, + sizeof(matrix_t)); + break; + } + + gl_matrix_dirty = GL_TRUE; +} + +static matrix_t mr __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 } +}; + +void glRotatef(GLfloat angle, + GLfloat x, GLfloat y, GLfloat z) { + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + GLfloat rcos = fcos(angle * DEG2RAD); + GLfloat rsin = fsin(angle * DEG2RAD); + GLfloat invrcos = (1.0f - rcos); + GLfloat mag = fsqrt(x*x + y*y + z*z); + GLfloat xx, yy, zz, xy, yz, zx; + + if (mag < 1.0e-6) { + /* Rotation vector is too small to be significant */ + return; + } + + /* Normalize the rotation vector */ + x /= mag; + y /= mag; + z /= mag; + + xx = x * x; + yy = y * y; + zz = z * z; + xy = (x * y * invrcos); + yz = (y * z * invrcos); + zx = (z * x * invrcos); + + /* Generate the rotation matrix */ + mr[0][0] = xx + rcos * (1.0f - xx); + mr[2][1] = yz - x * rsin; + mr[1][2] = yz + x * rsin; + + mr[1][1] = yy + rcos * (1.0f - yy); + mr[2][0] = zx + y * rsin; + mr[0][2] = zx - y * rsin; + + mr[2][2] = zz + rcos * (1.0f - zz); + mr[1][0] = xy - z * rsin; + mr[0][1] = xy + z * rsin; + + mat_load(gl_trans_mats + gl_matrix_mode); + mat_apply(&mr); + mat_store(gl_trans_mats + gl_matrix_mode); + + gl_matrix_dirty = GL_TRUE; +} + +static matrix_t ms __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 } +}; + +void glScalef(GLfloat x, GLfloat y, GLfloat z) { + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + ms[0][0] = x; + ms[1][1] = y; + ms[2][2] = z; + + mat_load(gl_trans_mats + gl_matrix_mode); + mat_apply(&ms); + mat_store(gl_trans_mats + gl_matrix_mode); + + gl_matrix_dirty = GL_TRUE; +} + +static matrix_t mt __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 glTranslatef(GLfloat x, GLfloat y, GLfloat z) { + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + mt[3][0] = x; + mt[3][1] = y; + mt[3][2] = z; + + mat_load(gl_trans_mats + gl_matrix_mode); + mat_apply(&mt); + mat_store(gl_trans_mats + gl_matrix_mode); + + gl_matrix_dirty = GL_TRUE; +} + +/* XXX - these should be in glu */ +void normalize(float v[3]) +{ + float r; + + r = fsqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] ); + if (r == 0.0) return; + + v[0] /= r; + v[1] /= r; + v[2] /= r; +} + +void cross(float v1[3], float v2[3], float result[3]) +{ + 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]; +} + +static matrix_t ml __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 } +}; + +/* XXX - should move to glu */ +void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx, + GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy, + GLfloat upz) +{ + float forward[3], side[3], up[3]; + + assert_msg(!gl_prim_type, "Not allowed within glBegin/glEnd pair."); + forward[0] = centerx - eyex; + forward[1] = centery - eyey; + forward[2] = centerz - eyez; + + up[0] = upx; + up[1] = upy; + up[2] = upz; + + normalize(forward); + + /* Side = forward x up */ + cross(forward, up, side); + normalize(side); + + /* Recompute up as: up = side x forward */ + cross(side, forward, up); + + ml[0][0] = side[0]; + ml[1][0] = side[1]; + ml[2][0] = side[2]; + + ml[0][1] = up[0]; + ml[1][1] = up[1]; + ml[2][1] = up[2]; + + ml[0][2] = -forward[0]; + ml[1][2] = -forward[1]; + ml[2][2] = -forward[2]; + + mat_load(gl_trans_mats + gl_matrix_mode); + mat_apply(&ml); + mat_store(gl_trans_mats + gl_matrix_mode); + + glTranslatef(-eyex, -eyey, -eyez); +} diff --git a/glvars.c b/glvars.c new file mode 100644 index 0000000..f43bdab --- /dev/null +++ b/glvars.c @@ -0,0 +1,103 @@ +/* KallistiGL for KOS ##version## + + glvars.c + (c)2001 Dan Potter +*/ + +#include +#include +#include "glinternal.h" + +CVSID("$Id: glvars.c,v 1.11 2002/06/28 04:52:42 axlen Exp $"); + +/* Variable definitions */ + +/* Background clear color (not currently used) */ +GLfloat gl_clear_color[4]; + +/* Capabilities bitfield: toggles for glEnable() / glDisable() */ +GLbitfield gl_capabilities; + +/* Current primitive type (or -1) */ +GLenum gl_prim_type; + +/* Current polygon context */ +pvr_poly_cxt_t gl_poly_cxt; + +/* Poly header buffer submitted? */ +GLboolean gl_pbuf_submitted; + +/* Current Blend functions */ +GLint gl_blend_src = PVR_BLEND_SRCALPHA; +GLint gl_blend_dst = PVR_BLEND_INVSRCALPHA; + +/* Currently selected texture */ +pvr_poly_cxt_t *gl_cur_texture; + +/* Null texture for colored polys */ +pvr_poly_cxt_t gl_null_texture; + +/* Screen size */ +GLsizei gl_screen_width; +GLsizei gl_screen_height; + +/* Viewport size */ +GLint gl_viewport_x1, gl_viewport_y1, + gl_viewport_width, gl_viewport_height; + +/* Viewport mapping */ +GLfloat gl_viewport_scale[3]; +GLfloat gl_viewport_offset[3]; + +/* Scissor clipping */ +GLint gl_scissor_x; +GLint gl_scissor_y; +GLsizei gl_scissor_width; +GLsizei gl_scissor_height; +GLboolean gl_scissor_dirty = GL_FALSE; + +/* Depth range */ +GLclampf gl_depthrange_near; +GLclampf gl_depthrange_far; + +/* Transformation matrices */ +matrix_t gl_trans_mats[GL_MATRIX_COUNT] __attribute__((aligned(32))); +int gl_matrix_mode; +GLboolean gl_matrix_dirty; + +/* Frustum attributes */ +gl_frustum_t gl_frustum; + +/* Enabled lists */ +GLbitfield gl_enabled_lists; + +/* Currently active list */ +GLbitfield gl_active_list; + +/* Face culling enabled/disabled */ +GLboolean gl_cull_face = GL_FALSE; + +/* Front face */ +GLenum gl_front_face = GL_CCW; + +/* Culling mode */ +GLenum gl_cull_mode = GL_BACK; + +/* Fog Attributes */ +GLfloat gl_fog_color[4] = {0.5f, 0.5f, 0.5f, 1.0f}; /* r, g, b, a */ +GLfloat gl_fog_density = 1.0f; /* Density >= 0.0 - exp exp2 fog */ +GLfloat gl_fog_start = 0.0f; /* linear fog */ +GLfloat gl_fog_end = 1.0f; /* linear fog */ +GLfloat gl_fog_index = 0.0f; /* unused */ +GLenum gl_fog_mode = GL_EXP; + +/* Point size */ +GLfloat gl_point_size = 1.0f; + +/* Vertex buffers */ +/* Pre-xformed vertex buffer */ +gl_vertex_t gl_vbuf[VBUF_SIZE] __attribute__((aligned(8192))); +/* Post-xformed vertex buffer */ +gl_vertex_t gl_xbuf[VBUF_SIZE] __attribute__((aligned(8192))); +int gl_vbuf_top; + diff --git a/kos/dreamcast.cnf b/kos/dreamcast.cnf new file mode 100644 index 0000000..e69de29