Merge branch '40-fix-mipmap-offsets' into 'master'
Resolve "Fix mipmap offsets" Closes #40 See merge request simulant/GLdc!48
This commit is contained in:
commit
7ac318e002
196
GL/framebuffer.c
196
GL/framebuffer.c
|
@ -1,4 +1,6 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "private.h"
|
||||
#include "../include/glkos.h"
|
||||
#include "../include/glext.h"
|
||||
|
@ -89,109 +91,164 @@ void APIENTRY glFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum
|
|||
ACTIVE_FRAMEBUFFER->texture_id = texture;
|
||||
}
|
||||
|
||||
static inline GLuint A1555(GLuint v) {
|
||||
static inline GLubyte A1555(GLushort v) {
|
||||
const GLuint MASK = (1 << 15);
|
||||
return (v & MASK) >> 15;
|
||||
return (v & MASK) >> 8;
|
||||
}
|
||||
|
||||
static inline GLuint R1555(GLuint v) {
|
||||
static inline GLubyte R1555(GLushort v) {
|
||||
const GLuint MASK = (31 << 10);
|
||||
return (v & MASK) >> 10;
|
||||
return (v & MASK) >> 7;
|
||||
}
|
||||
|
||||
static inline GLuint G1555(GLuint v) {
|
||||
static inline GLubyte G1555(GLushort v) {
|
||||
const GLuint MASK = (31 << 5);
|
||||
return (v & MASK) >> 5;
|
||||
return (v & MASK) >> 2;
|
||||
}
|
||||
|
||||
static inline GLuint B1555(GLuint v) {
|
||||
static inline GLubyte B1555(GLushort v) {
|
||||
const GLuint MASK = (31 << 0);
|
||||
return (v & MASK) >> 0;
|
||||
return (v & MASK) << 3;
|
||||
}
|
||||
|
||||
static inline GLuint A4444(GLuint v) {
|
||||
static inline GLubyte A4444(GLushort v) {
|
||||
const GLuint MASK = (0xF << 12);
|
||||
return (v & MASK) >> 12;
|
||||
}
|
||||
|
||||
static inline GLuint R4444(GLuint v) {
|
||||
static inline GLubyte R4444(GLushort v) {
|
||||
const GLuint MASK = (0xF << 8);
|
||||
return (v & MASK) >> 8;
|
||||
}
|
||||
|
||||
static inline GLuint G4444(GLuint v) {
|
||||
static inline GLubyte G4444(GLushort v) {
|
||||
const GLuint MASK = (0xF << 4);
|
||||
return (v & MASK) >> 4;
|
||||
}
|
||||
|
||||
static inline GLuint B4444(GLuint v) {
|
||||
static inline GLubyte B4444(GLushort v) {
|
||||
const GLuint MASK = (0xF << 0);
|
||||
return (v & MASK) >> 0;
|
||||
}
|
||||
|
||||
static inline GLuint R565(GLuint v) {
|
||||
static inline GLubyte R565(GLushort v) {
|
||||
const GLuint MASK = (31 << 11);
|
||||
return (v & MASK) >> 11;
|
||||
return (v & MASK) >> 8;
|
||||
}
|
||||
|
||||
static inline GLuint G565(GLuint v) {
|
||||
static inline GLubyte G565(GLushort v) {
|
||||
const GLuint MASK = (63 << 5);
|
||||
return (v & MASK) >> 5;
|
||||
return (v & MASK) >> 3;
|
||||
}
|
||||
|
||||
static inline GLuint B565(GLuint v) {
|
||||
static inline GLubyte B565(GLushort v) {
|
||||
const GLuint MASK = (31 << 0);
|
||||
return (v & MASK) >> 0;
|
||||
return (v & MASK) << 3;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
@ -219,53 +276,52 @@ void APIENTRY glGenerateMipmapEXT(GLenum target) {
|
|||
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;
|
||||
|
||||
/* Make sure there is room for the mipmap data on the texture object */
|
||||
_glAllocateSpaceForMipmaps(tex);
|
||||
|
||||
for(; i < _glGetMipmapLevelCount(tex); ++i) {
|
||||
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) {
|
||||
|
|
20
GL/private.h
20
GL/private.h
|
@ -12,6 +12,18 @@
|
|||
#include "../containers/aligned_vector.h"
|
||||
#include "../containers/named_array.h"
|
||||
|
||||
#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__);}
|
||||
|
||||
|
@ -105,6 +117,7 @@ typedef struct {
|
|||
GLuint index;
|
||||
GLvoid *data;
|
||||
GLuint dataStride;
|
||||
GLuint baseDataSize; /* The data size of mipmap level 0 */
|
||||
|
||||
GLenum minFilter;
|
||||
GLenum magFilter;
|
||||
|
@ -112,6 +125,13 @@ typedef struct {
|
|||
GLboolean isCompressed;
|
||||
GLboolean isPaletted;
|
||||
|
||||
/* 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;
|
||||
|
||||
TexturePalette* palette;
|
||||
|
||||
/* When using the shared palette, this is the bank (0-3) */
|
||||
|
|
14
GL/state.c
14
GL/state.c
|
@ -208,11 +208,19 @@ 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) ? PVR_MIPMAP_ENABLE : PVR_MIPMAP_DISABLE;
|
||||
context->txr.mipmap_bias = PVR_MIPBIAS_NORMAL;
|
||||
context->txr.width = tx1->width;
|
||||
context->txr.height = tx1->height;
|
||||
context->txr.base = tx1->data;
|
||||
|
||||
if(enableMipmaps) {
|
||||
context->txr.base = tx1->data;
|
||||
context->txr.mipmap = PVR_MIPMAP_ENABLE;
|
||||
context->txr.mipmap_bias = PVR_MIPBIAS_NORMAL;
|
||||
} else {
|
||||
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) {
|
||||
|
|
276
GL/texture.c
276
GL/texture.c
|
@ -23,12 +23,6 @@ static TexturePalette* SHARED_PALETTES[4] = {NULL, NULL, NULL, NULL};
|
|||
|
||||
static 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;
|
||||
|
@ -37,7 +31,7 @@ static TexturePalette* _initTexturePalette() {
|
|||
TexturePalette* palette = (TexturePalette*) malloc(sizeof(TexturePalette));
|
||||
assert(palette);
|
||||
|
||||
sq_clr(palette, (sizeof(TexturePalette) & 0xfffffffc) + 4);
|
||||
memset(palette, 0x0, sizeof(TexturePalette));
|
||||
palette->bank = -1;
|
||||
return palette;
|
||||
}
|
||||
|
@ -161,26 +155,94 @@ static GLint _determineStride(GLenum format, GLenum type) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
GLubyte* _glGetMipmapLocation(TextureObject* obj, GLuint level) {
|
||||
static GLuint _glGetMipmapDataOffset(TextureObject* obj, GLuint level) {
|
||||
GLuint offset = 0;
|
||||
GLuint size = obj->height;
|
||||
|
||||
GLuint i = 0;
|
||||
GLuint width = obj->width;
|
||||
GLuint height = obj->height;
|
||||
if(obj->width != obj->height) {
|
||||
fprintf(stderr, "ERROR: Accessing memory location of mipmaps on non-square texture\n");
|
||||
return obj->baseDataOffset;
|
||||
}
|
||||
|
||||
for(; i < level; ++i) {
|
||||
offset += (width * height * obj->dataStride);
|
||||
|
||||
if(width > 1) {
|
||||
width /= 2;
|
||||
if(obj->isPaletted){
|
||||
switch(size >> level){
|
||||
case 1024:
|
||||
offset = 0x55558;
|
||||
break;
|
||||
case 512:
|
||||
offset = 0x15558;
|
||||
break;
|
||||
case 256:
|
||||
offset = 0x05558;
|
||||
break;
|
||||
case 128:
|
||||
offset = 0x01558;
|
||||
break;
|
||||
case 64:
|
||||
offset = 0x00558;
|
||||
break;
|
||||
case 32:
|
||||
offset = 0x00158;
|
||||
break;
|
||||
case 16:
|
||||
offset = 0x00058;
|
||||
break;
|
||||
case 8:
|
||||
offset = 0x00018;
|
||||
break;
|
||||
case 4:
|
||||
offset = 0x00008;
|
||||
break;
|
||||
case 2:
|
||||
offset = 0x00004;
|
||||
break;
|
||||
case 1:
|
||||
offset = 0x00003;
|
||||
break;
|
||||
}
|
||||
|
||||
if(height > 1) {
|
||||
height /= 2;
|
||||
} else {
|
||||
switch(size >> level) {
|
||||
case 1024:
|
||||
offset = 0xAAAB0;
|
||||
break;
|
||||
case 512:
|
||||
offset = 0x2AAB0;
|
||||
break;
|
||||
case 256:
|
||||
offset = 0x0AAB0;
|
||||
break;
|
||||
case 128:
|
||||
offset = 0x02AB0;
|
||||
break;
|
||||
case 64:
|
||||
offset = 0x00AB0;
|
||||
break;
|
||||
case 32:
|
||||
offset = 0x002B0;
|
||||
break;
|
||||
case 16:
|
||||
offset = 0x000B0;
|
||||
break;
|
||||
case 8:
|
||||
offset = 0x00030;
|
||||
break;
|
||||
case 4:
|
||||
offset = 0x00010;
|
||||
break;
|
||||
case 2:
|
||||
offset = 0x00008;
|
||||
break;
|
||||
case 1:
|
||||
offset = 0x00006;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ((GLubyte*) obj->data) + offset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
GLubyte* _glGetMipmapLocation(TextureObject* obj, GLuint level) {
|
||||
return ((GLubyte*) obj->data) + _glGetMipmapDataOffset(obj, level);
|
||||
}
|
||||
|
||||
GLuint _glGetMipmapLevelCount(TextureObject* obj) {
|
||||
|
@ -188,25 +250,13 @@ GLuint _glGetMipmapLevelCount(TextureObject* obj) {
|
|||
}
|
||||
|
||||
static GLuint _glGetMipmapDataSize(TextureObject* obj) {
|
||||
GLuint size = 0;
|
||||
/* The mipmap data size is the offset + the size of the
|
||||
* image */
|
||||
|
||||
GLuint i = 0;
|
||||
GLuint width = obj->width;
|
||||
GLuint height = obj->height;
|
||||
GLuint imageSize = obj->baseDataSize;
|
||||
GLuint offset = _glGetMipmapDataOffset(obj, 0);
|
||||
|
||||
for(; i < _glGetMipmapLevelCount(obj); ++i) {
|
||||
size += (width * height * obj->dataStride);
|
||||
|
||||
if(width > 1) {
|
||||
width /= 2;
|
||||
}
|
||||
|
||||
if(height > 1) {
|
||||
height /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
return imageSize + offset;
|
||||
}
|
||||
|
||||
GLubyte _glInitTextures() {
|
||||
|
@ -269,6 +319,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;
|
||||
}
|
||||
|
@ -768,6 +821,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;
|
||||
}
|
||||
|
@ -782,16 +841,9 @@ 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) )
|
||||
#define MIN(a, b) ( (a)<(b)? (a):(b) )
|
||||
|
||||
|
||||
void _glAllocateSpaceForMipmaps(TextureObject* active) {
|
||||
if(active->data && active->mipmap > 1) {
|
||||
/* Already done */
|
||||
if(active->data && active->baseDataOffset > 0) {
|
||||
/* Already done - mipmaps have a dataOffset */
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -800,18 +852,27 @@ void _glAllocateSpaceForMipmaps(TextureObject* active) {
|
|||
* then free the original
|
||||
*/
|
||||
|
||||
GLubyte* src = active->data;
|
||||
GLubyte* dest = active->data = pvr_mem_malloc(_glGetMipmapDataSize(active));
|
||||
GLuint size = active->baseDataSize;
|
||||
|
||||
/* If there was existing data, then copy it across before freeing */
|
||||
if(src) {
|
||||
GLuint i = 0;
|
||||
for(; i < active->width * active->height * active->dataStride; ++i) {
|
||||
*dest++ = *src++;
|
||||
}
|
||||
/* Copy the data out of the pvr and back to ram */
|
||||
GLubyte* temp = (GLubyte*) malloc(size);
|
||||
memcpy(temp, active->data, size);
|
||||
|
||||
pvr_mem_free(src);
|
||||
}
|
||||
/* Free the PVR data */
|
||||
pvr_mem_free(active->data);
|
||||
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 */
|
||||
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,
|
||||
|
@ -892,7 +953,7 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
|
|||
|
||||
assert(active);
|
||||
|
||||
if(active->data) {
|
||||
if(active->data && level == 0) {
|
||||
/* pre-existing texture - check if changed */
|
||||
if(active->width != width ||
|
||||
active->height != height ||
|
||||
|
@ -903,6 +964,8 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
|
|||
active->mipmap = 0;
|
||||
active->mipmapCount = 0;
|
||||
active->dataStride = 0;
|
||||
active->baseDataOffset = 0;
|
||||
active->baseDataSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -925,25 +988,25 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
|
|||
/* Set the required mipmap count */
|
||||
active->mipmapCount = _glGetMipmapLevelCount(active);
|
||||
active->dataStride = destStride;
|
||||
active->baseDataSize = bytes;
|
||||
|
||||
GLuint size = bytes;
|
||||
assert(bytes);
|
||||
|
||||
/* If we're uploading a mipmap level, we need to allocate the full amount of space */
|
||||
if(level > 0) {
|
||||
size = _glGetMipmapDataSize(active);
|
||||
/* 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);
|
||||
}
|
||||
assert(size);
|
||||
|
||||
active->data = pvr_mem_malloc(size);
|
||||
assert(active->data);
|
||||
|
||||
active->isCompressed = GL_FALSE;
|
||||
active->isPaletted = isPaletted;
|
||||
}
|
||||
|
||||
/* We're supplying a mipmap level, but previously we only had
|
||||
* data for the first level (level 0, e.g. 1 << 0 == 1) */
|
||||
if(level > 0 && active->mipmap == 1) {
|
||||
* data for the first level (level 0) */
|
||||
if(level > 0 && active->baseDataOffset == 0) {
|
||||
_glAllocateSpaceForMipmaps(active);
|
||||
}
|
||||
|
||||
|
@ -952,7 +1015,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.
|
||||
|
@ -961,7 +1026,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) {
|
||||
|
@ -970,45 +1038,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 = _glGetMipmapLocation(active, level);
|
||||
GLubyte* targetData = (active->baseDataOffset == 0) ? active->data : _glGetMipmapLocation(active, level);
|
||||
assert(targetData);
|
||||
|
||||
GLubyte* conversionBuffer = NULL;
|
||||
|
||||
if(!data) {
|
||||
/* No data? Do nothing! */
|
||||
return;
|
||||
} else if(!needsConversion) {
|
||||
} 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;
|
||||
|
||||
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 */
|
||||
sq_cpy(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,
|
||||
|
@ -1020,12 +1075,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);
|
||||
|
||||
|
@ -1034,6 +1083,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) {
|
||||
|
@ -1043,6 +1100,33 @@ 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) {
|
||||
|
|
|
@ -28,3 +28,4 @@ all:
|
|||
$(KOS_MAKE) -C polymark all
|
||||
$(KOS_MAKE) -C polygon_offset all
|
||||
$(KOS_MAKE) -C blend_test all
|
||||
$(KOS_MAKE) -C mipmap all
|
||||
|
|
29
samples/mipmap/Makefile
Normal file
29
samples/mipmap/Makefile
Normal file
|
@ -0,0 +1,29 @@
|
|||
TARGET = mipmap.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)
|
235
samples/mipmap/main.c
Normal file
235
samples/mipmap/main.c
Normal file
|
@ -0,0 +1,235 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gl.h"
|
||||
#include "glu.h"
|
||||
#include "glkos.h"
|
||||
|
||||
extern uint8 romdisk[];
|
||||
KOS_INIT_ROMDISK(romdisk);
|
||||
|
||||
/* storage for one texture */
|
||||
int texture[1];
|
||||
|
||||
/* Image type - contains height, width, and data */
|
||||
struct Image {
|
||||
unsigned long sizeX;
|
||||
unsigned long sizeY;
|
||||
char *data;
|
||||
};
|
||||
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) {
|
||||
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.
|
||||
|
||||
// make sure the file is there.
|
||||
if ((file = fopen(filename, "rb"))==NULL)
|
||||
{
|
||||
printf("File Not Found : %s\n",filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// seek through the bmp header, up to the width/height:
|
||||
fseek(file, 18, SEEK_CUR);
|
||||
|
||||
// read the width
|
||||
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) {
|
||||
printf("Error reading height from %s.\n", filename);
|
||||
return 0;
|
||||
}
|
||||
printf("Height of %s: %lu\n", filename, image->sizeY);
|
||||
|
||||
// calculate the size (assuming 24 bits or 3 bytes per pixel).
|
||||
size = image->sizeX * image->sizeY * 3;
|
||||
|
||||
// read the planes
|
||||
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;
|
||||
}
|
||||
|
||||
// read the bpp
|
||||
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;
|
||||
}
|
||||
|
||||
// seek past the rest of the bitmap header.
|
||||
fseek(file, 24, SEEK_CUR);
|
||||
|
||||
// read the data.
|
||||
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;i<size;i+=3) { // reverse all of the colors. (bgr -> rgb)
|
||||
temp = image->data[i];
|
||||
image->data[i] = image->data[i+2];
|
||||
image->data[i+2] = temp;
|
||||
}
|
||||
|
||||
// we're done.
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Load Bitmaps And Convert To Textures
|
||||
void LoadGLTextures() {
|
||||
// Load Texture
|
||||
Image *image1;
|
||||
|
||||
// allocate space for texture
|
||||
image1 = (Image *) malloc(sizeof(Image));
|
||||
if (image1 == NULL) {
|
||||
printf("Error allocating space for image");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!ImageLoad("/rd/NeHe.bmp", image1)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Create Texture
|
||||
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_MIPMAP_LINEAR); // scale linearly when image smalled than texture
|
||||
|
||||
// 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, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);
|
||||
|
||||
glGenerateMipmapEXT(GL_TEXTURE_2D);
|
||||
};
|
||||
|
||||
/* 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.
|
||||
{
|
||||
LoadGLTextures();
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black
|
||||
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
|
||||
glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading
|
||||
|
||||
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() {
|
||||
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.
|
||||
}
|
||||
|
||||
static GLboolean mipmap_enabled = GL_FALSE;
|
||||
static GLuint timer = 0;
|
||||
|
||||
/* The main drawing function. */
|
||||
void DrawGLScene()
|
||||
{
|
||||
timer++;
|
||||
if(timer > 60) {
|
||||
timer = 0;
|
||||
mipmap_enabled = !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);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glLoadIdentity();
|
||||
glClearColor(0.5, 0.5, 0.5, 1.0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture[0]);
|
||||
|
||||
glTranslatef(-1.5f, 0.0f, -4.5f);
|
||||
DrawQuad();
|
||||
|
||||
glTranslatef(1.0f, 0.0f, -5.0f);
|
||||
DrawQuad();
|
||||
|
||||
glTranslatef(1.5f, 0.0f, -5.0f);
|
||||
DrawQuad();
|
||||
|
||||
glTranslatef(2.0f, 0.0f, -5.0f);
|
||||
DrawQuad();
|
||||
|
||||
glTranslatef(3.5f, 0.0f, -5.0f);
|
||||
DrawQuad();
|
||||
|
||||
glKosSwapBuffers();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
glKosInit();
|
||||
|
||||
InitGL(640, 480);
|
||||
ReSizeGLScene(640, 480);
|
||||
|
||||
while(1) {
|
||||
DrawGLScene();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
BIN
samples/mipmap/romdisk/NeHe.bmp
Normal file
BIN
samples/mipmap/romdisk/NeHe.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 192 KiB |
0
samples/mipmap/romdisk/PLACEHOLDER
Normal file
0
samples/mipmap/romdisk/PLACEHOLDER
Normal file
|
@ -123,6 +123,7 @@ 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.
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue
Block a user