Project

General

Profile

« Previous | Next » 

Revision e4237c21

Added by Leszek Koltunski over 8 years ago

Move the 'Save' effect to the Application and remove the 'OTHER' effect queue

View differences:

src/main/java/org/distorted/examples/save/SaveActivity.java
57 57
  @Override
58 58
  protected void onPause() 
59 59
    {
60
    SaveRenderer.stopThread();
61

  
60 62
    GLSurfaceView mView = (GLSurfaceView) this.findViewById(R.id.saveSurfaceView);
61 63
    mView.onPause();
62 64
      
......
72 74
      
73 75
    GLSurfaceView mView = (GLSurfaceView) this.findViewById(R.id.saveSurfaceView);
74 76
    mView.onResume();
77

  
78
    SaveRenderer.startThread(this);
75 79
    }
76 80
 
77 81
///////////////////////////////////////////////////////////////////////////////////////////////////
src/main/java/org/distorted/examples/save/SaveRenderer.java
22 22
import java.io.File;
23 23
import java.io.IOException;
24 24
import java.io.InputStream;
25
import java.util.Vector;
25
import java.nio.ByteBuffer;
26
import java.nio.ByteOrder;
26 27

  
27 28
import javax.microedition.khronos.egl.EGLConfig;
28 29
import javax.microedition.khronos.opengles.GL10;
......
31 32

  
32 33
import org.distorted.library.Distorted;
33 34
import org.distorted.library.DistortedBitmap;
34
import org.distorted.library.message.EffectListener;
35
import org.distorted.library.message.EffectMessage;
36 35
import org.distorted.library.EffectTypes;
37 36
import org.distorted.library.type.Float1D;
38 37
import org.distorted.library.type.Float2D;
......
45 44
import android.opengl.GLES20;
46 45
import android.opengl.GLSurfaceView;
47 46
import android.os.Environment;
48
import android.widget.Toast;
49 47

  
50 48
///////////////////////////////////////////////////////////////////////////////////////////////////
51 49

  
52
class SaveRenderer implements GLSurfaceView.Renderer ,EffectListener
50
class SaveRenderer implements GLSurfaceView.Renderer
53 51
  {
54 52
  private GLSurfaceView mView;
55 53
  private static DistortedBitmap mGirl;
......
61 59
  private int bmpHeight, bmpWidth;
62 60
  private static int scrHeight, scrWidth;
63 61
  private static float boobsSink;
62
  private static boolean isSaving = false;
63
  private static String mPath;
64 64

  
65
  private static class SaveInfo
66
    {
67
    private long id;
68
    private String path;
69

  
70
    SaveInfo(long id, String path)
71
      {
72
      this.id   =   id;
73
      this.path = path;
74
      }
75
    }
76

  
77
  private static Vector<SaveInfo> mSaveInfo;  // Vector keeping all the information about the PATH
78
                                              // where current 'SAVE' effects are saving to and also
79
                                              // the IDs of the effects.
80
                                              // We need to have a whole Vector because there can be
81
                                              // many concurrent 'SAVE' operations (click 'SAVE',
82
                                              // don't wait for the Toast to appear, immediately
83
                                              // click again! )
65
  private static SaveWorkerThread mWorkerThread =null;
84 66

  
85 67
///////////////////////////////////////////////////////////////////////////////////////////////////
86 68

  
......
101 83
    diSink.setCount(0.5f);
102 84
    diSink.setDuration(0);
103 85
    diSink.add(s0);
104

  
105
    mSaveInfo = new Vector<>();
106 86
    }
107 87

  
108 88
///////////////////////////////////////////////////////////////////////////////////////////////////
109 89

  
110
  public static void setSize(float s)
90
  public static void startThread(Activity act)
111 91
    {
112
    boobsSink = s;
113
    s0.set(boobsSink);
92
    if( mWorkerThread ==null ) mWorkerThread = new SaveWorkerThread();
93

  
94
    mWorkerThread.startSending(act);
114 95
    }
115 96

  
116 97
///////////////////////////////////////////////////////////////////////////////////////////////////
117 98

  
118
  public static void Save()
99
  public static void stopThread()
119 100
    {
120
    File file;
121
    int lowestNotFound = 1;
122
    String path;
101
    mWorkerThread.stopSending();
102
    mWorkerThread = null;
103
    }
123 104

  
124
    while(true)
125
      {
126
      path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/girl" + lowestNotFound +".png";
127
      file = new File(path);
105
///////////////////////////////////////////////////////////////////////////////////////////////////
128 106

  
129
      if( !file.exists() )
130
        {
131
        long id= mGirl.savePNG(file.getAbsolutePath(),0,0,scrWidth,scrHeight);
132
        mSaveInfo.add(new SaveInfo(id,path));
133
        break;
134
        }
135
      lowestNotFound++;
136
      }
107
  public static void setSize(float s)
108
    {
109
    boobsSink = s;
110
    s0.set(boobsSink);
137 111
    }
138 112

  
139 113
///////////////////////////////////////////////////////////////////////////////////////////////////
140
// the library sending messages to us. This does not run on this UI thread!
141 114

  
142
  public void effectMessage(final EffectMessage em, final long effectID, final int effectName, final long bitmapID, final String message)
115
  public static void Save()
143 116
    {
144
    int numSaves = mSaveInfo.size();
145
    int found = -1;
146

  
147
    for(int i=0; i<numSaves; i++)           // doesn't need to be synchronized with Save()
148
      {                                     // because over there we only add() and here we only
149
      if( effectID == mSaveInfo.get(i).id ) // remove() - and even if we add() in between of
150
        {                                   // computing the 'numSaves' above and this loop,
151
        found = i;                          // it still doesn't matter :)
152
        break;
153
        }
154
      }
155

  
156
    if( found>=0 )  // the message really is about one of the 'SAVE' effects in execution now
117
    if( isSaving==false )
157 118
      {
158
      Activity act = (Activity)mView.getContext();
159
      final String path = mSaveInfo.get(found).path;
160
      mSaveInfo.remove(found);
119
      isSaving = true;
161 120

  
162
      switch(em)
121
      File file;
122
      int lowestNotFound = 1;
123

  
124
      while(true)
163 125
        {
164
        case EFFECT_FINISHED: act.runOnUiThread(new Runnable()
165
                                {
166
                                public void run()
167
                                  {
168
                                  Toast.makeText(mView.getContext(),
169
                                      "Saving to \n\n"+path+"\n\nsuccessful" ,
170
                                      Toast.LENGTH_LONG).show();
171
                                  }
172
                                });
173
                              break;
174

  
175
        case EFFECT_FAILED  : act.runOnUiThread(new Runnable()
176
                                {
177
                                public void run()
178
                                  {
179
                                  Toast.makeText(mView.getContext(),
180
                                      "Saving to \n\n"+path+"\n\n failed: "+"\n\n"+message ,
181
                                      Toast.LENGTH_LONG).show();
182
                                  }
183
                                });
184
                              break;
185

  
186
        default             : break;
126
        mPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/girl" + lowestNotFound +".png";
127
        file = new File(mPath);
128

  
129
        if( !file.exists() ) break;
130

  
131
        lowestNotFound++;
187 132
        }
188 133
      }
189 134
    }
......
196 141
    GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
197 142
      
198 143
    mGirl.draw(System.currentTimeMillis());
144

  
145
    if( isSaving )  // we should save the buffer to location pointed at by mPath
146
      {
147
      ByteBuffer buf = ByteBuffer.allocateDirect( scrWidth*scrHeight*4 );
148
      buf.order(ByteOrder.LITTLE_ENDIAN);
149
      GLES20.glReadPixels( 0, 0, scrWidth, scrHeight , GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);
150

  
151
      mWorkerThread.newBuffer(buf,scrWidth,scrHeight,mPath);
152

  
153
      isSaving = false;
154
      }
199 155
    }
200 156

  
201 157
///////////////////////////////////////////////////////////////////////////////////////////////////
......
247 203
    bmpWidth  = bitmap.getWidth();
248 204
      
249 205
    mGirl = new DistortedBitmap(bitmap, 30);
250
    mGirl.addEventListener(this);
251 206

  
252 207
    mGirl.sink( diSink, sinkRegion, pLeft );
253 208
    mGirl.sink( diSink, sinkRegion, pRight);
src/main/java/org/distorted/examples/save/SaveWorkerThread.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Distorted is distributed in the hope that it will be useful,                                  //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

  
20
package org.distorted.examples.save;
21

  
22
import android.app.Activity;
23
import android.graphics.Bitmap;
24
import android.widget.Toast;
25

  
26
import java.io.BufferedOutputStream;
27
import java.io.FileOutputStream;
28
import java.io.IOException;
29
import java.lang.ref.WeakReference;
30
import java.nio.ByteBuffer;
31
import java.util.Vector;
32

  
33
public class SaveWorkerThread extends Thread
34
  {
35
  private static Vector<WorkLoad> mBuffers;
36
  private static SaveWorkerThread mThis=null;
37
  private static volatile boolean mPaused;
38
  private static WeakReference<Activity> mWeakAct;
39

  
40
  private static class WorkLoad
41
    {
42
    ByteBuffer buffer;
43
    int width;
44
    int height;
45
    String filename;
46

  
47
    WorkLoad(ByteBuffer buf, int w, int h, String name)
48
      {
49
      buffer   = buf;
50
      width    = w;
51
      height   = h;
52
      filename = name;
53
      }
54
    }
55

  
56
///////////////////////////////////////////////////////////////////////////////////////////////////
57

  
58
  public SaveWorkerThread()
59
    {
60
    }
61

  
62
///////////////////////////////////////////////////////////////////////////////////////////////////
63

  
64
  static void startSending(Activity act)
65
    {
66
    mWeakAct = new WeakReference(act);
67

  
68
    mPaused = false;
69

  
70
    if( mThis==null )
71
      {
72
      mBuffers = new Vector<>();
73
      mThis = new SaveWorkerThread();
74
      mThis.start();
75
      }
76
    else
77
      {
78
      synchronized(mThis)
79
        {
80
        mThis.notify();
81
        }
82
      }
83
    }
84

  
85
///////////////////////////////////////////////////////////////////////////////////////////////////
86

  
87
  static void stopSending()
88
    {
89
    mPaused = true;
90
    }
91

  
92
///////////////////////////////////////////////////////////////////////////////////////////////////
93

  
94
  public void run()
95
    {
96
    WorkLoad load;
97

  
98
    while(true)
99
      {
100
      if( mBuffers.size()>0 )
101
        {
102
        load = mBuffers.remove(0);
103
        process(load);
104
        }
105

  
106
      if( mPaused )
107
        {
108
        synchronized(mThis)
109
          {
110
          try  { mThis.wait(); }
111
          catch(InterruptedException ex) { }
112
          }
113
        }
114
      }
115
    }
116

  
117
///////////////////////////////////////////////////////////////////////////////////////////////////
118

  
119
  static void newBuffer(ByteBuffer buffer, int width, int height, String filename)
120
    {
121
    WorkLoad load = new WorkLoad(buffer,width,height,filename);
122
    mBuffers.add(load);
123
    }
124

  
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126

  
127
  private void process(WorkLoad load)
128
    {
129
    ByteBuffer buf = load.buffer;
130
    int width  = load.width;
131
    int height = load.height;
132
    final String filename = load.filename;
133

  
134
    byte[] tmp1 = new byte[width*4];
135
    byte[] tmp2 = new byte[width*4];
136

  
137
    for(int i=0; i<height/2; i++)
138
      {
139
      buf.position((         i)*width*4);  // GL uses a coordinate system from mathematics; i.e.
140
      buf.get(tmp1);                       // (0,0) is in the lower-left corner. 2D stuff has
141
      buf.position((height-1-i)*width*4);  // the origin on the upper-left corner; we have to flip
142
      buf.get(tmp2);                       // out bitmap upside down!
143

  
144
      buf.position((         i)*width*4);
145
      buf.put(tmp2);
146
      buf.position((height-1-i)*width*4);
147
      buf.put(tmp1);
148
      }
149

  
150
    buf.rewind();
151
    BufferedOutputStream bos =null;
152
    final Activity act = mWeakAct.get();
153

  
154
    try
155
      {
156
      bos = new BufferedOutputStream(new FileOutputStream(filename));
157
      Bitmap bmp = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888);
158
      bmp.copyPixelsFromBuffer(buf);
159
      bmp.compress(Bitmap.CompressFormat.PNG, 90, bos);
160
      bmp.recycle();
161

  
162
      act.runOnUiThread(new Runnable()
163
        {
164
        public void run()
165
          {
166
          Toast.makeText(act,
167
              "Saving to \n\n"+filename+"\n\nsuccessful" ,
168
              Toast.LENGTH_LONG).show();
169
          }
170
        });
171
      }
172
    catch(final Exception ex)
173
      {
174
      act.runOnUiThread(new Runnable()
175
        {
176
        public void run()
177
          {
178
          Toast.makeText(act,
179
              "Saving to \n\n"+filename+"\n\n failed: "+"\n\n"+ex.getMessage() ,
180
              Toast.LENGTH_LONG).show();
181
          }
182
        });
183
      }
184
    finally
185
      {
186
      if(bos!=null)
187
        {
188
        try { bos.close(); }
189
        catch(IOException io) {}
190
        }
191
      }
192
    }
193
  }

Also available in: Unified diff