ساختن محیط 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 API استفاده کند، باید عبارت زیر را به مانیفست خود اضافه کنید:

<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 به‌عنوان نمای اصلی خود استفاده می‌کند:

کاتلین

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)
    }
}

جاوا

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 (سطح میانای برنامه‌سازی کاربردی ۸) یا بالاتر نیاز دارد، بنابراین مطمئن شوید پروژه Android شما آن میانای برنامه‌سازی کاربردی یا بالاتر را هدف قرار می‌دهد.

ساختن شیء GLSurfaceView

GLSurfaceView نمای تخصصی‌ای است که در آن می‌توانید گرافیک‌های OpenGL ES را ترسیم کنید. به‌تنهایی کار زیادی انجام نمی‌دهد. طراحی واقعی اشیا در GLSurfaceView.Renderer که در این نما تنظیم کرده‌اید کنترل می‌شود. درواقع، کد این شیء آن‌قدر نازک است که ممکن است وسوسه شوید از گسترش آن صرف‌نظر کنید و فقط یک نمونه GLSurfaceView اصلاح‌نشده ایجاد کنید، اما این کار را نکنید. برای ضبط رویدادهای لمسی، باید این کلاس را گسترش دهید که در درس پاسخ دادن به رویدادهای لمسی پوشش داده شده است.

کد ضروری برای GLSurfaceView حداقل است، بنابراین برای پیاده‌سازی سریع، معمولاً فقط یک کلاس داخلی در فعالیتی که از آن استفاده می‌کند ایجاد می‌شود:

کاتلین

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)
    }
}

جاوا

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 رسم کند:

کاتلین

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

جاوا

// 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 انجام نمی‌دهد:

کاتلین

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)
    }
}

جاوا

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 استفاده می‌کنید. این امضاهای روش به‌سادگی برای میاناهای برنامه‌سازی کاربردی نسخه ۲.۰ دوباره استفاده می‌شوند تا کد چارچوب Android ساده‌تر بماند.

اگر با میاناهای برنامه‌سازی کاربردی OpenGL ES آشنا هستید، اکنون باید بتوانید محیط OpenGL ES را در برنامه‌تان راه‌اندازی کنید و ترسیم گرافیک را شروع کنید. اما اگر برای شروع کار با OpenGL به کمک بیشتری نیاز دارید، به درس‌های بعدی بروید تا چند نکته دیگر را ببینید.