I'm currently developing a software that involves drawing 3d scene
with OpenGL (ES) 2.0. I want users to be able to pick objects from the
scene by clicking (or touching) on the screen. My current approach is
to render the scene to an off-screen buffer and deduce the clicked
object by reading color values from that buffer. While this worked on
PC with regular OpenGL, it fails on N900. Most times glReadPixels
segfaults when reading a single pixel, and when it doesn't, it returns
invalid values. And if I read the whole buffer, I get strange, striped
results, where each row of pixels is accompanied with three empty
rows.

If anyone has any idea why the above is happening, or has suggestions
how to implement better picking, then any help would be appreciated. I
have attached an example code to this email which demonstrates my
problem. The example code uses Qt and QGLFramebufferObject, but I had
similar results with 'handmade' FBO too. The code is also available
from <http://zokier.net/stuff/fail.cpp> Also image of erroneous FBO is
available at <http://zokier.net/stuff/fbo.png>, it should have a
pinkish square in the middle, but it doesn't.

/Torste Aikio

ps. I am not very experienced with mailing lists, I hope this is the
correct place to discuss this.
#ifdef USE_GLEW
#include <GL/glew.h>
#endif

#include <QtOpenGL>
#include <QDebug>

#define FBO_SIZE_X 512
#define FBO_SIZE_Y 512

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

#pragma pack(push, 1)
struct Vertex {
    GLfloat x,y,z;
};
#pragma pack(pop)

class OGLWidget : public QGLWidget
{
public:
    OGLWidget(QWidget *parent = 0);
    ~OGLWidget();
    
    void mouseDoubleClickEvent(QMouseEvent *);
    void initializeGL();
    void paintGL();

private:
    void loadVBO();
    void loadShaders();
    void render();
    QGLFramebufferObject *m_fbo;
    GLuint m_vertexCount;
    GLuint m_vertices;
    GLuint m_indices;
    GLuint m_shaderProg;
    GLuint m_shaderAr;
};

OGLWidget::OGLWidget(QWidget *parent)
    : QGLWidget(parent)
    , m_fbo(NULL)
{
}

OGLWidget::~OGLWidget()
{
    delete m_fbo;
    glDeleteBuffers(1, &m_vertices);
    glDeleteBuffers(1, &m_indices);
    glDeleteProgram(m_shaderProg);
}

void OGLWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
    m_fbo->toImage().save("fbo.png", "PNG");
    int fbox = (event->x() / (double)width()) * FBO_SIZE_X;
    int fboy = (event->y() / (double)height()) * FBO_SIZE_Y;
    qDebug() << "fbo coords:" << fbox << fboy;
    qDebug() << "screen coords:" << event->x() << event->y();
    m_fbo->bind();
    unsigned char color[4] = {0, 0, 0, 0};

    //SEGFAULT happens here
    glReadPixels(fbox, fboy, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);

    m_fbo->release();
    qDebug() << "color (rgba):" << color[0] << color[1] << color[2] << color[3];
}

void OGLWidget::initializeGL()
{
#ifdef USE_GLEW
    glewInit();
#endif

    m_fbo = new QGLFramebufferObject(FBO_SIZE_X, FBO_SIZE_Y);
    loadShaders();
    loadVBO();
}

void OGLWidget::loadVBO()
{
    m_vertexCount = 6;
    Vertex vertices[] = {
        {-0.5,  0.5, 0.0}, 
        { 0.5,  0.5, 0.0}, 
        {-0.5, -0.5, 0.0}, 
        { 0.5, -0.5, 0.0}};
    GLushort indices[] = {2, 0, 1, 2, 1, 3};
    glGenBuffers(1, &m_vertices);
    glBindBuffer(GL_ARRAY_BUFFER, m_vertices);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STREAM_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glGenBuffers(1, &m_indices);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indices);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STREAM_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

void OGLWidget::loadShaders()
{
    const char *fragmentShSrc =
        "#version 100\n" 
        "\n" 
        "void main (void)\n" 
        "{\n" 
        "    gl_FragColor = vec4(0.8, 0.2, 0.4, 1.0);\n" 
        "}\n";

    const char *vertexShSrc =
        "#version 100\n"
        "\n"
        "attribute vec3 position;\n"
        "uniform float ar;\n"
        "\n"
        "mat4 v_frustum(float angle_of_view,\n"
        "               float aspect_ratio,\n"
        "               float z_near,\n"
        "               float z_far)\n"
        "{\n"
        "    return mat4(\n"
        "        vec4(1.0/tan(angle_of_view),           0.0, 0.0, 0.0),\n"
        "        vec4(0.0, aspect_ratio/tan(angle_of_view),  0.0, 0.0),\n"
        "        vec4(0.0, 0.0,    (z_far+z_near)/(z_far-z_near), 1.0),\n"
        "        vec4(0.0, 0.0, -2.0*z_far*z_near/(z_far-z_near), 0.0));\n"
        "}\n"
        "\n"
        "void main(void)\n"
        "{\n"
        "    vec4 d = mat4(vec4(1, 0, 0, 0),\n"
        "                  vec4(0, 1, 0, 0),\n"
        "                  vec4(0, 0, 1, 0),\n"
        "                  vec4(0, 0, 2, 1)) * vec4(position, 1.0);\n"
        "    gl_Position = v_frustum(radians(30.0), ar, 0.1, 15.0) * d;\n"
        "}\n";


    GLuint vertexSh = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexSh, 1, &vertexShSrc, NULL);
    glCompileShader(vertexSh);

    GLuint fragmentSh = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentSh, 1, &fragmentShSrc, NULL);
    glCompileShader(fragmentSh);

    m_shaderProg = glCreateProgram();
    glAttachShader(m_shaderProg, vertexSh);
    glAttachShader(m_shaderProg, fragmentSh);
    glLinkProgram(m_shaderProg);

    glDeleteShader(vertexSh);
    glDeleteShader(fragmentSh);

    m_shaderAr = glGetUniformLocation(m_shaderProg, "ar");
}

void OGLWidget::render()
{
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    GLuint position = glGetAttribLocation(m_shaderProg, "position");

    glBindBuffer(GL_ARRAY_BUFFER, m_vertices);
    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
            BUFFER_OFFSET(0));
    glEnableVertexAttribArray(position);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indices);
    glDrawElements(GL_TRIANGLES, m_vertexCount, GL_UNSIGNED_SHORT,
            BUFFER_OFFSET(0));
    glDisableVertexAttribArray(position);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

void OGLWidget::paintGL()
{
    glUseProgram(m_shaderProg);
    glUniform1f(m_shaderAr, width()/(double)height());
    m_fbo->bind();
    glViewport(0, 0, FBO_SIZE_X, FBO_SIZE_Y);
    render();
    m_fbo->release();
    glViewport(0, 0, width(), height());
    render();
}

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    OGLWidget w;
    w.show();
    return app.exec();
}

_______________________________________________
maemo-developers mailing list
maemo-developers@maemo.org
https://lists.maemo.org/mailman/listinfo/maemo-developers

Reply via email to