Hi, all.
Firstly, I am Japanes, so I am not good at English, sorry.
I develop a graphics porgram using OGLES-1.1_WINDOWS_PCEMULATION_2.05.25.0804 on WindowsXP.
And, I have a problem.
I can draw a sprite using glDrawTexfOES when format of texture is GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG or GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG.
But, the program hung when format of texture is not GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG or GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG.
Is there someone who have same problem?
A test code is below.
#include <windows.h>
#include <assert.h>
#include <GLES/gl.h>
#include <EGL/egl.h>
#include "PVRTglesExt.h"
#include "PVRTTexture.h"
#ifndef VRETURN
#define VRETURN(b) if(!(b)) { assert(false); return false; }
#endif
#define _READ(fp, b, size) VRETURN(fread(b, 1, size, fp) == size);
#define _SKIP(fp, offset) VRETURN(fseek(fp, offset, SEEK_CUR) == 0);
namespace {
// Get configs
inline bool _GetConfigs(
const PVR_Texture_Header& header,
GLenum* format,
GLenum* type,
int* bpp)
{
bool ret = true;
PVRTuint32 fmt = header.dwpfFlags & PVRTEX_PIXELTYPE;
switch (fmt) {
case OGL_RGBA_4444:
*format = GL_RGBA;
*type = GL_UNSIGNED_SHORT_4_4_4_4;
*bpp = 2;
break;
case OGL_RGBA_8888:
*format = GL_RGBA;
*type = GL_UNSIGNED_BYTE;
*bpp = 4;
break;
case OGL_RGB_565:
*format = GL_RGB;
*type = GL_UNSIGNED_SHORT_5_6_5;
*bpp = 2;
break;
case OGL_PVRTC2:
*format = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
*type = GL_UNSIGNED_BYTE; // Not use
*bpp = 0; // Not use
break;
case OGL_PVRTC4:
*format = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
*type = GL_UNSIGNED_BYTE; // Not use
*bpp = 0; // Not use
break;
case OGL_RGBA_5551:
case OGL_RGB_555:
case OGL_RGB_888:
case OGL_I_8:
case OGL_AI_88:
// TODO
assert(false);
ret = false;
break;
}
return ret;
}
// Return whether compressed format
inline bool _IsComressedFormat(const PVR_Texture_Header& header)
{
PVRTuint32 fmt = header.dwpfFlags & PVRTEX_PIXELTYPE;
bool ret = ((fmt == OGL_PVRTC2)
|| (fmt == OGL_PVRTC4));
return ret;
}
// Get biyesize
inline unsigned int _GetBytes(
const PVR_Texture_Header& header,
PVRTuint32 width,
PVRTuint32 height)
{
unsigned int ret = 0;
if (_IsComressedFormat(header)) {
PVRTuint32 fmt = header.dwpfFlags & PVRTEX_PIXELTYPE;
if (fmt == OGL_PVRTC2) {
ret = (PVRT_MAX(width, PVRTC2_MIN_TEXWIDTH) * PVRT_MAX(height, PVRTC2_MIN_TEXHEIGHT) * header.dwBitCount + 7) / 8;
}
else {
ret = (PVRT_MAX(width, PVRTC4_MIN_TEXWIDTH) * PVRT_MAX(height, PVRTC4_MIN_TEXHEIGHT) * header.dwBitCount + 7) / 8;
}
}
else {
ret = (width * height * header.dwBitCount + 7) / 8;
}
return ret;
}
struct SPvr {
int width;
int height;
unsigned int size;
int bpp;
GLenum format;
GLenum type;
void* data;
GLuint name;
SPvr()
{
width = 0;
height = 0;
size = 0;
bpp = 0;
format = 0;
type = 0;
data = NULL;
name = 0;
}
~SPvr() { Clear(); }
void Clear()
{
if (data != NULL) {
free(data);
}
if (name > 0) {
glDeleteTextures(1, &name);
}
width = 0;
height = 0;
size = 0;
bpp = 0;
format = 0;
type = 0;
data = NULL;
name = 0;
}
};
class CFilePtr {
public:
CFilePtr(FILE* fp) { m_FP = fp; }
~CFilePtr()
{
if (m_FP != NULL) {
fclose(m_FP);
}
}
private:
FILE* m_FP;
};
bool _ReadPvr(
const char* path,
SPvr* pvr)
{
FILE* fp = fopen(path, "rb");
CFilePtr filePtr(fp);
VRETURN(fp != NULL);
PVR_Texture_Header header;
_READ(fp, &header, sizeof(header));
// Check error
{
VRETURN(header.dwPVR == PVRTEX_IDENTIFIER);
VRETURN(
(header.dwHeaderSize == sizeof(header))
&& (header.dwNumSurfs > 0));
// Only accept untwiddled data UNLESS texture format is PVRTC
VRETURN(
!(((header.dwpfFlags & PVRTEX_TWIDDLE) == PVRTEX_TWIDDLE)
&& ((header.dwpfFlags & PVRTEX_PIXELTYPE) != OGL_PVRTC2)
&& ((header.dwpfFlags & PVRTEX_PIXELTYPE) != OGL_PVRTC4)));
// Prohibit cubemap
VRETURN(
((header.dwpfFlags & PVRTEX_CUBEMAP) == 0)
&& (header.dwNumSurfs == 1));
}
// Get configs
VRETURN(_GetConfigs(
header,
&pvr->format,
&pvr->type,
&pvr->bpp));
pvr->width = header.dwWidth;
pvr->height = header.dwHeight;
// Texture size
pvr->size = _GetBytes(header, header.dwWidth, header.dwHeight);
VRETURN(pvr->size > 0);
// Alloc buffer
pvr->data = malloc(pvr->size);
VRETURN(pvr->data != NULL);
// Read pixels
_READ(fp, pvr->data, pvr->size);
// TODO
// mipmap
return true;
}
} // namespace
namespace {
bool _isPVRCompressedFormat(GLenum format)
{
return ((format == GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG)
|| (format == GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG));
}
SPvr* s_pPvr = NULL;
} // namespace
#define VGOTO(b, label) if (!(b)) { assert(false); goto label; }
bool init()
{
s_pPvr = new SPvr;
bool ret = _ReadPvr("data/foo.pvr", s_pPvr);
VGOTO(ret, __EXIT__);
GLenum format = s_pPvr->format;
GLenum type = s_pPvr->type;
glGenTextures(1, &s_pPvr->name);
ret = (s_pPvr->name > 0);
VGOTO(ret, __EXIT__);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, s_pPvr->name);
if (_isPVRCompressedFormat(format)) {
int w = s_pPvr->width;
int h = s_pPvr->height;
int size = s_pPvr->size;
glCompressedTexImage2D(
GL_TEXTURE_2D,
0,
format,
w,
h,
0,
size,
s_pPvr->data);
}
else {
int w = s_pPvr->width;
int h = s_pPvr->height;
glPixelStorei(GL_UNPACK_ALIGNMENT, s_pPvr->bpp);
glTexImage2D(
GL_TEXTURE_2D,
0,
format,
w,
h,
0,
format,
type,
s_pPvr->data);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
__EXIT__:
return ret;
}
namespace {
void _Ortho(
GLfloat left, GLfloat right, GLfloat bottom, GLfloat top,
GLfloat fNear, GLfloat fFar)
{
GLfloat mat[16];
memset(mat, 0, sizeof(mat));
mat[0] = 2 / (right - left);
mat[5] = 2 / (top - bottom);
mat[10] = 2 / (fNear - fFar);
mat[15] = 1;
mat[12] = (right + left) / (left - right);
mat[13] = (top + bottom) / (bottom - top);
mat[14] = (fFar + fNear) / (fNear - fFar);
glMultMatrixf(mat);
}
void _drawRect(
int x, int y,
int width,
int height)
{
struct SVtx {
GLfloat pos[2];
GLfloat uv[2];
int color;
};
SVtx vtx[4];
vtx[0].uv[0] = 0.0f;
vtx[0].uv[1] = 0.0f;
vtx[1].uv[0] = 0.0f;
vtx[1].uv[1] = 1.0f;
vtx[2].uv[0] = 1.0f;
vtx[2].uv[1] = 0.0f;
vtx[3].uv[0] = 1.0f;
vtx[3].uv[1] = 1.0f;
vtx[0].color = 0xffffffff;
vtx[1].color = 0xffffffff;
vtx[2].color = 0xffffffff;
vtx[3].color = 0xffffffff;
unsigned char* p = reinterpret_cast<unsigned char*>(vtx);
static const int OFFSET_VTX_POS = 0;
static const int OFFSET_VTX_UV = sizeof(GLfloat) * 2;
static const int OFFSET_VTX_CLR = sizeof(GLfloat) * 4;
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, sizeof(SVtx), p + OFFSET_VTX_POS);
glTexCoordPointer(2, GL_FLOAT, sizeof(SVtx), p + OFFSET_VTX_UV);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(SVtx), p + OFFSET_VTX_CLR);
vtx[0].pos[0] = x;
vtx[0].pos[1] = y;
vtx[1].pos[0] = x;
vtx[1].pos[1] = y + height;
vtx[2].pos[0] = x + width;
vtx[2].pos[1] = y;
vtx[3].pos[0] = x + width;
vtx[3].pos[1] = y + height;
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
typedef void (APIENTRY * PFNGLDRAWTEXFOES) (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height);
PFNGLDRAWTEXFOES glDrawTexfOES = NULL;
void _drawSprite(
int screenH,
const GLint* rcSrc,
const GLint* rcDst)
{
if (glDrawTexfOES == NULL) {
glDrawTexfOES = (PFNGLDRAWTEXFOES)eglGetProcAddress("glDrawTexfOES");
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glScalef(-1.0f, -1.0f, 0.0f);
glEnable(GL_TEXTURE_2D);
glTexParameteriv(
GL_TEXTURE_2D,
GL_TEXTURE_CROP_RECT_OES,
rcSrc);
GLfloat w = rcDst[2];
GLfloat h = rcDst[3];
GLfloat x = rcDst[0];
GLfloat y = screenH - rcDst[1] - h;
(*glDrawTexfOES)(
x, y, 0.0f,
w, h);
}
} // namespace
void doFrame(int w, int h)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
_Ortho(0, w, h, 0, -1, 1);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, w, h);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, s_pPvr->name);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
#if 0
_drawRect(100, 100, 128, 128);
#else
GLint rcSrc[] = {
0, 0,
s_pPvr->width,
s_pPvr->height,
};
GLint rcDst[] = {
100, 100,
128, 128,
};
_drawSprite(
h,
rcSrc,
rcDst);
#endif
}
void end()
{
if (s_pPvr != NULL) {
delete s_pPvr;
}
}
Regards.