1

我正在尝试通过 GLSurfaceView 实现手指画应用程序。

但是四边形闪烁太多,以至于我不得不重新绘制它们几次(请参阅 PaintGL 类中的 onTouchEvent)。似乎我正在使用不同的帧缓冲区,但我不知道如何在它们之间切换或禁用它们以避免这种讨厌的闪烁。

这是我的渲染器:

public class PaintRenderer implements GLSurfaceView.Renderer 
{

    private FloatBuffer vertexBuffer;
    public ArrayList<HardPoint> l;
    public boolean isPressed = false;

    public PaintRenderer()
    {
        super ();
        l = new ArrayList<HardPoint>();
    }

    public void onDrawFrame(GL10 gl) 
    {

        ArrayList<HardPoint> n;
        int count;

        synchronized (l) 
        {
            n = (ArrayList<HardPoint>) l.clone();
        }

        if (n.size() == 0)
            return;

        n.add(n.get(n.size() - 1));

        for (int i = 1; i < n.size(); i++) {

            HardPoint start = n.get(i-1);
            HardPoint end = n.get(i);

            if (!end.isPressed)
                continue;

            float dx = end.x - start.x;
            float dy = end.y - start.y;

            count = (int) Math.ceil(Math.max(Math.sqrt(dx * dx + dy * dy), 1));

            for (int j = 0; j < count; j++) 
            {
                drawQuad(gl, new PointF(start.x + dx * (float)j/count , start.y + dy * (float)j/count), 40.0f);
            }

        }

    }

    public void onSurfaceChanged(GL10 gl, int width, int height) 
    {
        gl.glViewport(0, 0, width, height);

        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glOrthof(0.0f, width, 0.0f, height, -1.0f, 1.0f);

        gl.glMatrixMode(GL10.GL_MODELVIEW);

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisable(GL10.GL_DEPTH_TEST);

    }

    public void onSurfaceCreated(GL10 gl, EGLConfig config) 
    {
    }

    public void drawQuad(GL10 gl_main, PointF center, float side)
    {
        int VERTEX_COUNT = 4;
        float vertices[] = 
            {
                // Вершины квадрата
                  center.x - side/2, center.y + side/2,  // 0. левая нижняя
                  center.x + side/2, center.y + side/2,  // 1. правая нижняя
                  center.x - side/2, center.y - side/2,  // 2. левая верхняя
                  center.x + side/2, center.y - side/2,   // 3. правая верхняя
            };

        ByteBuffer vbb = ByteBuffer.allocateDirect(VERTEX_COUNT * 3 * 4);
        vbb.order(ByteOrder.nativeOrder());
        vertexBuffer = vbb.asFloatBuffer();

        vertexBuffer.put(vertices);

        vertexBuffer.position(0);

        gl_main.glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
        gl_main.glVertexPointer(2, GL10.GL_FLOAT, 0, vertexBuffer);

        gl_main.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

    }

}

这是我的 GLSurfaceView 类:

public class PaintGL extends GLSurfaceView
{

    private Context mContext;
    private PaintRenderer renderer;
    private PointF prev_loc, cur_loc;

    public PaintGL(Context context) {
        super(context);
        mContext = context;
        renderer = new PaintRenderer();
        setRenderer(renderer);
        setRenderMode(RENDERMODE_WHEN_DIRTY);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) 
    {
        if (event.getAction() == MotionEvent.ACTION_DOWN)
        {
            synchronized (renderer.l) 
            {
                renderer.l.add(0, new HardPoint(event.getX(), this.getHeight() - event.getY(), true));
            }
        }
        if (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_UP)
        {
            //FIXME Мерцание первого quad'a при достаточно большом количестве точек
            int count = 10;
            synchronized (renderer.l) {
                renderer.l.add(0, new HardPoint(event.getX(), this.getHeight() - event.getY(), 
                        event.getAction() == MotionEvent.ACTION_UP ? false : true));
                while (renderer.l.size() > count)
                {
                    renderer.l.remove(count);
                }
            }
            requestRender();
            Log.d("x", renderer.l.size()+" ");
        }

        return true;
    }

}

和 HardPoint 类:

public class HardPoint extends PointF 
{
    boolean isPressed;

    public HardPoint() 
    {
        isPressed = false;
    }

    public HardPoint (float x, float y, boolean pressed)
    {
        super(x, y);
        isPressed = pressed;
    }

}
4

1 回答 1

1

几点:

编写高效代码有两个基本规则:

  • 不要做你不需要做的工作。
  • 如果可以避免,请不要分配内存。
  • ArrayList.clone创建一个浅拷贝。您必须为深层副本添加代码或使用克隆之类的库。

  • 摆脱单一列表上 UI- 和 Renderthread 之间的同步。使用第二个列表,其中 UI 线程仅添加HardPoint实例(同步)。在开始时onDrawFrame,将HardPoint实例转移到“渲染”列表(同步)。然后,您可以限制列表的大小。这消除了clone.

  • 不要每次都重新创建四边形几何,而是创建一次,然后将其转换到正确的位置。

  • 为了消除HardPoint实例的创建,您可以应用一个池(这里是 AndEngine 之一)预分配实例。

于 2012-05-12T16:29:04.487 回答