我正在阅读《Beginning Android c++ Game Development》这本书。目前在第5章,本书的代码可以从他们的网站下载。
我已经跟随我的书到第4章没有问题,但来第5章渲染纹理时,我得到这个:
http://i193.photobucket.com/albums/z127/johto760/error - 1. - png
你可以看到颜色是不正确的,我希望是这样的:
http://i193.photobucket.com/albums/z127/johto760/somewhatexpected.png甚至在第二个RGB是颠倒的,我使用TGA文件的图像。我从星期天开始就在谷歌上搜索解决方案,今天是星期二。
下面是我正在处理的相关代码:
SampleTask.cpp
namespace {
float verts[] = {-0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f};
unsigned short indices[] = {0, 2, 1, 2, 3, 1};
}
SampleTask::SampleTask(Framework::Renderer* renderer,
const unsigned int priority) :
Framework::Task(priority), m_state(RUNNING), m_renderer(renderer), m_readBytes(
0), m_TGABuffer(NULL), m_file("test.tga"), m_fileLength(0) {
m_renderable.SetGeometry(&m_geometry);
m_renderable.SetShader(&m_textureShader);
}
SampleTask::~SampleTask() {
m_renderer->RemoveRenderable(&m_renderable);
m_renderer->RemoveTexture(&m_texture);
m_renderer->RemoveShader(&m_textureShader);
if (m_TGABuffer) {
delete[] static_cast<char*>(m_TGABuffer);
m_TGABuffer = 0;
}
}
bool SampleTask::Start() {
Framework::Geometry* pGeometry = m_renderable.GetGeometry();
pGeometry->SetName("quad");
pGeometry->SetVertexBuffer(verts);
pGeometry->SetNumVertices(4);
pGeometry->SetIndexBuffer(indices);
pGeometry->SetNumIndices(6);
pGeometry->SetNumVertexPositionElements(3);
pGeometry->SetNumTexCoordsElements(2);
pGeometry->SetVertexStride(sizeof(float) * 5);
bool success = false;
if (m_file.Open()) {
m_fileLength = m_file.Length();
m_TGABuffer = new char[m_fileLength];
m_state = LOADING_FILE;
success = true;
}
return success;
}
void SampleTask::Stop() {
m_renderer->RemoveRenderable(&m_renderable);
}
void SampleTask::Update() {
switch (m_state) {
case (LOADING_FILE): {
void* currentDataPos = static_cast<char*>(m_TGABuffer)
+ (sizeof(char) * m_readBytes);
size_t bytesRead = 0;
m_file.Read(currentDataPos, 512 * 1024, bytesRead);
m_readBytes += bytesRead;
if (m_readBytes == m_fileLength) {
m_state = CREATE_TEXTURE;
}
}
break;
case (CREATE_TEXTURE): {
Framework::TGAFile tgaFile(m_TGABuffer);
Framework::Texture::Header textureHeader;
textureHeader.m_width = tgaFile.GetWidth();
textureHeader.m_height = tgaFile.GetHeight();
textureHeader.m_bytesPerPixel = 4;
textureHeader.m_dataSize = textureHeader.m_width
* textureHeader.m_height * textureHeader.m_bytesPerPixel;
m_texture.SetData(textureHeader, tgaFile.GetImageData());
m_textureShader.SetTexture(&m_texture);
m_renderer->AddTexture(&m_texture);
m_renderer->AddShader(&m_textureShader);
m_renderer->AddRenderable(&m_renderable);
m_state = RUNNING;
}
break;
};
}
Renderer.cpp
void Renderer::Update() {
if (m_initialized) {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
for (RenderableVectorIterator iter = m_renderables.begin();
iter != m_renderables.end(); iter++) {
Renderable* pRenderable = *iter;
if (pRenderable) {
Draw(pRenderable);
}
}
eglSwapBuffers(m_display, m_surface);
}
}
void Renderer::Init() {
// initialize OpenGL ES and EGL
/*
* Here specify the attributes of the desired configuration.
* Below, we select an EGLConfig with at least 8 bits per color
* component compatible with on-screen windows
*/
const EGLint attribs[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_NONE };
EGLint format;
EGLint numConfigs;
EGLConfig config;
m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(m_display, NULL, NULL);
/* Here, the application chooses the configuration it desires. In this
* sample, we have a very simplified selection process, where we pick
* the first EGLConfig that matches our criteria */
eglChooseConfig(m_display, attribs, &config, 1, &numConfigs);
/* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
* guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
* As soon as we picked a EGLConfig, we can safely reconfigure the
* ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
eglGetConfigAttrib(m_display, config, EGL_NATIVE_VISUAL_ID, &format);
ANativeWindow_setBuffersGeometry(m_state->window, 0, 0, format);
m_surface = eglCreateWindowSurface(m_display, config, m_state->window,
NULL);
EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE };
m_context = eglCreateContext(m_display, config, NULL, contextAttribs);
eglMakeCurrent(m_display, m_surface, m_surface, m_context);
eglQuerySurface(m_display, m_surface, EGL_WIDTH, &m_width);
eglQuerySurface(m_display, m_surface, EGL_HEIGHT, &m_height);
for (TextureVectorIterator iter = m_textures.begin();
iter != m_textures.end(); ++iter) {
Texture* pCurrent = *iter;
pCurrent->Init();
}
for (ShaderVectorIterator iter = m_shaders.begin(); iter != m_shaders.end();
++iter) {
Shader* pCurrent = *iter;
pCurrent->Link();
}
m_initialized = true;
}
void Renderer::Draw(Renderable* renderable) {
assert(renderable);
if (renderable) {
Geometry* geometry = renderable->GetGeometry();
Shader* shader = renderable->GetShader();
assert(geometry && shader);
if (geometry && shader) {
shader->Setup(*renderable);
glDrawElements(GL_TRIANGLES, geometry->GetNumIndices(),
GL_UNSIGNED_SHORT, geometry->GetIndexBuffer());
}
}
}
Texture.cpp
void Texture::Init() {
GLint packBits = 4;
GLint internalFormat = GL_RGBA;
GLenum format = GL_RGBA;
switch (m_header.m_bytesPerPixel) {
case 1: {
packBits = 1;
internalFormat = GL_ALPHA;
format = GL_ALPHA;
}
break;
};
glGenTextures(1, &m_id);
glBindTexture(GL_TEXTURE_2D, m_id);
glPixelStorei(GL_UNPACK_ALIGNMENT, packBits);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_header.m_width,
m_header.m_height, 0, format, GL_UNSIGNED_BYTE, m_imageData);
}
TextureShader.cpp
m_vertexShaderCode =
"attribute vec4 a_vPosition; n"
"attribute vec2 a_texCoord; n"
"varying vec2 v_texCoord; n"
"void main(){ n"
" gl_Position = a_vPosition; n"
" v_texCoord = a_texCoord; n"
"} n";
m_fragmentShaderCode =
"precision highp float; n"
"varying vec2 v_texCoord; n"
"uniform sampler2D s_texture; n"
"void main(){ n"
" gl_FragColor = texture2D(s_texture, v_texCoord); n"
"} n";
void TextureShader::Link() {
Shader::Link();
m_positionAttribHandle = glGetAttribLocation(m_programId, "a_vPosition");
m_texCoordAttribHandle = glGetAttribLocation(m_programId, "a_texCoord");
m_samplerHandle = glGetUniformLocation(m_programId, "s_texture");
}
void TextureShader::Setup(Renderable& renderable){
assert(m_texture);
Geometry* pGeometry = renderable.GetGeometry();
if (pGeometry && m_texture) {
Shader::Setup(renderable);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_texture->GetId());
glUniform1i(m_samplerHandle, 0);
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_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glVertexAttribPointer(m_positionAttribHandle,
pGeometry->GetNumVertexPositionElements(),
GL_FLOAT,
GL_FALSE, pGeometry->GetVertexStride(),
pGeometry->GetVertexBuffer());
glEnableVertexAttribArray (m_positionAttribHandle);
glVertexAttribPointer(m_texCoordAttribHandle,
pGeometry->GetNumTexCoordsElements(),
GL_FLOAT,
GL_FALSE, pGeometry->GetVertexStride(),
&static_cast<GLfloat*>(pGeometry->GetVertexBuffer())[pGeometry->GetNumVertexPositionElements()]);
glEnableVertexAttribArray (m_texCoordAttribHandle);
}
}
找到问题所在了。
我决定使用本书网站上的头文件和cpp文件,然后我从自己的代码版本中逐一复制粘贴每个cpp文件,结果是TGA文件的图像数据大小"计算错误"。
我的错误在代码中:
m_imageData = static_cast<void*>(static_cast<char*>(data) + sizeof(m_header));
我正在计算"m_header"变量的大小,相反,我应该计算TGAHeader类的大小,我认为这是18个字节或什么的,所以我把m_header改成了TGAHeader,像这样:
m_imageData = static_cast<void*>(static_cast<char*>(data) + sizeof(TGAHeader));
现在颜色是正确的,我还将格式从GL_RGB更改为GL_BGR_EXT,并保持内部格式为GL_RGB,以便在进入gl的缓冲区时反转颜色