diff --git a/.gitignore b/.gitignore index 46e6163..c1b78b3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ *.img dc-build.sh .buildconfig +GL/version.h diff --git a/GL/clip.c b/GL/clip.c index 73ac433..d6b97fe 100644 --- a/GL/clip.c +++ b/GL/clip.c @@ -26,7 +26,7 @@ void _glEnableClipping(unsigned char v) { void _glClipLineToNearZ(const Vertex* v1, const Vertex* v2, Vertex* vout, float* t) __attribute__((optimize("fast-math"))); void _glClipLineToNearZ(const Vertex* v1, const Vertex* v2, Vertex* vout, float* t) { - const float NEAR_PLANE = 0.2; // FIXME: this needs to be read from the projection matrix.. somehow + const float NEAR_PLANE = NEAR_PLANE_DISTANCE + 0.0001f; *t = (NEAR_PLANE - v1->w) / (v2->w - v1->w); @@ -87,6 +87,11 @@ void _glClipTriangle(const Triangle* triangle, const uint8_t visible, Submission const Vertex* vertices = triangle->vertex; const VertexExtra* extras = triangle->extra; + char* bgra = (char*) vertices[2].bgra; + + /* Used when flat shading is enabled */ + uint32_t finalColour = *((uint32_t*) bgra); + for(i = 0; i < 4; ++i) { uint8_t thisIndex = (i == 3) ? 0 : i; @@ -116,16 +121,8 @@ void _glClipTriangle(const Triangle* triangle, const uint8_t visible, Submission interpolateVec2(ve1->st, ve2->st, t, veNext.st); if(flatShade) { - /* Original */ - //*((uint32_t*) next.bgra) = *((uint32_t*) vertices[2].bgra); - - /* "Correct" memcpy */ - //memcpy(next.bgra, vertices[2].bgra, 4); - - /* manual aliasing */ - uint32_t* a = (void*)(&vertices[2].bgra[0]); - uint32_t* b = (void*)(&next.bgra[0]); - *b = *a; + char* next_bgra = (char*) next.bgra; + *((uint32_t*) next_bgra) = finalColour; } else { interpolateColour(v1->bgra, v2->bgra, t, next.bgra); } @@ -184,6 +181,23 @@ void _glClipTriangle(const Triangle* triangle, const uint8_t visible, Submission static inline void markDead(Vertex* vert) { vert->flags = VERTEX_CMD_EOL; + + // If we're debugging, wipe out the xyz +#ifndef NDEBUG + typedef union { + float* f; + int* i; + } cast; + + cast v1, v2, v3; + v1.f = &vert->xyz[0]; + v2.f = &vert->xyz[1]; + v3.f = &vert->xyz[2]; + + *v1.i = 0xDEADBEEF; + *v2.i = 0xDEADBEEF; + *v3.i = 0xDEADBEEF; +#endif } #define B000 0 diff --git a/GL/draw.c b/GL/draw.c index e97e263..f6831b4 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "../include/gl.h" #include "../include/glext.h" @@ -20,7 +21,7 @@ static AttribPointer DIFFUSE_POINTER; static GLuint ENABLED_VERTEX_ATTRIBUTES = 0; static GLubyte ACTIVE_CLIENT_TEXTURE = 0; - +static GLboolean FAST_PATH_ENABLED = GL_FALSE; #define ITERATE(count) \ GLuint i = count; \ @@ -56,7 +57,45 @@ void _glInitAttributePointers() { NORMAL_POINTER.size = 3; } -static INLINE_DEBUG GLuint byte_size(GLenum type) { +static GLboolean _glIsVertexDataFastPathCompatible() { + /* + * We provide a "fast path" if vertex data is provided in + * exactly the right format that matches what the PVR can handle. + * This function returns true if all the requirements are met. + */ + + /* + * At least these attributes need to be enabled, because we're not going to do any checking + * in the loop + */ + if((ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG) != VERTEX_ENABLED_FLAG) return GL_FALSE; + if((ENABLED_VERTEX_ATTRIBUTES & UV_ENABLED_FLAG) != UV_ENABLED_FLAG) return GL_FALSE; + if((ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG) != DIFFUSE_ENABLED_FLAG) return GL_FALSE; + + // All 3 attribute types must have a stride of 32 + if(VERTEX_POINTER.stride != 32) return GL_FALSE; + if(UV_POINTER.stride != 32) return GL_FALSE; + if(DIFFUSE_POINTER.stride != 32) return GL_FALSE; + + // UV must follow vertex, diffuse must follow UV + if((UV_POINTER.ptr - VERTEX_POINTER.ptr) != sizeof(GLfloat) * 3) return GL_FALSE; + if((DIFFUSE_POINTER.ptr - UV_POINTER.ptr) != sizeof(GLfloat) * 2) return GL_FALSE; + + if(VERTEX_POINTER.type != GL_FLOAT) return GL_FALSE; + if(VERTEX_POINTER.size != 3) return GL_FALSE; + + if(UV_POINTER.type != GL_FLOAT) return GL_FALSE; + if(UV_POINTER.size != 2) return GL_FALSE; + + if(DIFFUSE_POINTER.type != GL_UNSIGNED_BYTE) return GL_FALSE; + + /* BGRA is the required color order */ + if(DIFFUSE_POINTER.size != GL_BGRA) return GL_FALSE; + + return GL_TRUE; +} + +static inline GLuint byte_size(GLenum type) { switch(type) { case GL_BYTE: return sizeof(GLbyte); case GL_UNSIGNED_BYTE: return sizeof(GLubyte); @@ -65,6 +104,8 @@ static INLINE_DEBUG GLuint byte_size(GLenum type) { case GL_INT: return sizeof(GLint); case GL_UNSIGNED_INT: return sizeof(GLuint); case GL_DOUBLE: return sizeof(GLdouble); + case GL_UNSIGNED_INT_2_10_10_10_REV: return sizeof(GLuint); + case GL_INT_2_10_10_10_REV: return sizeof(GLint); case GL_FLOAT: default: return sizeof(GLfloat); } @@ -75,6 +116,11 @@ typedef void (*ByteParseFunc)(GLubyte* out, const GLubyte* in); typedef void (*PolyBuildFunc)(Vertex* first, Vertex* previous, Vertex* vertex, Vertex* next, const GLsizei i); +static inline float clamp(float d, float min, float max) { + const float t = d < min ? min : d; + return t > max ? max : t; +} + static void _readVertexData3f3f(const float* input, GLuint count, GLubyte stride, float* output) { ITERATE(count) { output[0] = input[0]; @@ -86,6 +132,32 @@ static void _readVertexData3f3f(const float* input, GLuint count, GLubyte stride } } + +static inline float conv_i10_to_norm_float(int i10) { + struct attr_bits_10 { + signed int x:10; + } val; + + val.x = i10; + + return (2.0F * (float)val.x + 1.0F) * (1.0F / 1023.0F); +} + +// 10:10:10:2REV format +static void _readVertexData1i3f(const GLuint* input, GLuint count, GLubyte stride, float* output) { + ITERATE(count) { + int inp = *input; + output[0] = conv_i10_to_norm_float((inp) & 0x3ff); + output[1] = conv_i10_to_norm_float(((inp) >> 10) & 0x3ff); + output[2] = conv_i10_to_norm_float(((inp) >> 20) & 0x3ff); + + // fprintf(stderr, "%d -> %f %f %f\n", inp, output[0], output[1], output[2]); + + input = (GLuint*) (((GLubyte*) input) + stride); + output = (GLfloat*) (((GLubyte*) output) + sizeof(VertexExtra)); + } +} + /* VE == VertexExtra */ static void _readVertexData3f3fVE(const float* input, GLuint count, GLubyte stride, float* output) { ITERATE(count) { @@ -300,28 +372,28 @@ static void _readVertexData4ubARGB(const GLubyte* input, GLuint count, GLubyte s output[B8IDX] = input[2]; output[A8IDX] = input[3]; - input = (GLubyte*) (((GLubyte*) input) + stride); - output = (GLubyte*) (((GLubyte*) output) + sizeof(Vertex)); + input += stride; + output += sizeof(Vertex); } } static void _readVertexData4fARGB(const float* input, GLuint count, GLubyte stride, GLubyte* output) { ITERATE(count) { - output[R8IDX] = (GLubyte) (input[0] * 255.0f); - output[G8IDX] = (GLubyte) (input[1] * 255.0f); - output[B8IDX] = (GLubyte) (input[2] * 255.0f); - output[A8IDX] = (GLubyte) (input[3] * 255.0f); + output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); + output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); + output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); + output[A8IDX] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); input = (float*) (((GLubyte*) input) + stride); - output = (GLubyte*) (((GLubyte*) output) + sizeof(Vertex)); + output += sizeof(Vertex); } } static void _readVertexData3fARGB(const float* input, GLuint count, GLubyte stride, GLubyte* output) { ITERATE(count) { - output[R8IDX] = (GLubyte) (input[0] * 255.0f); - output[G8IDX] = (GLubyte) (input[1] * 255.0f); - output[B8IDX] = (GLubyte) (input[2] * 255.0f); + output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); + output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); + output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); output[A8IDX] = 1.0f; input = (float*) (((GLubyte*) input) + stride); @@ -341,6 +413,30 @@ static void _readVertexData3ubARGB(const GLubyte* input, GLuint count, GLubyte s } } +static void _readVertexData4ubRevARGB(const GLubyte* input, GLuint count, GLubyte stride, GLubyte* output) { + ITERATE(count) { + output[B8IDX] = input[0]; + output[G8IDX] = input[1]; + output[R8IDX] = input[2]; + output[A8IDX] = input[3]; + + input += stride; + output += sizeof(Vertex); + } +} + +static void _readVertexData4fRevARGB(const float* input, GLuint count, GLubyte stride, GLubyte* output) { + ITERATE(count) { + output[0] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); + output[1] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); + output[2] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); + output[3] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); + + input = (float*) (((GLubyte*) input) + stride); + output += sizeof(Vertex); + } +} + static void _fillWithNegZVE(GLuint count, GLfloat* output) { ITERATE(count) { output[0] = output[1] = 0.0f; @@ -408,6 +504,22 @@ static void _readVertexData4uiARGB(const GLuint* input, GLuint count, GLubyte st assert(0 && "Not Implemented"); } +static void _readVertexData4usRevARGB(const GLushort* input, GLuint count, GLubyte stride, GLubyte* output) { + (void)input; + (void)count; + (void)stride; + (void)output; + assert(0 && "Not Implemented"); +} + +static void _readVertexData4uiRevARGB(const GLuint* input, GLuint count, GLubyte stride, GLubyte* output) { + (void)input; + (void)count; + (void)stride; + (void)output; + assert(0 && "Not Implemented"); +} + GLuint* _glGetEnabledAttributes() { return &ENABLED_VERTEX_ATTRIBUTES; } @@ -523,23 +635,22 @@ Vertex* _glSubmissionTargetEnd(SubmissionTarget* target) { } static inline void genTriangles(Vertex* output, GLuint count) { + const GLuint tris = count / 3; Vertex* it = output + 2; - ITERATE(count / 3) { + ITERATE(tris) { it->flags = PVR_CMD_VERTEX_EOL; it += 3; } } static inline void genQuads(Vertex* output, GLuint count) { - Vertex* this = output + 2; - Vertex* next = output + 3; + const GLuint quads = count / 4; + Vertex* final = output + 3; - ITERATE(count / 4) { - swapVertex(this, next); - next->flags = PVR_CMD_VERTEX_EOL; - - this += 4; - next += 4; + ITERATE(quads) { + swapVertex((final - 1), final); + final->flags = PVR_CMD_VERTEX_EOL; + final += 4; } } @@ -568,6 +679,7 @@ static inline void _readPositionData(const GLuint first, const GLuint count, Ver if(VERTEX_POINTER.size == 3) { switch(VERTEX_POINTER.type) { + case GL_DOUBLE: case GL_FLOAT: _readVertexData3f3f(vptr, count, vstride, output[0].xyz); break; @@ -588,6 +700,7 @@ static inline void _readPositionData(const GLuint first, const GLuint count, Ver } } else if(VERTEX_POINTER.size == 2) { switch(VERTEX_POINTER.type) { + case GL_DOUBLE: case GL_FLOAT: _readVertexData2f3f(vptr, count, vstride, output[0].xyz); break; @@ -640,6 +753,7 @@ static inline void _readUVData(const GLuint first, const GLuint count, Vertex* o if(UV_POINTER.size == 2) { switch(UV_POINTER.type) { + case GL_DOUBLE: case GL_FLOAT: _readVertexData2f2f(uvptr, count, uvstride, output[0].uv); break; @@ -674,6 +788,7 @@ static inline void _readSTData(const GLuint first, const GLuint count, VertexExt if(ST_POINTER.size == 2) { switch(ST_POINTER.type) { + case GL_DOUBLE: case GL_FLOAT: _readVertexData2f2fVE(stptr, count, ststride, extra->st); break; @@ -704,10 +819,12 @@ static inline void _readNormalData(const GLuint first, const GLuint count, Verte } const GLuint nstride = (NORMAL_POINTER.stride) ? NORMAL_POINTER.stride : NORMAL_POINTER.size * byte_size(NORMAL_POINTER.type); + const void* nptr = ((GLubyte*) NORMAL_POINTER.ptr + (first * nstride)); - if(NORMAL_POINTER.size == 3) { + if(NORMAL_POINTER.size == 3 || NORMAL_POINTER.type == GL_INT_2_10_10_10_REV) { switch(NORMAL_POINTER.type) { + case GL_DOUBLE: case GL_FLOAT: _readVertexData3f3fVE(nptr, count, nstride, extra->nxyz); break; @@ -723,21 +840,43 @@ static inline void _readNormalData(const GLuint first, const GLuint count, Verte case GL_UNSIGNED_INT: _readVertexData3ui3fVE(nptr, count, nstride, extra->nxyz); break; + case GL_INT_2_10_10_10_REV: + _readVertexData1i3f(nptr, count, nstride, extra->nxyz); + break; default: assert(0 && "Not Implemented"); } } else { assert(0 && "Not Implemented"); } + + if(_glIsNormalizeEnabled()) { + GLubyte* ptr = (GLubyte*) extra->nxyz; + GLfloat l; + ITERATE(count) { + GLfloat* n = (GLfloat*) ptr; + + vec3f_length(n[0], n[1], n[2], l); + + l = 1.0f / l; + + n[0] *= l; + n[1] *= l; + n[2] *= l; + + ptr += sizeof(VertexExtra); + } + } } static inline void _readDiffuseData(const GLuint first, const GLuint count, Vertex* output) { const GLubyte cstride = (DIFFUSE_POINTER.stride) ? DIFFUSE_POINTER.stride : DIFFUSE_POINTER.size * byte_size(DIFFUSE_POINTER.type); - const void* cptr = ((GLubyte*) DIFFUSE_POINTER.ptr + (first * cstride)); + const void* cptr = ((GLubyte*) DIFFUSE_POINTER.ptr) + (first * cstride); if(DIFFUSE_POINTER.size == 3) { switch(DIFFUSE_POINTER.type) { + case GL_DOUBLE: case GL_FLOAT: _readVertexData3fARGB(cptr, count, cstride, output[0].bgra); break; @@ -758,6 +897,7 @@ static inline void _readDiffuseData(const GLuint first, const GLuint count, Vert } } else if(DIFFUSE_POINTER.size == 4) { switch(DIFFUSE_POINTER.type) { + case GL_DOUBLE: case GL_FLOAT: _readVertexData4fARGB(cptr, count, cstride, output[0].bgra); break; @@ -776,7 +916,28 @@ static inline void _readDiffuseData(const GLuint first, const GLuint count, Vert default: assert(0 && "Not Implemented"); } - } else { + } else if(DIFFUSE_POINTER.size == GL_BGRA) { + switch(DIFFUSE_POINTER.type) { + case GL_DOUBLE: + case GL_FLOAT: + _readVertexData4fRevARGB(cptr, count, cstride, output[0].bgra); + break; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + _readVertexData4ubRevARGB(cptr, count, cstride, output[0].bgra); + break; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + _readVertexData4usRevARGB(cptr, count, cstride, output[0].bgra); + break; + case GL_INT: + case GL_UNSIGNED_INT: + _readVertexData4uiRevARGB(cptr, count, cstride, output[0].bgra); + break; + default: + assert(0 && "Not Implemented"); + } + }else { assert(0 && "Not Implemented"); } } @@ -786,6 +947,7 @@ static void generate(SubmissionTarget* target, const GLenum mode, const GLsizei /* Read from the client buffers and generate an array of ClipVertices */ TRACE(); + static const uint32_t FAST_PATH_BYTE_SIZE = (sizeof(GLfloat) * 3) + (sizeof(GLfloat) * 2) + (sizeof(GLubyte) * 4); const GLsizei istride = byte_size(type); if(!indices) { @@ -836,18 +998,37 @@ static void generate(SubmissionTarget* target, const GLenum mode, const GLsizei Vertex* start = _glSubmissionTargetStart(target); - _readPositionData(first, count, start); - profiler_checkpoint("positions"); - - if((ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG) != DIFFUSE_ENABLED_FLAG) { - /* Just fill the whole thing white if the attribute is disabled */ - _fillWhiteARGB(count, start[0].bgra); + if(FAST_PATH_ENABLED) { + /* Copy the pos, uv and color directly in one go */ + const GLubyte* pos = VERTEX_POINTER.ptr; + Vertex* it = start; + ITERATE(count) { + it->flags = PVR_CMD_VERTEX; + memcpy(it->xyz, pos, FAST_PATH_BYTE_SIZE); + it++; + pos += VERTEX_POINTER.stride; + } } else { - _readDiffuseData(first, count, start); - } - profiler_checkpoint("diffuse"); + _readPositionData(first, count, start); + profiler_checkpoint("positions"); - if(doTexture) _readUVData(first, count, start); + if((ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG) != DIFFUSE_ENABLED_FLAG) { + /* Just fill the whole thing white if the attribute is disabled */ + _fillWhiteARGB(count, start[0].bgra); + } else { + _readDiffuseData(first, count, start); + } + profiler_checkpoint("diffuse"); + + if(doTexture) _readUVData(first, count, start); + + Vertex* it = _glSubmissionTargetStart(target); + + ITERATE(count) { + it->flags = PVR_CMD_VERTEX; + ++it; + } + } VertexExtra* ve = aligned_vector_at(target->extras, 0); @@ -855,15 +1036,6 @@ static void generate(SubmissionTarget* target, const GLenum mode, const GLsizei if(doTexture && doMultitexture) _readSTData(first, count, ve); profiler_checkpoint("others"); - Vertex* it = _glSubmissionTargetStart(target); - - ITERATE(count) { - it->flags = PVR_CMD_VERTEX; - ++it; - } - - profiler_checkpoint("flags"); - // Drawing arrays switch(mode) { case GL_TRIANGLES: @@ -879,6 +1051,7 @@ static void generate(SubmissionTarget* target, const GLenum mode, const GLsizei genTriangleStrip(_glSubmissionTargetStart(target), count); break; default: + fprintf(stderr, "Unhandled mode %d\n", (int) mode); assert(0 && "Not Implemented"); } @@ -893,28 +1066,51 @@ static void generate(SubmissionTarget* target, const GLenum mode, const GLsizei Vertex* vertices = _glSubmissionTargetStart(target); VertexExtra* extras = aligned_vector_at(target->extras, 0); - ITERATE(count) { - j = indexFunc(idx); + if(FAST_PATH_ENABLED) { + typedef struct FastPath { + float xyz[3]; + float uv[2]; + uint8_t bgra[4]; + } FastPath; - _readPositionData(j, 1, vertices); - _readDiffuseData(j, 1, vertices); - if(doTexture) _readUVData(j, 1, vertices); - if(doLighting) _readNormalData(j, 1, extras); - if(doTexture && doMultitexture) _readSTData(j, 1, extras); + GLboolean readST = doTexture && doMultitexture; - ++vertices; - ++extras; + ITERATE(count) { + j = indexFunc(idx); - idx += istride; + vertices->flags = PVR_CMD_VERTEX; + + FastPath* srcV = (FastPath*) ((uint8_t*) VERTEX_POINTER.ptr + (VERTEX_POINTER.stride * j)); + FastPath* dst = (FastPath*) vertices->xyz; + *dst = *srcV; + + if(doLighting) _readNormalData(j, 1, extras); + if(readST) _readSTData(j, 1, extras); + + ++vertices; + ++extras; + + idx += istride; + } + } else { + ITERATE(count) { + j = indexFunc(idx); + vertices->flags = PVR_CMD_VERTEX; + + _readPositionData(j, 1, vertices); + _readDiffuseData(j, 1, vertices); + if(doTexture) _readUVData(j, 1, vertices); + if(doLighting) _readNormalData(j, 1, extras); + if(doTexture && doMultitexture) _readSTData(j, 1, extras); + + ++vertices; + ++extras; + + idx += istride; + } } Vertex* it = _glSubmissionTargetStart(target); - const Vertex* end = _glSubmissionTargetEnd(target); - while(it < end) { - (it++)->flags = PVR_CMD_VERTEX; - } - - it = _glSubmissionTargetStart(target); // Drawing arrays switch(mode) { case GL_TRIANGLES: @@ -947,7 +1143,7 @@ static void transform(SubmissionTarget* target) { register float __x __asm__("fr12") = (vertex->xyz[0]); register float __y __asm__("fr13") = (vertex->xyz[1]); register float __z __asm__("fr14") = (vertex->xyz[2]); - register float __w __asm__("fr15"); + register float __w __asm__("fr15") = (vertex->w); __asm__ __volatile__( "fldi1 fr15\n" @@ -1006,64 +1202,6 @@ static void mat_transform_normal3(const float* xyz, const float* xyzOut, const u static void light(SubmissionTarget* target) { -#if 0 - typedef struct { - float xyz[3]; - float n[3]; - } EyeSpaceData; - - static AlignedVector* eye_space_data = NULL; - - if(!eye_space_data) { - eye_space_data = (AlignedVector*) malloc(sizeof(AlignedVector)); - aligned_vector_init(eye_space_data, sizeof(EyeSpaceData)); - } - - aligned_vector_resize(eye_space_data, target->count); - - /* Perform lighting calculations and manipulate the colour */ - Vertex* vertex = _glSubmissionTargetStart(target); - VertexExtra* extra = aligned_vector_at(target->extras, 0); - EyeSpaceData* eye_space = (EyeSpaceData*) eye_space_data->data; - - _glMatrixLoadModelView(); - mat_transform3(vertex->xyz, eye_space->xyz, target->count, sizeof(Vertex), sizeof(EyeSpaceData)); - - _glMatrixLoadNormal(); - mat_transform_normal3(extra->nxyz, eye_space->n, target->count, sizeof(VertexExtra), sizeof(EyeSpaceData)); - - GLsizei i; - EyeSpaceData* ES = aligned_vector_at(eye_space_data, 0); - - for(i = 0; i < target->count; ++i, ++vertex, ++ES) { - /* We ignore diffuse colour when lighting is enabled. If GL_COLOR_MATERIAL is enabled - * then the lighting calculation should possibly take it into account */ - - GLfloat total [] = {0.0f, 0.0f, 0.0f, 0.0f}; - GLfloat to_add [] = {0.0f, 0.0f, 0.0f, 0.0f}; - GLubyte j; - for(j = 0; j < MAX_LIGHTS; ++j) { - if(_glIsLightEnabled(j)) { - _glCalculateLightingContribution(j, ES->xyz, ES->n, vertex->bgra, to_add); - - total[0] += to_add[0]; - total[1] += to_add[1]; - total[2] += to_add[2]; - total[3] += to_add[3]; - } - } - - vertex->bgra[A8IDX] = (GLubyte) (255.0f * fminf(total[3], 1.0f)); - vertex->bgra[R8IDX] = (GLubyte) (255.0f * fminf(total[0], 1.0f)); - vertex->bgra[G8IDX] = (GLubyte) (255.0f * fminf(total[1], 1.0f)); - vertex->bgra[B8IDX] = (GLubyte) (255.0f * fminf(total[2], 1.0f)); - } -#endif - - if(!_glIsLightingEnabled()) { - return; - } - static AlignedVector* eye_space_data = NULL; if(!eye_space_data) { @@ -1086,7 +1224,6 @@ static void light(SubmissionTarget* target) { EyeSpaceData* ES = aligned_vector_at(eye_space_data, 0); _glPerformLighting(vertex, ES, target->count); - } static void divide(SubmissionTarget* target) { @@ -1096,17 +1233,16 @@ static void divide(SubmissionTarget* target) { Vertex* vertex = _glSubmissionTargetStart(target); ITERATE(target->count) { - vertex->xyz[2] = 1.0f / vertex->w; - vertex->xyz[0] *= vertex->xyz[2]; - vertex->xyz[1] *= vertex->xyz[2]; + float f = 1.0f / vertex->w; + vertex->xyz[0] *= f; + vertex->xyz[1] *= f; + vertex->xyz[2] = 1.0 - ((DEPTH_RANGE_MULTIPLIER_L * vertex->xyz[2] * f) + DEPTH_RANGE_MULTIPLIER_H); ++vertex; } } -static void push(PVRHeader* header, Vertex* output, const GLuint count, PolyList* activePolyList, GLshort textureUnit) { +static void push(PVRHeader* header, GLboolean multiTextureHeader, PolyList* activePolyList, GLshort textureUnit) { TRACE(); - (void)output; - (void)count; // Compile the header pvr_poly_cxt_t cxt = *_glGetPVRContext(); @@ -1114,6 +1250,16 @@ static void push(PVRHeader* header, Vertex* output, const GLuint count, PolyList _glUpdatePVRTextureContext(&cxt, textureUnit); + if(multiTextureHeader) { + assert(cxt.list_type == PVR_LIST_TR_POLY); + + cxt.gen.alpha = PVR_ALPHA_ENABLE; + cxt.txr.alpha = PVR_TXRALPHA_ENABLE; + cxt.blend.src = PVR_BLEND_ZERO; + cxt.blend.dst = PVR_BLEND_DESTCOLOR; + cxt.depth.comparison = PVR_DEPTHCMP_EQUAL; + } + pvr_poly_compile(&header->hdr, &cxt); /* Post-process the vertex list */ @@ -1146,6 +1292,11 @@ static void submitVertices(GLenum mode, GLsizei first, GLuint count, GLenum type return; } + if(mode == GL_LINE_STRIP || mode == GL_LINES) { + fprintf(stderr, "Line drawing is currently unsupported\n"); + return; + } + static SubmissionTarget* target = NULL; static AlignedVector extras; @@ -1303,7 +1454,7 @@ static void submitVertices(GLenum mode, GLsizei first, GLuint count, GLenum type profiler_checkpoint("divide"); - push(_glSubmissionTargetHeader(target), _glSubmissionTargetStart(target), target->count, target->output, 0); + push(_glSubmissionTargetHeader(target), GL_FALSE, target->output, 0); profiler_checkpoint("push"); /* @@ -1338,7 +1489,6 @@ static void submitVertices(GLenum mode, GLsizei first, GLuint count, GLenum type assert(vertex); PVRHeader* mtHeader = (PVRHeader*) vertex++; - Vertex* mtStart = vertex; /* Replace the UV coordinates with the ST ones */ VertexExtra* ve = aligned_vector_at(target->extras, 0); @@ -1349,6 +1499,8 @@ static void submitVertices(GLenum mode, GLsizei first, GLuint count, GLenum type ++ve; } + /*@Note: unsure if we still need this */ + #if 0 /* Store state, as we're about to mess around with it */ GLint depthFunc, blendSrc, blendDst; glGetIntegerv(GL_DEPTH_FUNC, &depthFunc); @@ -1363,15 +1515,10 @@ static void submitVertices(GLenum mode, GLsizei first, GLuint count, GLenum type /* This is modulation, we need to switch depending on the texture env mode! */ //glBlendFunc(GL_DST_COLOR, GL_ZERO); + #endif /* Send the buffer again to the transparent list */ - push(mtHeader, mtStart, target->count, _glTransparentPolyList(), 1); - - /* Reset state */ - glDepthFunc(depthFunc); - glBlendFunc(blendSrc, blendDst); - (blendEnabled) ? glEnable(GL_BLEND) : glDisable(GL_BLEND); - (depthEnabled) ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST); + push(mtHeader, GL_TRUE, _glTransparentPolyList(), 1); profiler_pop(); } @@ -1423,6 +1570,8 @@ void APIENTRY glEnableClientState(GLenum cap) { default: _glKosThrowError(GL_INVALID_ENUM, __func__); } + + _glRecalcFastPath(); } void APIENTRY glDisableClientState(GLenum cap) { @@ -1444,8 +1593,10 @@ void APIENTRY glDisableClientState(GLenum cap) { (ENABLED_VERTEX_ATTRIBUTES &= ~UV_ENABLED_FLAG); break; default: - _glKosThrowError(GL_INVALID_ENUM, __func__); + _glKosThrowError(GL_INVALID_ENUM, __func__); } + + _glRecalcFastPath(); } GLuint _glGetActiveClientTexture() { @@ -1467,33 +1618,62 @@ void APIENTRY glClientActiveTextureARB(GLenum texture) { ACTIVE_CLIENT_TEXTURE = (texture == GL_TEXTURE1_ARB) ? 1 : 0; } +GLboolean _glRecalcFastPath() { + FAST_PATH_ENABLED = _glIsVertexDataFastPathCompatible(); + return FAST_PATH_ENABLED; +} + void APIENTRY glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { TRACE(); + if(size < 1 || size > 4) { + _glKosThrowError(GL_INVALID_VALUE, __func__); + _glKosPrintError(); + return; + } + AttribPointer* tointer = (ACTIVE_CLIENT_TEXTURE == 0) ? &UV_POINTER : &ST_POINTER; tointer->ptr = pointer; tointer->stride = stride; tointer->type = type; tointer->size = size; + + _glRecalcFastPath(); } void APIENTRY glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { TRACE(); + if(size < 2 || size > 4) { + _glKosThrowError(GL_INVALID_VALUE, __func__); + _glKosPrintError(); + return; + } + VERTEX_POINTER.ptr = pointer; VERTEX_POINTER.stride = stride; VERTEX_POINTER.type = type; VERTEX_POINTER.size = size; + + _glRecalcFastPath(); } void APIENTRY glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { TRACE(); + if(size != 3 && size != 4 && size != GL_BGRA) { + _glKosThrowError(GL_INVALID_VALUE, __func__); + _glKosPrintError(); + return; + } + DIFFUSE_POINTER.ptr = pointer; DIFFUSE_POINTER.stride = stride; DIFFUSE_POINTER.type = type; DIFFUSE_POINTER.size = size; + + _glRecalcFastPath(); } void APIENTRY glNormalPointer(GLenum type, GLsizei stride, const GLvoid * pointer) { @@ -1502,5 +1682,7 @@ void APIENTRY glNormalPointer(GLenum type, GLsizei stride, const GLvoid * poin NORMAL_POINTER.ptr = pointer; NORMAL_POINTER.stride = stride; NORMAL_POINTER.type = type; - NORMAL_POINTER.size = 3; + NORMAL_POINTER.size = (type == GL_INT_2_10_10_10_REV) ? 1 : 3; + + _glRecalcFastPath(); } diff --git a/GL/flush.c b/GL/flush.c index 9661fc2..2ad52d5 100644 --- a/GL/flush.c +++ b/GL/flush.c @@ -6,6 +6,7 @@ #include "../containers/aligned_vector.h" #include "private.h" #include "profiler.h" +#include "version.h" #define TA_SQ_ADDR (unsigned int *)(void *) \ (0xe0000000 | (((unsigned long)0x10000000) & 0x03ffffe0)) @@ -96,6 +97,8 @@ void APIENTRY glKosInitConfig(GLdcConfig* config) { void APIENTRY glKosInitEx(GLdcConfig* config) { TRACE(); + printf("\nWelcome to GLdc! Git revision: %s\n\n", GLDC_VERSION); + _glInitPVR(config->autosort_enabled); _glInitMatrices(); diff --git a/GL/framebuffer.c b/GL/framebuffer.c index 5ca2824..176ce81 100644 --- a/GL/framebuffer.c +++ b/GL/framebuffer.c @@ -1,4 +1,6 @@ #include +#include + #include "private.h" #include "config.h" #include "../include/glkos.h" @@ -97,22 +99,22 @@ void APIENTRY glFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum static INLINE_DEBUG GLuint A1555(GLuint v) { const GLuint MASK = (1 << 15); - return (v & MASK) >> 15; + return (v & MASK) >> 8; } static INLINE_DEBUG GLuint R1555(GLuint v) { const GLuint MASK = (31 << 10); - return (v & MASK) >> 10; + return (v & MASK) >> 7; } static INLINE_DEBUG GLuint G1555(GLuint v) { const GLuint MASK = (31 << 5); - return (v & MASK) >> 5; + return (v & MASK) >> 2; } static INLINE_DEBUG GLuint B1555(GLuint v) { const GLuint MASK = (31 << 0); - return (v & MASK) >> 0; + return (v & MASK) << 3; } static INLINE_DEBUG GLuint A4444(GLuint v) { @@ -137,67 +139,122 @@ static INLINE_DEBUG GLuint B4444(GLuint v) { static INLINE_DEBUG GLuint R565(GLuint v) { const GLuint MASK = (31 << 11); - return (v & MASK) >> 11; + return (v & MASK) >> 8; } static INLINE_DEBUG GLuint G565(GLuint v) { const GLuint MASK = (63 << 5); - return (v & MASK) >> 5; + return (v & MASK) >> 3; } static INLINE_DEBUG GLuint B565(GLuint v) { const GLuint MASK = (31 << 0); - return (v & MASK) >> 0; + return (v & MASK) << 3; } -static NO_INSTRUMENT GLboolean _glCalculateAverageTexel(const GLubyte* src, const GLuint srcWidth, const GLuint pvrFormat, GLubyte* dest) { - GLushort* s1 = ((GLushort*) src); - GLushort* s2 = ((GLushort*) src) + 1; - GLushort* s3 = ((GLushort*) src) + srcWidth; - GLushort* s4 = ((GLushort*) src) + srcWidth + 1; - GLushort* d1 = ((GLushort*) dest); - +static NO_INSTRUMENT GLboolean _glCalculateAverageTexel(GLuint pvrFormat, const GLubyte* src1, const GLubyte* src2, const GLubyte* src3, const GLubyte* src4, GLubyte* t) { GLuint a, r, g, b; - if((pvrFormat & PVR_TXRFMT_ARGB1555) == PVR_TXRFMT_ARGB1555) { - a = A1555(*s1) + A1555(*s2) + A1555(*s3) + A1555(*s4); - r = R1555(*s1) + R1555(*s2) + R1555(*s3) + R1555(*s4); - g = G1555(*s1) + R1555(*s2) + R1555(*s3) + R1555(*s4); - b = B1555(*s1) + R1555(*s2) + R1555(*s3) + R1555(*s4); + GLubyte format = ((pvrFormat & (1 << 27)) | (pvrFormat & (1 << 26))) >> 26; + + const GLubyte ARGB1555 = 0; + const GLubyte ARGB4444 = 1; + const GLubyte RGB565 = 2; + + if((pvrFormat & PVR_TXRFMT_PAL8BPP) == PVR_TXRFMT_PAL8BPP) { + /* Paletted... all we can do really is just pick one of the + * 4 texels.. unless we want to change the palette (bad) or + * pick the closest available colour (slow, and probably bad) + */ + *t = *src1; + } else if(format == RGB565) { + GLushort* s1 = (GLushort*) src1; + GLushort* s2 = (GLushort*) src2; + GLushort* s3 = (GLushort*) src3; + GLushort* s4 = (GLushort*) src4; + GLushort* d1 = (GLushort*) t; + + r = R565(*s1) + R565(*s2) + R565(*s3) + R565(*s4); + g = G565(*s1) + G565(*s2) + G565(*s3) + G565(*s4); + b = B565(*s1) + B565(*s2) + B565(*s3) + B565(*s4); - a /= 4; r /= 4; g /= 4; b /= 4; - *d1 = (a << 15 | r << 10 | g << 5 | b); - } else if((pvrFormat & PVR_TXRFMT_ARGB4444) == PVR_TXRFMT_ARGB4444) { + *d1 = PACK_RGB565(r, g, b); + } else if(format == ARGB4444) { + GLushort* s1 = (GLushort*) src1; + GLushort* s2 = (GLushort*) src2; + GLushort* s3 = (GLushort*) src3; + GLushort* s4 = (GLushort*) src4; + GLushort* d1 = (GLushort*) t; + a = A4444(*s1) + A4444(*s2) + A4444(*s3) + A4444(*s4); r = R4444(*s1) + R4444(*s2) + R4444(*s3) + R4444(*s4); - g = G4444(*s1) + R4444(*s2) + R4444(*s3) + R4444(*s4); - b = B4444(*s1) + R4444(*s2) + R4444(*s3) + R4444(*s4); + g = G4444(*s1) + G4444(*s2) + G4444(*s3) + G4444(*s4); + b = B4444(*s1) + B4444(*s2) + B4444(*s3) + B4444(*s4); a /= 4; r /= 4; g /= 4; b /= 4; - *d1 = (a << 12 | r << 8 | g << 4 | b); - } else if((pvrFormat & PVR_TXRFMT_RGB565) == PVR_TXRFMT_ARGB4444) { - r = R565(*s1) + R565(*s2) + R565(*s3) + R565(*s4); - g = G565(*s1) + R565(*s2) + R565(*s3) + R565(*s4); - b = B565(*s1) + R565(*s2) + R565(*s3) + R565(*s4); + *d1 = PACK_ARGB4444(a, r, g, b); + } else { + assert(format == ARGB1555); + GLushort* s1 = (GLushort*) src1; + GLushort* s2 = (GLushort*) src2; + GLushort* s3 = (GLushort*) src3; + GLushort* s4 = (GLushort*) src4; + GLushort* d1 = (GLushort*) t; + + a = A1555(*s1) + A1555(*s2) + A1555(*s3) + A1555(*s4); + r = R1555(*s1) + R1555(*s2) + R1555(*s3) + R1555(*s4); + g = G1555(*s1) + G1555(*s2) + G1555(*s3) + G1555(*s4); + b = B1555(*s1) + B1555(*s2) + B1555(*s3) + B1555(*s4); + + a /= 4; r /= 4; g /= 4; b /= 4; - *d1 = (r << 11 | g << 5 | b); + *d1 = PACK_ARGB1555((GLubyte) a, (GLubyte) r, (GLubyte) g, (GLubyte) b); + } + + return GL_TRUE; +} + +GLboolean _glGenerateMipmapTwiddled(const GLuint pvrFormat, const GLubyte* prevData, GLuint thisWidth, GLuint thisHeight, GLubyte* thisData) { + uint32_t lastWidth = thisWidth * 2; + uint32_t lastHeight = thisHeight * 2; + + uint32_t i, j; + uint32_t stride = 0; + + if((pvrFormat & PVR_TXRFMT_PAL8BPP) == PVR_TXRFMT_PAL8BPP) { + stride = 1; } else { - fprintf(stderr, "ERROR: Unsupported PVR format for mipmap generation"); - _glKosThrowError(GL_INVALID_OPERATION, __func__); - _glKosPrintError(); - return GL_FALSE; + stride = 2; + } + + for(i = 0, j = 0; i < lastWidth * lastHeight; i += 4, j++) { + + /* In a twiddled texture, the neighbouring texels + * are next to each other. By averaging them we just basically shrink + * the reverse Ns so each reverse N becomes the next level down... if that makes sense!? */ + + const GLubyte* s1 = &prevData[i * stride]; + const GLubyte* s2 = s1 + stride; + const GLubyte* s3 = s2 + stride; + const GLubyte* s4 = s3 + stride; + GLubyte* t = &thisData[j * stride]; + + assert(s4 < prevData + (lastHeight * lastWidth * stride)); + assert(t < thisData + (thisHeight * thisWidth * stride)); + + _glCalculateAverageTexel(pvrFormat, s1, s2, s3, s4, t); } return GL_TRUE; @@ -212,56 +269,65 @@ void APIENTRY glGenerateMipmapEXT(GLenum target) { TextureObject* tex = _glGetBoundTexture(); + if(tex->width != tex->height) { + fprintf(stderr, "[GL ERROR] Mipmaps cannot be supported on non-square textures\n"); + _glKosThrowError(GL_INVALID_OPERATION, __func__); + _glKosPrintError(); + return; + } + if(!tex || !tex->data || !tex->mipmapCount) { _glKosThrowError(GL_INVALID_OPERATION, __func__); _glKosPrintError(); return; } - if(_glIsMipmapComplete(tex)) { + if((tex->color & PVR_TXRFMT_NONTWIDDLED) == PVR_TXRFMT_NONTWIDDLED) { + /* glTexImage2D should twiddle internally textures in nearly all cases + * so this error is unlikely */ + + fprintf(stderr, "[GL ERROR] Mipmaps are only supported on twiddled textures\n"); + _glKosThrowError(GL_INVALID_OPERATION, __func__); + _glKosPrintError(); + return; + } + + GLboolean complete = _glIsMipmapComplete(tex); + if(!complete && tex->isCompressed) { + fprintf(stderr, "[GL ERROR] Generating mipmaps for compressed textures is not yet supported\n"); + _glKosThrowError(GL_INVALID_OPERATION, __func__); + _glKosPrintError(); + return; + } + + if(complete) { /* Nothing to do */ return; } - GLuint i = 1; - GLuint sx, sy, dx, dy; + GLuint i; GLuint prevWidth = tex->width; GLuint prevHeight = tex->height; - for(; i < _glGetMipmapLevelCount(tex); ++i) { + /* Make sure there is room for the mipmap data on the texture object */ + _glAllocateSpaceForMipmaps(tex); + + for(i = 1; i < _glGetMipmapLevelCount(tex); ++i) { GLubyte* prevData = _glGetMipmapLocation(tex, i - 1); GLubyte* thisData = _glGetMipmapLocation(tex, i); GLuint thisWidth = (prevWidth > 1) ? prevWidth / 2 : 1; GLuint thisHeight = (prevHeight > 1) ? prevHeight / 2 : 1; - /* Do the minification */ - for(sx = 0, dx = 0; sx < prevWidth; sx += 2, dx += 1) { - for(sy = 0, dy = 0; sy < prevHeight; sy += 2, dy += 1) { - GLubyte* srcTexel = &prevData[ - ((sy * prevWidth) + sx) * tex->dataStride - ]; - - GLubyte* destTexel = &thisData[ - ((dy * thisWidth) + dx) * tex->dataStride - ]; - - if(!_glCalculateAverageTexel( - srcTexel, - prevWidth, - tex->color, - destTexel - )) { - return; - } - } - } + _glGenerateMipmapTwiddled(tex->color, prevData, thisWidth, thisHeight, thisData); tex->mipmap |= (1 << i); prevWidth = thisWidth; prevHeight = thisHeight; } + + assert(_glIsMipmapComplete(tex)); } GLenum APIENTRY glCheckFramebufferStatusEXT(GLenum target) { diff --git a/GL/glu.c b/GL/glu.c index 610caf3..23706a0 100644 --- a/GL/glu.c +++ b/GL/glu.c @@ -5,14 +5,12 @@ /* Set the Perspective */ void APIENTRY gluPerspective(GLfloat angle, GLfloat aspect, GLfloat znear, GLfloat zfar) { - GLfloat xmin, xmax, ymin, ymax; + GLfloat fW, fH; - ymax = znear * tanf(angle * F_PI / 360.0f); - ymin = -ymax; - xmin = ymin * aspect; - xmax = ymax * aspect; + fH = tanf(angle * (F_PI / 360)) * znear; + fW = fH * aspect; - glFrustum(xmin, xmax, ymin, ymax, znear, zfar); + glFrustum(-fW, fW, -fH, fH, znear, zfar); } void APIENTRY gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top) { diff --git a/GL/immediate.c b/GL/immediate.c index 6e6563e..0ca3bb2 100644 --- a/GL/immediate.c +++ b/GL/immediate.c @@ -7,8 +7,12 @@ * 3. This is entirely untested. */ +#include +#include + #include "../include/gl.h" #include "../include/glext.h" +#include "../include/glkos.h" #include "profiler.h" #include "private.h" @@ -17,18 +21,14 @@ static GLboolean IMMEDIATE_MODE_ACTIVE = GL_FALSE; static GLenum ACTIVE_POLYGON_MODE = GL_TRIANGLES; static AlignedVector VERTICES; -static AlignedVector COLOURS; -static AlignedVector UV_COORDS; static AlignedVector ST_COORDS; static AlignedVector NORMALS; - static GLfloat NORMAL[3] = {0.0f, 0.0f, 1.0f}; static GLubyte COLOR[4] = {255, 255, 255, 255}; static GLfloat UV_COORD[2] = {0.0f, 0.0f}; static GLfloat ST_COORD[2] = {0.0f, 0.0f}; - static AttribPointer VERTEX_ATTRIB; static AttribPointer DIFFUSE_ATTRIB; static AttribPointer UV_ATTRIB; @@ -36,42 +36,38 @@ static AttribPointer ST_ATTRIB; static AttribPointer NORMAL_ATTRIB; void _glInitImmediateMode(GLuint initial_size) { - aligned_vector_init(&VERTICES, sizeof(GLfloat)); - aligned_vector_init(&COLOURS, sizeof(GLubyte)); - aligned_vector_init(&UV_COORDS, sizeof(GLfloat)); + aligned_vector_init(&VERTICES, sizeof(GLVertexKOS)); aligned_vector_init(&ST_COORDS, sizeof(GLfloat)); - aligned_vector_init(&NORMALS, sizeof(GLfloat)); + aligned_vector_init(&NORMALS, sizeof(GLuint)); aligned_vector_reserve(&VERTICES, initial_size); - aligned_vector_reserve(&COLOURS, initial_size); - aligned_vector_reserve(&UV_COORDS, initial_size); - aligned_vector_reserve(&ST_COORDS, initial_size); + aligned_vector_reserve(&ST_COORDS, initial_size * 2); aligned_vector_reserve(&NORMALS, initial_size); - VERTEX_ATTRIB.ptr = VERTICES.data; + VERTEX_ATTRIB.ptr = VERTICES.data + sizeof(uint32_t); VERTEX_ATTRIB.size = 3; VERTEX_ATTRIB.type = GL_FLOAT; - VERTEX_ATTRIB.stride = 0; + VERTEX_ATTRIB.stride = 32; - DIFFUSE_ATTRIB.ptr = COLOURS.data; - DIFFUSE_ATTRIB.size = 4; - DIFFUSE_ATTRIB.type = GL_UNSIGNED_BYTE; - DIFFUSE_ATTRIB.stride = 0; - - UV_ATTRIB.ptr = UV_COORDS.data; - UV_ATTRIB.stride = 0; + UV_ATTRIB.ptr = VERTEX_ATTRIB.ptr + (sizeof(GLfloat) * 3); + UV_ATTRIB.stride = 32; UV_ATTRIB.type = GL_FLOAT; UV_ATTRIB.size = 2; + DIFFUSE_ATTRIB.ptr = VERTEX_ATTRIB.ptr + (sizeof(GLfloat) * 5); + DIFFUSE_ATTRIB.size = GL_BGRA; /* Flipped color order */ + DIFFUSE_ATTRIB.type = GL_UNSIGNED_BYTE; + DIFFUSE_ATTRIB.stride = 32; + + NORMAL_ATTRIB.ptr = NORMALS.data; + NORMAL_ATTRIB.stride = 0; + NORMAL_ATTRIB.type = GL_INT_2_10_10_10_REV; + NORMAL_ATTRIB.size = 1; + ST_ATTRIB.ptr = ST_COORDS.data; ST_ATTRIB.stride = 0; ST_ATTRIB.type = GL_FLOAT; ST_ATTRIB.size = 2; - - NORMAL_ATTRIB.ptr = NORMALS.data; - NORMAL_ATTRIB.stride = 0; - NORMAL_ATTRIB.type = GL_FLOAT; - NORMAL_ATTRIB.size = 3; } GLubyte _glCheckImmediateModeInactive(const char* func) { @@ -131,6 +127,13 @@ void APIENTRY glColor3ub(GLubyte red, GLubyte green, GLubyte blue) { COLOR[3] = 255; } +void APIENTRY glColor3ubv(const GLubyte *v) { + COLOR[0] = v[0]; + COLOR[1] = v[1]; + COLOR[2] = v[2]; + COLOR[3] = 255; +} + void APIENTRY glColor3fv(const GLfloat* v) { COLOR[0] = (GLubyte)(v[0] * 255); COLOR[1] = (GLubyte)(v[1] * 255); @@ -138,18 +141,42 @@ void APIENTRY glColor3fv(const GLfloat* v) { COLOR[3] = 255; } +static inline uint32_t pack_vertex_attribute_vec3_1i(float x, float y, float z) { + const float w = 0.0f; + + const uint32_t xs = x < 0; + const uint32_t ys = y < 0; + const uint32_t zs = z < 0; + const uint32_t ws = w < 0; + + uint32_t vi = + ws << 31 | ((uint32_t)(w + (ws << 1)) & 1) << 30 | + zs << 29 | ((uint32_t)(z * 511 + (zs << 9)) & 511) << 20 | + ys << 19 | ((uint32_t)(y * 511 + (ys << 9)) & 511) << 10 | + xs << 9 | ((uint32_t)(x * 511 + (xs << 9)) & 511); + + return vi; +} + void APIENTRY glVertex3f(GLfloat x, GLfloat y, GLfloat z) { - aligned_vector_reserve(&VERTICES, VERTICES.size + 3); - aligned_vector_push_back(&VERTICES, &x, 1); - aligned_vector_push_back(&VERTICES, &y, 1); - aligned_vector_push_back(&VERTICES, &z, 1); + GLVertexKOS* vert = aligned_vector_extend(&VERTICES, 1); + GLfloat* st = aligned_vector_extend(&ST_COORDS, 2); + GLuint* n = aligned_vector_extend(&NORMALS, 1); + vert->x = x; + vert->y = y; + vert->z = z; + vert->u = UV_COORD[0]; + vert->v = UV_COORD[1]; - /* Push back the stashed colour, normal and uv_coordinate */ - aligned_vector_push_back(&COLOURS, COLOR, 4); - aligned_vector_push_back(&UV_COORDS, UV_COORD, 2); - aligned_vector_push_back(&ST_COORDS, ST_COORD, 2); - aligned_vector_push_back(&NORMALS, NORMAL, 3); + vert->bgra[R8IDX] = COLOR[0]; + vert->bgra[G8IDX] = COLOR[1]; + vert->bgra[B8IDX] = COLOR[2]; + vert->bgra[A8IDX] = COLOR[3]; + + *n = pack_vertex_attribute_vec3_1i(NORMAL[0], NORMAL[1], NORMAL[2]); + + memcpy(st, ST_COORD, sizeof(GLfloat) * 2); } void APIENTRY glVertex3fv(const GLfloat* v) { @@ -212,11 +239,12 @@ void APIENTRY glEnd() { IMMEDIATE_MODE_ACTIVE = GL_FALSE; /* Resizing could have invalidated these pointers */ - VERTEX_ATTRIB.ptr = VERTICES.data; - DIFFUSE_ATTRIB.ptr = COLOURS.data; - UV_ATTRIB.ptr = UV_COORDS.data; - ST_ATTRIB.ptr = ST_COORDS.data; + VERTEX_ATTRIB.ptr = VERTICES.data + sizeof(uint32_t); + UV_ATTRIB.ptr = VERTEX_ATTRIB.ptr + (sizeof(GLfloat) * 3); + DIFFUSE_ATTRIB.ptr = VERTEX_ATTRIB.ptr + (sizeof(GLfloat) * 5); + NORMAL_ATTRIB.ptr = NORMALS.data; + ST_ATTRIB.ptr = ST_COORDS.data; GLuint* attrs = _glGetEnabledAttributes(); @@ -244,7 +272,15 @@ void APIENTRY glEnd() { *attrs = ~0; // Enable everything - glDrawArrays(ACTIVE_POLYGON_MODE, 0, VERTICES.size / 3); +#ifndef NDEBUG + _glRecalcFastPath(); +#else + // Immediate mode should always activate the fast path + GLboolean fastPathEnabled = _glRecalcFastPath(); + assert(fastPathEnabled); +#endif + + glDrawArrays(ACTIVE_POLYGON_MODE, 0, VERTICES.size); /* Restore everything */ *vattr = vptr; @@ -257,8 +293,6 @@ void APIENTRY glEnd() { /* Clear arrays for next polys */ aligned_vector_clear(&VERTICES); - aligned_vector_clear(&COLOURS); - aligned_vector_clear(&UV_COORDS); aligned_vector_clear(&ST_COORDS); aligned_vector_clear(&NORMALS); diff --git a/GL/lighting.c b/GL/lighting.c index 10038a5..53d2a86 100644 --- a/GL/lighting.c +++ b/GL/lighting.c @@ -1,9 +1,14 @@ #include #include - +#include +#include #include #include "private.h" +/* Lighting will not be calculated if the attenuation + * multiplier ends up less than this value */ +#define ATTENUATION_THRESHOLD 0.01f + static GLfloat SCENE_AMBIENT [] = {0.2, 0.2, 0.2, 1.0}; static GLboolean VIEWER_IN_EYE_COORDINATES = GL_TRUE; static GLenum COLOR_CONTROL = GL_SINGLE_COLOR; @@ -48,8 +53,6 @@ void _glInitLights() { LIGHTS[i].constant_attenuation = 1.0f; LIGHTS[i].linear_attenuation = 0.0f; LIGHTS[i].quadratic_attenuation = 0.0f; - - LIGHTS[i].is_directional = GL_FALSE; } } @@ -112,8 +115,7 @@ void APIENTRY glLightfv(GLenum light, GLenum pname, const GLfloat *params) { _glMatrixLoadModelView(); memcpy(LIGHTS[idx].position, params, sizeof(GLfloat) * 4); - LIGHTS[idx].is_directional = (params[3] == 0.0f) ? GL_TRUE : GL_FALSE; - if(LIGHTS[idx].is_directional) { + if(params[3] == 0.0f) { //FIXME: Do we need to rotate directional lights? } else { mat_trans_single4( @@ -209,7 +211,7 @@ void APIENTRY glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) { memcpy(MATERIAL.specular, params, sizeof(GLfloat) * 4); break; case GL_EMISSION: - memcpy(MATERIAL.specular, params, sizeof(GLfloat) * 4); + memcpy(MATERIAL.emissive, params, sizeof(GLfloat) * 4); break; case GL_AMBIENT_AND_DIFFUSE: { glMaterialfv(face, GL_AMBIENT, params); @@ -239,19 +241,19 @@ void APIENTRY glColorMaterial(GLenum face, GLenum mode) { COLOR_MATERIAL_MODE = mode; } -static inline GLboolean isDiffuseColorMaterial() { +GL_FORCE_INLINE GLboolean isDiffuseColorMaterial() { return (COLOR_MATERIAL_MODE == GL_DIFFUSE || COLOR_MATERIAL_MODE == GL_AMBIENT_AND_DIFFUSE); } -static inline GLboolean isAmbientColorMaterial() { +GL_FORCE_INLINE GLboolean isAmbientColorMaterial() { return (COLOR_MATERIAL_MODE == GL_AMBIENT || COLOR_MATERIAL_MODE == GL_AMBIENT_AND_DIFFUSE); } -static inline GLboolean isSpecularColorMaterial() { +GL_FORCE_INLINE GLboolean isSpecularColorMaterial() { return (COLOR_MATERIAL_MODE == GL_SPECULAR); } -static inline void initVec3(struct vec3f* v, const GLfloat* src) { +GL_FORCE_INLINE void initVec3(struct vec3f* v, const GLfloat* src) { memcpy(v, src, sizeof(GLfloat) * 3); } @@ -259,7 +261,7 @@ static inline void initVec3(struct vec3f* v, const GLfloat* src) { #define EXP_A 184 #define EXP_C 16249 -static inline float FEXP(float y) { +GL_FORCE_INLINE float FEXP(float y) { union { float d; struct { @@ -271,34 +273,56 @@ static inline float FEXP(float y) { return eco.d; } -static inline float FLOG(float y) { - int *nTemp = (int *)&y; - y = (*nTemp) >> 16; - return (y - EXP_C) / EXP_A; +/* Inspired by: https://web.archive.org/web/20180423090243/www.dctsystems.co.uk/Software/power.html */ +#define SHIFT23 (1 << 23) +#define INVSHIFT23 (1.0f / SHIFT23) +#define LOGBODGE 0.346607f +#define POWBODGE 0.33971f + +static const float FINT_MAX = (float) INT_MAX; + +GL_FORCE_INLINE float FFLOOR(float x) { + return (int)(x + FINT_MAX) - INT_MAX; } -static inline float FPOW(float b, float p) { - return FEXP(FLOG(b) * p); +GL_FORCE_INLINE float FLOG2(float i) { + float y; + + union { + float f; + int i; + } x; + + x.i = i; + + x.f *= INVSHIFT23; + x.f = x.f - 127; + + y = x.f - FFLOOR(x.f); + y = (y - y * y) * LOGBODGE; + + return x.f + y; } -#define LIGHT_COMPONENT(C) { \ - const GLfloat* acm = &MA[C]; \ - const GLfloat* dcm = &MD[C]; \ - const GLfloat* scm = &MS[C]; \ - const GLfloat* scli = &light->specular[C]; \ - const GLfloat* dcli = &light->diffuse[C]; \ - const GLfloat* acli = &light->ambient[C]; \ - const GLfloat* srm = &MATERIAL.exponent; \ - const GLfloat fi = (LdotN == 0) ? 0 : 1; \ - GLfloat component = (*acm * *acli); \ - component += (LdotN * *dcm * *dcli); \ - component += (FPOW((fi * NdotH), *srm) * *scm * *scli); \ - component *= att; \ - component *= spot; \ - final[C] += component; \ +GL_FORCE_INLINE float FPOW2(float i) { + float y = i - FFLOOR(i); + y = (y - y * y) * POWBODGE; + + union { + float f; + float i; + } x; + + x.f = i + 127 - y; + x.f *= SHIFT23; + return x.i; } -static inline float vec3_dot_limited( +GL_FORCE_INLINE float FPOW(float a, float b) { + return FPOW2(b * FLOG2(a)); +} + +GL_FORCE_INLINE float vec3_dot_limited( const float* x1, const float* y1, const float* z1, const float* x2, const float* y2, const float* z2) { @@ -307,117 +331,149 @@ static inline float vec3_dot_limited( return (ret < 0) ? 0 : ret; } +#define _MIN(x, y) (x < y) ? x : y + +GL_FORCE_INLINE void _glLightVertexDirectional(uint8_t* final, int8_t lid, float LdotN, float NdotH) { + float F; + float FI = (LdotN != 0.0f); + uint8_t FO; + +#define _PROCESS_COMPONENT(T, X) \ + F = (MATERIAL.ambient[X] * LIGHTS[lid].ambient[X]); \ + F += (LdotN * MATERIAL.diffuse[X] * LIGHTS[lid].diffuse[X]); \ + FI = (MATERIAL.exponent) ? FPOW(FI * NdotH, MATERIAL.exponent) : 1.0f; \ + F += FI * MATERIAL.specular[X] * LIGHTS[lid].specular[X]; \ + FO = (uint8_t) (_MIN(F * 255.0f, 255.0f)); \ +\ + final[T] += _MIN(FO, 255 - final[T]); \ + + _PROCESS_COMPONENT(R8IDX, 0); + _PROCESS_COMPONENT(G8IDX, 1); + _PROCESS_COMPONENT(B8IDX, 2); + +#undef _PROCESS_COMPONENT +} + +GL_FORCE_INLINE void _glLightVertexPoint(uint8_t* final, int8_t lid, float LdotN, float NdotH, float att) { + float F; + float FI = (LdotN != 0.0f); + uint8_t FO; + +#define _PROCESS_COMPONENT(T, X) \ + F = (MATERIAL.ambient[X] * LIGHTS[lid].ambient[X]); \ + F += (LdotN * MATERIAL.diffuse[X] * LIGHTS[lid].diffuse[X]); \ + FI = (MATERIAL.exponent) ? FPOW(FI * NdotH, MATERIAL.exponent) : 1.0f; \ + F += FI * MATERIAL.specular[X] * LIGHTS[lid].specular[X]; \ + FO = (uint8_t) (_MIN(F * att * 255.0f, 255.0f)); \ +\ + final[T] += _MIN(FO, 255 - final[T]); \ + + _PROCESS_COMPONENT(R8IDX, 0); + _PROCESS_COMPONENT(G8IDX, 1); + _PROCESS_COMPONENT(B8IDX, 2); + +#undef _PROCESS_COMPONENT +} + void _glPerformLighting(Vertex* vertices, const EyeSpaceData* es, const int32_t count) { int8_t i; int32_t j; - const LightSource* light = NULL; - - const GLboolean colorMaterial = _glIsColorMaterialEnabled(); - const GLboolean isDiffuseCM = isDiffuseColorMaterial(); - const GLboolean isAmbientCM = isAmbientColorMaterial(); - const GLboolean isSpecularCM = isSpecularColorMaterial(); - - static GLfloat CM[4]; - - /* So the DC has 16 floating point registers, that means - * we need to limit the number of floats as much as possible - * to give the compiler a good enough chance to do the right - * thing */ - Vertex* vertex = vertices; const EyeSpaceData* data = es; - - static const float ONE_OVER_255 = 1.0f / 255.0f; + float base; for(j = 0; j < count; ++j, ++vertex, ++data) { - /* When GL_COLOR_MATERIAL is on, we need to pull out - * the passed in diffuse and use it */ - const GLfloat* MD = MATERIAL.diffuse; - const GLfloat* MA = MATERIAL.ambient; - const GLfloat* MS = MATERIAL.specular; - - if(colorMaterial) { - CM[0] = ((GLfloat) vertex->bgra[R8IDX]) * ONE_OVER_255; - CM[1] = ((GLfloat) vertex->bgra[G8IDX]) * ONE_OVER_255; - CM[2] = ((GLfloat) vertex->bgra[B8IDX]) * ONE_OVER_255; - CM[3] = ((GLfloat) vertex->bgra[A8IDX]) * ONE_OVER_255; - - MD = (isDiffuseCM) ? CM : MATERIAL.diffuse; - MA = (isAmbientCM) ? CM : MATERIAL.ambient; - MS = (isSpecularCM) ? CM : MATERIAL.specular; - } - - float final[4]; - /* Initial, non-light related values */ - final[0] = (SCENE_AMBIENT[0] * MA[0]) + MATERIAL.emissive[0]; - final[1] = (SCENE_AMBIENT[1] * MA[1]) + MATERIAL.emissive[1]; - final[2] = (SCENE_AMBIENT[2] * MA[2]) + MATERIAL.emissive[2]; - final[3] = MD[3]; + base = (SCENE_AMBIENT[0] * MATERIAL.ambient[0]) + MATERIAL.emissive[0]; + vertex->bgra[R8IDX] = (uint8_t)(_MIN(base * 255.0f, 255.0f)); - float Vx, Vy, Vz; - Vx = -data->xyz[0]; - Vy = -data->xyz[1]; - Vz = -data->xyz[2]; + base = (SCENE_AMBIENT[1] * MATERIAL.ambient[1]) + MATERIAL.emissive[1]; + vertex->bgra[G8IDX] = (uint8_t)(_MIN(base * 255.0f, 255.0f)); + + base = (SCENE_AMBIENT[2] * MATERIAL.ambient[2]) + MATERIAL.emissive[2]; + vertex->bgra[B8IDX] = (uint8_t)(_MIN(base * 255.0f, 255.0f)); + vertex->bgra[A8IDX] = (uint8_t)(_MIN(MATERIAL.diffuse[3] * 255.0f, 255.0f)); + + float Vx = -data->xyz[0]; + float Vy = -data->xyz[1]; + float Vz = -data->xyz[2]; vec3f_normalize(Vx, Vy, Vz); + const float Nx = data->n[0]; + const float Ny = data->n[1]; + const float Nz = data->n[2]; + for(i = 0; i < MAX_LIGHTS; ++i) { if(!_glIsLightEnabled(i)) continue; - /* Calc light specific parameters */ - light = &LIGHTS[i]; + if(LIGHTS[i].position[3] == 0.0f) { + float Lx = -LIGHTS[i].position[0]; + float Ly = -LIGHTS[i].position[1]; + float Lz = -LIGHTS[i].position[2]; + float Hx = (Lx + Vx); + float Hy = (Ly + Vy); + float Hz = (Lz + Vz); - float Lx, Ly, Lz, D; - float Hx, Hy, Hz; - const float* Nx = &data->n[0]; - const float* Ny = &data->n[1]; - const float* Nz = &data->n[2]; + vec3f_normalize(Lx, Ly, Lz); + vec3f_normalize(Hx, Hy, Hz); - Lx = light->position[0] - data->xyz[0]; - Ly = light->position[1] - data->xyz[1]; - Lz = light->position[2] - data->xyz[2]; - vec3f_length(Lx, Ly, Lz, D); + const float LdotN = vec3_dot_limited( + &Nx, &Ny, &Nz, + &Lx, &Ly, &Lz + ); - { - /* Normalize L - scoping ensures Llen is temporary */ - const float Llen = 1.0f / D; - Lx *= Llen; - Ly *= Llen; - Lz *= Llen; + const float NdotH = vec3_dot_limited( + &Nx, &Ny, &Nz, + &Hx, &Hy, &Hz + ); + + _glLightVertexDirectional( + vertex->bgra, + i, LdotN, NdotH + ); + } else { + float Lx = LIGHTS[i].position[0] - data->xyz[0]; + float Ly = LIGHTS[i].position[1] - data->xyz[1]; + float Lz = LIGHTS[i].position[2] - data->xyz[2]; + float D; + + vec3f_length(Lx, Ly, Lz, D); + + float att = ( + LIGHTS[i].constant_attenuation + ( + LIGHTS[i].linear_attenuation * D + ) + (LIGHTS[i].quadratic_attenuation * D * D) + ); + + att = MATH_fsrra(att * att); + + if(att >= ATTENUATION_THRESHOLD) { + float Hx = (Lx + Vx); + float Hy = (Ly + Vy); + float Hz = (Lz + Vz); + + vec3f_normalize(Lx, Ly, Lz); + vec3f_normalize(Hx, Hy, Hz); + + const float LdotN = vec3_dot_limited( + &Nx, &Ny, &Nz, + &Lx, &Ly, &Lz + ); + + const float NdotH = vec3_dot_limited( + &Nx, &Ny, &Nz, + &Hx, &Hy, &Hz + ); + + _glLightVertexPoint( + vertex->bgra, + i, LdotN, NdotH, att + ); + } } - - Hx = (Lx + Vx); - Hy = (Ly + Vy); - Hz = (Lz + Vz); - vec3f_normalize(Hx, Hy, Hz); - - const float LdotN = vec3_dot_limited( - &Lx, &Ly, &Lz, - Nx, Ny, Nz - ); - - const float NdotH = vec3_dot_limited( - Nx, Ny, Nz, - &Hx, &Hy, &Hz - ); - - const float att = ( - light->position[3] == 0.0f) ? 1.0f : - 1.0f / (light->constant_attenuation + (light->linear_attenuation * D) + (light->quadratic_attenuation * D * D) - ); - - const float spot = 1.0f; - - LIGHT_COMPONENT(0); - LIGHT_COMPONENT(1); - LIGHT_COMPONENT(2); } - - vertex->bgra[R8IDX] = (GLubyte)(fminf(final[0] * 255.0f, 255.0f)); - vertex->bgra[G8IDX] = (GLubyte)(fminf(final[1] * 255.0f, 255.0f)); - vertex->bgra[B8IDX] = (GLubyte)(fminf(final[2] * 255.0f, 255.0f)); - vertex->bgra[A8IDX] = (GLubyte)(fminf(final[3] * 255.0f, 255.0f)); } } +#undef LIGHT_COMPONENT diff --git a/GL/matrix.c b/GL/matrix.c index 76b4f8f..c20f07c 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -299,7 +299,7 @@ void APIENTRY glFrustum(GLfloat left, GLfloat right, /* Frustum Matrix */ static Matrix4x4 FrustumMatrix __attribute__((aligned(32))); - memset4(FrustumMatrix, 0, sizeof(float) * 16); + memset(FrustumMatrix, 0, sizeof(float) * 16); const float near2 = 2.0f * znear; const float A = (right + left) / (right - left); @@ -522,6 +522,7 @@ void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx, m[2] = -f[0]; m[6] = -f[1]; m[10] = -f[2]; m[14] = 0.0f; m[3] = 0.0f; m[7] = 0.0f; m[11] = 0.0f; m[15] = 1.0f; +/* static Matrix4x4 trn __attribute__((aligned(32))) = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, @@ -538,6 +539,9 @@ void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx, multiply_matrix(&trn); multiply_matrix(stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF))); download_matrix(stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF))); + */ + glMultMatrixf(m); + glTranslatef(-eyex, -eyey, -eyez); } void _glApplyRenderMatrix() { diff --git a/GL/private.h b/GL/private.h index 7a8a67a..6449d2c 100644 --- a/GL/private.h +++ b/GL/private.h @@ -2,6 +2,11 @@ #define PRIVATE_H #include +#include +#include +#include +#include +#include #include "../include/gl.h" #include "../containers/aligned_vector.h" @@ -11,6 +16,20 @@ extern void* memcpy4 (void *dest, const void *src, size_t count); +#define GL_FORCE_INLINE __attribute__((always_inline)) static __inline__ + +#define FASTCPY(dst, src, bytes) \ + (bytes % 32 == 0) ? sq_cpy(dst, src, bytes) : memcpy(dst, src, bytes); + +#define _PACK4(v) ((v * 0xF) / 0xFF) +#define PACK_ARGB4444(a,r,g,b) (_PACK4(a) << 12) | (_PACK4(r) << 8) | (_PACK4(g) << 4) | (_PACK4(b)) +#define PACK_ARGB8888(a,r,g,b) ( ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF) ) +#define PACK_ARGB1555(a,r,g,b) \ + (((GLushort)(a > 0) << 15) | (((GLushort) r >> 3) << 10) | (((GLushort)g >> 3) << 5) | ((GLushort)b >> 3)) + +#define PACK_RGB565(r,g,b) \ + ((((GLushort)r & 0xf8) << 8) | (((GLushort) g & 0xfc) << 3) | ((GLushort) b >> 3)) + #define TRACE_ENABLED 0 #define TRACE() if(TRACE_ENABLED) {fprintf(stderr, "%s\n", __func__);} @@ -68,7 +87,6 @@ typedef float Matrix4x4[16]; #define M15 15 #endif - typedef struct { pvr_poly_hdr_t hdr; } PVRHeader; @@ -125,6 +143,16 @@ typedef struct { GLboolean isCompressed; GLboolean isPaletted; //44 + + /* Mipmap textures have a different + * offset for the base level when supplying the data, this + * keeps track of that. baseDataOffset == 0 + * means that the texture has no mipmaps + */ + GLuint baseDataOffset; + //48 + GLuint baseDataSize; /* The data size of mipmap level 0 */ + //52 } TextureObject; typedef struct { @@ -132,6 +160,8 @@ typedef struct { GLfloat ambient[4]; GLfloat diffuse[4]; GLfloat specular[4]; + + /* Valid values are 0-128 */ GLfloat exponent; } Material; @@ -146,7 +176,6 @@ typedef struct { GLfloat diffuse[4]; GLfloat specular[4]; GLfloat ambient[4]; - GLboolean is_directional; } LightSource; typedef struct { @@ -163,11 +192,10 @@ typedef struct { } Vertex; #define swapVertex(a, b) \ -do { \ - Vertex temp __attribute__((aligned(32))); \ - memcpy4(&temp, &b, 32); \ - memcpy4(&b, &a, 32); \ - memcpy4(&b, &temp, 32); \ +do { \ + Vertex c = *a; \ + *a = *b; \ + *b = c; \ } while(0) /* ClipVertex doesn't have room for these, so we need to parse them @@ -244,6 +272,10 @@ GLubyte _glInitTextures(); void _glUpdatePVRTextureContext(pvr_poly_cxt_t* context, GLshort textureUnit); void _glAllocateSpaceForMipmaps(TextureObject* active); +extern GLfloat NEAR_PLANE_DISTANCE; + +GLfloat _glGetNearPlane(); + typedef struct { const void* ptr; GLenum type; @@ -251,11 +283,6 @@ typedef struct { GLint size; } AttribPointer; -typedef struct { - float xyz[3]; - float n[3]; -} EyeSpaceData; - GLboolean _glCheckValidEnum(GLint param, GLint* values, const char* func); GLuint* _glGetEnabledAttributes(); @@ -281,13 +308,24 @@ GLboolean _glIsBlendingEnabled(); GLboolean _glIsAlphaTestEnabled(); GLboolean _glIsMipmapComplete(const TextureObject* obj); -GLubyte* _glGetMipmapLocation(TextureObject* obj, GLuint level); -GLuint _glGetMipmapLevelCount(TextureObject* obj); +GLuint _glGetMipmapDataOffset(const TextureObject* obj, GLuint level); +GLubyte* _glGetMipmapLocation(const TextureObject* obj, GLuint level); +GLuint _glGetMipmapLevelCount(const TextureObject* obj); GLboolean _glIsLightingEnabled(); GLboolean _glIsLightEnabled(GLubyte light); GLboolean _glIsColorMaterialEnabled(); -void _glPerformLighting(Vertex* vertices, const EyeSpaceData* es, const int32_t count); + +GLboolean _glIsNormalizeEnabled(); + +GLboolean _glRecalcFastPath(); + +typedef struct { + float xyz[3]; + float n[3]; +} EyeSpaceData; + +extern void _glPerformLighting(Vertex* vertices, const EyeSpaceData* es, const int32_t count); unsigned char _glIsClippingEnabled(); void _glEnableClipping(unsigned char v); diff --git a/GL/state.c b/GL/state.c index 4711ed3..fbaddf3 100644 --- a/GL/state.c +++ b/GL/state.c @@ -33,6 +33,8 @@ static GLboolean ALPHA_TEST_ENABLED = GL_FALSE; static GLboolean POLYGON_OFFSET_ENABLED = GL_FALSE; +static GLboolean NORMALIZE_ENABLED = GL_FALSE; + GLboolean _glIsSharedTexturePaletteEnabled() { return SHARED_PALETTE_ENABLED; } @@ -61,17 +63,17 @@ static int _calc_pvr_depth_test() { case GL_NEVER: return PVR_DEPTHCMP_NEVER; case GL_LESS: - return PVR_DEPTHCMP_GREATER; + return PVR_DEPTHCMP_GEQUAL; case GL_EQUAL: return PVR_DEPTHCMP_EQUAL; case GL_LEQUAL: - return PVR_DEPTHCMP_GEQUAL; + return PVR_DEPTHCMP_GREATER; case GL_GREATER: - return PVR_DEPTHCMP_LESS; + return PVR_DEPTHCMP_LEQUAL; case GL_NOTEQUAL: return PVR_DEPTHCMP_NOTEQUAL; case GL_GEQUAL: - return PVR_DEPTHCMP_LEQUAL; + return PVR_DEPTHCMP_LESS; break; case GL_ALWAYS: default: @@ -86,6 +88,10 @@ static GLboolean BLEND_ENABLED = GL_FALSE; static GLfloat OFFSET_FACTOR = 0.0f; static GLfloat OFFSET_UNITS = 0.0f; +GLboolean _glIsNormalizeEnabled() { + return NORMALIZE_ENABLED; +} + GLboolean _glIsBlendingEnabled() { return BLEND_ENABLED; } @@ -121,17 +127,12 @@ static int _calcPVRBlendFactor(GLenum factor) { static void _updatePVRBlend(pvr_poly_cxt_t* context) { if(BLEND_ENABLED) { context->gen.alpha = PVR_ALPHA_ENABLE; - context->blend.src = _calcPVRBlendFactor(BLEND_SFACTOR); - context->blend.dst = _calcPVRBlendFactor(BLEND_DFACTOR); - context->blend.src_enable = PVR_BLEND_DISABLE; - context->blend.dst_enable = PVR_BLEND_DISABLE; } else { context->gen.alpha = PVR_ALPHA_DISABLE; - context->blend.src = PVR_BLEND_ONE; - context->blend.dst = PVR_BLEND_ZERO; - context->blend.src_enable = PVR_BLEND_DISABLE; - context->blend.dst_enable = PVR_BLEND_DISABLE; } + + context->blend.src = _calcPVRBlendFactor(BLEND_SFACTOR); + context->blend.dst = _calcPVRBlendFactor(BLEND_DFACTOR); } GLboolean _glCheckValidEnum(GLint param, GLint* values, const char* func) { @@ -158,15 +159,16 @@ GLboolean TEXTURES_ENABLED [] = {GL_FALSE, GL_FALSE}; void _glUpdatePVRTextureContext(pvr_poly_cxt_t* context, GLshort textureUnit) { const TextureObject *tx1 = (textureUnit == 0) ? _glGetTexture0() : _glGetTexture1(); + /* Disable all texturing to start with */ + context->txr.enable = PVR_TEXTURE_DISABLE; + context->txr2.enable = PVR_TEXTURE_DISABLE; + context->txr2.alpha = PVR_TXRALPHA_DISABLE; + if(!TEXTURES_ENABLED[textureUnit] || !tx1) { - context->txr.enable = PVR_TEXTURE_DISABLE; - context->txr.base = 0; - context->txr.format = 0; return; } - context->txr2.enable = PVR_TEXTURE_DISABLE; - context->txr2.alpha = PVR_TXRALPHA_DISABLE; + context->txr.alpha = (BLEND_ENABLED) ? PVR_TXRALPHA_ENABLE : PVR_TXRALPHA_DISABLE; GLuint filter = PVR_FILTER_NEAREST; GLboolean enableMipmaps = GL_FALSE; @@ -223,29 +225,25 @@ void _glUpdatePVRTextureContext(pvr_poly_cxt_t* context, GLshort textureUnit) { if(tx1->data) { context->txr.enable = PVR_TEXTURE_ENABLE; context->txr.filter = filter; - context->txr.mipmap = enableMipmaps; - context->txr.mipmap_bias = tx1->mipmap_bias; context->txr.width = tx1->width; context->txr.height = tx1->height; - if(enableMipmaps){ + + if(enableMipmaps) { context->txr.base = tx1->data; + context->txr.mipmap = PVR_MIPMAP_ENABLE; + context->txr.mipmap_bias = PVR_MIPBIAS_NORMAL; } else { - if(tx1->mipmap > 1) - context->txr.base = _glGetMipmapLocation((TextureObject*)tx1,0); - /* We should need this? */ - else - context->txr.base = tx1->data; + context->txr.base = tx1->data + tx1->baseDataOffset; + context->txr.mipmap = PVR_MIPMAP_DISABLE; + context->txr.mipmap_bias = PVR_MIPBIAS_NORMAL; } - + context->txr.format = tx1->color; if(tx1->isPaletted) { if(_glIsSharedTexturePaletteEnabled()) { - //TexturePalette* palette = _glGetSharedPalette(tx1->shared_bank); - context->txr.format |= PVR_TXRFMT_8BPP_PAL(tx1->shared_bank); - if(tx1->shared_bank != 0){ - //printf("%s chose bank %d!\n",__func__,tx1->shared_bank); - } + TexturePalette* palette = _glGetSharedPalette(tx1->shared_bank); + context->txr.format |= PVR_TXRFMT_8BPP_PAL(palette->bank); } else { context->txr.format |= PVR_TXRFMT_8BPP_PAL((tx1->palette) ? tx1->palette->bank : 0); } @@ -254,9 +252,6 @@ void _glUpdatePVRTextureContext(pvr_poly_cxt_t* context, GLshort textureUnit) { context->txr.env = tx1->env; context->txr.uv_flip = PVR_UVFLIP_NONE; context->txr.uv_clamp = tx1->uv_clamp; - context->txr.alpha = PVR_TXRALPHA_ENABLE; - } else { - context->txr.enable = PVR_TEXTURE_DISABLE; } } @@ -359,7 +354,10 @@ GLAPI void APIENTRY glEnable(GLenum cap) { case GL_POLYGON_OFFSET_LINE: case GL_POLYGON_OFFSET_FILL: POLYGON_OFFSET_ENABLED = GL_TRUE; - break; + break; + case GL_NORMALIZE: + NORMALIZE_ENABLED = GL_TRUE; + break; default: break; } @@ -418,7 +416,10 @@ GLAPI void APIENTRY glDisable(GLenum cap) { case GL_POLYGON_OFFSET_LINE: case GL_POLYGON_OFFSET_FILL: POLYGON_OFFSET_ENABLED = GL_FALSE; - break; + break; + case GL_NORMALIZE: + NORMALIZE_ENABLED = GL_FALSE; + break; default: break; } @@ -465,7 +466,6 @@ GLAPI void APIENTRY glReadBuffer(GLenum mode) { GLAPI void APIENTRY glDepthMask(GLboolean flag) { GL_CONTEXT.depth.write = (flag == GL_TRUE) ? PVR_DEPTHWRITE_ENABLE : PVR_DEPTHWRITE_DISABLE; - GL_CONTEXT.depth.comparison = _calc_pvr_depth_test(); } GLAPI void APIENTRY glDepthFunc(GLenum func) { @@ -731,7 +731,7 @@ const GLubyte *glGetString(GLenum name) { return (const GLubyte*) "1.2 (partial) - GLdc 1.1"; case GL_EXTENSIONS: - return (const GLubyte*) "GL_ARB_framebuffer_object, GL_ARB_multitexture, GL_ARB_texture_rg, GL_EXT_paletted_texture, GL_EXT_shared_texture_palette, GL_KOS_multiple_shared_palette"; + return (const GLubyte*) "GL_ARB_framebuffer_object, GL_ARB_multitexture, GL_ARB_texture_rg, GL_EXT_paletted_texture, GL_EXT_shared_texture_palette, GL_KOS_multiple_shared_palette, GL_ARB_vertex_array_bgra, GL_ARB_vertex_type_2_10_10_10_rev"; } return (const GLubyte*) "GL_KOS_ERROR: ENUM Unsupported\n"; diff --git a/GL/texture.c b/GL/texture.c index 95ec42f..6e257e0 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -9,6 +9,7 @@ #include "config.h" #include "../include/glext.h" #include "../include/glkos.h" +#include #define CLAMP_U (1<<1) #define CLAMP_V (1<<0) @@ -21,12 +22,6 @@ static TexturePalette* SHARED_PALETTES[4] = {NULL, NULL, NULL, NULL}; GLuint _determinePVRFormat(GLint internalFormat, GLenum type); -#define PACK_ARGB8888(a,r,g,b) ( ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF) ) - - -#define _PACK4(v) ((v * 0xF) / 0xFF) -#define PACK_ARGB4444(a,r,g,b) (_PACK4(a) << 12) | (_PACK4(r) << 8) | (_PACK4(g) << 4) | (_PACK4(b)) - static GLboolean BANKS_USED[4]; // Each time a 256 colour bank is used, this is set to true static GLboolean SUBBANKS_USED[4][16]; // 4 counts of the used 16 colour banks within the 256 ones static GLenum INTERNAL_PALETTE_FORMAT = GL_RGBA4; @@ -141,9 +136,9 @@ GLubyte _glGetActiveTexture() { switch(type) { case GL_BYTE: case GL_UNSIGNED_BYTE: - return (format == GL_RED) ? 1 : (format == GL_RGB) ? 3 : 4; + return (format == GL_RED || format == GL_ALPHA) ? 1 : (format == GL_RGB) ? 3 : 4; case GL_UNSIGNED_SHORT: - return (format == GL_RED) ? 2 : (format == GL_RGB) ? 6 : 8; + return (format == GL_RED || format == GL_ALPHA) ? 2 : (format == GL_RGB) ? 6 : 8; case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_5_6_5_REV: case GL_UNSIGNED_SHORT_5_6_5_TWID_KOS: @@ -159,19 +154,23 @@ GLubyte _glGetActiveTexture() { return -1; } -GLubyte* _glGetMipmapLocation(TextureObject* obj, GLuint level) { +GLuint _glGetMipmapDataOffset(const TextureObject* obj, GLuint level) { GLuint offset = 0; GLuint size = obj->height; - if(obj->width == size){ - if(obj->isPaletted){ + if(obj->width != obj->height) { + fprintf(stderr, "ERROR: Accessing memory location of mipmaps on non-square texture\n"); + return offset; + } + + if(obj->isPaletted){ switch(size >> level){ case 1024: offset = 0x55558; break; case 512: offset = 0x15558; - break; + break; case 256: offset = 0x05558; break; @@ -274,14 +273,16 @@ GLubyte* _glGetMipmapLocation(TextureObject* obj, GLuint level) { offset = 0x00006; break; } - - } } - return ((GLubyte*) obj->data) + offset; + return offset; } -GLuint _glGetMipmapLevelCount(TextureObject* obj) { +GLubyte* _glGetMipmapLocation(const TextureObject* obj, GLuint level) { + return ((GLubyte*) obj->data) + _glGetMipmapDataOffset(obj, level); +} + +GLuint _glGetMipmapLevelCount(const TextureObject* obj) { return 1 + floorf(log2f(MAX(obj->width, obj->height))); } @@ -358,7 +359,7 @@ static void _glInitializeTextureObject(TextureObject* txr, unsigned int id) { txr->width = txr->height = 0; txr->mipmap = 0; txr->uv_clamp = 0; - txr->env = PVR_TXRENV_MODULATEALPHA; + txr->env = PVR_TXRENV_MODULATE; txr->data = NULL; txr->mipmapCount = 0; txr->minFilter = GL_NEAREST; @@ -367,6 +368,9 @@ static void _glInitializeTextureObject(TextureObject* txr, unsigned int id) { txr->isCompressed = GL_FALSE; txr->isPaletted = GL_FALSE; + /* Not mipmapped by default */ + txr->baseDataOffset = 0; + /* Always default to the first shared bank */ txr->shared_bank = 0; } @@ -484,7 +488,7 @@ void APIENTRY glTexEnvi(GLenum target, GLenum pname, GLint param) { break; default: break; - } + } } break; @@ -802,10 +806,17 @@ static INLINE_DEBUG void _i8_to_i8(const GLubyte* source, GLubyte* dest) { *dst = *source; } +static inline void _alpha8_to_argb4444(const GLubyte* source, GLubyte* dest) { + *((GLushort*) dest) = (*source & 0xF0) << 8 | (0xFF & 0xF0) << 4 | (0xFF & 0xF0) | (0xFF & 0xF0) >> 4; +} + static TextureConversionFunc _determineConversion(GLint internalFormat, GLenum format, GLenum type) { switch(internalFormat) { case GL_ALPHA: { - if(type == GL_UNSIGNED_BYTE && format == GL_RGBA) { + if(format == GL_ALPHA) { + /* Dreamcast doesn't really support GL_ALPHA internally, so store as argb with each rgb value as white */ + return _alpha8_to_argb4444; + } else if(type == GL_UNSIGNED_BYTE && format == GL_RGBA) { return _rgba8888_to_a000; } else if(type == GL_BYTE && format == GL_RGBA) { return _rgba8888_to_a000; @@ -870,6 +881,7 @@ static TextureConversionFunc _determineConversion(GLint internalFormat, GLenum f static GLboolean _isSupportedFormat(GLenum format) { switch(format) { + case GL_ALPHA: case GL_RED: case GL_RGB: case GL_RGBA: @@ -882,6 +894,12 @@ static GLboolean _isSupportedFormat(GLenum format) { } GLboolean _glIsMipmapComplete(const TextureObject* obj) { + + // Non-square textures can't have mipmaps + if(obj->width != obj->height) { + return GL_FALSE; + } + if(!obj->mipmap || !obj->mipmapCount) { return GL_FALSE; } @@ -896,34 +914,38 @@ GLboolean _glIsMipmapComplete(const TextureObject* obj) { return GL_TRUE; } -#define TWIDTAB(x) ( (x&1)|((x&2)<<1)|((x&4)<<2)|((x&8)<<3)|((x&16)<<4)| \ - ((x&32)<<5)|((x&64)<<6)|((x&128)<<7)|((x&256)<<8)|((x&512)<<9) ) - -#define TWIDOUT(x, y) ( TWIDTAB((y)) | (TWIDTAB((x)) << 1) ) - void _glAllocateSpaceForMipmaps(TextureObject* active) { - if(!active->data){ + if(active->data && active->baseDataOffset > 0) { + /* Already done - mipmaps have a dataOffset */ return; } - if(active->data && active->mipmap > 1) { - /* Already done */ - return; - } - - int size = active->height*active->width*active->dataStride; /* We've allocated level 0 before, but now we're allocating * a level beyond that, we need to reallocate the data, copy level 0 * then free the original */ - GLubyte* temp = malloc(size); - memcpy4(temp, active->data, size); + + GLuint size = active->baseDataSize; + + /* Copy the data out of the pvr and back to ram */ + GLubyte* temp = (GLubyte*) malloc(size); + memcpy(temp, active->data, size); + + /* Free the PVR data */ pvr_mem_free(active->data); - active->data = pvr_mem_malloc(_glGetMipmapDataSize(active)); + active->data = NULL; + + /* Figure out how much room to allocate for mipmaps */ + GLuint bytes = _glGetMipmapDataSize(active); + + active->data = pvr_mem_malloc(bytes); /* If there was existing data, then copy it where it should go */ - memcpy4(_glGetMipmapLocation(active,0), temp, size); - free(temp); + memcpy(_glGetMipmapLocation(active, 0), temp, size); + + /* Set the data offset depending on whether or not this is a + * paletted texure */ + active->baseDataOffset = _glGetMipmapDataOffset(active, 0); } void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, @@ -931,32 +953,28 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLenum format, GLenum type, const GLvoid *data) { TRACE(); - if(!data) { - /* No data? Do nothing! */ - return; - } if(target != GL_TEXTURE_2D) { - _glKosThrowError(GL_INVALID_ENUM, "glTexImage2D"); + _glKosThrowError(GL_INVALID_ENUM, "glTexImage2D1"); } if(format != GL_COLOR_INDEX) { if(!_isSupportedFormat(format)) { - _glKosThrowError(GL_INVALID_ENUM, "glTexImage2D"); + _glKosThrowError(GL_INVALID_ENUM, "glTexImage2D2"); } /* Abuse determineStride to see if type is valid */ if(_determineStride(GL_RGBA, type) == -1) { - _glKosThrowError(GL_INVALID_ENUM, "glTexImage2D"); + _glKosThrowError(GL_INVALID_ENUM, "glTexImage2D3"); } internalFormat = _cleanInternalFormat(internalFormat); if(internalFormat == -1) { - _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D"); + _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D4"); } } else { if(internalFormat != GL_COLOR_INDEX8_EXT) { - _glKosThrowError(GL_INVALID_ENUM, __func__); + _glKosThrowError(GL_INVALID_ENUM, "glTexImage2D5"); } } @@ -965,26 +983,31 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, if(level == 0){ if((w < 8 || (w & -w) != w)) { /* Width is not a power of two. Must be!*/ - _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D"); + _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D6"); } if((h < 8 || (h & -h) != h)) { /* height is not a power of two. Must be!*/ - _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D"); + _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D7"); } } if(level < 0) { - _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D"); + _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D8"); + } + + if(level > 0 && width != height) { + fprintf(stderr, "[GL ERROR] Mipmaps cannot be supported on non-square textures\n"); + _glKosThrowError(GL_INVALID_OPERATION, "glTexImage2D9"); } if(border) { - _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D"); + _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D10"); } if(!TEXTURE_UNITS[ACTIVE_TEXTURE]) { - _glKosThrowError(GL_INVALID_OPERATION, __func__); + _glKosThrowError(GL_INVALID_OPERATION, "glTexImage2D11"); } GLboolean isPaletted = (internalFormat == GL_COLOR_INDEX8_EXT) ? GL_TRUE : GL_FALSE; @@ -1001,7 +1024,7 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, assert(active); - if(active->data && (level == 0) ) { + if(active->data && level == 0) { /* pre-existing texture - check if changed */ if(active->width != width || active->height != height || @@ -1011,8 +1034,9 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, active->data = NULL; active->mipmap = 0; active->mipmapCount = 0; - active->mipmap_bias = GL_KOS_INTERNAL_DEFAULT_MIPMAP_LOD_BIAS; // in the scale of -8 - 8 moved to 1-15, -4 = 4 active->dataStride = 0; + active->baseDataOffset = 0; + active->baseDataSize = 0; } } @@ -1022,7 +1046,7 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLint destStride = isPaletted ? 1 : 2; GLuint bytes = (width * height * destStride); - if(!active->data && (level == 0)) { + if(!active->data) { assert(active); assert(width); assert(height); @@ -1034,24 +1058,27 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, active->color = pvr_format; /* Set the required mipmap count */ active->mipmapCount = _glGetMipmapLevelCount(active); - active->mipmap_bias = GL_KOS_INTERNAL_DEFAULT_MIPMAP_LOD_BIAS; // in the scale of -8 - 8 moved to 1-15, -4 = 4 - active->dataStride = destStride; + active->baseDataSize = bytes; + + assert(bytes); + + if(level > 0) { + /* If we're uploading a mipmap level, we need to allocate the full amount of space */ + _glAllocateSpaceForMipmaps(active); + } else { + active->data = pvr_mem_malloc(active->baseDataSize); + } - active->data = pvr_mem_malloc(destStride*width*height); assert(active->data); - active->isCompressed = GL_FALSE; active->isPaletted = isPaletted; - } else if(!active->data && (level != 0)){ - printf("Spooky!\n"); - assert(0 && "GLdc broken, sorry! @neo"); - return; } - /* Check if we need to re-alloc and move texture data */ - if(level > 0){ - _glAllocateSpaceForMipmaps(active); + /* We're supplying a mipmap level, but previously we only had + * data for the first level (level 0) */ + if(level > 0 && active->baseDataOffset == 0) { + _glAllocateSpaceForMipmaps(active); } /* Mark this level as set in the mipmap bitmask */ @@ -1059,7 +1086,9 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, /* Let's assume we need to convert */ GLboolean needsConversion = GL_TRUE; - GLboolean needsTwiddling = GL_FALSE; + + /* Let's assume we need twiddling - we always store things twiddled! */ + GLboolean needsTwiddling = GL_TRUE; /* * These are the only formats where the source format passed in matches the pvr format. @@ -1068,7 +1097,10 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, if(format == GL_COLOR_INDEX) { /* Don't convert color indexes */ needsConversion = GL_FALSE; - needsTwiddling = type == GL_UNSIGNED_BYTE; + + if(type == GL_UNSIGNED_BYTE_TWID_KOS) { + needsTwiddling = GL_FALSE; + } } else if(format == GL_BGRA && type == GL_UNSIGNED_SHORT_4_4_4_4_REV && internalFormat == GL_RGBA) { needsConversion = GL_FALSE; } else if(format == GL_BGRA && type == GL_UNSIGNED_SHORT_1_5_5_5_REV && internalFormat == GL_RGBA) { @@ -1077,56 +1109,32 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, needsConversion = GL_FALSE; } else if(format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5_TWID_KOS && internalFormat == GL_RGB) { needsConversion = GL_FALSE; + needsTwiddling = GL_FALSE; } else if(format == GL_BGRA && type == GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS && internalFormat == GL_RGBA) { needsConversion = GL_FALSE; + needsTwiddling = GL_FALSE; } else if(format == GL_BGRA && type == GL_UNSIGNED_SHORT_4_4_4_4_REV_TWID_KOS && internalFormat == GL_RGBA) { needsConversion = GL_FALSE; + needsTwiddling = GL_FALSE; } - GLubyte* targetData = NULL; - - if(active->mipmap == 1 && level==0){ - targetData = active->data; - } else { - targetData = _glGetMipmapLocation(active, level); - } - + GLubyte* targetData = (active->baseDataOffset == 0) ? active->data : _glGetMipmapLocation(active, level); assert(targetData); - if(!needsConversion) { + GLubyte* conversionBuffer = NULL; + + if(!data) { + /* No data? Do nothing! */ + return; + } else if(!needsConversion && !needsTwiddling) { assert(targetData); assert(data); assert(bytes); - if(needsTwiddling) { - assert(type == GL_UNSIGNED_BYTE); // Anything else needs this loop adjusting - GLuint x, y, min, mask; - - GLubyte *pixels = (GLubyte*) data; - GLushort *vtex = (GLushort*) targetData; - - min = MIN(w, h); - mask = min - 1; - - if(height == 1 || width == 1){ - targetData[0] = ((GLubyte*)data)[0]; - targetData[1] = ((GLubyte*)data)[0]; - targetData[2] = ((GLubyte*)data)[0]; - targetData[3] = ((GLubyte*)data)[0]; - } else { - for(y = 0; y < h; y += 2) { - for(x = 0; x < w; x++) { - vtex[TWIDOUT((y & mask) / 2, x & mask) + (x / min + y / min)*min * min / 2] = pixels[y * w + x] | (pixels[(y + 1) * w + x] << 8); - } - } - } - } else { - /* No conversion? Just copy the data, and the pvr_format is correct */ - FASTCPY(targetData, data, bytes); - } - + /* No conversion? Just copy the data, and the pvr_format is correct */ + FASTCPY(targetData, data, bytes); return; - } else { + } else if(needsConversion) { TextureConversionFunc convert = _determineConversion( internalFormat, format, @@ -1138,12 +1146,6 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, return; } - GLubyte* dest = (GLubyte*) targetData; - const GLubyte* source = data; - - assert(dest); - assert(source); - GLint stride = _determineStride(format, type); assert(stride > -1); @@ -1152,6 +1154,14 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, return; } + conversionBuffer = malloc(bytes); + + GLubyte* dest = conversionBuffer; + const GLubyte* source = data; + + assert(conversionBuffer); + assert(source); + /* Perform the conversion */ GLuint i; for(i = 0; i < bytes; i += destStride) { @@ -1161,8 +1171,36 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, source += stride; } } + + if(needsTwiddling) { + const GLubyte *pixels = (GLubyte*) (conversionBuffer) ? conversionBuffer : data; + + if(internalFormat == GL_COLOR_INDEX8_EXT) { + pvr_txr_load_ex((void*) pixels, targetData, width, height, PVR_TXRLOAD_8BPP); + } else { + pvr_txr_load_ex((void*) pixels, targetData, width, height, PVR_TXRLOAD_16BPP); + } + + /* We make sure we remove nontwiddled and add twiddled. We could always + * make it twiddled when determining the format but I worry that would make the + * code less flexible to change in the future */ + active->color &= ~(1 << 26); + } else { + /* We should only get here if we converted twiddled data... which is never currently */ + assert(conversionBuffer); + + // We've already converted the data and we + // don't need to twiddle it! + FASTCPY(targetData, conversionBuffer, bytes); + } + + if(conversionBuffer) { + free(conversionBuffer); + conversionBuffer = NULL; + } } + void APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param) { TRACE(); diff --git a/GL/util.c b/GL/util.c new file mode 100644 index 0000000..eaf2e17 --- /dev/null +++ b/GL/util.c @@ -0,0 +1,15 @@ +#include "../include/glkos.h" + +void APIENTRY glVertexPackColor3fKOS(GLVertexKOS* vertex, float r, float g, float b) { + vertex->bgra[3] = 255; + vertex->bgra[2] = (r * 255.0f); + vertex->bgra[1] = (g * 255.0f); + vertex->bgra[0] = (b * 255.0f); +} + +void APIENTRY glVertexPackColor4fKOS(GLVertexKOS* vertex, float r, float g, float b, float a) { + vertex->bgra[3] = (a * 255.0f); + vertex->bgra[2] = (r * 255.0f); + vertex->bgra[1] = (g * 255.0f); + vertex->bgra[0] = (b * 255.0f); +} diff --git a/Makefile b/Makefile index ac3cac6..957fd0c 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # kos-ports/libgl Makefile # Copyright (C) 2013, 2014 Josh Pearson # Copyright (C) 2014 Lawrence Sebald -# Copyright (C) 2018 Luke Benstead +# Copyright (C) 2020 Luke Benstead TARGET = libGLdc.a OBJS = GL/gldc.o @@ -40,7 +40,11 @@ export OBJEXTRA := $(LIB_DIR)/libGLdc.a link: | $(OBJS) ; $(KOS_AR) rcs $(TARGET) $(OBJS) -build: $(OBJS) +GL/version.h: + rm -f $@ + @echo -e '#pragma once\n#define GLDC_VERSION "$(shell git describe --abbrev=4 --dirty --always --tags)"\n' > $@ + +build: GL/version.h $(OBJS) samples: build $(KOS_MAKE) -C samples all diff --git a/containers/aligned_vector.c b/containers/aligned_vector.c index 1657a60..2f408ca 100644 --- a/containers/aligned_vector.c +++ b/containers/aligned_vector.c @@ -26,7 +26,6 @@ void aligned_vector_init(AlignedVector* vector, unsigned int element_size) { aligned_vector_reserve(vector, ALIGNED_VECTOR_CHUNK_SIZE); } - static INLINE_DEBUG unsigned int round_to_chunk_size(unsigned int val) { const unsigned int n = val; const unsigned int m = ALIGNED_VECTOR_CHUNK_SIZE; @@ -34,7 +33,6 @@ static INLINE_DEBUG unsigned int round_to_chunk_size(unsigned int val) { return ((n + m - 1) / m) * m; } - void aligned_vector_reserve(AlignedVector* vector, unsigned int element_count) { if(element_count == 0) { return; diff --git a/include/gl.h b/include/gl.h index ba9dd29..8c002bd 100644 --- a/include/gl.h +++ b/include/gl.h @@ -19,25 +19,18 @@ __BEGIN_DECLS #include -#include -#include -#include -#include -#include -#include - /* Primitive Types taken from GL for compatability */ /* Not all types are implemented in Open GL DC V.1.0 */ -#define GL_POINTS 0x01 -#define GL_LINES 0x02 -#define GL_LINE_LOOP 0x03 -#define GL_LINE_STRIP 0x04 -#define GL_TRIANGLES 0x05 -#define GL_TRIANGLE_STRIP 0x06 -#define GL_TRIANGLE_FAN 0x07 -#define GL_QUADS 0x08 -#define GL_QUAD_STRIP 0x09 -#define GL_POLYGON 0x0A +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_QUADS 0x0007 +#define GL_QUAD_STRIP 0x0008 +#define GL_POLYGON 0x0009 /* FrontFaceDirection */ #define GL_CW 0x0900 @@ -232,6 +225,13 @@ __BEGIN_DECLS #define GL_SINGLE_COLOR 0x81F9 #define GL_SEPARATE_SPECULAR_COLOR 0x81FA +/* glPolygonOffset */ +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 + /* Client state caps */ #define GL_VERTEX_ARRAY 0x8074 #define GL_NORMAL_ARRAY 0x8075 @@ -335,6 +335,9 @@ __BEGIN_DECLS #define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 #define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_INT_2_10_10_10_REV 0x8D9F + #define GL_COLOR_INDEX 0x1900 #define GL_RED 0x1903 #define GL_GREEN 0x1904 @@ -431,6 +434,7 @@ GLAPI void APIENTRY glColor1ui(GLuint argb); GLAPI void APIENTRY glColor4ub(GLubyte r, GLubyte g, GLubyte b, GLubyte a); GLAPI void APIENTRY glColor3f(GLfloat r, GLfloat g, GLfloat b); GLAPI void APIENTRY glColor3ub(GLubyte r, GLubyte g, GLubyte b); +GLAPI void APIENTRY glColor3ubv(const GLubyte *v); GLAPI void APIENTRY glColor3fv(const GLfloat *rgb); GLAPI void APIENTRY glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a); GLAPI void APIENTRY glColor4fv(const GLfloat *rgba); @@ -488,6 +492,7 @@ GLAPI void APIENTRY glClearDepth(GLfloat depth); GLAPI void APIENTRY glClearDepthf(GLfloat depth); GLAPI void APIENTRY glDepthMask(GLboolean flag); GLAPI void APIENTRY glDepthFunc(GLenum func); +GLAPI void APIENTRY glDepthRange(GLclampf n, GLclampf f); /* Hints */ /* Currently Supported Capabilities: diff --git a/include/glkos.h b/include/glkos.h index 622bca3..627e243 100644 --- a/include/glkos.h +++ b/include/glkos.h @@ -53,6 +53,20 @@ typedef struct { } GLdcConfig; +typedef struct { + GLuint padding0; + GLfloat x; + GLfloat y; + GLfloat z; + GLfloat u; + GLfloat v; + GLubyte bgra[4]; + GLuint padding1; +} GLVertexKOS; + +GLAPI void APIENTRY glVertexPackColor3fKOS(GLVertexKOS* vertex, float r, float g, float b); +GLAPI void APIENTRY glVertexPackColor4fKOS(GLVertexKOS* vertex, float r, float g, float b, float a); + GLAPI void APIENTRY glKosInitConfig(GLdcConfig* config); /* Usage: diff --git a/samples/Makefile b/samples/Makefile index 177f547..b565d58 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -26,3 +26,7 @@ all: $(KOS_MAKE) -C paletted_pcx all $(KOS_MAKE) -C depth_funcs all $(KOS_MAKE) -C polymark all + $(KOS_MAKE) -C polygon_offset all + $(KOS_MAKE) -C blend_test all + $(KOS_MAKE) -C mipmap all + $(KOS_MAKE) -C lights all diff --git a/samples/blend_test/Makefile b/samples/blend_test/Makefile new file mode 100644 index 0000000..cfff063 --- /dev/null +++ b/samples/blend_test/Makefile @@ -0,0 +1,29 @@ +TARGET = blend_test.elf +OBJS = main.o + +all: rm-elf $(TARGET) + +include $(KOS_BASE)/Makefile.rules + +clean: + -rm -f $(TARGET) $(OBJS) romdisk.* + +rm-elf: + -rm -f $(TARGET) romdisk.* + +$(TARGET): $(OBJS) romdisk.o + $(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \ + $(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS) + +romdisk.img: + $(KOS_GENROMFS) -f romdisk.img -d romdisk -v + +romdisk.o: romdisk.img + $(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o + +run: $(TARGET) + $(KOS_LOADER) $(TARGET) + +dist: + rm -f $(OBJS) romdisk.o romdisk.img + $(KOS_STRIP) $(TARGET) diff --git a/samples/blend_test/main.c b/samples/blend_test/main.c new file mode 100644 index 0000000..4fcad50 --- /dev/null +++ b/samples/blend_test/main.c @@ -0,0 +1,100 @@ +/* + * This sample is to demonstrate a bug where rendering an unblended + * polygon, before a series of blended ones would result in no blended + * output and incorrect depth testing + */ + +#include "gl.h" +#include "glu.h" +#include "glkos.h" + +/* A general OpenGL initialization function. Sets all of the initial parameters. */ +void InitGL(int Width, int Height) // We call this right after our OpenGL window is created. +{ + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // This Will Clear The Background Color To Black + glClearDepth(1.0); // Enables Clearing Of The Depth Buffer + glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do + glEnable(GL_DEPTH_TEST); // Enables Depth Testing + glEnable(GL_TEXTURE_2D); + glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading + glDisable(GL_BLEND); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); // Reset The Projection Matrix + + gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); // Calculate The Aspect Ratio Of The Window + + glMatrixMode(GL_MODELVIEW); +} + +/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */ +void ReSizeGLScene(int Width, int Height) +{ + if (Height == 0) // Prevent A Divide By Zero If The Window Is Too Small + Height = 1; + + glViewport(0, 0, Width, Height); // Reset The Current Viewport And Perspective Transformation + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); + glMatrixMode(GL_MODELVIEW); +} + + +void DrawQuad(const float* colour) { + glBegin(GL_QUADS); + glColor4fv(colour); + glVertex3f(-1.0,-1.0, 0.0); + glVertex3f( 1.0,-1.0, 0.0); + glVertex3f( 1.0, 1.0, 0.0); + glVertex3f(-1.0, 1.0, 0.0); + glEnd(); +} + +/* The main drawing function. */ +void DrawGLScene() +{ + const float RED [] = {1.0, 0, 0, 0.5}; + const float BLUE [] = {0.0, 0, 1, 0.5}; + const float NONE [] = {0, 0, 0, 0}; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer + glLoadIdentity(); // Reset The View + + glTranslatef(0, 0, -10.0f); // Move Left 1.5 Units And Into The Screen 6.0 + + glPushMatrix(); + glTranslatef(-4.0, 0, -10); + DrawQuad(RED); + glPopMatrix(); + + glTranslatef(4.0, 0, 0); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + /* Draw 3 overlapping quads, 2 of which should be totally transparent so the + * output should be the third */ + DrawQuad(NONE); + DrawQuad(NONE); + DrawQuad(BLUE); + + glDisable(GL_BLEND); + + glKosSwapBuffers(); +} + +int main(int argc, char **argv) +{ + glKosInit(); + + InitGL(640, 480); + ReSizeGLScene(640, 480); + + while(1) { + DrawGLScene(); + } + + return 0; +} diff --git a/samples/blend_test/romdisk/PLACEHOLDER b/samples/blend_test/romdisk/PLACEHOLDER new file mode 100644 index 0000000..e69de29 diff --git a/samples/lights/Makefile b/samples/lights/Makefile new file mode 100644 index 0000000..b268753 --- /dev/null +++ b/samples/lights/Makefile @@ -0,0 +1,29 @@ +TARGET = lights.elf +OBJS = main.o + +all: rm-elf $(TARGET) + +include $(KOS_BASE)/Makefile.rules + +clean: + -rm -f $(TARGET) $(OBJS) romdisk.* + +rm-elf: + -rm -f $(TARGET) romdisk.* + +$(TARGET): $(OBJS) romdisk.o + $(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \ + $(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS) + +romdisk.img: + $(KOS_GENROMFS) -f romdisk.img -d romdisk -v + +romdisk.o: romdisk.img + $(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o + +run: $(TARGET) + $(KOS_LOADER) $(TARGET) + +dist: + rm -f $(OBJS) romdisk.o romdisk.img + $(KOS_STRIP) $(TARGET) diff --git a/samples/lights/main.c b/samples/lights/main.c new file mode 100644 index 0000000..c6c2609 --- /dev/null +++ b/samples/lights/main.c @@ -0,0 +1,296 @@ +#include + +#include "gl.h" +#include "glu.h" +#include "glkos.h" + +extern uint8 romdisk[]; +KOS_INIT_ROMDISK(romdisk); + + +float xrot, yrot, zrot; + + +int texture[1]; + + +struct Image { + unsigned long sizeX; + unsigned long sizeY; + char *data; +}; +typedef struct Image Image; + + + +int ImageLoad(char *filename, Image *image) { + FILE *file; + unsigned long size; + unsigned long i; + unsigned short int planes; + unsigned short int bpp; + char temp; + + + if ((file = fopen(filename, "rb"))==NULL) + { + printf("File Not Found : %s\n",filename); + return 0; + } + + + fseek(file, 18, SEEK_CUR); + + + if ((i = fread(&image->sizeX, 4, 1, file)) != 1) { + printf("Error reading width from %s.\n", filename); + return 0; + } + printf("Width of %s: %lu\n", filename, image->sizeX); + + + if ((i = fread(&image->sizeY, 4, 1, file)) != 1) { + printf("Error reading height from %s.\n", filename); + return 0; + } + printf("Height of %s: %lu\n", filename, image->sizeY); + + + size = image->sizeX * image->sizeY * 3; + + + if ((fread(&planes, 2, 1, file)) != 1) { + printf("Error reading planes from %s.\n", filename); + return 0; + } + if (planes != 1) { + printf("Planes from %s is not 1: %u\n", filename, planes); + return 0; + } + + + if ((i = fread(&bpp, 2, 1, file)) != 1) { + printf("Error reading bpp from %s.\n", filename); + return 0; + } + if (bpp != 24) { + printf("Bpp from %s is not 24: %u\n", filename, bpp); + return 0; + } + + + fseek(file, 24, SEEK_CUR); + + + image->data = (char *) malloc(size); + if (image->data == NULL) { + printf("Error allocating memory for color-corrected image data"); + return 0; + } + + if ((i = fread(image->data, size, 1, file)) != 1) { + printf(stderr, "Error reading image data from %s.\n", filename); + return 0; + } + + for (i=0;idata[i]; + image->data[i] = image->data[i+2]; + image->data[i+2] = temp; + } + + + return 1; +} + + +void LoadGLTextures() { + + Image *image1; + + + image1 = (Image *) malloc(sizeof(Image)); + if (image1 == NULL) { + printf("Error allocating space for image"); + exit(0); + } + + if (!ImageLoad("/rd/NeHe.bmp", image1)) { + exit(1); + } + + glGenTextures(1, &texture[0]); + glBindTexture(GL_TEXTURE_2D, texture[0]); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); + + + + glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data); + + glGenerateMipmapEXT(GL_TEXTURE_2D); +}; + + +void InitGL(int Width, int Height) +{ + LoadGLTextures(); + glEnable(GL_TEXTURE_2D); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(1.0); + glDepthFunc(GL_LESS); + glEnable(GL_DEPTH_TEST); + glShadeModel(GL_SMOOTH); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); + + glMatrixMode(GL_MODELVIEW); + + glEnable(GL_COLOR_MATERIAL); + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + + glClearColor(0.5, 0.5, 0.5, 0.5); + + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + + // Create light components + GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f }; + GLfloat diffuseLight[] = { 1.0f, 0.0f, 0.0, 1.0f }; + GLfloat specularLight[] = { 0.5f, 0.5f, 0.5f, 1.0f }; + GLfloat position[] = { -1.5f, -1.0f, 0.0f, 0.0f }; + + // Assign created components to GL_LIGHT0 + glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); + glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); + glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); + glLightfv(GL_LIGHT0, GL_POSITION, position); + + glDisable(GL_TEXTURE_2D); + + diffuseLight[1] = 1.0f; + + glEnable(GL_LIGHT1); + glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuseLight); + glLightfv(GL_LIGHT1, GL_SPECULAR, specularLight); + + glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.0); + glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 4.5 / 100); + glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 75.0f / (100 * 100)); + + glEnable(GL_NORMALIZE); +} + + +void ReSizeGLScene(int Width, int Height) +{ + if (Height == 0) + Height = 1; + + glViewport(0, 0, Width, Height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); + glMatrixMode(GL_MODELVIEW); +} + +void DrawCube(float x, float z) { + static float pos = 0.0f; + const static float radius = 30.0f; + + pos += 0.001f; + + GLfloat position[] = { cos(pos) * radius, 15.0f, sin(pos) * radius, 1.0f }; + glLightfv(GL_LIGHT1, GL_POSITION, position); + + glPushMatrix(); + glTranslatef(x, 0, z); + glColor4f(1, 1, 1, 1); + + glBegin(GL_QUADS); + + + glNormal3f(0, 0, -1); + glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); + glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); + + + glNormal3f(0, 0, 1); + glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); + glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); + glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); + glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); + + + glNormal3f(0, 1, 0); + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); + glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); + glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); + + glNormal3f(0, -1, 0); + glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); + glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); + glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); + glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); + + glNormal3f(1, 0, 0); + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); + glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); + glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); + glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); + + glNormal3f(-1, 0, 0); + glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); + glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); + glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); + + glEnd(); + + glPopMatrix(); +} + +void DrawGLScene() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); + + + glTranslatef(0.0f, 0.0f, -55.0f); + glRotatef(45, 1, 0, 0); + glTranslatef(0, 0, -30); + + glBindTexture(GL_TEXTURE_2D, texture[0]); + + int x, z; + for(z = -100; z < 100; z += 10) { + for(x = -100; x < 100; x += 10) { + DrawCube(x, z); + } + } + + glKosSwapBuffers(); +} + +int main(int argc, char **argv) +{ + glKosInit(); + + InitGL(640, 480); + ReSizeGLScene(640, 480); + + while(1) { + DrawGLScene(); + } + + return 0; +} diff --git a/samples/lights/romdisk/NeHe.bmp b/samples/lights/romdisk/NeHe.bmp new file mode 100644 index 0000000..6b3db10 Binary files /dev/null and b/samples/lights/romdisk/NeHe.bmp differ diff --git a/samples/lights/romdisk/PLACEHOLDER b/samples/lights/romdisk/PLACEHOLDER new file mode 100644 index 0000000..e69de29 diff --git a/samples/mipmap/main.c b/samples/mipmap/main.c index 388dc9a..d9ba908 100644 --- a/samples/mipmap/main.c +++ b/samples/mipmap/main.c @@ -13,8 +13,7 @@ KOS_INIT_ROMDISK(romdisk); int texture[1]; /* Image type - contains height, width, and data */ -struct Image -{ +struct Image { unsigned long sizeX; unsigned long sizeY; char *data; @@ -23,19 +22,18 @@ typedef struct Image Image; // quick and dirty bitmap loader...for 24 bit bitmaps with 1 plane only. // See http://www.dcs.ed.ac.uk/~mxr/gfx/2d/BMP.txt for more info. -int ImageLoad(char *filename, Image *image) -{ +int ImageLoad(char *filename, Image *image) { FILE *file; - unsigned long size; // size of the image in bytes. - unsigned long i; // standard counter. - unsigned short int planes; // number of planes in image (must be 1) - unsigned short int bpp; // number of bits per pixel (must be 24) - char temp; // temporary color storage for bgr-rgb conversion. + unsigned long size; // size of the image in bytes. + unsigned long i; // standard counter. + unsigned short int planes; // number of planes in image (must be 1) + unsigned short int bpp; // number of bits per pixel (must be 24) + char temp; // temporary color storage for bgr-rgb conversion. // make sure the file is there. - if ((file = fopen(filename, "rb")) == NULL) + if ((file = fopen(filename, "rb"))==NULL) { - printf("File Not Found : %s\n", filename); + printf("File Not Found : %s\n",filename); return 0; } @@ -43,16 +41,14 @@ int ImageLoad(char *filename, Image *image) fseek(file, 18, SEEK_CUR); // read the width - if ((i = fread(&image->sizeX, 4, 1, file)) != 1) - { + if ((i = fread(&image->sizeX, 4, 1, file)) != 1) { printf("Error reading width from %s.\n", filename); return 0; } printf("Width of %s: %lu\n", filename, image->sizeX); // read the height - if ((i = fread(&image->sizeY, 4, 1, file)) != 1) - { + if ((i = fread(&image->sizeY, 4, 1, file)) != 1) { printf("Error reading height from %s.\n", filename); return 0; } @@ -62,25 +58,21 @@ int ImageLoad(char *filename, Image *image) size = image->sizeX * image->sizeY * 3; // read the planes - if ((fread(&planes, 2, 1, file)) != 1) - { + if ((fread(&planes, 2, 1, file)) != 1) { printf("Error reading planes from %s.\n", filename); return 0; } - if (planes != 1) - { + if (planes != 1) { printf("Planes from %s is not 1: %u\n", filename, planes); return 0; } // read the bpp - if ((i = fread(&bpp, 2, 1, file)) != 1) - { + if ((i = fread(&bpp, 2, 1, file)) != 1) { printf("Error reading bpp from %s.\n", filename); return 0; } - if (bpp != 24) - { + if (bpp != 24) { printf("Bpp from %s is not 24: %u\n", filename, bpp); return 0; } @@ -89,24 +81,21 @@ int ImageLoad(char *filename, Image *image) fseek(file, 24, SEEK_CUR); // read the data. - image->data = (char *)malloc(size); - if (image->data == NULL) - { + image->data = (char *) malloc(size); + if (image->data == NULL) { printf("Error allocating memory for color-corrected image data"); return 0; } - if ((i = fread(image->data, size, 1, file)) != 1) - { + if ((i = fread(image->data, size, 1, file)) != 1) { printf(stderr, "Error reading image data from %s.\n", filename); return 0; } - for (i = 0; i < size; i += 3) - { // reverse all of the colors. (bgr -> rgb) + for (i=0;i rgb) temp = image->data[i]; - image->data[i] = image->data[i + 2]; - image->data[i + 2] = temp; + image->data[i] = image->data[i+2]; + image->data[i+2] = temp; } // we're done. @@ -149,15 +138,13 @@ void LoadGLTextures() Image *image1; // allocate space for texture - image1 = (Image *)malloc(sizeof(Image)); - if (image1 == NULL) - { + image1 = (Image *) malloc(sizeof(Image)); + if (image1 == NULL) { printf("Error allocating space for image"); exit(0); } - if (!ImageLoad("/rd/NeHe.bmp", image1)) - { + if (!ImageLoad("/rd/NeHe.bmp", image1)) { exit(1); } @@ -204,30 +191,25 @@ void InitGL(int Width, int Height) // We call this right after our OpenGL window /* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */ void ReSizeGLScene(int Width, int Height) { - if (Height == 0) // Prevent A Divide By Zero If The Window Is Too Small + if (Height == 0) // Prevent A Divide By Zero If The Window Is Too Small Height = 1; - glViewport(0, 0, Width, Height); // Reset The Current Viewport And Perspective Transformation + glViewport(0, 0, Width, Height); // Reset The Current Viewport And Perspective Transformation glMatrixMode(GL_PROJECTION); glLoadIdentity(); - gluPerspective(45.0f, (GLfloat)Width / (GLfloat)Height, 0.1f, 100.0f); + gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); glMatrixMode(GL_MODELVIEW); } -void DrawQuad() -{ +void DrawQuad() { glBegin(GL_QUADS); - glTexCoord2f(0.0f, 0.0f); - glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left Of The Texture and Quad - glTexCoord2f(1.0f, 0.0f); - glVertex3f(1.0f, -1.0f, 0.0f); // Bottom Right Of The Texture and Quad - glTexCoord2f(1.0f, 1.0f); - glVertex3f(1.0f, 1.0f, 0.0f); // Top Right Of The Texture and Quad - glTexCoord2f(0.0f, 1.0f); - glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left Of The Texture and Quad - glEnd(); // done with the polygon. + glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left Of The Texture and Quad + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 0.0f); // Bottom Right Of The Texture and Quad + glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right Of The Texture and Quad + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left Of The Texture and Quad + glEnd(); // done with the polygon. } static GLboolean mipmap_enabled = GL_FALSE; @@ -245,23 +227,18 @@ void movebias(void) { void DrawGLScene() { timer++; - if (timer > 60) - { + if(timer > 60) { timer = 0; mipmap_enabled = !mipmap_enabled; - if (mipmap_enabled) - { + if(mipmap_enabled) { printf("Enabling mipmaps!\n"); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - movebias(); - } - else - { + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); + } else { printf("Disabling mipmaps!\n"); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); } } @@ -297,8 +274,7 @@ int main(int argc, char **argv) InitGL(640, 480); ReSizeGLScene(640, 480); - while (1) - { + while(1) { DrawGLScene(); } diff --git a/samples/mipmap/romdisk/NeHe.bmp b/samples/mipmap/romdisk/NeHe.bmp new file mode 100644 index 0000000..6b3db10 Binary files /dev/null and b/samples/mipmap/romdisk/NeHe.bmp differ diff --git a/samples/mipmap/romdisk/PLACEHOLDER b/samples/mipmap/romdisk/PLACEHOLDER new file mode 100644 index 0000000..e69de29 diff --git a/samples/multitexture_arrays/main.c b/samples/multitexture_arrays/main.c index 27b57cf..58bf860 100644 --- a/samples/multitexture_arrays/main.c +++ b/samples/multitexture_arrays/main.c @@ -67,7 +67,7 @@ void RenderCallback(GLuint texID0, GLuint texID1) { glClientActiveTextureARB(GL_TEXTURE0_ARB); /* Bind the Color Array */ - glColorPointer(1, GL_UNSIGNED_INT, 0, ARGB_ARRAY); + glColorPointer(GL_BGRA, GL_UNSIGNED_BYTE, 0, ARGB_ARRAY); /* Bind the Vertex Array */ glVertexPointer(3, GL_FLOAT, 0, VERTEX_ARRAY); diff --git a/samples/paletted/main.c b/samples/paletted/main.c index 3cbce97..5def756 100644 --- a/samples/paletted/main.c +++ b/samples/paletted/main.c @@ -117,12 +117,13 @@ void LoadGLTextures() { glGenTextures(1, &texture[0]); glBindTexture(GL_TEXTURE_2D, texture[0]); // 2d texture (x and y size) - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); // scale linearly when image bigger than texture - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); // scale linearly when image smalled than texture + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); // 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image, // border 0 (normal), rgb color data, unsigned byte data, and finally the data itself. glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, image1->width, image1->height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE_TWID_KOS, image1->data); + glGenerateMipmapEXT(GL_TEXTURE_2D); } /* A general OpenGL initialization function. Sets all of the initial parameters. */ @@ -130,7 +131,7 @@ void InitGL(int Width, int Height) // We call this right after our OpenG { LoadGLTextures(); glEnable(GL_TEXTURE_2D); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black + glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClearDepth(1.0); // Enables Clearing Of The Depth Buffer glDepthFunc(GL_LESS); // The Type Of Depth Test To Do glEnable(GL_DEPTH_TEST); // Enables Depth Testing diff --git a/samples/polygon_offset/Makefile b/samples/polygon_offset/Makefile index 3c50b0e..572bd91 100644 --- a/samples/polygon_offset/Makefile +++ b/samples/polygon_offset/Makefile @@ -11,7 +11,7 @@ clean: rm-elf: -rm -f $(TARGET) -$(TARGET): $(OBJS) +$(TARGET): $(OBJS) $(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \ $(OBJS) $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS) diff --git a/samples/polygon_offset/main.c b/samples/polygon_offset/main.c index 3d39237..101f4d6 100644 --- a/samples/polygon_offset/main.c +++ b/samples/polygon_offset/main.c @@ -182,14 +182,14 @@ void DrawGLScene() } - glColor3f(0.0f, 0.0f, 0.0f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - drawBox(); + glColor3f(0.0f, 0.0f, 0.0f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + drawBox(); - if (offset) - glDisable(GL_POLYGON_OFFSET_LINE); + if (offset) + glDisable(GL_POLYGON_OFFSET_LINE); - glFlush(); + glFlush(); #endif // swap buffers to display, since we're double buffered. glKosSwapBuffers();