Revision b9615af9
Added by Leszek Koltunski almost 8 years ago
src/main/java/org/distorted/examples/save/SaveRenderer.java | ||
---|---|---|
4 | 4 |
import java.io.File; |
5 | 5 |
import java.io.IOException; |
6 | 6 |
import java.io.InputStream; |
7 |
import java.util.Vector; |
|
7 | 8 |
|
8 | 9 |
import javax.microedition.khronos.egl.EGLConfig; |
9 | 10 |
import javax.microedition.khronos.opengles.GL10; |
... | ... | |
12 | 13 |
|
13 | 14 |
import org.distorted.library.Distorted; |
14 | 15 |
import org.distorted.library.DistortedBitmap; |
16 |
import org.distorted.library.EffectListener; |
|
17 |
import org.distorted.library.EffectMessage; |
|
15 | 18 |
import org.distorted.library.EffectTypes; |
16 | 19 |
import org.distorted.library.Float1D; |
17 | 20 |
import org.distorted.library.Float2D; |
18 | 21 |
import org.distorted.library.Float4D; |
19 | 22 |
import org.distorted.library.Interpolator1D; |
20 | 23 |
|
24 |
import android.app.Activity; |
|
21 | 25 |
import android.graphics.Bitmap; |
22 | 26 |
import android.graphics.BitmapFactory; |
23 | 27 |
import android.opengl.GLES20; |
24 | 28 |
import android.opengl.GLSurfaceView; |
25 | 29 |
import android.os.Environment; |
30 |
import android.widget.Toast; |
|
26 | 31 |
|
27 | 32 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
28 | 33 |
|
29 |
class SaveRenderer implements GLSurfaceView.Renderer |
|
30 |
{ |
|
31 |
private GLSurfaceView mView; |
|
32 |
private static DistortedBitmap mGirl; |
|
33 |
private Float2D pLeft, pRight; |
|
34 |
private Float4D sinkRegion; |
|
35 |
private static Interpolator1D diSink; |
|
36 |
private static Float1D s0; |
|
37 |
|
|
38 |
private int bmpHeight, bmpWidth; |
|
39 |
|
|
40 |
private static float boobsSink; |
|
41 |
|
|
34 |
class SaveRenderer implements GLSurfaceView.Renderer ,EffectListener |
|
35 |
{ |
|
36 |
private GLSurfaceView mView; |
|
37 |
private static DistortedBitmap mGirl; |
|
38 |
private Float2D pLeft, pRight; |
|
39 |
private Float4D sinkRegion; |
|
40 |
private static Interpolator1D diSink; |
|
41 |
private static Float1D s0; |
|
42 |
|
|
43 |
private int bmpHeight, bmpWidth; |
|
44 |
private static int scrHeight, scrWidth; |
|
45 |
private static float boobsSink; |
|
46 |
|
|
47 |
private static class SaveInfo |
|
48 |
{ |
|
49 |
private long id; |
|
50 |
private String path; |
|
51 |
|
|
52 |
SaveInfo(long id, String path) |
|
53 |
{ |
|
54 |
this.id = id; |
|
55 |
this.path = path; |
|
56 |
} |
|
57 |
} |
|
58 |
|
|
59 |
private static Vector<SaveInfo> mSaveInfo; // Vector keeping all the information about the PATH |
|
60 |
// where current 'SAVE' effects are saving to and also |
|
61 |
// the IDs of the effects. |
|
62 |
// We need to have a whole Vector because there can be |
|
63 |
// many concurrent 'SAVE' operations (click 'SAVE', |
|
64 |
// don't wait for the Toast to appear, immediately |
|
65 |
// click again! ) |
|
66 |
|
|
42 | 67 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
43 | 68 |
|
44 |
public SaveRenderer(GLSurfaceView v)
|
|
45 |
{
|
|
46 |
mView = v;
|
|
69 |
public SaveRenderer(GLSurfaceView v)
|
|
70 |
{ |
|
71 |
mView = v; |
|
47 | 72 |
|
48 |
boobsSink = 1.0f;
|
|
73 |
boobsSink = 1.0f; |
|
49 | 74 |
|
50 |
pLeft = new Float2D(132, 264);
|
|
51 |
pRight= new Float2D(247, 264);
|
|
75 |
pLeft = new Float2D(132, 264); |
|
76 |
pRight= new Float2D(247, 264); |
|
52 | 77 |
|
53 |
// Make the boobs bigger |
|
54 |
sinkRegion = new Float4D(0,0,60,60); |
|
78 |
sinkRegion = new Float4D(0,0,60,60); |
|
55 | 79 |
|
56 |
s0 = new Float1D(boobsSink);
|
|
80 |
s0 = new Float1D(boobsSink); |
|
57 | 81 |
|
58 |
diSink = new Interpolator1D(); |
|
59 |
diSink.setCount(0.5f); |
|
60 |
diSink.setDuration(0); |
|
61 |
diSink.add(s0); |
|
62 |
} |
|
82 |
diSink = new Interpolator1D(); |
|
83 |
diSink.setCount(0.5f); |
|
84 |
diSink.setDuration(0); |
|
85 |
diSink.add(s0); |
|
86 |
|
|
87 |
mSaveInfo = new Vector<>(); |
|
88 |
} |
|
63 | 89 |
|
64 | 90 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
65 | 91 |
|
66 |
public static void setSize(float s)
|
|
67 |
{
|
|
68 |
boobsSink = s;
|
|
69 |
s0.set(boobsSink);
|
|
70 |
}
|
|
92 |
public static void setSize(float s) |
|
93 |
{ |
|
94 |
boobsSink = s; |
|
95 |
s0.set(boobsSink); |
|
96 |
} |
|
71 | 97 |
|
72 | 98 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
73 | 99 |
|
74 |
public static void Save() |
|
75 |
{ |
|
76 |
File file; |
|
77 |
String filePath; |
|
78 |
int lowestNotFound = 1; |
|
79 |
|
|
80 |
while(true) |
|
81 |
{ |
|
82 |
filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/girl" + lowestNotFound +".png"; |
|
83 |
file = new File(filePath); |
|
84 |
|
|
85 |
if( !file.exists() ) |
|
86 |
{ |
|
87 |
android.util.Log.e("SAVE", "Saving to "+file.getAbsolutePath()); |
|
88 |
mGirl.savePNG(file.getAbsolutePath()); |
|
89 |
break; |
|
90 |
} |
|
91 |
lowestNotFound++; |
|
92 |
} |
|
93 |
} |
|
100 |
public static void Save() |
|
101 |
{ |
|
102 |
File file; |
|
103 |
int lowestNotFound = 1; |
|
104 |
String path; |
|
94 | 105 |
|
95 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
96 |
|
|
97 |
public void onDrawFrame(GL10 glUnused) |
|
106 |
while(true) |
|
98 | 107 |
{ |
99 |
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
|
100 |
GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); |
|
101 |
|
|
102 |
mGirl.draw(System.currentTimeMillis()); |
|
108 |
path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/girl" + lowestNotFound +".png"; |
|
109 |
file = new File(path); |
|
110 |
|
|
111 |
if( !file.exists() ) |
|
112 |
{ |
|
113 |
long id= mGirl.savePNG(file.getAbsolutePath(),0,0,scrWidth,scrHeight); |
|
114 |
mSaveInfo.add(new SaveInfo(id,path)); |
|
115 |
break; |
|
116 |
} |
|
117 |
lowestNotFound++; |
|
103 | 118 |
} |
119 |
} |
|
104 | 120 |
|
105 | 121 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
106 |
|
|
107 |
public void onSurfaceChanged(GL10 glUnused, int width, int height) |
|
108 |
{ |
|
109 |
mGirl.abortEffects(EffectTypes.MATRIX); |
|
110 |
|
|
111 |
if( bmpHeight/bmpWidth > height/width ) |
|
112 |
{ |
|
113 |
int w = (height*bmpWidth)/bmpHeight; |
|
114 |
mGirl.move((width-w)/2 ,0, 0); |
|
115 |
mGirl.scale((float)height/bmpHeight); |
|
122 |
// the library sending messages to us. This does not run on this UI thread! |
|
123 |
|
|
124 |
public void effectMessage(final EffectMessage em, final long effectID, final int effectName, final long bitmapID, final String message) |
|
125 |
{ |
|
126 |
int numSaves = mSaveInfo.size(); |
|
127 |
int found = -1; |
|
128 |
|
|
129 |
for(int i=0; i<numSaves; i++) // doesn't need to be synchronized with Save() |
|
130 |
{ // because over there we only add() and here we only |
|
131 |
if( effectID == mSaveInfo.get(i).id ) // remove() - and even if we add() in between of |
|
132 |
{ // computing the 'numSaves' above and this loop, |
|
133 |
found = i; // it still doesn't matter :) |
|
134 |
break; |
|
116 | 135 |
} |
117 |
else |
|
136 |
} |
|
137 |
|
|
138 |
if( found>=0 ) // the message really is about one of the 'SAVE' effects in execution now |
|
139 |
{ |
|
140 |
Activity act = (Activity)mView.getContext(); |
|
141 |
final String path = mSaveInfo.get(found).path; |
|
142 |
mSaveInfo.remove(found); |
|
143 |
|
|
144 |
switch(em) |
|
118 | 145 |
{ |
119 |
int h = (width*bmpHeight)/bmpWidth; |
|
120 |
mGirl.move(0 ,(height-h)/2, 0); |
|
121 |
mGirl.scale((float)width/bmpWidth); |
|
146 |
case EFFECT_FINISHED: act.runOnUiThread(new Runnable() |
|
147 |
{ |
|
148 |
public void run() |
|
149 |
{ |
|
150 |
Toast.makeText(mView.getContext(), |
|
151 |
"Saving to \n\n"+path+"\n\nsuccessful" , |
|
152 |
Toast.LENGTH_LONG).show(); |
|
153 |
} |
|
154 |
}); |
|
155 |
break; |
|
156 |
|
|
157 |
case EFFECT_FAILED : act.runOnUiThread(new Runnable() |
|
158 |
{ |
|
159 |
public void run() |
|
160 |
{ |
|
161 |
Toast.makeText(mView.getContext(), |
|
162 |
"Saving to \n\n"+path+"\n\n failed: "+"\n\n"+message , |
|
163 |
Toast.LENGTH_LONG).show(); |
|
164 |
} |
|
165 |
}); |
|
166 |
break; |
|
167 |
|
|
168 |
default : break; |
|
122 | 169 |
} |
170 |
} |
|
171 |
} |
|
172 |
|
|
173 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
174 |
|
|
175 |
public void onDrawFrame(GL10 glUnused) |
|
176 |
{ |
|
177 |
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
|
178 |
GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); |
|
123 | 179 |
|
124 |
Distorted.onSurfaceChanged(width, height); |
|
180 |
mGirl.draw(System.currentTimeMillis()); |
|
181 |
} |
|
182 |
|
|
183 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
184 |
|
|
185 |
public void onSurfaceChanged(GL10 glUnused, int width, int height) |
|
186 |
{ |
|
187 |
scrWidth = width; |
|
188 |
scrHeight= height; |
|
189 |
|
|
190 |
mGirl.abortEffects(EffectTypes.MATRIX); |
|
191 |
|
|
192 |
if( bmpHeight/bmpWidth > height/width ) |
|
193 |
{ |
|
194 |
int w = (height*bmpWidth)/bmpHeight; |
|
195 |
mGirl.move((width-w)/2 ,0, 0); |
|
196 |
mGirl.scale((float)height/bmpHeight); |
|
125 | 197 |
} |
198 |
else |
|
199 |
{ |
|
200 |
int h = (width*bmpHeight)/bmpWidth; |
|
201 |
mGirl.move(0 ,(height-h)/2, 0); |
|
202 |
mGirl.scale((float)width/bmpWidth); |
|
203 |
} |
|
204 |
|
|
205 |
Distorted.onSurfaceChanged(width, height); |
|
206 |
} |
|
126 | 207 |
|
127 | 208 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
128 | 209 |
|
129 |
public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
|
|
130 |
{
|
|
131 |
InputStream is = mView.getContext().getResources().openRawResource(R.raw.girl);
|
|
132 |
Bitmap bitmap;
|
|
210 |
public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
|
|
211 |
{
|
|
212 |
InputStream is = mView.getContext().getResources().openRawResource(R.raw.girl); |
|
213 |
Bitmap bitmap; |
|
133 | 214 |
|
134 |
try |
|
135 |
{ |
|
136 |
bitmap = BitmapFactory.decodeStream(is); |
|
137 |
} |
|
138 |
finally |
|
215 |
try |
|
216 |
{ |
|
217 |
bitmap = BitmapFactory.decodeStream(is); |
|
218 |
} |
|
219 |
finally |
|
220 |
{ |
|
221 |
try |
|
139 | 222 |
{ |
140 |
try |
|
141 |
{ |
|
142 |
is.close(); |
|
143 |
} |
|
144 |
catch(IOException e) { } |
|
145 |
} |
|
223 |
is.close(); |
|
224 |
} |
|
225 |
catch(IOException e) { } |
|
226 |
} |
|
146 | 227 |
|
147 |
bmpHeight = bitmap.getHeight();
|
|
148 |
bmpWidth = bitmap.getWidth();
|
|
228 |
bmpHeight = bitmap.getHeight(); |
|
229 |
bmpWidth = bitmap.getWidth(); |
|
149 | 230 |
|
150 |
mGirl = new DistortedBitmap(bitmap, 30); |
|
231 |
mGirl = new DistortedBitmap(bitmap, 30); |
|
232 |
mGirl.addEventListener(this); |
|
151 | 233 |
|
152 |
mGirl.sink( diSink, sinkRegion, pLeft );
|
|
153 |
mGirl.sink( diSink, sinkRegion, pRight);
|
|
234 |
mGirl.sink( diSink, sinkRegion, pLeft ); |
|
235 |
mGirl.sink( diSink, sinkRegion, pRight); |
|
154 | 236 |
|
155 |
try |
|
156 |
{ |
|
157 |
Distorted.onSurfaceCreated(mView.getContext()); |
|
158 |
} |
|
159 |
catch(Exception ex) |
|
160 |
{ |
|
161 |
android.util.Log.e("Renderer", ex.getMessage() ); |
|
162 |
} |
|
237 |
try |
|
238 |
{ |
|
239 |
Distorted.onSurfaceCreated(mView.getContext()); |
|
240 |
} |
|
241 |
catch(Exception ex) |
|
242 |
{ |
|
243 |
android.util.Log.e("Renderer", ex.getMessage() ); |
|
163 | 244 |
} |
164 |
} |
|
245 |
} |
|
246 |
} |
Also available in: Unified diff
Save PNG effect almost finished. Supporting App (hopefully!) completely finished.
What remains to be done: put actual saving of the Bitmap in a separate thread, away from the Graphics thread!!