1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.example.android.mediaeffects;
18
19import android.graphics.Bitmap;
20import android.graphics.BitmapFactory;
21import android.graphics.Color;
22import android.media.effect.Effect;
23import android.media.effect.EffectContext;
24import android.media.effect.EffectFactory;
25import android.opengl.GLES20;
26import android.opengl.GLSurfaceView;
27import android.opengl.GLUtils;
28import android.os.Bundle;
29import android.support.annotation.Nullable;
30import android.support.v4.app.Fragment;
31import android.view.LayoutInflater;
32import android.view.Menu;
33import android.view.MenuInflater;
34import android.view.MenuItem;
35import android.view.View;
36import android.view.ViewGroup;
37
38import javax.microedition.khronos.egl.EGLConfig;
39import javax.microedition.khronos.opengles.GL10;
40
41public class MediaEffectsFragment extends Fragment implements GLSurfaceView.Renderer {
42
43    private static final String STATE_CURRENT_EFFECT = "current_effect";
44
45    private GLSurfaceView mEffectView;
46    private int[] mTextures = new int[2];
47    private EffectContext mEffectContext;
48    private Effect mEffect;
49    private TextureRenderer mTexRenderer = new TextureRenderer();
50    private int mImageWidth;
51    private int mImageHeight;
52    private boolean mInitialized = false;
53    private int mCurrentEffect;
54
55    @Override
56    public void onCreate(Bundle savedInstanceState) {
57        super.onCreate(savedInstanceState);
58        setHasOptionsMenu(true);
59    }
60
61    @Override
62    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
63                             @Nullable Bundle savedInstanceState) {
64        return inflater.inflate(R.layout.fragment_media_effects, container, false);
65    }
66
67    @Override
68    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
69        mEffectView = (GLSurfaceView) view.findViewById(R.id.effectsview);
70        mEffectView.setEGLContextClientVersion(2);
71        mEffectView.setRenderer(this);
72        mEffectView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
73        if (null != savedInstanceState && savedInstanceState.containsKey(STATE_CURRENT_EFFECT)) {
74            setCurrentEffect(savedInstanceState.getInt(STATE_CURRENT_EFFECT));
75        } else {
76            setCurrentEffect(R.id.none);
77        }
78    }
79
80    @Override
81    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
82        inflater.inflate(R.menu.media_effects, menu);
83    }
84
85    @Override
86    public boolean onOptionsItemSelected(MenuItem item) {
87        setCurrentEffect(item.getItemId());
88        mEffectView.requestRender();
89        return true;
90    }
91
92    @Override
93    public void onSaveInstanceState(Bundle outState) {
94        outState.putInt(STATE_CURRENT_EFFECT, mCurrentEffect);
95    }
96
97    @Override
98    public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
99        // Nothing to do here
100    }
101
102    @Override
103    public void onSurfaceChanged(GL10 gl, int width, int height) {
104        if (mTexRenderer != null) {
105            mTexRenderer.updateViewSize(width, height);
106        }
107    }
108
109    @Override
110    public void onDrawFrame(GL10 gl) {
111        if (!mInitialized) {
112            //Only need to do this once
113            mEffectContext = EffectContext.createWithCurrentGlContext();
114            mTexRenderer.init();
115            loadTextures();
116            mInitialized = true;
117        }
118        if (mCurrentEffect != R.id.none) {
119            //if an effect is chosen initialize it and apply it to the texture
120            initEffect();
121            applyEffect();
122        }
123        renderResult();
124    }
125
126    private void setCurrentEffect(int effect) {
127        mCurrentEffect = effect;
128    }
129
130    private void loadTextures() {
131        // Generate textures
132        GLES20.glGenTextures(2, mTextures, 0);
133
134        // Load input bitmap
135        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.puppy);
136        mImageWidth = bitmap.getWidth();
137        mImageHeight = bitmap.getHeight();
138        mTexRenderer.updateTextureSize(mImageWidth, mImageHeight);
139
140        // Upload to texture
141        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
142        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
143
144        // Set texture parameters
145        GLToolbox.initTexParams();
146    }
147
148    private void initEffect() {
149        EffectFactory effectFactory = mEffectContext.getFactory();
150        if (mEffect != null) {
151            mEffect.release();
152        }
153        // Initialize the correct effect based on the selected menu/action item
154        switch (mCurrentEffect) {
155
156            case R.id.none:
157                break;
158
159            case R.id.autofix:
160                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_AUTOFIX);
161                mEffect.setParameter("scale", 0.5f);
162                break;
163
164            case R.id.bw:
165                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_BLACKWHITE);
166                mEffect.setParameter("black", .1f);
167                mEffect.setParameter("white", .7f);
168                break;
169
170            case R.id.brightness:
171                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_BRIGHTNESS);
172                mEffect.setParameter("brightness", 2.0f);
173                break;
174
175            case R.id.contrast:
176                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_CONTRAST);
177                mEffect.setParameter("contrast", 1.4f);
178                break;
179
180            case R.id.crossprocess:
181                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_CROSSPROCESS);
182                break;
183
184            case R.id.documentary:
185                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_DOCUMENTARY);
186                break;
187
188            case R.id.duotone:
189                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_DUOTONE);
190                mEffect.setParameter("first_color", Color.YELLOW);
191                mEffect.setParameter("second_color", Color.DKGRAY);
192                break;
193
194            case R.id.filllight:
195                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_FILLLIGHT);
196                mEffect.setParameter("strength", .8f);
197                break;
198
199            case R.id.fisheye:
200                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_FISHEYE);
201                mEffect.setParameter("scale", .5f);
202                break;
203
204            case R.id.flipvert:
205                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_FLIP);
206                mEffect.setParameter("vertical", true);
207                break;
208
209            case R.id.fliphor:
210                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_FLIP);
211                mEffect.setParameter("horizontal", true);
212                break;
213
214            case R.id.grain:
215                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_GRAIN);
216                mEffect.setParameter("strength", 1.0f);
217                break;
218
219            case R.id.grayscale:
220                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_GRAYSCALE);
221                break;
222
223            case R.id.lomoish:
224                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_LOMOISH);
225                break;
226
227            case R.id.negative:
228                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_NEGATIVE);
229                break;
230
231            case R.id.posterize:
232                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_POSTERIZE);
233                break;
234
235            case R.id.rotate:
236                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_ROTATE);
237                mEffect.setParameter("angle", 180);
238                break;
239
240            case R.id.saturate:
241                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_SATURATE);
242                mEffect.setParameter("scale", .5f);
243                break;
244
245            case R.id.sepia:
246                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_SEPIA);
247                break;
248
249            case R.id.sharpen:
250                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_SHARPEN);
251                break;
252
253            case R.id.temperature:
254                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_TEMPERATURE);
255                mEffect.setParameter("scale", .9f);
256                break;
257
258            case R.id.tint:
259                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_TINT);
260                mEffect.setParameter("tint", Color.MAGENTA);
261                break;
262
263            case R.id.vignette:
264                mEffect = effectFactory.createEffect(EffectFactory.EFFECT_VIGNETTE);
265                mEffect.setParameter("scale", .5f);
266                break;
267
268            default:
269                break;
270        }
271    }
272
273    private void applyEffect() {
274        mEffect.apply(mTextures[0], mImageWidth, mImageHeight, mTextures[1]);
275    }
276
277    private void renderResult() {
278        if (mCurrentEffect != R.id.none) {
279            // if no effect is chosen, just render the original bitmap
280            mTexRenderer.renderTexture(mTextures[1]);
281        } else {
282            // render the result of applyEffect()
283            mTexRenderer.renderTexture(mTextures[0]);
284        }
285    }
286
287}
288