Hello. I have an application that draws terrain by mapping textures onto triangles using fixed OpenGL-ES 1.x functions on Linux on an OMAP3530. The triangles are rotated into view based on the orientation of the viewer. When I do this, I see texture magnification errors. I've confirmed the same thing happens on a Beagleboard with the latest Beagle graphics SDK from TI. (The other board is a Gumstix Overo Water with the 3.00.00.09 SDK). In the first image below using the GL_NEAREST mag filter, the problem is obvious. The alternating color pattern should line up everywhere. The second, correct image is from an Intel GPU. The errors change with slight changes to the view. With GL_LINEAR and small rotations in the model matrix, the drawing errors make the terrain look like it's jumping around.
This is what I'm seeing:
This is what it should look like: (output from a completely different GPU)
I don't know where to report problems with the graphics. I need to get this fixed or find a workaround.
I created a test application that renders the test image from one of the demos in the PowerVR SDK framework. Basically I create a 512x512 texture and draw it as a bunch of triangles with shared edges. With ANIMATE defined the drawing errors jump around.
#include <GLES/egl.h>
#include "PVRShell.h"
#include "OGLESTools.h"
// Size of the texture we create
#define TEX_SIZE 512
class OGLESTexturing : public PVRShell
{
// Texture handle
GLuint m_uiTexture;
int vertex_count;
struct vertex_t {
VERTTYPE x, y, z;
} *pfVertices;
struct texcoord_t {
VERTTYPE s, t;
} *pfTexCoord;
public:
virtual bool InitApplication();
virtual bool InitView();
virtual bool ReleaseView();
virtual bool QuitApplication();
virtual bool RenderScene();
void init_vertex(int i, int x, int y, int z)
{
pfVertices[i].x = f2vt(x);
pfVertices[i].y = f2vt(y);
pfVertices[i].z = f2vt(z);
pfTexCoord[i].s = f2vt(x/512.f);
pfTexCoord[i].t = f2vt(y/512.f);
}
};
bool OGLESTexturing::InitApplication()
{
const int span = 4;
vertex_count = (512/span)*(512/span)*6;
pfVertices = new vertex_t[vertex_count];
pfTexCoord = new texcoord_t[vertex_count];
int i = 0;
for (int y = 0; y < 512; y += span) {
for (int x = 0; x < 512; x += span) {
int z1 = x%(span*2)>=span ? 1024 : 0;
int z2 = (x+span)%(span*2)>=span ? 1024 : 0;
init_vertex(i++, x, y+span, z1);
init_vertex(i++, x, y, z1);
init_vertex(i++, x+span, y+span, z2);
init_vertex(i++, x+span, y+span, z2);
init_vertex(i++, x, y, z1);
init_vertex(i++, x+span, y, z2);
}
}
return true;
}
bool OGLESTexturing::QuitApplication()
{
delete [] pfVertices;
delete [] pfTexCoord;
return true;
}
bool OGLESTexturing::InitView()
{
// Sets the clear color
myglClearColor(0, 0, 0, 0);
// Enables texturing
glEnable(GL_TEXTURE_2D);
// The problem occurs with or without depth testing and culling
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);
// Allocates one texture handle
glGenTextures(1, &m_uiTexture);
// Binds this texture handle so we can load the data into it
glBindTexture(GL_TEXTURE_2D, m_uiTexture);
// Creates the data as a 8bits integer array (8bits per component)
GLubyte* pTexData = new GLubyte[TEX_SIZE*TEX_SIZE*3];
for (int i = 0; i < TEX_SIZE*TEX_SIZE*3; ) {
pTexData[i++] = 0;
pTexData[i++] = 255;
pTexData[i++] = 255;
if (i < TEX_SIZE*TEX_SIZE*3) {
pTexData[i++] = 255;
pTexData[i++] = 0;
pTexData[i++] = 255;
}
if (i < TEX_SIZE*TEX_SIZE*3) {
pTexData[i++] = 255;
pTexData[i++] = 255;
pTexData[i++] = 0;
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEX_SIZE, TEX_SIZE, 0, GL_RGB, GL_UNSIGNED_BYTE, pTexData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
// Deletes the texture data, it's now in OpenGL memory
delete [] pTexData;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
myglFrustum(f2vt(-0.039f), f2vt(0.039f),
f2vt(-0.02925f), f2vt(0.02925f),
f2vt(0.1f), f2vt(5.0f));
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
return true;
}
bool OGLESTexturing::ReleaseView()
{
// Frees the texture
glDeleteTextures(1, &m_uiTexture);
return true;
}
bool OGLESTexturing::RenderScene()
{
// Clears the color buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
#ifdef ANIMATE
unsigned long tick = PVRShellGetTime()%10000;
myglRotate(f2vt(tick*2.f/10000), 0.0, 0.0, 1.0);
#endif // ANIMATE
myglRotate(f2vt(-90), f2vt(1.0f), 0, 0);
myglTranslate(f2vt(-505*(60.f/1200.f)), f2vt(0.2f), f2vt(-0.2f));
myglScale(f2vt(60.f/1200.f), f2vt(60.f/1200.f), f2vt(1.f/6000.f));
// Pass the vertex data
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3,VERTTYPEENUM,0,pfVertices);
// Pass the texture coordinates data
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2,VERTTYPEENUM,0,pfTexCoord);
// Draws a non-indexed triangle array
glDrawArrays(GL_TRIANGLES, 0, vertex_count);
return true;
}
PVRShell* NewDemo()
{
return new OGLESTexturing();
}