Revision 862fcd79
Added by Leszek Koltunski over 9 years ago
| build.gradle | ||
|---|---|---|
| 6 | 6 | 
     | 
| 7 | 7 | 
        defaultConfig {
   | 
| 8 | 8 | 
    applicationId "org.distorted.examples"  | 
| 9 | 
            minSdkVersion 15
   | 
|
| 9 | 
            minSdkVersion 18
   | 
|
| 10 | 10 | 
    targetSdkVersion 23  | 
| 11 | 11 | 
    }  | 
| 12 | 12 | 
     | 
| src/main/AndroidManifest.xml | ||
|---|---|---|
| 34 | 34 | 
    <activity android:name=".cubes.CubesActivity" />  | 
| 35 | 35 | 
    <activity android:name=".quaternion.QuaternionActivity" />  | 
| 36 | 36 | 
    <activity android:name=".effects3d.Effects3DActivity" />  | 
| 37 | 
    <activity android:name=".plainmonalisa.PlainMonaLisaActivity" />  | 
|
| 37 | 38 | 
    </application>  | 
| 38 | 39 | 
    </manifest>  | 
| src/main/java/org/distorted/examples/TableOfContents.java | ||
|---|---|---|
| 36 | 36 | 
    import org.distorted.examples.cubes.CubesActivity;  | 
| 37 | 37 | 
    import org.distorted.examples.quaternion.QuaternionActivity;  | 
| 38 | 38 | 
    import org.distorted.examples.effects3d.Effects3DActivity;  | 
| 39 | 
    import org.distorted.examples.plainmonalisa.PlainMonaLisaActivity;  | 
|
| 39 | 40 | 
     | 
| 40 | 41 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
| 41 | 42 | 
     | 
| ... | ... | |
| 238 | 239 | 
    data.add(item);  | 
| 239 | 240 | 
    activityMapping.put(i++, Effects3DActivity.class);  | 
| 240 | 241 | 
    }  | 
| 242 | 
     | 
|
| 243 | 
       {
   | 
|
| 244 | 
    final Map<String, Object> item = new HashMap<String, Object>();  | 
|
| 245 | 
    item.put(ITEM_IMAGE, R.drawable.icon_example_monalisa);  | 
|
| 246 | 
    item.put(ITEM_TITLE, (i+1)+". "+getText(R.string.example_plainmonalisa));  | 
|
| 247 | 
    item.put(ITEM_SUBTITLE, getText(R.string.example_plainmonalisa_subtitle));  | 
|
| 248 | 
    data.add(item);  | 
|
| 249 | 
    activityMapping.put(i++, PlainMonaLisaActivity.class);  | 
|
| 250 | 
    }  | 
|
| 241 | 251 | 
     | 
| 242 | 252 | 
       final SimpleAdapter dataAdapter = new SimpleAdapter(this, data, R.layout.toc_item, new String[] {ITEM_IMAGE, ITEM_TITLE, ITEM_SUBTITLE}, new int[] {R.id.Image, R.id.Title, R.id.SubTitle});
   | 
| 243 | 253 | 
    setListAdapter(dataAdapter);  | 
| src/main/java/org/distorted/examples/plainmonalisa/EglCore.java | ||
|---|---|---|
| 1 | 
    package org.distorted.examples.plainmonalisa;  | 
|
| 2 | 
     | 
|
| 3 | 
    import android.graphics.SurfaceTexture;  | 
|
| 4 | 
    import android.opengl.EGL14;  | 
|
| 5 | 
    import android.opengl.EGLConfig;  | 
|
| 6 | 
    import android.opengl.EGLContext;  | 
|
| 7 | 
    import android.opengl.EGLDisplay;  | 
|
| 8 | 
    import android.opengl.EGLExt;  | 
|
| 9 | 
    import android.opengl.EGLSurface;  | 
|
| 10 | 
    import android.util.Log;  | 
|
| 11 | 
    import android.view.Surface;  | 
|
| 12 | 
     | 
|
| 13 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 14 | 
    /**  | 
|
| 15 | 
    * Core EGL state (display, context, config).  | 
|
| 16 | 
    * <p>  | 
|
| 17 | 
    * The EGLContext must only be attached to one thread at a time. This class is not thread-safe.  | 
|
| 18 | 
    */  | 
|
| 19 | 
    public final class EglCore  | 
|
| 20 | 
      {
   | 
|
| 21 | 
    private static final String TAG = "EglCore";  | 
|
| 22 | 
     | 
|
| 23 | 
    /**  | 
|
| 24 | 
    * Constructor flag: surface must be recordable. This discourages EGL from using a  | 
|
| 25 | 
    * pixel format that cannot be converted efficiently to something usable by the video  | 
|
| 26 | 
    * encoder.  | 
|
| 27 | 
    */  | 
|
| 28 | 
    public static final int FLAG_RECORDABLE = 0x01;  | 
|
| 29 | 
     | 
|
| 30 | 
    /**  | 
|
| 31 | 
    * Constructor flag: ask for GLES3, fall back to GLES2 if not available. Without this  | 
|
| 32 | 
    * flag, GLES2 is used.  | 
|
| 33 | 
    */  | 
|
| 34 | 
    public static final int FLAG_TRY_GLES3 = 0x02;  | 
|
| 35 | 
     | 
|
| 36 | 
    // Android-specific extension.  | 
|
| 37 | 
    private static final int EGL_RECORDABLE_ANDROID = 0x3142;  | 
|
| 38 | 
     | 
|
| 39 | 
    private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;  | 
|
| 40 | 
    private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT;  | 
|
| 41 | 
    private EGLConfig mEGLConfig = null;  | 
|
| 42 | 
    private int mGlVersion = -1;  | 
|
| 43 | 
     | 
|
| 44 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 45 | 
    /**  | 
|
| 46 | 
    * Prepares EGL display and context.  | 
|
| 47 | 
    * <p>  | 
|
| 48 | 
    * Equivalent to EglCore(null, 0).  | 
|
| 49 | 
    */  | 
|
| 50 | 
      public EglCore() {
   | 
|
| 51 | 
    this(null, 0);  | 
|
| 52 | 
    }  | 
|
| 53 | 
     | 
|
| 54 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 55 | 
    /**  | 
|
| 56 | 
    * Prepares EGL display and context.  | 
|
| 57 | 
    * <p>  | 
|
| 58 | 
    * @param sharedContext The context to share, or null if sharing is not desired.  | 
|
| 59 | 
    * @param flags Configuration bit flags, e.g. FLAG_RECORDABLE.  | 
|
| 60 | 
    */  | 
|
| 61 | 
    public EglCore(EGLContext sharedContext, int flags)  | 
|
| 62 | 
        {
   | 
|
| 63 | 
    if (mEGLDisplay != EGL14.EGL_NO_DISPLAY)  | 
|
| 64 | 
          {
   | 
|
| 65 | 
          throw new RuntimeException("EGL already set up");
   | 
|
| 66 | 
    }  | 
|
| 67 | 
     | 
|
| 68 | 
    if (sharedContext == null)  | 
|
| 69 | 
          {
   | 
|
| 70 | 
    sharedContext = EGL14.EGL_NO_CONTEXT;  | 
|
| 71 | 
    }  | 
|
| 72 | 
     | 
|
| 73 | 
    mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);  | 
|
| 74 | 
     | 
|
| 75 | 
    if (mEGLDisplay == EGL14.EGL_NO_DISPLAY)  | 
|
| 76 | 
          {
   | 
|
| 77 | 
          throw new RuntimeException("unable to get EGL14 display");
   | 
|
| 78 | 
    }  | 
|
| 79 | 
     | 
|
| 80 | 
    int[] version = new int[2];  | 
|
| 81 | 
     | 
|
| 82 | 
    if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1))  | 
|
| 83 | 
          {
   | 
|
| 84 | 
    mEGLDisplay = null;  | 
|
| 85 | 
          throw new RuntimeException("unable to initialize EGL14");
   | 
|
| 86 | 
    }  | 
|
| 87 | 
     | 
|
| 88 | 
    // Try to get a GLES3 context, if requested.  | 
|
| 89 | 
    if ((flags & FLAG_TRY_GLES3) != 0)  | 
|
| 90 | 
          {
   | 
|
| 91 | 
    //Log.d(TAG, "Trying GLES 3");  | 
|
| 92 | 
    EGLConfig config = getConfig(flags, 3);  | 
|
| 93 | 
     | 
|
| 94 | 
    if (config != null)  | 
|
| 95 | 
            {
   | 
|
| 96 | 
            int[] attrib3_list =  { EGL14.EGL_CONTEXT_CLIENT_VERSION, 3, EGL14.EGL_NONE };
   | 
|
| 97 | 
    EGLContext context = EGL14.eglCreateContext(mEGLDisplay, config, sharedContext, attrib3_list, 0);  | 
|
| 98 | 
     | 
|
| 99 | 
    if (EGL14.eglGetError() == EGL14.EGL_SUCCESS)  | 
|
| 100 | 
              {
   | 
|
| 101 | 
    //Log.d(TAG, "Got GLES 3 config");  | 
|
| 102 | 
    mEGLConfig = config;  | 
|
| 103 | 
    mEGLContext = context;  | 
|
| 104 | 
    mGlVersion = 3;  | 
|
| 105 | 
    }  | 
|
| 106 | 
    }  | 
|
| 107 | 
    }  | 
|
| 108 | 
     | 
|
| 109 | 
    if (mEGLContext == EGL14.EGL_NO_CONTEXT)  | 
|
| 110 | 
          {  // GLES 2 only, or GLES 3 attempt failed
   | 
|
| 111 | 
    //Log.d(TAG, "Trying GLES 2");  | 
|
| 112 | 
    EGLConfig config = getConfig(flags, 2);  | 
|
| 113 | 
     | 
|
| 114 | 
    if (config == null)  | 
|
| 115 | 
            {
   | 
|
| 116 | 
            throw new RuntimeException("Unable to find a suitable EGLConfig");
   | 
|
| 117 | 
    }  | 
|
| 118 | 
          int[] attrib2_list = { EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE };
   | 
|
| 119 | 
    EGLContext context = EGL14.eglCreateContext(mEGLDisplay, config, sharedContext, attrib2_list, 0);  | 
|
| 120 | 
          checkEglError("eglCreateContext");
   | 
|
| 121 | 
    mEGLConfig = config;  | 
|
| 122 | 
    mEGLContext = context;  | 
|
| 123 | 
    mGlVersion = 2;  | 
|
| 124 | 
    }  | 
|
| 125 | 
     | 
|
| 126 | 
    // Confirm with query.  | 
|
| 127 | 
    int[] values = new int[1];  | 
|
| 128 | 
    EGL14.eglQueryContext(mEGLDisplay, mEGLContext, EGL14.EGL_CONTEXT_CLIENT_VERSION, values, 0);  | 
|
| 129 | 
     | 
|
| 130 | 
    Log.d(TAG, "EGLContext created, client version " + values[0]);  | 
|
| 131 | 
    }  | 
|
| 132 | 
     | 
|
| 133 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 134 | 
    /**  | 
|
| 135 | 
    * Finds a suitable EGLConfig.  | 
|
| 136 | 
    *  | 
|
| 137 | 
    * @param flags Bit flags from constructor.  | 
|
| 138 | 
    * @param version Must be 2 or 3.  | 
|
| 139 | 
    */  | 
|
| 140 | 
    private EGLConfig getConfig(int flags, int version)  | 
|
| 141 | 
        {
   | 
|
| 142 | 
    int renderableType = EGL14.EGL_OPENGL_ES2_BIT;  | 
|
| 143 | 
     | 
|
| 144 | 
    if (version >= 3)  | 
|
| 145 | 
          {
   | 
|
| 146 | 
    renderableType |= EGLExt.EGL_OPENGL_ES3_BIT_KHR;  | 
|
| 147 | 
    }  | 
|
| 148 | 
     | 
|
| 149 | 
    // The actual surface is generally RGBA or RGBX, so situationally omitting alpha  | 
|
| 150 | 
    // doesn't really help. It can also lead to a huge performance hit on glReadPixels()  | 
|
| 151 | 
    // when reading into a GL_RGBA buffer.  | 
|
| 152 | 
    int[] attribList =  | 
|
| 153 | 
                    {
   | 
|
| 154 | 
    EGL14.EGL_RED_SIZE, 8,  | 
|
| 155 | 
    EGL14.EGL_GREEN_SIZE, 8,  | 
|
| 156 | 
    EGL14.EGL_BLUE_SIZE, 8,  | 
|
| 157 | 
    EGL14.EGL_ALPHA_SIZE, 8,  | 
|
| 158 | 
    //EGL14.EGL_DEPTH_SIZE, 16,  | 
|
| 159 | 
    //EGL14.EGL_STENCIL_SIZE, 8,  | 
|
| 160 | 
    EGL14.EGL_RENDERABLE_TYPE, renderableType,  | 
|
| 161 | 
    EGL14.EGL_NONE, 0, // placeholder for recordable [@-3]  | 
|
| 162 | 
    EGL14.EGL_NONE  | 
|
| 163 | 
    };  | 
|
| 164 | 
     | 
|
| 165 | 
    if ((flags & FLAG_RECORDABLE) != 0)  | 
|
| 166 | 
          {
   | 
|
| 167 | 
    attribList[attribList.length - 3] = EGL_RECORDABLE_ANDROID;  | 
|
| 168 | 
    attribList[attribList.length - 2] = 1;  | 
|
| 169 | 
    }  | 
|
| 170 | 
     | 
|
| 171 | 
    EGLConfig[] configs = new EGLConfig[1];  | 
|
| 172 | 
    int[] numConfigs = new int[1];  | 
|
| 173 | 
     | 
|
| 174 | 
    if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length, numConfigs, 0))  | 
|
| 175 | 
          {
   | 
|
| 176 | 
    Log.w(TAG, "unable to find RGB8888 / " + version + " EGLConfig");  | 
|
| 177 | 
    return null;  | 
|
| 178 | 
    }  | 
|
| 179 | 
     | 
|
| 180 | 
    return configs[0];  | 
|
| 181 | 
    }  | 
|
| 182 | 
     | 
|
| 183 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 184 | 
    /**  | 
|
| 185 | 
    * Discards all resources held by this class, notably the EGL context. This must be  | 
|
| 186 | 
    * called from the thread where the context was created.  | 
|
| 187 | 
    * <p>  | 
|
| 188 | 
    * On completion, no context will be current.  | 
|
| 189 | 
    */  | 
|
| 190 | 
    public void release()  | 
|
| 191 | 
        {
   | 
|
| 192 | 
    if (mEGLDisplay != EGL14.EGL_NO_DISPLAY)  | 
|
| 193 | 
          {
   | 
|
| 194 | 
    // Android is unusual in that it uses a reference-counted EGLDisplay. So for  | 
|
| 195 | 
    // every eglInitialize() we need an eglTerminate().  | 
|
| 196 | 
    EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);  | 
|
| 197 | 
    EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);  | 
|
| 198 | 
    EGL14.eglReleaseThread();  | 
|
| 199 | 
    EGL14.eglTerminate(mEGLDisplay);  | 
|
| 200 | 
    }  | 
|
| 201 | 
     | 
|
| 202 | 
    mEGLDisplay = EGL14.EGL_NO_DISPLAY;  | 
|
| 203 | 
    mEGLContext = EGL14.EGL_NO_CONTEXT;  | 
|
| 204 | 
    mEGLConfig = null;  | 
|
| 205 | 
    }  | 
|
| 206 | 
     | 
|
| 207 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 208 | 
    @Override  | 
|
| 209 | 
    protected void finalize() throws Throwable  | 
|
| 210 | 
        {
   | 
|
| 211 | 
    try  | 
|
| 212 | 
          {
   | 
|
| 213 | 
    if (mEGLDisplay != EGL14.EGL_NO_DISPLAY)  | 
|
| 214 | 
            {
   | 
|
| 215 | 
    // We're limited here -- finalizers don't run on the thread that holds  | 
|
| 216 | 
    // the EGL state, so if a surface or context is still current on another  | 
|
| 217 | 
    // thread we can't fully release it here. Exceptions thrown from here  | 
|
| 218 | 
    // are quietly discarded. Complain in the log file.  | 
|
| 219 | 
    Log.w(TAG, "WARNING: EglCore was not explicitly released -- state may be leaked");  | 
|
| 220 | 
    release();  | 
|
| 221 | 
    }  | 
|
| 222 | 
    }  | 
|
| 223 | 
    finally  | 
|
| 224 | 
          {
   | 
|
| 225 | 
    super.finalize();  | 
|
| 226 | 
    }  | 
|
| 227 | 
    }  | 
|
| 228 | 
     | 
|
| 229 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 230 | 
    /**  | 
|
| 231 | 
    * Destroys the specified surface. Note the EGLSurface won't actually be destroyed if it's  | 
|
| 232 | 
    * still current in a context.  | 
|
| 233 | 
    */  | 
|
| 234 | 
    public void releaseSurface(EGLSurface eglSurface)  | 
|
| 235 | 
        {
   | 
|
| 236 | 
    EGL14.eglDestroySurface(mEGLDisplay, eglSurface);  | 
|
| 237 | 
    }  | 
|
| 238 | 
     | 
|
| 239 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 240 | 
    /**  | 
|
| 241 | 
    * Creates an EGL surface associated with a Surface.  | 
|
| 242 | 
    * <p>  | 
|
| 243 | 
    * If this is destined for MediaCodec, the EGLConfig should have the "recordable" attribute.  | 
|
| 244 | 
    */  | 
|
| 245 | 
    public EGLSurface createWindowSurface(Object surface)  | 
|
| 246 | 
        {
   | 
|
| 247 | 
    if (!(surface instanceof Surface) && !(surface instanceof SurfaceTexture))  | 
|
| 248 | 
          {
   | 
|
| 249 | 
          throw new RuntimeException("invalid surface: " + surface);
   | 
|
| 250 | 
    }  | 
|
| 251 | 
     | 
|
| 252 | 
    // Create a window surface, and attach it to the Surface we received.  | 
|
| 253 | 
        int[] surfaceAttribs = { EGL14.EGL_NONE };
   | 
|
| 254 | 
    EGLSurface eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surface, surfaceAttribs, 0);  | 
|
| 255 | 
        checkEglError("eglCreateWindowSurface");
   | 
|
| 256 | 
     | 
|
| 257 | 
    if (eglSurface == null)  | 
|
| 258 | 
          {
   | 
|
| 259 | 
          throw new RuntimeException("surface was null");
   | 
|
| 260 | 
    }  | 
|
| 261 | 
    return eglSurface;  | 
|
| 262 | 
    }  | 
|
| 263 | 
     | 
|
| 264 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 265 | 
    /**  | 
|
| 266 | 
    * Makes our EGL context current, using the supplied surface for both "draw" and "read".  | 
|
| 267 | 
    */  | 
|
| 268 | 
    public void makeCurrent(EGLSurface eglSurface)  | 
|
| 269 | 
        {
   | 
|
| 270 | 
    if (mEGLDisplay == EGL14.EGL_NO_DISPLAY)  | 
|
| 271 | 
          {
   | 
|
| 272 | 
    // called makeCurrent() before create?  | 
|
| 273 | 
    Log.d(TAG, "NOTE: makeCurrent w/o display");  | 
|
| 274 | 
    }  | 
|
| 275 | 
    if (!EGL14.eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext))  | 
|
| 276 | 
          {
   | 
|
| 277 | 
          throw new RuntimeException("eglMakeCurrent failed");
   | 
|
| 278 | 
    }  | 
|
| 279 | 
    }  | 
|
| 280 | 
     | 
|
| 281 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 282 | 
    /**  | 
|
| 283 | 
    * Makes no context current.  | 
|
| 284 | 
    */  | 
|
| 285 | 
    public void makeNothingCurrent()  | 
|
| 286 | 
        {
   | 
|
| 287 | 
    if (!EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT))  | 
|
| 288 | 
          {
   | 
|
| 289 | 
          throw new RuntimeException("eglMakeCurrent failed");
   | 
|
| 290 | 
    }  | 
|
| 291 | 
    }  | 
|
| 292 | 
     | 
|
| 293 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 294 | 
    /**  | 
|
| 295 | 
    * Returns the GLES version this context is configured for (currently 2 or 3).  | 
|
| 296 | 
    */  | 
|
| 297 | 
    public int getGlVersion()  | 
|
| 298 | 
        {
   | 
|
| 299 | 
    return mGlVersion;  | 
|
| 300 | 
    }  | 
|
| 301 | 
     | 
|
| 302 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 303 | 
    /**  | 
|
| 304 | 
    * Calls eglSwapBuffers. Use this to "publish" the current frame.  | 
|
| 305 | 
    *  | 
|
| 306 | 
    * @return false on failure  | 
|
| 307 | 
    */  | 
|
| 308 | 
    public boolean swapBuffers(EGLSurface eglSurface)  | 
|
| 309 | 
        {
   | 
|
| 310 | 
    return EGL14.eglSwapBuffers(mEGLDisplay, eglSurface);  | 
|
| 311 | 
    }  | 
|
| 312 | 
     | 
|
| 313 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 314 | 
    /**  | 
|
| 315 | 
    * Checks for EGL errors. Throws an exception if an error has been raised.  | 
|
| 316 | 
    */  | 
|
| 317 | 
    private void checkEglError(String msg)  | 
|
| 318 | 
        {
   | 
|
| 319 | 
    int error;  | 
|
| 320 | 
     | 
|
| 321 | 
    if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS)  | 
|
| 322 | 
          {
   | 
|
| 323 | 
    throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error));  | 
|
| 324 | 
    }  | 
|
| 325 | 
    }  | 
|
| 326 | 
    }  | 
|
| 327 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| src/main/java/org/distorted/examples/plainmonalisa/PlainMonaLisaActivity.java | ||
|---|---|---|
| 1 | 
    package org.distorted.examples.plainmonalisa;  | 
|
| 2 | 
     | 
|
| 3 | 
    import org.distorted.library.Distorted;  | 
|
| 4 | 
     | 
|
| 5 | 
    import android.app.Activity;  | 
|
| 6 | 
    import android.os.Bundle;  | 
|
| 7 | 
     | 
|
| 8 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 9 | 
     | 
|
| 10 | 
    public class PlainMonaLisaActivity extends Activity  | 
|
| 11 | 
    {
   | 
|
| 12 | 
    private PlainMonaLisaSurfaceView mView;  | 
|
| 13 | 
     | 
|
| 14 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 15 | 
     | 
|
| 16 | 
    @Override  | 
|
| 17 | 
    protected void onCreate(Bundle icicle)  | 
|
| 18 | 
          {
   | 
|
| 19 | 
    super.onCreate(icicle);  | 
|
| 20 | 
    mView = new PlainMonaLisaSurfaceView(this);  | 
|
| 21 | 
    setContentView(mView);  | 
|
| 22 | 
    }  | 
|
| 23 | 
     | 
|
| 24 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 25 | 
     | 
|
| 26 | 
    @Override  | 
|
| 27 | 
    protected void onPause()  | 
|
| 28 | 
          {
   | 
|
| 29 | 
    mView.onPause();  | 
|
| 30 | 
    super.onPause();  | 
|
| 31 | 
    }  | 
|
| 32 | 
     | 
|
| 33 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 34 | 
     | 
|
| 35 | 
    @Override  | 
|
| 36 | 
    protected void onResume()  | 
|
| 37 | 
          {
   | 
|
| 38 | 
    super.onResume();  | 
|
| 39 | 
    mView.onResume();  | 
|
| 40 | 
    }  | 
|
| 41 | 
     | 
|
| 42 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 43 | 
     | 
|
| 44 | 
    @Override  | 
|
| 45 | 
    protected void onDestroy()  | 
|
| 46 | 
          {
   | 
|
| 47 | 
    Distorted.onDestroy();  | 
|
| 48 | 
    super.onDestroy();  | 
|
| 49 | 
    }  | 
|
| 50 | 
     | 
|
| 51 | 
    }  | 
|
| src/main/java/org/distorted/examples/plainmonalisa/PlainMonaLisaSurfaceView.java | ||
|---|---|---|
| 1 | 
    package org.distorted.examples.plainmonalisa;  | 
|
| 2 | 
     | 
|
| 3 | 
    import android.content.Context;  | 
|
| 4 | 
    import android.view.Choreographer;  | 
|
| 5 | 
    import android.view.SurfaceView;  | 
|
| 6 | 
    import android.view.SurfaceHolder;  | 
|
| 7 | 
    import android.util.Log;  | 
|
| 8 | 
     | 
|
| 9 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 10 | 
     | 
|
| 11 | 
    class PlainMonaLisaSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Choreographer.FrameCallback  | 
|
| 12 | 
      {
   | 
|
| 13 | 
    private static final String TAG = "MonaLisaSurface";  | 
|
| 14 | 
    private RenderThread mRenderThread;  | 
|
| 15 | 
     | 
|
| 16 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 17 | 
     | 
|
| 18 | 
    public PlainMonaLisaSurfaceView(Context context)  | 
|
| 19 | 
        {
   | 
|
| 20 | 
    super(context);  | 
|
| 21 | 
    getHolder().addCallback(this);  | 
|
| 22 | 
    }  | 
|
| 23 | 
     | 
|
| 24 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 25 | 
     | 
|
| 26 | 
    public void surfaceCreated(SurfaceHolder holder)  | 
|
| 27 | 
        {
   | 
|
| 28 | 
    Log.d(TAG, "surfaceCreated holder=" + holder);  | 
|
| 29 | 
     | 
|
| 30 | 
    mRenderThread = new RenderThread(holder, this);  | 
|
| 31 | 
        mRenderThread.setName("GL render");
   | 
|
| 32 | 
    mRenderThread.start();  | 
|
| 33 | 
    mRenderThread.waitUntilReady();  | 
|
| 34 | 
     | 
|
| 35 | 
    RenderHandler rh = mRenderThread.getHandler();  | 
|
| 36 | 
     | 
|
| 37 | 
    if (rh != null)  | 
|
| 38 | 
          {
   | 
|
| 39 | 
    rh.sendSurfaceCreated();  | 
|
| 40 | 
    }  | 
|
| 41 | 
     | 
|
| 42 | 
    Choreographer.getInstance().postFrameCallback(this);  | 
|
| 43 | 
    }  | 
|
| 44 | 
     | 
|
| 45 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 46 | 
     | 
|
| 47 | 
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)  | 
|
| 48 | 
        {
   | 
|
| 49 | 
    Log.d(TAG, "surfaceChanged fmt=" + format + " size=" + width + "x" + height +" holder=" + holder);  | 
|
| 50 | 
     | 
|
| 51 | 
    RenderHandler rh = mRenderThread.getHandler();  | 
|
| 52 | 
     | 
|
| 53 | 
    if (rh != null)  | 
|
| 54 | 
          {
   | 
|
| 55 | 
    rh.sendSurfaceChanged(format, width, height);  | 
|
| 56 | 
    }  | 
|
| 57 | 
    }  | 
|
| 58 | 
     | 
|
| 59 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 60 | 
     | 
|
| 61 | 
    public void surfaceDestroyed(SurfaceHolder holder)  | 
|
| 62 | 
        {
   | 
|
| 63 | 
    Log.d(TAG, "surfaceDestroyed holder=" + holder);  | 
|
| 64 | 
     | 
|
| 65 | 
    // We need to wait for the render thread to shut down before continuing because we  | 
|
| 66 | 
    // don't want the Surface to disappear out from under it mid-render. The frame  | 
|
| 67 | 
    // notifications will have been stopped back in onPause(), but there might have  | 
|
| 68 | 
    // been one in progress.  | 
|
| 69 | 
     | 
|
| 70 | 
    RenderHandler rh = mRenderThread.getHandler();  | 
|
| 71 | 
     | 
|
| 72 | 
    if (rh != null)  | 
|
| 73 | 
          {
   | 
|
| 74 | 
    rh.sendShutdown();  | 
|
| 75 | 
     | 
|
| 76 | 
    try  | 
|
| 77 | 
            {
   | 
|
| 78 | 
    mRenderThread.join();  | 
|
| 79 | 
    }  | 
|
| 80 | 
    catch (InterruptedException ie)  | 
|
| 81 | 
            {
   | 
|
| 82 | 
            throw new RuntimeException("join was interrupted", ie);
   | 
|
| 83 | 
    }  | 
|
| 84 | 
    }  | 
|
| 85 | 
    mRenderThread = null;  | 
|
| 86 | 
     | 
|
| 87 | 
    Log.d(TAG, "surfaceDestroyed complete");  | 
|
| 88 | 
    }  | 
|
| 89 | 
     | 
|
| 90 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 91 | 
     | 
|
| 92 | 
    public void onPause()  | 
|
| 93 | 
        {
   | 
|
| 94 | 
    Log.d(TAG, "onPause unhooking choreographer");  | 
|
| 95 | 
    Choreographer.getInstance().removeFrameCallback(this);  | 
|
| 96 | 
    }  | 
|
| 97 | 
     | 
|
| 98 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 99 | 
     | 
|
| 100 | 
    public void onResume()  | 
|
| 101 | 
        {
   | 
|
| 102 | 
    if (mRenderThread != null)  | 
|
| 103 | 
          {
   | 
|
| 104 | 
    Log.d(TAG, "onResume re-hooking choreographer");  | 
|
| 105 | 
    Choreographer.getInstance().postFrameCallback(this);  | 
|
| 106 | 
    }  | 
|
| 107 | 
    }  | 
|
| 108 | 
     | 
|
| 109 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 110 | 
     | 
|
| 111 | 
    @Override  | 
|
| 112 | 
    public void doFrame(long frameTimeNanos)  | 
|
| 113 | 
        {
   | 
|
| 114 | 
    RenderHandler rh = mRenderThread.getHandler();  | 
|
| 115 | 
     | 
|
| 116 | 
    if (rh != null)  | 
|
| 117 | 
          {
   | 
|
| 118 | 
    Choreographer.getInstance().postFrameCallback(this);  | 
|
| 119 | 
    rh.sendDoFrame(frameTimeNanos);  | 
|
| 120 | 
    }  | 
|
| 121 | 
    }  | 
|
| 122 | 
    }  | 
|
| 123 | 
     | 
|
| 124 | 
     | 
|
| src/main/java/org/distorted/examples/plainmonalisa/RenderHandler.java | ||
|---|---|---|
| 1 | 
    package org.distorted.examples.plainmonalisa;  | 
|
| 2 | 
     | 
|
| 3 | 
    import android.os.Handler;  | 
|
| 4 | 
    import android.os.Message;  | 
|
| 5 | 
    import android.util.Log;  | 
|
| 6 | 
     | 
|
| 7 | 
    import java.lang.ref.WeakReference;  | 
|
| 8 | 
     | 
|
| 9 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 10 | 
     | 
|
| 11 | 
    /**  | 
|
| 12 | 
    * Handler for RenderThread. Used for messages sent from the UI thread to the render thread.  | 
|
| 13 | 
    * <p>  | 
|
| 14 | 
    * The object is created on the render thread, and the various "send" methods are called  | 
|
| 15 | 
    * from the UI thread.  | 
|
| 16 | 
    */  | 
|
| 17 | 
    public class RenderHandler extends Handler  | 
|
| 18 | 
      {
   | 
|
| 19 | 
    private static final String TAG = "RenderHandler";  | 
|
| 20 | 
     | 
|
| 21 | 
    private static final int MSG_SURFACE_CREATED = 0;  | 
|
| 22 | 
    private static final int MSG_SURFACE_CHANGED = 1;  | 
|
| 23 | 
    private static final int MSG_DO_FRAME = 2;  | 
|
| 24 | 
    private static final int MSG_SHUTDOWN = 4;  | 
|
| 25 | 
     | 
|
| 26 | 
    // This shouldn't need to be a weak ref, since we'll go away when the Looper quits,  | 
|
| 27 | 
    // but no real harm in it.  | 
|
| 28 | 
    private WeakReference<RenderThread> mWeakRenderThread;  | 
|
| 29 | 
     | 
|
| 30 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 31 | 
    /**  | 
|
| 32 | 
    * Call from render thread.  | 
|
| 33 | 
    */  | 
|
| 34 | 
    public RenderHandler(RenderThread rt)  | 
|
| 35 | 
          {
   | 
|
| 36 | 
    mWeakRenderThread = new WeakReference<>(rt);  | 
|
| 37 | 
    }  | 
|
| 38 | 
     | 
|
| 39 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 40 | 
    /**  | 
|
| 41 | 
    * Sends the "surface created" message.  | 
|
| 42 | 
    * <p>  | 
|
| 43 | 
    * Call from UI thread.  | 
|
| 44 | 
    */  | 
|
| 45 | 
    public void sendSurfaceCreated()  | 
|
| 46 | 
        {
   | 
|
| 47 | 
    sendMessage(obtainMessage(RenderHandler.MSG_SURFACE_CREATED));  | 
|
| 48 | 
    }  | 
|
| 49 | 
     | 
|
| 50 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 51 | 
    /**  | 
|
| 52 | 
    * Sends the "surface changed" message, forwarding what we got from the SurfaceHolder.  | 
|
| 53 | 
    * <p>  | 
|
| 54 | 
    * Call from UI thread.  | 
|
| 55 | 
    */  | 
|
| 56 | 
      public void sendSurfaceChanged(@SuppressWarnings("unused") int format, int width, int height)
   | 
|
| 57 | 
        {
   | 
|
| 58 | 
    sendMessage(obtainMessage(RenderHandler.MSG_SURFACE_CHANGED, width, height));  | 
|
| 59 | 
    }  | 
|
| 60 | 
     | 
|
| 61 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 62 | 
    /**  | 
|
| 63 | 
    * Sends the "do frame" message, forwarding the Choreographer event.  | 
|
| 64 | 
    * <p>  | 
|
| 65 | 
    * Call from UI thread.  | 
|
| 66 | 
    */  | 
|
| 67 | 
    public void sendDoFrame(long frameTimeNanos)  | 
|
| 68 | 
        {
   | 
|
| 69 | 
    sendMessage(obtainMessage(RenderHandler.MSG_DO_FRAME, (int) (frameTimeNanos >> 32), (int) frameTimeNanos));  | 
|
| 70 | 
    }  | 
|
| 71 | 
     | 
|
| 72 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 73 | 
    /**  | 
|
| 74 | 
    * Sends the "shutdown" message, which tells the render thread to halt.  | 
|
| 75 | 
    * <p>  | 
|
| 76 | 
    * Call from UI thread.  | 
|
| 77 | 
    */  | 
|
| 78 | 
    public void sendShutdown()  | 
|
| 79 | 
          {
   | 
|
| 80 | 
    sendMessage(obtainMessage(RenderHandler.MSG_SHUTDOWN));  | 
|
| 81 | 
    }  | 
|
| 82 | 
     | 
|
| 83 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 84 | 
    @Override // runs on RenderThread  | 
|
| 85 | 
    public void handleMessage(Message msg)  | 
|
| 86 | 
        {
   | 
|
| 87 | 
    int what = msg.what;  | 
|
| 88 | 
    //Log.d(TAG, "RenderHandler [" + this + "]: what=" + what);  | 
|
| 89 | 
    RenderThread renderThread = mWeakRenderThread.get();  | 
|
| 90 | 
     | 
|
| 91 | 
    if (renderThread == null)  | 
|
| 92 | 
          {
   | 
|
| 93 | 
    Log.w(TAG, "RenderHandler.handleMessage: weak ref is null");  | 
|
| 94 | 
    return;  | 
|
| 95 | 
    }  | 
|
| 96 | 
     | 
|
| 97 | 
    switch (what)  | 
|
| 98 | 
          {
   | 
|
| 99 | 
    case MSG_SURFACE_CREATED: renderThread.surfaceCreated();  | 
|
| 100 | 
    break;  | 
|
| 101 | 
    case MSG_SURFACE_CHANGED: renderThread.surfaceChanged(msg.arg1, msg.arg2);  | 
|
| 102 | 
    break;  | 
|
| 103 | 
    case MSG_DO_FRAME: long timestamp = (((long) msg.arg1) << 32) | (((long) msg.arg2) & 0xffffffffL);  | 
|
| 104 | 
    renderThread.doFrame(timestamp);  | 
|
| 105 | 
    break;  | 
|
| 106 | 
    case MSG_SHUTDOWN: renderThread.shutdown();  | 
|
| 107 | 
    break;  | 
|
| 108 | 
          default:                  throw new RuntimeException("unknown message " + what);
   | 
|
| 109 | 
    }  | 
|
| 110 | 
    }  | 
|
| 111 | 
    }  | 
|
| 112 | 
     | 
|
| 113 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| src/main/java/org/distorted/examples/plainmonalisa/RenderThread.java | ||
|---|---|---|
| 1 | 
    package org.distorted.examples.plainmonalisa;  | 
|
| 2 | 
     | 
|
| 3 | 
    import android.graphics.Bitmap;  | 
|
| 4 | 
    import android.graphics.BitmapFactory;  | 
|
| 5 | 
    import android.opengl.EGL14;  | 
|
| 6 | 
    import android.opengl.EGLSurface;  | 
|
| 7 | 
    import android.opengl.GLES20;  | 
|
| 8 | 
    import android.os.Looper;  | 
|
| 9 | 
    import android.os.Trace;  | 
|
| 10 | 
    import android.util.Log;  | 
|
| 11 | 
    import android.view.Surface;  | 
|
| 12 | 
    import android.view.SurfaceHolder;  | 
|
| 13 | 
    import android.view.SurfaceView;  | 
|
| 14 | 
     | 
|
| 15 | 
    import org.distorted.library.Distorted;  | 
|
| 16 | 
    import org.distorted.library.DistortedBitmap;  | 
|
| 17 | 
    import org.distorted.library.Float2D;  | 
|
| 18 | 
    import org.distorted.library.Float3D;  | 
|
| 19 | 
    import org.distorted.library.Float4D;  | 
|
| 20 | 
    import org.distorted.examples.R;  | 
|
| 21 | 
     | 
|
| 22 | 
    import java.io.IOException;  | 
|
| 23 | 
    import java.io.InputStream;  | 
|
| 24 | 
     | 
|
| 25 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 26 | 
    /**  | 
|
| 27 | 
    * This class handles all OpenGL rendering.  | 
|
| 28 | 
    * <p>  | 
|
| 29 | 
    * Start the render thread after the Surface has been created.  | 
|
| 30 | 
    */  | 
|
| 31 | 
    public class RenderThread extends Thread  | 
|
| 32 | 
      {
   | 
|
| 33 | 
    private static final String TAG = "RenderThread";  | 
|
| 34 | 
     | 
|
| 35 | 
    // Object must be created on render thread to get correct Looper, but is used from  | 
|
| 36 | 
    // UI thread, so we need to declare it volatile to ensure the UI thread sees a fully  | 
|
| 37 | 
    // constructed object.  | 
|
| 38 | 
    private volatile RenderHandler mHandler;  | 
|
| 39 | 
     | 
|
| 40 | 
    // Used to wait for the thread to start.  | 
|
| 41 | 
    private Object mStartLock = new Object();  | 
|
| 42 | 
    private boolean mReady = false;  | 
|
| 43 | 
    private volatile SurfaceHolder mSurfaceHolder; // may be updated by UI thread  | 
|
| 44 | 
    private EglCore eglCore;  | 
|
| 45 | 
    private EGLSurface eglSurface;  | 
|
| 46 | 
     | 
|
| 47 | 
    private DistortedBitmap monaLisa;  | 
|
| 48 | 
    private int bmpHeight, bmpWidth;  | 
|
| 49 | 
     | 
|
| 50 | 
    private Float2D pLeft, pRight;  | 
|
| 51 | 
    private Float4D rLeft, rRight;  | 
|
| 52 | 
    private Float3D vLeft, vRight;  | 
|
| 53 | 
     | 
|
| 54 | 
    SurfaceView mView;  | 
|
| 55 | 
     | 
|
| 56 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 57 | 
    /**  | 
|
| 58 | 
    * Pass in the SurfaceView's SurfaceHolder. Note the Surface may not yet exist.  | 
|
| 59 | 
    */  | 
|
| 60 | 
    public RenderThread(SurfaceHolder holder, SurfaceView view)  | 
|
| 61 | 
        {
   | 
|
| 62 | 
    mSurfaceHolder = holder;  | 
|
| 63 | 
    mView = view;  | 
|
| 64 | 
     | 
|
| 65 | 
    pLeft = new Float2D( 90, 258);  | 
|
| 66 | 
    pRight= new Float2D(176, 255);  | 
|
| 67 | 
     | 
|
| 68 | 
    rLeft = new Float4D(-10,-10,25,25);  | 
|
| 69 | 
    rRight= new Float4D( 10, -5,25,25);  | 
|
| 70 | 
     | 
|
| 71 | 
    vLeft = new Float3D(-20,-20,0);  | 
|
| 72 | 
    vRight= new Float3D( 20,-10,0);  | 
|
| 73 | 
    }  | 
|
| 74 | 
     | 
|
| 75 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 76 | 
    /**  | 
|
| 77 | 
    * Thread entry point.  | 
|
| 78 | 
    * <p>  | 
|
| 79 | 
    * The thread should not be started until the Surface associated with the SurfaceHolder  | 
|
| 80 | 
    * has been created. That way we don't have to wait for a separate "surface created"  | 
|
| 81 | 
    * message to arrive.  | 
|
| 82 | 
    */  | 
|
| 83 | 
    @Override  | 
|
| 84 | 
    public void run()  | 
|
| 85 | 
        {
   | 
|
| 86 | 
    Looper.prepare();  | 
|
| 87 | 
    mHandler = new RenderHandler(this);  | 
|
| 88 | 
    eglCore = new EglCore(null, EglCore.FLAG_RECORDABLE | EglCore.FLAG_TRY_GLES3);  | 
|
| 89 | 
     | 
|
| 90 | 
    synchronized (mStartLock)  | 
|
| 91 | 
          {
   | 
|
| 92 | 
    mReady = true;  | 
|
| 93 | 
    mStartLock.notify(); // signal waitUntilReady()  | 
|
| 94 | 
    }  | 
|
| 95 | 
     | 
|
| 96 | 
    Looper.loop();  | 
|
| 97 | 
    Log.d(TAG, "looper quit");  | 
|
| 98 | 
     | 
|
| 99 | 
        checkGlError("releaseGl start");
   | 
|
| 100 | 
     | 
|
| 101 | 
    if (eglSurface != null)  | 
|
| 102 | 
          {
   | 
|
| 103 | 
    eglCore.releaseSurface(eglSurface);  | 
|
| 104 | 
    eglSurface = EGL14.EGL_NO_SURFACE;  | 
|
| 105 | 
    }  | 
|
| 106 | 
     | 
|
| 107 | 
        checkGlError("releaseGl done");
   | 
|
| 108 | 
     | 
|
| 109 | 
    eglCore.makeNothingCurrent();  | 
|
| 110 | 
    eglCore.release();  | 
|
| 111 | 
     | 
|
| 112 | 
    synchronized (mStartLock)  | 
|
| 113 | 
          {
   | 
|
| 114 | 
    mReady = false;  | 
|
| 115 | 
    }  | 
|
| 116 | 
    }  | 
|
| 117 | 
     | 
|
| 118 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 119 | 
    /**  | 
|
| 120 | 
    * Waits until the render thread is ready to receive messages.  | 
|
| 121 | 
    * <p>  | 
|
| 122 | 
    * Call from the UI thread.  | 
|
| 123 | 
    */  | 
|
| 124 | 
    public void waitUntilReady()  | 
|
| 125 | 
        {
   | 
|
| 126 | 
    synchronized (mStartLock)  | 
|
| 127 | 
          {
   | 
|
| 128 | 
    while (!mReady)  | 
|
| 129 | 
            {
   | 
|
| 130 | 
    try  | 
|
| 131 | 
              {
   | 
|
| 132 | 
    mStartLock.wait();  | 
|
| 133 | 
    }  | 
|
| 134 | 
            catch (InterruptedException ie) { /* not expected */ }
   | 
|
| 135 | 
    }  | 
|
| 136 | 
    }  | 
|
| 137 | 
    }  | 
|
| 138 | 
     | 
|
| 139 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 140 | 
    /**  | 
|
| 141 | 
    * Shuts everything down.  | 
|
| 142 | 
    */  | 
|
| 143 | 
    void shutdown()  | 
|
| 144 | 
        {
   | 
|
| 145 | 
    Log.d(TAG, "shutdown");  | 
|
| 146 | 
    Looper.myLooper().quit();  | 
|
| 147 | 
    }  | 
|
| 148 | 
     | 
|
| 149 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 150 | 
    /**  | 
|
| 151 | 
    * Returns the render thread's Handler. This may be called from any thread.  | 
|
| 152 | 
    */  | 
|
| 153 | 
    public RenderHandler getHandler()  | 
|
| 154 | 
          {
   | 
|
| 155 | 
    return mHandler;  | 
|
| 156 | 
    }  | 
|
| 157 | 
     | 
|
| 158 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 159 | 
    /**  | 
|
| 160 | 
    * Prepares the surface.  | 
|
| 161 | 
    */  | 
|
| 162 | 
    void surfaceCreated()  | 
|
| 163 | 
        {
   | 
|
| 164 | 
    Surface surface = mSurfaceHolder.getSurface();  | 
|
| 165 | 
     | 
|
| 166 | 
    eglSurface = eglCore.createWindowSurface(surface);  | 
|
| 167 | 
    eglCore.makeCurrent(eglSurface);  | 
|
| 168 | 
     | 
|
| 169 | 
    InputStream is = mView.getContext().getResources().openRawResource(R.raw.monalisa);  | 
|
| 170 | 
    Bitmap bmp;  | 
|
| 171 | 
     | 
|
| 172 | 
    try  | 
|
| 173 | 
          {
   | 
|
| 174 | 
    bmp = BitmapFactory.decodeStream(is);  | 
|
| 175 | 
    }  | 
|
| 176 | 
    finally  | 
|
| 177 | 
          {
   | 
|
| 178 | 
    try  | 
|
| 179 | 
            {
   | 
|
| 180 | 
    is.close();  | 
|
| 181 | 
    }  | 
|
| 182 | 
          catch(IOException io) {}
   | 
|
| 183 | 
    }  | 
|
| 184 | 
     | 
|
| 185 | 
    monaLisa = new DistortedBitmap(bmp, 10);  | 
|
| 186 | 
    monaLisa.distort( vLeft, rLeft , pLeft, 1000, 0);  | 
|
| 187 | 
    monaLisa.distort(vRight, rRight, pRight,1000, 0);  | 
|
| 188 | 
     | 
|
| 189 | 
    bmpHeight = bmp.getHeight();  | 
|
| 190 | 
    bmpWidth = bmp.getWidth();  | 
|
| 191 | 
     | 
|
| 192 | 
    try  | 
|
| 193 | 
          {
   | 
|
| 194 | 
    Distorted.onSurfaceCreated(mView.getContext());  | 
|
| 195 | 
    }  | 
|
| 196 | 
    catch(Exception ex)  | 
|
| 197 | 
          {
   | 
|
| 198 | 
          Log.e("MonaLisa", ex.getMessage() );
   | 
|
| 199 | 
    }  | 
|
| 200 | 
    }  | 
|
| 201 | 
     | 
|
| 202 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 203 | 
     | 
|
| 204 | 
    void surfaceChanged(int width, int height)  | 
|
| 205 | 
        {
   | 
|
| 206 | 
    Log.d(TAG, "surfaceChanged " + width + "x" + height);  | 
|
| 207 | 
     | 
|
| 208 | 
    monaLisa.abortAllEffects(Distorted.TYPE_MATR);  | 
|
| 209 | 
     | 
|
| 210 | 
    if( bmpHeight/bmpWidth > height/width )  | 
|
| 211 | 
          {
   | 
|
| 212 | 
    int w = (height*bmpWidth)/bmpHeight;  | 
|
| 213 | 
    monaLisa.move((width-w)/2 ,0, 0);  | 
|
| 214 | 
    monaLisa.scale((float)height/bmpHeight);  | 
|
| 215 | 
    }  | 
|
| 216 | 
    else  | 
|
| 217 | 
          {
   | 
|
| 218 | 
    int h = (width*bmpHeight)/bmpWidth;  | 
|
| 219 | 
    monaLisa.move(0 ,(height-h)/2, 0);  | 
|
| 220 | 
    monaLisa.scale((float)width/bmpWidth);  | 
|
| 221 | 
    }  | 
|
| 222 | 
     | 
|
| 223 | 
    Distorted.onSurfaceChanged(width, height);  | 
|
| 224 | 
    }  | 
|
| 225 | 
     | 
|
| 226 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 227 | 
     | 
|
| 228 | 
    public void doFrame(long frameTimeNs)  | 
|
| 229 | 
        {
   | 
|
| 230 | 
        Trace.beginSection("doFrame draw");
   | 
|
| 231 | 
    eglCore.makeCurrent(eglSurface);  | 
|
| 232 | 
     | 
|
| 233 | 
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);  | 
|
| 234 | 
    GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);  | 
|
| 235 | 
    monaLisa.draw(System.currentTimeMillis());  | 
|
| 236 | 
     | 
|
| 237 | 
    eglCore.swapBuffers(eglSurface);  | 
|
| 238 | 
    Trace.endSection();  | 
|
| 239 | 
    }  | 
|
| 240 | 
     | 
|
| 241 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| 242 | 
     | 
|
| 243 | 
    public static void checkGlError(String op)  | 
|
| 244 | 
        {
   | 
|
| 245 | 
    int error = GLES20.glGetError();  | 
|
| 246 | 
     | 
|
| 247 | 
    if (error != GLES20.GL_NO_ERROR)  | 
|
| 248 | 
          {
   | 
|
| 249 | 
    String msg = op + ": glError 0x" + Integer.toHexString(error);  | 
|
| 250 | 
    Log.e(TAG, msg);  | 
|
| 251 | 
    throw new RuntimeException(msg);  | 
|
| 252 | 
    }  | 
|
| 253 | 
    }  | 
|
| 254 | 
    }  | 
|
| 255 | 
    ///////////////////////////////////////////////////////////////////////////////////////////////////  | 
|
| src/main/res/values/strings.xml | ||
|---|---|---|
| 80 | 80 | 
    <string name="example_quaternion_subtitle">Random rotations using quaternions.</string>  | 
| 81 | 81 | 
    <string name="example_effects3d">Effects3D</string>  | 
| 82 | 82 | 
    <string name="example_effects3d_subtitle">Test results of all effects on a 3D object.</string>  | 
| 83 | 
     | 
|
| 83 | 
    <string name="example_plainmonalisa">PlainMonaLisa</string>  | 
|
| 84 | 
    <string name="example_plainmonalisa_subtitle">MonaLisa rendered on a plain SurfaceView</string>  | 
|
| 85 | 
     | 
|
| 84 | 86 | 
    <string name="example_movingeffects_toast">Click on \'RESET\' and define your path by touching the screen. Then click on one of the effects and see it move along your path.</string>  | 
| 85 | 87 | 
    <string name="example_cubes_toast">Rotate the cubes by swiping the screen</string>  | 
| 86 | 88 | 
    </resources>  | 
Also available in: Unified diff
New app: PlainMonaLisa (Mona Lisa rendered on plain SurfaceView)