diff --git a/CMakeLists.txt b/CMakeLists.txt index 97e9515..dd69e25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -198,6 +198,7 @@ gen_sample(nehe06_vq samples/nehe06_vq/main.c) gen_sample(nehe06_4444twid samples/nehe06_4444twid/main.c) gen_sample(nehe08 samples/nehe08/main.c samples/nehe08/pvr-texture.c) gen_sample(nehe10 samples/nehe10/main.c samples/loadbmp.c) +gen_sample(nehe16 samples/nehe16/main.c samples/nehe16/pvr-texture.c) gen_sample(nehe20 samples/nehe20/main.c samples/loadbmp.c) gen_sample(ortho2d samples/ortho2d/main.c) gen_sample(paletted samples/paletted/main.c) diff --git a/GL/attributes.c b/GL/attributes.c index f12f1ed..8222d2e 100644 --- a/GL/attributes.c +++ b/GL/attributes.c @@ -31,11 +31,10 @@ GL_FORCE_INLINE GLboolean _glStateUnchanged(AttribPointer* p, GLint size, GLenum return (p->size == size && p->type == type && p->stride == stride); } -GLuint* _glGetEnabledAttributes() { +GLuint* _glGetEnabledAttributes(void) { return &ATTRIB_LIST.enabled; } - static void _readPosition3f3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { const float* input = (const float*) in; Vertex* it = (Vertex*) out; @@ -47,6 +46,17 @@ static void _readPosition3f3f(const GLubyte* __restrict__ in, GLubyte* __restric TransformVertex(x, y, z, w, it->xyz, &it->w); } +static void _readPosition3d3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { + const double* input = (const double*) in; + Vertex* it = (Vertex*) out; + + float x = input[0]; + float y = input[1]; + float z = input[2]; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); +} + static void _readPosition3ub3f(const GLubyte* input, GLubyte* out) { Vertex* it = (Vertex*)out; @@ -90,6 +100,17 @@ static void _readPosition2f3f(const GLubyte* in, GLubyte* out) { TransformVertex(x, y, z, w, it->xyz, &it->w); } +static void _readPosition2d3f(const GLubyte* in, GLubyte* out) { + const double* input = (const double*) in; + Vertex* it = (Vertex*) out; + + float x = input[0]; + float y = input[1]; + float z = 0.0f; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); +} + static void _readPosition2ub3f(const GLubyte* input, GLubyte* out) { Vertex* it = (Vertex*) out; @@ -122,10 +143,12 @@ static void _readPosition2ui3f(const GLubyte* in, GLubyte* out) { TransformVertex(x, y, z, w, it->xyz, &it->w); } -static ReadAttributeFunc calcReadPositionFunc() { +static ReadAttributeFunc calcReadPositionFunc(void) { switch(ATTRIB_LIST.vertex.type) { - default: case GL_DOUBLE: + return (ATTRIB_LIST.vertex.size == 3) ? _readPosition3d3f: + _readPosition2d3f; + default: case GL_FLOAT: return (ATTRIB_LIST.vertex.size == 3) ? _readPosition3f3f: _readPosition2f3f; @@ -144,7 +167,6 @@ static ReadAttributeFunc calcReadPositionFunc() { } } - static void _fillWhiteARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { _GL_UNUSED(input); *((uint32_t*) output) = ~0; @@ -157,24 +179,6 @@ static void _readColour4ubARGB(const GLubyte* input, GLubyte* output) { output[A8IDX] = input[3]; } -static void _readColour4fARGB(const GLubyte* in, GLubyte* output) { - const float* input = (const float*) in; - - 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); -} - -static void _readColour3fARGB(const GLubyte* in, GLubyte* output) { - const float* input = (const float*) in; - - 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] = 255; -} - static void _readColour3ubARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { output[R8IDX] = input[0]; output[G8IDX] = input[1]; @@ -182,6 +186,30 @@ static void _readColour3ubARGB(const GLubyte* __restrict__ input, GLubyte* __res output[A8IDX] = 255; } +#define DEF_READ_COLOUR_4_ARGB_FP(prefix, intype) \ + static void _readColour##prefix##ARGB(const GLubyte* __restrict in, GLubyte* __restrict out) { \ + const intype* input = (const intype*) in; \ + out[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); \ + out[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); \ + out[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); \ + out[A8IDX] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); \ + } + +#define DEF_READ_COLOUR_3_ARGB_FP(prefix, intype) \ + static void _readColour##prefix##ARGB(const GLubyte* __restrict in, GLubyte* __restrict out) { \ + const intype* input = (const intype*) in; \ + out[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); \ + out[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); \ + out[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); \ + out[A8IDX] = 255; \ + } + +DEF_READ_COLOUR_4_ARGB_FP(4f, float) +DEF_READ_COLOUR_4_ARGB_FP(4d, double) + +DEF_READ_COLOUR_3_ARGB_FP(3f, float) +DEF_READ_COLOUR_3_ARGB_FP(3d, double) + static void _readColour4ubRevARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { argbcpy(output, input); } @@ -195,51 +223,58 @@ static void _readColour4fRevARGB(const GLubyte* __restrict__ in, GLubyte* __rest output[3] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); } -static void _readColour3usARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); +static void _readColour4dRevARGB(const GLubyte* __restrict__ in, GLubyte* __restrict__ output) { + const double* input = (const double*) in; + + 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); } -static void _readColour3uiARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} +#define DEF_READ_COLOUR_N_ARGB_INT(prefix, intype, max, alpha, i0, i1, i2, i3) \ + static void _readColour##prefix##ARGB(const GLubyte* __restrict in, GLubyte* __restrict out) { \ + const intype* input = (const intype*) in; \ + out[i0] = (GLubyte) clamp((float)input[0] / (float)max * 255.0f, 0, 255); \ + out[i1] = (GLubyte) clamp((float)input[1] / (float)max * 255.0f, 0, 255); \ + out[i2] = (GLubyte) clamp((float)input[2] / (float)max * 255.0f, 0, 255); \ + out[i3] = alpha; \ + } -static void _readColour4usARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} +#define DEF_READ_COLOUR_3_ARGB_INT(prefix, intype, max) \ + DEF_READ_COLOUR_N_ARGB_INT(prefix, intype, max, 255, R8IDX, G8IDX, B8IDX, A8IDX) -static void _readColour4uiARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} +#define DEF_READ_COLOUR_4_ARGB_INT(prefix, intype, max) \ + DEF_READ_COLOUR_N_ARGB_INT(prefix, intype, max, \ + ((GLubyte)clamp((float)input[3] / (float)max * 255.0f, 0, 255)), \ + R8IDX, G8IDX, B8IDX, A8IDX) -static void _readColour4usRevARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} +#define DEF_READ_COLOUR_4_REV_ARGB_INT(prefix, intype, max) \ + DEF_READ_COLOUR_N_ARGB_INT(prefix##Rev, intype, max, \ + ((GLubyte)clamp((float)input[3] / (float)max * 255.0f, 0, 255)), \ + 0, 1, 2, 3) -static void _readColour4uiRevARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} +DEF_READ_COLOUR_3_ARGB_INT(3us, GLushort, UINT16_MAX) +DEF_READ_COLOUR_3_ARGB_INT(3ui, GLuint, UINT32_MAX) -static ReadAttributeFunc calcReadDiffuseFunc() { +DEF_READ_COLOUR_4_ARGB_INT(4us, GLushort, UINT16_MAX) +DEF_READ_COLOUR_4_ARGB_INT(4ui, GLuint, UINT32_MAX) + +DEF_READ_COLOUR_4_REV_ARGB_INT(4us, GLushort, UINT16_MAX) +DEF_READ_COLOUR_4_REV_ARGB_INT(4ui, GLuint, UINT32_MAX) + +static ReadAttributeFunc calcReadDiffuseFunc(void) { if((ATTRIB_LIST.enabled & DIFFUSE_ENABLED_FLAG) != DIFFUSE_ENABLED_FLAG) { /* Just fill the whole thing white if the attribute is disabled */ return _fillWhiteARGB; } switch(ATTRIB_LIST.colour.type) { - default: case GL_DOUBLE: + return (ATTRIB_LIST.colour.size == 3) ? _readColour3dARGB: + (ATTRIB_LIST.colour.size == 4) ? _readColour4dARGB: + _readColour4dRevARGB; + default: case GL_FLOAT: return (ATTRIB_LIST.colour.size == 3) ? _readColour3fARGB: (ATTRIB_LIST.colour.size == 4) ? _readColour4fARGB: @@ -276,6 +311,11 @@ static void _readTexcoord2f2f(const GLubyte* in, GLubyte* out) { vec2cpy(out, in); } +static void _readTexcoord2d2f(const GLubyte* in, GLubyte* out) { + ((float*)out)[0] = ((const double*)in)[0]; + ((float*)out)[1] = ((const double*)in)[1]; +} + static void _readTexcoord2ub2f(const GLubyte* input, GLubyte* out) { float* output = (float*) out; @@ -299,14 +339,15 @@ static void _readTexcoord2ui2f(const GLubyte* in, GLubyte* out) { output[1] = input[1]; } -static ReadAttributeFunc calcReadUVFunc() { +static ReadAttributeFunc calcReadUVFunc(void) { if((ATTRIB_LIST.enabled & UV_ENABLED_FLAG) != UV_ENABLED_FLAG) { return _fillZero2f; } switch(ATTRIB_LIST.uv.type) { - default: case GL_DOUBLE: + return _readTexcoord2d2f; + default: case GL_FLOAT: return _readTexcoord2f2f; case GL_BYTE: @@ -321,14 +362,15 @@ static ReadAttributeFunc calcReadUVFunc() { } } -static ReadAttributeFunc calcReadSTFunc() { +static ReadAttributeFunc calcReadSTFunc(void) { if((ATTRIB_LIST.enabled & ST_ENABLED_FLAG) != ST_ENABLED_FLAG) { return _fillZero2f; } switch(ATTRIB_LIST.st.type) { - default: case GL_DOUBLE: + return _readTexcoord2d2f; + default: case GL_FLOAT: return _readTexcoord2f2f; case GL_BYTE: @@ -357,6 +399,12 @@ static void _readNormal3f3f(const GLubyte* __restrict__ in, GLubyte* __restrict_ vec3cpy(out, in); } +static void _readNormal3d3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { + ((float*)out)[0] = ((const double*)in)[0]; + ((float*)out)[1] = ((const double*)in)[1]; + ((float*)out)[2] = ((const double*)in)[2]; +} + static void _readNormal3ub3f(const GLubyte* input, GLubyte* out) { float* output = (float*) out; @@ -406,15 +454,16 @@ static void _readNormal1i3f(const GLubyte* in, GLubyte* out) { output[2] = (2.0f * (float) input.bits.z + 1.0f) * MULTIPLIER; } -static ReadAttributeFunc calcReadNormalFunc() { +static ReadAttributeFunc calcReadNormalFunc(void) { if((ATTRIB_LIST.enabled & NORMAL_ENABLED_FLAG) != NORMAL_ENABLED_FLAG) { return _fillWithNegZVE; } switch(ATTRIB_LIST.normal.type) { - default: case GL_DOUBLE: + return _readNormal3d3f; case GL_FLOAT: + default: return _readNormal3f3f; break; case GL_BYTE: @@ -497,7 +546,7 @@ void APIENTRY glDisableClientState(GLenum cap) { } -void APIENTRY glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { +void APIENTRY glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { TRACE(); stride = (stride) ? stride : size * byte_size(type); @@ -591,7 +640,7 @@ void APIENTRY glNormalPointer(GLenum type, GLsizei stride, const GLvoid * poin } -void _glInitAttributePointers() { +void _glInitAttributePointers(void) { TRACE(); ATTRIB_LIST.dirty = ~0; // all attributes dirty @@ -601,7 +650,7 @@ void _glInitAttributePointers() { glNormalPointer(GL_FLOAT, 0, NULL); } -GL_FORCE_INLINE GLuint _glIsVertexDataFastPathCompatible() { +GL_FORCE_INLINE GLuint _glIsVertexDataFastPathCompatible(void) { /* The fast path is enabled when all enabled elements of the vertex * match the output format. This means: * @@ -649,7 +698,7 @@ GL_FORCE_INLINE GLuint _glIsVertexDataFastPathCompatible() { return GL_TRUE; } -void _glUpdateAttributes() { +void _glUpdateAttributes(void) { if(ATTRIB_LIST.dirty & VERTEX_ENABLED_FLAG) { ATTRIB_LIST.vertex_func = calcReadPositionFunc(); } diff --git a/GL/fog.c b/GL/fog.c index e83d624..17f2ad3 100644 --- a/GL/fog.c +++ b/GL/fog.c @@ -1,73 +1,138 @@ +/* + TODO: glGetX() fog values +*/ + #include #include "private.h" -static GLfloat FOG_START = 0.0f; -static GLfloat FOG_END = 1.0f; -static GLfloat FOG_DENSITY = 1.0f; -static GLenum FOG_MODE = GL_EXP; -static GLfloat FOG_COLOR [] = {0.0f, 0.0f, 0.0f, 0.0f}; +static struct { + GLfloat START; + GLfloat END; + GLfloat DENSITY; + GLenum MODE; + GLfloat COLOR[4]; +} FOG = { + 0.0f, 1.0f, 1.0f, GL_EXP, { 0.0f, 0.0f, 0.0f, 0.0f } +}; -static void updatePVRFog() { - if(FOG_MODE == GL_LINEAR) { - GPUSetFogLinear(FOG_START, FOG_END); - } else if(FOG_MODE == GL_EXP) { - GPUSetFogExp(FOG_DENSITY); - } else if(FOG_MODE == GL_EXP2) { - GPUSetFogExp2(FOG_DENSITY); +static void updatePVRFog(void) { + switch(FOG.MODE) { + case GL_LINEAR: + GPUSetFogLinear(FOG.START, FOG.END); + break; + + case GL_EXP: + GPUSetFogExp(FOG.DENSITY); + break; + + case GL_EXP2: + GPUSetFogExp2(FOG.DENSITY); + break; } - GPUSetFogColor(FOG_COLOR[3], FOG_COLOR[0], FOG_COLOR[1], FOG_COLOR[2]); + + GPUSetFogColor(FOG.COLOR[3], FOG.COLOR[0], FOG.COLOR[1], FOG.COLOR[2]); } -void APIENTRY glFogf(GLenum pname, GLfloat param) { +void APIENTRY glFogf(GLenum pname, GLfloat param) { switch(pname) { - case GL_FOG_MODE: { - FOG_MODE = (GLenum) param; - updatePVRFog(); - } break; - case GL_FOG_DENSITY: { - FOG_DENSITY = param; - updatePVRFog(); - } break; - case GL_FOG_START: { - FOG_START = param; - updatePVRFog(); - } break; - case GL_FOG_END: { - FOG_END = param; - updatePVRFog(); - } break; - case GL_FOG_INDEX: - default: { - _glKosThrowError(GL_INVALID_ENUM, __func__); - } + case GL_FOG_DENSITY: + if(FOG.DENSITY != param) { + if(param < 0.0f) + _glKosThrowError(GL_INVALID_VALUE, __func__); + else { + FOG.DENSITY = param; + updatePVRFog(); + } + } + break; + + case GL_FOG_START: + if(FOG.START != param) { + FOG.START = param; + updatePVRFog(); + } + break; + + case GL_FOG_END: + if(FOG.END != param) { + FOG.END = param; + updatePVRFog(); + } + break; + + default: + _glKosThrowError(GL_INVALID_ENUM, __func__); } } -void APIENTRY glFogi(GLenum pname, GLint param) { - glFogf(pname, (GLfloat) param); -} +void APIENTRY glFogi(GLenum pname, GLint param) { + switch(pname) { + case GL_FOG_DENSITY: + case GL_FOG_START: + case GL_FOG_END: + glFogf(pname, (GLfloat)param); + break; -void APIENTRY glFogfv(GLenum pname, const GLfloat* params) { - if(pname == GL_FOG_COLOR) { - FOG_COLOR[0] = params[0]; - FOG_COLOR[1] = params[1]; - FOG_COLOR[2] = params[2]; - FOG_COLOR[3] = params[3]; - updatePVRFog(); - } else { - glFogf(pname, *params); + case GL_FOG_MODE: + if(FOG.MODE != param) { + switch(param) { + case GL_LINEAR: + case GL_EXP: + case GL_EXP2: + FOG.MODE = param; + updatePVRFog(); + break; + + default: + _glKosThrowError(GL_INVALID_ENUM, __func__); + } + } + break; + + case GL_FOG_INDEX: + default: + _glKosThrowError(GL_INVALID_ENUM, __func__); } } -void APIENTRY glFogiv(GLenum pname, const GLint* params) { - if(pname == GL_FOG_COLOR) { - FOG_COLOR[0] = ((GLfloat) params[0]) / (GLfloat) INT_MAX; - FOG_COLOR[1] = ((GLfloat) params[1]) / (GLfloat) INT_MAX; - FOG_COLOR[2] = ((GLfloat) params[2]) / (GLfloat) INT_MAX; - FOG_COLOR[3] = ((GLfloat) params[3]) / (GLfloat) INT_MAX; - updatePVRFog(); - } else { - glFogi(pname, *params); +void APIENTRY glFogfv(GLenum pname, const GLfloat* params) { + switch(pname) { + case GL_FOG_COLOR: { + GLfloat color[] = { + CLAMP(params[0], 0.0f, 1.0f), + CLAMP(params[1], 0.0f, 1.0f), + CLAMP(params[2], 0.0f, 1.0f), + CLAMP(params[3], 0.0f, 1.0f) + }; + + if(memcmp(color, FOG.COLOR, sizeof(float) * 4)) { + memcpy(FOG.COLOR, color, sizeof(float) * 4); + updatePVRFog(); + } + break; + } + + default: + glFogf(pname, *params); + } +} + +void APIENTRY glFogiv(GLenum pname, const GLint* params) { + switch(pname) { + case GL_FOG_COLOR: { + GLfloat color[] = { + (GLfloat)params[0] / (GLfloat)INT_MAX, + (GLfloat)params[1] / (GLfloat)INT_MAX, + (GLfloat)params[2] / (GLfloat)INT_MAX, + (GLfloat)params[3] / (GLfloat)INT_MAX, + }; + + glFogfv(pname, color); + break; + } + + default: + glFogi(pname, *params); } } diff --git a/GL/matrix.c b/GL/matrix.c index 75d4526..0728395 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -209,11 +209,11 @@ void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { 0.0f, 0.0f, 0.0f, 1.0f }; - float r = DEG2RAD * angle; #ifdef __DREAMCAST__ float s, c; - fsincos(r, &s, &c); + fsincos(angle, &s, &c); #else + float r = DEG2RAD * angle; float c = cosf(r); float s = sinf(r); #endif diff --git a/GL/platforms/software.h b/GL/platforms/software.h index d797ce3..08cf4ed 100644 --- a/GL/platforms/software.h +++ b/GL/platforms/software.h @@ -5,6 +5,8 @@ #include "../types.h" +#define __restrict + #define PREFETCH(addr) do {} while(0) #define MATH_fsrra(x) (1.0f / sqrtf((x))) diff --git a/GL/texture.c b/GL/texture.c index 30c7976..99d1e06 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -906,6 +906,55 @@ void APIENTRY glCompressedTexImage2DARB(GLenum target, _glGPUStateMarkDirty(); } +void APIENTRY glCompressedTexSubImage2DARB(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const GLvoid *data) { + TRACE(); + + if (target != GL_TEXTURE_2D) { + _glKosThrowError(GL_INVALID_ENUM, __func__); + return; + } + + if (xoffset < 0 || yoffset < 0 || width <= 0 || height <= 0) { + _glKosThrowError(GL_INVALID_VALUE, __func__); + return; + } + + gl_assert(ACTIVE_TEXTURE < MAX_GLDC_TEXTURE_UNITS); + TextureObject* active = TEXTURE_UNITS[ACTIVE_TEXTURE]; + + if (!active) { + _glKosThrowError(GL_INVALID_OPERATION, __func__); + return; + } + + GLuint original_id = active->index; + + // Ensure that we're modifying the correct texture + if (active->index != original_id) { + _glKosThrowError(GL_INVALID_OPERATION, __func__); + return; + } + + // Copy raw compressed texture data into the texture buffer. + GLubyte* targetData = active->data; + GLubyte* src = (GLubyte*)data; + + // Copy the compressed data directly to the texture + if (data) { + FASTCPY(targetData + (yoffset * active->width + xoffset), src, imageSize); + } + + _glGPUStateMarkDirty(); +} + /** * Takes an internal format, and returns a GL format matching how we'd store * it internally, so it'll return one of the following: diff --git a/include/GL/glext.h b/include/GL/glext.h index 565ed40..ca0ad10 100644 --- a/include/GL/glext.h +++ b/include/GL/glext.h @@ -185,6 +185,15 @@ GLAPI void APIENTRY glCompressedTexImage2DARB(GLenum target, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexSubImage2DARB(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLsizei imageSize, + const GLvoid *data); /* Core aliases */ #define GL_INVALID_FRAMEBUFFER_OPERATION GL_INVALID_FRAMEBUFFER_OPERATION_EXT @@ -195,6 +204,7 @@ GLAPI void APIENTRY glCompressedTexImage2DARB(GLenum target, #define glGenerateMipmapEXT glGenerateMipmap #define glCompressedTexImage2D glCompressedTexImage2DARB +#define glCompressedTexSubImage2D glCompressedTexSubImage2DARB #ifndef GL_VERSION_1_4 #define GL_VERSION_1_4 1 diff --git a/samples/nehe06_vq/main.c b/samples/nehe06_vq/main.c index 754f458..bd0df56 100644 --- a/samples/nehe06_vq/main.c +++ b/samples/nehe06_vq/main.c @@ -165,9 +165,16 @@ void LoadGLTextures() { // 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. + // Allocate texture memory (but don't upload compressed data yet) glCompressedTexImage2DARB( GL_TEXTURE_2D, 0, image1->internalFormat, image1->sizeX, image1->sizeY, 0, - image1->dataSize, image1->data + image1->dataSize, NULL // NULL here means we are not uploading data yet + ); + + // Now use glCompressedTexSubImage2DARB to upload the compressed data to the texture + glCompressedTexSubImage2DARB( + GL_TEXTURE_2D, 0, 0, 0, image1->sizeX, image1->sizeY, + image1->internalFormat, image1->dataSize, image1->data ); free(image1); diff --git a/samples/nehe16/main.c b/samples/nehe16/main.c new file mode 100644 index 0000000..c080a1a --- /dev/null +++ b/samples/nehe16/main.c @@ -0,0 +1,247 @@ +/* + KallistiOS 2.0.0 + + nehe16.c + (c)2025 Falco Girgis + (c)2014 Josh Pearson + (c)2001 Benoit Miller + (c)2000 Jeff Molofee +*/ + +#include +#include +#include +#include + +#ifdef __DREAMCAST__ +#include +extern uint8 romdisk[]; +KOS_INIT_ROMDISK(romdisk); +#define IMG_PATH "/rd/glass.pvr" +#else +#define IMG_PATH "../samples/nehe08/romdisk/glass.pvr" +#endif + +/* Simple GL example to demonstrate fog (PVR table fog). + + Essentially the same thing as NeHe's lesson16 code. + To learn more, go to http://nehe.gamedev.net/. + + DPAD controls the cube rotation, button A & B control the depth + of the cube, button X toggles fog on/off, and button Y toggles fog type. +*/ + +static GLfloat xrot; /* X Rotation */ +static GLfloat yrot; /* Y Rotation */ +static GLfloat xspeed; /* X Rotation Speed */ +static GLfloat yspeed; /* Y Rotation Speed */ +static GLfloat z = -5.0f; /* Depth Into The Screen */ + +static GLuint texture; /* Storage For Texture */ + +/* Storage For Three Types Of Fog */ +GLuint fogType = 0; /* use GL_EXP initially */ +GLuint fogMode[] = { GL_EXP, GL_EXP2, GL_LINEAR }; +char cfogMode[3][10] = {"GL_EXP ", "GL_EXP2 ", "GL_LINEAR" }; +GLfloat fogColor[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; /* Fog Color */ +int fog = GL_TRUE; + +/* Load a PVR texture - located in pvr-texture.c */ +extern GLuint glTextureLoadPVR(char *fname, unsigned char isMipMapped, unsigned char glMipMap); + +void draw_gl(void) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); + glTranslatef(0.0f, 0.0f, z); + + glRotatef(xrot, 1.0f, 0.0f, 0.0f); + glRotatef(yrot, 0.0f, 1.0f, 0.0f); + + glBindTexture(GL_TEXTURE_2D, texture); + + glBegin(GL_QUADS); + /* Front Face */ + glNormal3f(0.0f, 0.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); + glTexCoord2f(0.0f, 1.0f); + glVertex3f(-1.0f, 1.0f, 1.0f); + /* Back Face */ + glNormal3f(0.0f, 0.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); + glTexCoord2f(0.0f, 0.0f); + glVertex3f(1.0f, -1.0f, -1.0f); + /* Top Face */ + glNormal3f(0.0f, 1.0f, 0.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); + glTexCoord2f(1.0f, 1.0f); + glVertex3f(1.0f, 1.0f, -1.0f); + /* Bottom Face */ + glNormal3f(0.0f, -1.0f, 0.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); + glTexCoord2f(1.0f, 0.0f); + glVertex3f(-1.0f, -1.0f, 1.0f); + /* Right face */ + glNormal3f(1.0f, 0.0f, 0.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); + glTexCoord2f(0.0f, 0.0f); + glVertex3f(1.0f, -1.0f, 1.0f); + /* Left Face */ + glNormal3f(-1.0f, 0.0f, 0.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); + glTexCoord2f(0.0f, 1.0f); + glVertex3f(-1.0f, 1.0f, -1.0f); + glEnd(); + + xrot += xspeed; + yrot += yspeed; +} + +int main(int argc, char **argv) { + GLboolean xp = GL_FALSE; + GLboolean yp = GL_FALSE; + + printf("nehe16 beginning\n"); + + /* Get basic stuff initialized */ + glKosInit(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45.0f, 640.0f / 480.0f, 0.1f, 100.0f); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glEnable(GL_TEXTURE_2D); + glShadeModel(GL_SMOOTH); + glClearColor(0.5f, 0.5f, 0.5f, 1.0f); + glClearDepth(1.0f); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + + glColor4f(1.0f, 1.0f, 1.0f, 0.5); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + + /* Enable Lighting and GL_LIGHT0 */ + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + + /* Set up the fog */ + glFogi(GL_FOG_MODE, fogMode[fogType]); /* Fog Mode */ + glFogfv(GL_FOG_COLOR, fogColor); /* Set Fog Color */ + glFogf(GL_FOG_DENSITY, 0.35f); /* How Dense The Fog is */ + glHint(GL_FOG_HINT, GL_DONT_CARE); /* Fog Hint Value */ + glFogf(GL_FOG_START, 0.0f); /* Fog Start Depth */ + glFogf(GL_FOG_END, 5.0f); /* Fog End Depth */ + glEnable(GL_FOG); /* Enables GL_FOG */ + + /* Set up the textures */ + texture = glTextureLoadPVR(IMG_PATH, 0, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + while(1) { +#ifdef __DREAMCAST__ + maple_device_t *cont; + cont_state_t *state; + + cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); + + /* Check key status */ + state = (cont_state_t *)maple_dev_status(cont); + + if(!state) { + printf("Error reading controller\n"); + break; + } + + if(state->start) + break; + + if(state->a) { + if(z >= -15.0f) z -= 0.02f; + } + + if(state->b) { + if(z <= 0.0f) z += 0.02f; + } + + if(state->x && !xp) { + xp = GL_TRUE; + fogType = (fogType + 1) % 3; + glFogi(GL_FOG_MODE, fogMode[fogType]); + printf("%s\n", cfogMode[fogType]); + } + + if(!state->x) + xp = GL_FALSE; + + if(state->y && !yp) { + yp = GL_TRUE; + fog = !fog; + } + + if(!state->y) + yp = GL_FALSE; + + if(state->dpad_up) + xspeed -= 0.1f; + + if(state->dpad_down) + xspeed += 0.1f; + + if(state->dpad_left) + yspeed -= 0.1f; + + if(state->dpad_right) + yspeed += 0.1f; +#endif + + /* Switch fog off/on */ + if(fog) { + glEnable(GL_FOG); + } + else { + glDisable(GL_FOG); + } + + /* Draw the GL "scene" */ + draw_gl(); + + /* Finish the frame */ + glKosSwapBuffers(); + } + + return 0; +} + + diff --git a/samples/nehe16/pvr-texture.c b/samples/nehe16/pvr-texture.c new file mode 100644 index 0000000..c9d5f92 --- /dev/null +++ b/samples/nehe16/pvr-texture.c @@ -0,0 +1,176 @@ +/* + KallistiOS 2.0.0 + + pvr-texture.c + (c)2014 Josh PH3NOM Pearson + + Load A PVR Texture to the PVR using Open GL +*/ +#include +#include +#include + +#include "GL/gl.h" +#include "GL/glu.h" +#include "GL/glkos.h" +#include "GL/glext.h" + +#define PVR_HDR_SIZE 0x20 +#define MAX(x, y) ((x > y) ? x : y) + +static GLuint PVR_TextureHeight(unsigned char *HDR); +static GLuint PVR_TextureWidth(unsigned char *HDR); +static GLuint PVR_TextureFormat(unsigned char *HDR); + +static GLuint _glGetMipmapLevelCount(GLuint width, GLuint height) { + return 1 + floor(log2(MAX(width, height))); +} + +static GLuint _glGetMipmapDataSize(GLuint width, GLuint height) { + GLuint size = 0; + + GLuint i = 0; + + for(; i < _glGetMipmapLevelCount(width, height); ++i) { + size += (width * height * 2); + + if(width > 1) { + width /= 2; + } + + if(height > 1) { + height /= 2; + } + } + + return size; +} + +/* Load a PVR texture file into memory, and then bind the texture to Open GL. + fname is the name of the PVR texture file to be opened and read. + isMipMapped should be passed as 1 if the texture contains MipMap levels, 0 otherwise. + glMipMap should be passed as 1 if Open GL should calculate the Mipmap levels, 0 otherwise */ +GLuint glTextureLoadPVR(char *fname, unsigned char isMipMapped, unsigned char glMipMap) { + FILE *tex = NULL; + uint16_t *TEX0 = NULL; + uint8_t HDR[PVR_HDR_SIZE]; + GLuint texID, texSize, texW, texH, texFormat; + + /* Open the PVR texture file, and get its file size */ + tex = fopen(fname, "rb"); + + if(tex == NULL) { + printf("FILE READ ERROR: %s\n", fname); + + while(1); + } + + fseek(tex, 0, SEEK_END); + texSize = ftell(tex) - PVR_HDR_SIZE; + fseek(tex, 0, SEEK_SET); + + /* Read in the PVR texture file header */ + fread(HDR, 1, PVR_HDR_SIZE, tex); + + /* Extract some information from the PVR texture file header */ + texW = PVR_TextureWidth(HDR); + texH = PVR_TextureHeight(HDR); + texFormat = PVR_TextureFormat(HDR); + + /* Allocate Some Memory for the texture. If we are using Open GL to build the MipMap, + we need to allocate enough space to hold the MipMap texture levels. */ + if(!isMipMapped && glMipMap) + TEX0 = malloc(_glGetMipmapDataSize(texW, texH)); + else + TEX0 = malloc(texSize); + + fread(TEX0, 1, texSize, tex); /* Read in the PVR texture data */ + + /* Generate and bind a texture as normal for Open GL */ + glGenTextures(1, &texID); + glBindTexture(GL_TEXTURE_2D, texID); + + if(texFormat != GL_UNSIGNED_SHORT_5_6_5) + glCompressedTexImage2DARB(GL_TEXTURE_2D, + 0, + texFormat, + texW, + texH, + 0, + texSize, + TEX0); + else { + fprintf(stderr, "%x\n", texFormat); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGB, + texW, texH, + 0, + GL_RGB, + texFormat, + TEX0); + if(!isMipMapped && glMipMap) + glGenerateMipmapEXT(GL_TEXTURE_2D); + } + + free(TEX0); + + return texID; +} + +static GLuint PVR_TextureFormat(unsigned char *HDR) { + GLuint color = (GLuint)HDR[PVR_HDR_SIZE - 8]; + GLuint format = (GLuint)HDR[PVR_HDR_SIZE - 7]; + + GLboolean twiddled = format == 0x01; + GLboolean compressed = (format == 0x10 || format == 0x03); + + if(compressed) { + if(twiddled) { + switch(color) { + case 0x0: { + return GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS; + } break; + case 0x01: { + return GL_COMPRESSED_RGB_565_VQ_TWID_KOS; + } break; + case 0x02: { + return GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS; + } + break; + default: + fprintf(stderr, "Invalid texture format"); + return 0; + } + } else { + switch(color) { + case 0: { + return GL_COMPRESSED_ARGB_1555_VQ_KOS; + } break; + case 1: { + return GL_COMPRESSED_RGB_565_VQ_KOS; + } break; + case 2: { + return GL_COMPRESSED_ARGB_4444_VQ_KOS; + } + break; + default: + fprintf(stderr, "Invalid texture format"); + return 0; + } + } + } else { + if(color == 1) { + return GL_UNSIGNED_SHORT_5_6_5; + } + return 0; + } +} + +static GLuint PVR_TextureWidth(unsigned char *HDR) { + return (GLuint)HDR[PVR_HDR_SIZE - 4] | HDR[PVR_HDR_SIZE - 3] << 8; +} + +static GLuint PVR_TextureHeight(unsigned char *HDR) { + return (GLuint)HDR[PVR_HDR_SIZE - 2] | HDR[PVR_HDR_SIZE - 1] << 8; +} diff --git a/samples/nehe16/romdisk/glass.pvr b/samples/nehe16/romdisk/glass.pvr new file mode 100644 index 0000000..3f81ec0 Binary files /dev/null and b/samples/nehe16/romdisk/glass.pvr differ