إنشاء بيئة OpenGL ES

لرسم رسومات باستخدام OpenGL ES في تطبيق Android، يجب إنشاء حاوية عرض لها. ومن بين الطرق الأكثر وضوحًا لتنفيذ ذلك، استخدام الترميزَين GLSurfaceView وGLSurfaceView.Renderer. علامة GLSurfaceView هي حاوية عرض للرسومات المرسومة باستخدام OpenGL، وتتحكّم GLSurfaceView.Renderer في ما يتم رسمه في هذا العرض. لمزيد من المعلومات حول هذه الصفوف، اطّلع على دليل مطوّري البرامج OpenGL ES.

GLSurfaceView ما هو إلا طريقة واحدة لدمج رسومات OpenGL ES في تطبيقك. لمشاهدة عرض الرسومات بملء الشاشة أو شبه بملء الشاشة، يكون هذا اختيارًا معقولاً. أمّا المطوّرون الذين يريدون دمج رسومات OpenGL ES في جزء صغير من تنسيقاتهم، فعليهم الاطّلاع على TextureView. بالنسبة إلى المطوّرين الذين ينفّذون المهام بأنفسهم، من الممكن أيضًا إنشاء عرض OpenGL ES باستخدام SurfaceView، ولكن هذا يتطلّب كتابة قدر كبير من الرموز الإضافية.

يشرح هذا الدرس كيفية إكمال الحد الأدنى من تنفيذ GLSurfaceView وGLSurfaceView.Renderer في نشاط تطبيق بسيط.

توضيح استخدام OpenGL ES في البيان

لكي يستخدم تطبيقك واجهة برمجة التطبيقات OpenGL ES 2.0، يجب إضافة البيان التالي إلى البيان:

<uses-feature android:glEsVersion="0x00020000" android:required="true" />

إذا كان تطبيقك يستخدم ضغط البنية، يجب أيضًا توضيح تنسيقات الضغط المتوافقة مع تطبيقك، حتى يتم تثبيته على الأجهزة المتوافقة فقط.

<supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />
<supports-gl-texture android:name="GL_OES_compressed_paletted_texture" />

للحصول على مزيد من المعلومات حول تنسيقات ضغط البنية، راجع دليل المطوِّر حول OpenGL.

إنشاء نشاط لرسومات OpenGL ES

تشتمل تطبيقات Android التي تستخدم OpenGL ES على أنشطة كأي تطبيق آخر له واجهة مستخدم. يتمثل الاختلاف الرئيسي عن التطبيقات الأخرى في ما تضعه في تخطيط لنشاطك. يمكنك استخدام TextView وButton وListView في العديد من التطبيقات، ولكن في التطبيق الذي يستخدم OpenGL ES، يمكنك أيضًا إضافة GLSurfaceView.

يوضِّح مثال الرمز التالي الحد الأدنى من تنفيذ نشاط يستخدم GLSurfaceView كعرض أساسي له:

Kotlin

class OpenGLES20Activity : Activity() {

    private lateinit var gLView: GLSurfaceView

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Create a GLSurfaceView instance and set it
        // as the ContentView for this Activity.
        gLView = MyGLSurfaceView(this)
        setContentView(gLView)
    }
}

Java

public class OpenGLES20Activity extends Activity {

    private GLSurfaceView gLView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a GLSurfaceView instance and set it
        // as the ContentView for this Activity.
        gLView = new MyGLSurfaceView(this);
        setContentView(gLView);
    }
}

ملاحظة: يتطلّب OpenGL ES 2.0 توفّر الإصدار Android 2.2 (المستوى 8 من واجهة برمجة التطبيقات) أو إصدارًا أحدث، لذا تأكّد من أنّ مشروع Android يستهدف واجهة برمجة التطبيقات هذه أو إصدارًا أحدث.

إنشاء كائن GLSurfaceView

GLSurfaceView هي طريقة عرض متخصّصة يمكنك من خلالها رسم رسومات OpenGL ES. ولا يفعل الكثير من تلقاء نفسه. ويتم التحكّم في الرسم الفعلي للكائنات في GLSurfaceView.Renderer التي تضبطها في طريقة العرض هذه. في الواقع، الرمز البرمجي لهذا الكائن ضعيف جدًا، وقد تميل إلى تخطي توسيعه وإنشاء مثيل GLSurfaceView غير معدّل، ولكن لا تفعل ذلك. تحتاج إلى توسيع نطاق هذا الصف لتسجيل أحداث اللمس، وهو أمر تمت تغطيته في الدرس الاستجابة لأحداث اللمس.

الرمز الأساسي لـ GLSurfaceView بسيط جدًا، ولذلك من أجل تنفيذ سريع، من الشائع إنشاء فئة داخلية فقط في النشاط الذي يستخدمها:

Kotlin

import android.content.Context
import android.opengl.GLSurfaceView

class MyGLSurfaceView(context: Context) : GLSurfaceView(context) {

    private val renderer: MyGLRenderer

    init {

        // Create an OpenGL ES 2.0 context
        setEGLContextClientVersion(2)

        renderer = MyGLRenderer()

        // Set the Renderer for drawing on the GLSurfaceView
        setRenderer(renderer)
    }
}

Java

import android.content.Context;
import android.opengl.GLSurfaceView;

class MyGLSurfaceView extends GLSurfaceView {

    private final MyGLRenderer renderer;

    public MyGLSurfaceView(Context context){
        super(context);

        // Create an OpenGL ES 2.0 context
        setEGLContextClientVersion(2);

        renderer = new MyGLRenderer();

        // Set the Renderer for drawing on the GLSurfaceView
        setRenderer(renderer);
    }
}

من الإضافات الاختيارية الأخرى لتنفيذ GLSurfaceView، وهي ضبط وضع العرض لرسم طريقة العرض فقط عندما يكون هناك تغيير في بيانات الرسم باستخدام الإعداد GLSurfaceView.RENDERMODE_WHEN_DIRTY:

Kotlin

// Render the view only when there is a change in the drawing data
renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY

Java

// Render the view only when there is a change in the drawing data
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

ويؤدّي هذا الإعداد إلى منع إعادة رسم إطار GLSurfaceView إلى أن يتم استدعاء requestRender()، وهو أكثر فعالية لنموذج التطبيق هذا.

إنشاء فئة عارض

ويبدأ استخدام فئة GLSurfaceView.Renderer أو العارض (أو العارض) في التطبيق الذي يستخدم OpenGL ES في بدء التجربة المثيرة للاهتمام. وتتحكم هذه الفئة في المحتوى الذي يتم رسمه على GLSurfaceView المرتبطة به. هناك ثلاث طرق في العارض يطلبها نظام Android لمعرفة ماذا وآلية الرسم على GLSurfaceView:

  • onSurfaceCreated() - يتم طلبها مرة واحدة لإعداد بيئة OpenGL ES بطريقة العرض.
  • onDrawFrame() - يتم استدعاؤها لكل عملية إعادة رسم للعرض.
  • onSurfaceChanged(): يتم استدعاء هذه السمة إذا تغيّر الشكل الهندسي للعرض، على سبيل المثال عندما يتغيّر اتجاه شاشة الجهاز.

في ما يلي طريقة تنفيذ أساسية جدًا لعارض OpenGL ES، وهو لا يتعدى رسم خلفية سوداء في GLSurfaceView:

Kotlin

import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

import android.opengl.GLES20
import android.opengl.GLSurfaceView

class MyGLRenderer : GLSurfaceView.Renderer {

    override fun onSurfaceCreated(unused: GL10, config: EGLConfig) {
        // Set the background frame color
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
    }

    override fun onDrawFrame(unused: GL10) {
        // Redraw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
    }

    override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) {
        GLES20.glViewport(0, 0, width, height)
    }
}

Java

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;

public class MyGLRenderer implements GLSurfaceView.Renderer {

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        // Set the background frame color
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    }

    public void onDrawFrame(GL10 unused) {
        // Redraw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    }

    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    }
}

هذا كل ما في الأمر! تنشئ أمثلة التعليمات البرمجية أعلاه تطبيق Android بسيطًا يعرض شاشة سوداء باستخدام OpenGL. على الرغم من أن هذه التعليمات البرمجية لا تفعل أي شيء مثير للاهتمام، إلا أنه من خلال إنشاء هذه الفئات، تكون قد وضعت الأساس الذي تحتاجه لبدء رسم العناصر الرسومية باستخدام OpenGL.

ملاحظة: قد تتساءل عن سبب احتواء هذه الطرق على معلمة GL10، عند استخدام واجهات برمجة تطبيقات OpengGL ES 2.0. تتم ببساطة إعادة استخدام توقيعات الطرق هذه لواجهات برمجة التطبيقات الإصدار 2.0 من أجل تسهيل عملية ترميز إطار عمل Android.

إذا كنت على دراية بواجهات برمجة تطبيقات OpenGL ES، فمن المفترض أن تتمكن الآن من إعداد بيئة OpenGL ES في تطبيقك وبدء رسم الرسومات. ومع ذلك، إذا كنت بحاجة إلى مزيد من المساعدة لبدء استخدام OpenGL، فانتقل إلى الدروس التالية للحصول على بعض التلميحات الإضافية.