同事跑路了,公司把爛攤子扔給了我,是一個關於畫圖有關的項目,偶從來沒牽扯的領域,而且零文檔! T_T
我奮鬥了幾日,終於在大片花花綠綠的bug單中,成功幹掉了幾小隻,甚是欣慰,原以爲不過如此……在與一個看似很白癡的問題糾纏了數日仍未有任何進展的時候,我痛下決心,從零開始學習OpenGL。
本文用來記錄學習過程中遇到的一些問題,以免遺忘以及給同在水深火熱之中的XDJM一些啓示和救贖吧 ^v^~
(……額,如果你還不知道啥是OpenGL,我建議你收藏下,免得下次你也跟我掉到了同一個洞中,沒人救你,嘿嘿)
咱們就從錯誤說起吧。
1. call to OpenGL ES API with no current context (logged once per thread)
如果你也遇到了這個問題,說明你還是不夠解他——GLSurfaceView。
本錯誤的直接原因是OpenGL ES API運行缺少當前的上下文。
好像……明明……不應該啊,WHY?
通常遇到這個問題是現場是這樣的——
例如,我們點擊了什麼、或Touch了什麼或其他形式的用戶輸入,然後,我們想以此爲契機改變與OpenGL有關的內容。
比如像下面這樣,點擊按鈕,想在下面的區域描畫既定的圖形:
對應的代碼如下:
public void onClick(View v) {
switch(v.getId()) {
case R.id.btnTriangle:
Shape sp;
sp = new Triangle();
sp.init();
renderer.setShape(sp);
break;
default:
break;
}
}
運行後,點擊按鈕時,提示如下錯誤:
call to OpenGL ES API with no current context (logged once per thread)
看到這裏,你有沒有想到點什麼?
咳咳,來點嚴肅的:
GLSurfaceView是多線程操作的,其對應的渲染器Renderer擁有獨立的渲染線程,也就是說,需要我們實現的onSurfaceCreated、onSurfaceChanged、onDrawFrame即是運行在此渲染線程。
這樣即保證了線程的安全,又使設計清晰,方便用戶使用。
簡單點說,GLSurfaceView把與渲染關聯的處理都鎖定在了渲染器的線程中,外部如果要操作此類,必須通過他規定的方式進行。
而用戶操作是在哪裏運行的?
對,主線程! 問題,就出在這裏!
GLSurfaceView渲染處理都封在自己的渲染器裏了,你需要做的是拿着麪粉和雞蛋到他家門口去告訴他你想讓他幫忙做成啥樣的點心就行。
好了,關鍵是——你找對門了嗎?
沒有!
你直接闖到人家家裏,拖了一個糕點師到你家,指着一袋子麪粉說:“給我做成法式七層糖霜大蛋糕!”。
即便是師傅再良善,也是愛莫能助啊,爲啥?
沒工具啊!
而工具,就是這裏的上下文。
上帝在關上一扇門的時候,總會開個窗。
窗在哪裏?
就是他——
public void queueEvent(Runnable r)
queueEvent提供了入口,讓你把需要在渲染線程中的處理告訴他,他來執行即可。
於是,上面的代碼需要改成這樣:
@Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.btnTriangle:
glSurfaceView.queueEvent(new Runnable() {
@Override
public void run() {
Shape sp = new Triangle();
sp.init();
renderer.setShape(sp);
}
});
break;
default:
break;
}
}
OK,大功告成~
未完待續……
轉載請說明出處哦~