Revision c6e1c219
Added by Leszek Koltunski over 9 years ago
| src/main/java/org/distorted/library/DistortedObject.java | ||
|---|---|---|
| 2528 | 2528 |
* @param filename Full path to the file. |
| 2529 | 2529 |
* @return ID of the effect added, or -1 if we failed to add one. |
| 2530 | 2530 |
*/ |
| 2531 |
public long savePNG(String filename) |
|
| 2531 |
public long savePNG(String filename, int left, int top, int width, int height)
|
|
| 2532 | 2532 |
{
|
| 2533 |
return mO.add(EffectNames.SAVE_PNG, filename); |
|
| 2533 |
return mO.add(EffectNames.SAVE_PNG, filename, left, top, width, height);
|
|
| 2534 | 2534 |
} |
| 2535 | 2535 |
} |
| src/main/java/org/distorted/library/EffectListener.java | ||
|---|---|---|
| 9 | 9 |
|
| 10 | 10 |
public interface EffectListener |
| 11 | 11 |
{
|
| 12 |
|
|
| 13 | 12 |
/** |
| 14 | 13 |
* Gets called when event of type 'em' happens to effect 'effectID'. |
| 15 | 14 |
* |
| 16 |
* @param eventMessage Type of event that happened.
|
|
| 17 |
* @param effectID ID of the effect the event happened to. This ID must have been previously returned by one
|
|
| 18 |
* of the DistortedBitmap.{deform,distort,move,...} functions.
|
|
| 19 |
* @param effectType Type of the effect as defined in EffectNames, e.g. if effectType==EffectNames.MOVE.ordinal(),
|
|
| 20 |
* then the event happened to a MOVE effect.
|
|
| 21 |
* @param bitmapID the ID of the DistortedBitmap object, as returned by {@link DistortedBitmap#getID()}, this event
|
|
| 22 |
* happened to. If the object has been created using a copy constructor from another instance of
|
|
| 23 |
* DistortedBitmap, the ID here will be the one of the original object.
|
|
| 24 |
*
|
|
| 15 |
* @param eventType Type of event that happened.
|
|
| 16 |
* @param effectID ID of the effect the event happened to. This ID must have been previously returned by one |
|
| 17 |
* of the DistortedBitmap.{deform,distort,move,...} functions.
|
|
| 18 |
* @param effectName Name of the effect as defined in EffectNames, e.g. if effectType==EffectNames.MOVE.ordinal(),
|
|
| 19 |
* then the event happened to a MOVE effect.
|
|
| 20 |
* @param bitmapID the ID of the DistortedBitmap object, as returned by {@link DistortedBitmap#getID()}, this event
|
|
| 21 |
* happened to. If the object has been created using a copy constructor from another instance of |
|
| 22 |
* DistortedBitmap, the ID here will be the one of the original object.
|
|
| 23 |
* @param message Any message string associated with it. 'Failed' event types have one.
|
|
| 25 | 24 |
* @see EffectMessage |
| 26 | 25 |
* @see EffectNames |
| 27 | 26 |
*/ |
| 28 | 27 |
|
| 29 |
void effectMessage(EffectMessage eventMessage, long effectID, int effectType, long bitmapID);
|
|
| 28 |
void effectMessage(final EffectMessage eventType, final long effectID, final int effectName, final long bitmapID, final String message);
|
|
| 30 | 29 |
} |
| 31 | 30 |
|
| 32 | 31 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| src/main/java/org/distorted/library/EffectMessage.java | ||
|---|---|---|
| 11 | 11 |
* The effect has been removed. This can happen if: |
| 12 | 12 |
* <ul> |
| 13 | 13 |
* <li> someone explicitly removed the effect with a call to {@link DistortedBitmap#abortEffect(long)} (or one of the other 'abort' methods)
|
| 14 |
* <li> the interpolation of the effect has finished and the end result is equal to the effect's zero point.
|
|
| 14 |
* <li> the interpolation of the effect has finished and the end result is equal to the effect's unity.
|
|
| 15 | 15 |
* </ul> |
| 16 | 16 |
*/ |
| 17 | 17 |
EFFECT_REMOVED, |
| ... | ... | |
| 25 | 25 |
* finishes. You will never get this message if you set the effect to go on indefinitely with a call to |
| 26 | 26 |
* {@link Interpolator#setCount(float)}.
|
| 27 | 27 |
* <p> |
| 28 |
* If then the end effect is equal to the effect's zero point, then immediately after this message you
|
|
| 28 |
* If then the end effect is equal to the effect's unity, then immediately after this message you
|
|
| 29 | 29 |
* will also get a EFFECT_REMOVED message. |
| 30 | 30 |
*/ |
| 31 | 31 |
EFFECT_FINISHED, |
| ... | ... | |
| 35 | 35 |
* <p> |
| 36 | 36 |
* Currently only OTHER effects (saving to PNG file and to a MP4 movie) can fail. |
| 37 | 37 |
*/ |
| 38 |
EFFECT_FAILED;
|
|
| 38 |
EFFECT_FAILED |
|
| 39 | 39 |
} |
| 40 | 40 |
|
| 41 | 41 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| src/main/java/org/distorted/library/EffectMessageSender.java | ||
|---|---|---|
| 11 | 11 |
EffectListener mListener; |
| 12 | 12 |
EffectMessage mMessage; |
| 13 | 13 |
long mEffectID; |
| 14 |
int mEffectType;
|
|
| 14 |
int mEffectName;
|
|
| 15 | 15 |
long mBitmapID; |
| 16 |
|
|
| 17 |
Message(EffectListener l, EffectMessage m, long id, int type, long bmpID) |
|
| 16 |
String mStr; |
|
| 17 |
|
|
| 18 |
Message(EffectListener l, EffectMessage m, long id, int name, long bmpID, String str) |
|
| 18 | 19 |
{
|
| 19 | 20 |
mListener = l; |
| 20 | 21 |
mMessage = m; |
| 21 | 22 |
mEffectID = id; |
| 22 |
mEffectType = type;
|
|
| 23 |
mEffectName = name;
|
|
| 23 | 24 |
mBitmapID = bmpID; |
| 25 |
mStr = str; |
|
| 24 | 26 |
} |
| 25 | 27 |
} |
| 26 | 28 |
|
| ... | ... | |
| 42 | 44 |
|
| 43 | 45 |
if( mThis==null ) |
| 44 | 46 |
{
|
| 45 |
mList = new Vector<Message>();
|
|
| 47 |
mList = new Vector<>(); |
|
| 46 | 48 |
mThis = new EffectMessageSender(); |
| 47 | 49 |
mThis.start(); |
| 48 | 50 |
} |
| ... | ... | |
| 73 | 75 |
if( mList.size()>0 ) |
| 74 | 76 |
{
|
| 75 | 77 |
tmp = mList.get(0); |
| 76 |
tmp.mListener.effectMessage(tmp.mMessage, tmp.mEffectID, tmp.mEffectType, tmp.mBitmapID);
|
|
| 78 |
tmp.mListener.effectMessage(tmp.mMessage, tmp.mEffectID, tmp.mEffectName, tmp.mBitmapID, tmp.mStr);
|
|
| 77 | 79 |
mList.remove(0); |
| 78 | 80 |
} |
| 79 | 81 |
|
| ... | ... | |
| 90 | 92 |
|
| 91 | 93 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 92 | 94 |
|
| 93 |
static void newMessage(EffectListener l, EffectMessage m, long id, int type, long bmpID)
|
|
| 95 |
static void newMessage(EffectListener l, EffectMessage m, long id, int name, long bmpID, String str)
|
|
| 94 | 96 |
{
|
| 95 |
Message msg = mThis.new Message(l,m,id,type,bmpID);
|
|
| 97 |
Message msg = mThis.new Message(l,m,id,name,bmpID,str);
|
|
| 96 | 98 |
mList.add(msg); |
| 97 | 99 |
} |
| 98 | 100 |
} |
| src/main/java/org/distorted/library/EffectNames.java | ||
|---|---|---|
| 90 | 90 |
} |
| 91 | 91 |
|
| 92 | 92 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 93 |
|
|
| 93 |
// yes, I know we could have used values(i) |
|
| 94 |
|
|
| 94 | 95 |
static EffectTypes getType(int ordinal) |
| 95 | 96 |
{
|
| 96 | 97 |
if( ordinal<DISTORT.ordinal() ) return EffectTypes.MATRIX; |
| src/main/java/org/distorted/library/EffectQueue.java | ||
|---|---|---|
| 157 | 157 |
if( mType[i]==ord ) |
| 158 | 158 |
{
|
| 159 | 159 |
remove(i); |
| 160 |
// TODO: don't we have to do a 'i--' here? Check this. |
|
| 160 | 161 |
ret = true; |
| 161 | 162 |
} |
| 162 | 163 |
} |
| ... | ... | |
| 227 | 228 |
EffectMessage.EFFECT_REMOVED, |
| 228 | 229 |
(removedID<<EffectTypes.LENGTH)+EffectNames.getType(removedType).type, |
| 229 | 230 |
removedType, |
| 230 |
mBitmapID); |
|
| 231 |
mBitmapID, |
|
| 232 |
null); |
|
| 231 | 233 |
} |
| 232 | 234 |
|
| 233 | 235 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| src/main/java/org/distorted/library/EffectQueueFragment.java | ||
|---|---|---|
| 55 | 55 |
EffectMessage.EFFECT_FINISHED, |
| 56 | 56 |
(mID[i]<<EffectTypes.LENGTH)+EffectTypes.FRAGMENT.type, |
| 57 | 57 |
mType[i], |
| 58 |
mBitmapID); |
|
| 58 |
mBitmapID, |
|
| 59 |
null); |
|
| 59 | 60 |
|
| 60 | 61 |
if( EffectNames.isUnity(mType[i], mUniforms, NUM_UNIFORMS*i) ) |
| 61 | 62 |
{
|
| src/main/java/org/distorted/library/EffectQueueMatrix.java | ||
|---|---|---|
| 88 | 88 |
EffectMessage.EFFECT_FINISHED, |
| 89 | 89 |
(mID[i]<<EffectTypes.LENGTH)+EffectTypes.MATRIX.type, |
| 90 | 90 |
mType[i], |
| 91 |
mBitmapID); |
|
| 91 |
mBitmapID, |
|
| 92 |
null); |
|
| 92 | 93 |
|
| 93 | 94 |
if( EffectNames.isUnity(mType[i], mUniforms, NUM_UNIFORMS*i+3) ) |
| 94 | 95 |
{
|
| src/main/java/org/distorted/library/EffectQueueOther.java | ||
|---|---|---|
| 13 | 13 |
|
| 14 | 14 |
class EffectQueueOther extends EffectQueue |
| 15 | 15 |
{
|
| 16 |
private static final int NUM_UNIFORMS = 0;
|
|
| 16 |
private static final int NUM_UNIFORMS = 4;
|
|
| 17 | 17 |
private static final int INDEX = EffectTypes.OTHER.ordinal(); |
| 18 | 18 |
private String[] mFilename; |
| 19 | 19 |
|
| ... | ... | |
| 34 | 34 |
protected void moveEffect(int index) |
| 35 | 35 |
{
|
| 36 | 36 |
mFilename[index] = mFilename[index+1]; |
| 37 |
|
|
| 38 |
mUniforms[NUM_UNIFORMS*index ] = mUniforms[NUM_UNIFORMS*(index+1) ]; |
|
| 39 |
mUniforms[NUM_UNIFORMS*index+1] = mUniforms[NUM_UNIFORMS*(index+1)+1]; |
|
| 40 |
mUniforms[NUM_UNIFORMS*index+2] = mUniforms[NUM_UNIFORMS*(index+1)+2]; |
|
| 41 |
mUniforms[NUM_UNIFORMS*index+3] = mUniforms[NUM_UNIFORMS*(index+1)+3]; |
|
| 37 | 42 |
} |
| 38 | 43 |
|
| 39 | 44 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| ... | ... | |
| 45 | 50 |
{
|
| 46 | 51 |
if (mType[i] == EffectNames.SAVE_PNG.ordinal() ) |
| 47 | 52 |
{
|
| 48 |
ByteBuffer buf = ByteBuffer.allocateDirect( (int)(mObjHalfX * mObjHalfY * 16) ); |
|
| 53 |
int left = (int)mUniforms[NUM_UNIFORMS*i ]; |
|
| 54 |
int top = (int)mUniforms[NUM_UNIFORMS*i+1]; |
|
| 55 |
int width = (int)mUniforms[NUM_UNIFORMS*i+2]; |
|
| 56 |
int height= (int)mUniforms[NUM_UNIFORMS*i+3]; |
|
| 57 |
|
|
| 58 |
ByteBuffer buf = ByteBuffer.allocateDirect( width*height*4 ); |
|
| 49 | 59 |
buf.order(ByteOrder.LITTLE_ENDIAN); |
| 50 |
GLES20.glReadPixels(0, 0, (int)(2*mObjHalfX), (int)(2*mObjHalfY) , GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);
|
|
| 60 |
GLES20.glReadPixels( left, top, width, height , GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);
|
|
| 51 | 61 |
|
| 62 |
flipUpsideDown(buf,width,height); // GL uses a coordinate system from mathematics; i.e. |
|
| 63 |
// (0,0) is in the lower-left corner. 2D stuff has |
|
| 64 |
// the origin on the upper-left corner; we have to flip |
|
| 65 |
// out bitmap upside down! |
|
| 52 | 66 |
buf.rewind(); |
| 53 |
|
|
| 54 | 67 |
BufferedOutputStream bos = null; |
| 55 | 68 |
|
| 56 | 69 |
try |
| 57 | 70 |
{
|
| 58 | 71 |
bos = new BufferedOutputStream(new FileOutputStream(mFilename[i])); |
| 59 |
Bitmap bmp = Bitmap.createBitmap( (int)(2*mObjHalfX), (int)(2*mObjHalfY), Bitmap.Config.ARGB_8888);
|
|
| 72 |
Bitmap bmp = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888);
|
|
| 60 | 73 |
bmp.copyPixelsFromBuffer(buf); |
| 61 | 74 |
bmp.compress(Bitmap.CompressFormat.PNG, 90, bos); |
| 62 | 75 |
bmp.recycle(); |
| ... | ... | |
| 66 | 79 |
EffectMessage.EFFECT_FINISHED, |
| 67 | 80 |
(mID[i]<<EffectTypes.LENGTH)+EffectTypes.OTHER.type, |
| 68 | 81 |
mType[i], |
| 69 |
mBitmapID); |
|
| 82 |
mBitmapID, |
|
| 83 |
null); |
|
| 70 | 84 |
} |
| 71 | 85 |
catch(Exception e) |
| 72 | 86 |
{
|
| ... | ... | |
| 75 | 89 |
EffectMessage.EFFECT_FAILED, |
| 76 | 90 |
(mID[i]<<EffectTypes.LENGTH)+EffectTypes.OTHER.type, |
| 77 | 91 |
mType[i], |
| 78 |
mBitmapID); |
|
| 92 |
mBitmapID, |
|
| 93 |
e.getMessage()); |
|
| 79 | 94 |
} |
| 80 | 95 |
finally |
| 81 | 96 |
{
|
| ... | ... | |
| 99 | 114 |
|
| 100 | 115 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 101 | 116 |
|
| 102 |
synchronized long add(EffectNames eln, String filename) |
|
| 117 |
synchronized long add(EffectNames eln, String filename, int left, int top, int width, int height)
|
|
| 103 | 118 |
{
|
| 104 | 119 |
if( mMax[INDEX]>mNumEffects ) |
| 105 | 120 |
{
|
| ... | ... | |
| 107 | 122 |
mInterI[mNumEffects] = null; |
| 108 | 123 |
mInterP[mNumEffects] = null; |
| 109 | 124 |
|
| 125 |
mUniforms[NUM_UNIFORMS*mNumEffects ] = left; |
|
| 126 |
mUniforms[NUM_UNIFORMS*mNumEffects+1] = top; |
|
| 127 |
mUniforms[NUM_UNIFORMS*mNumEffects+2] = width; |
|
| 128 |
mUniforms[NUM_UNIFORMS*mNumEffects+3] =height; |
|
| 129 |
|
|
| 110 | 130 |
return addBase(eln); |
| 111 | 131 |
} |
| 112 | 132 |
|
| 113 | 133 |
return -1; |
| 114 | 134 |
} |
| 135 |
|
|
| 136 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 137 |
|
|
| 138 |
private void flipUpsideDown(ByteBuffer buf, int width, int height) |
|
| 139 |
{
|
|
| 140 |
byte[] tmp1 = new byte[width*4]; |
|
| 141 |
byte[] tmp2 = new byte[width*4]; |
|
| 142 |
|
|
| 143 |
for(int i=0; i<height/2; i++) |
|
| 144 |
{
|
|
| 145 |
buf.position(( i)*width*4); |
|
| 146 |
buf.get(tmp1); |
|
| 147 |
buf.position((height-1-i)*width*4); |
|
| 148 |
buf.get(tmp2); |
|
| 149 |
|
|
| 150 |
buf.position(( i)*width*4); |
|
| 151 |
buf.put(tmp2); |
|
| 152 |
buf.position((height-1-i)*width*4); |
|
| 153 |
buf.put(tmp1); |
|
| 154 |
} |
|
| 155 |
} |
|
| 115 | 156 |
} |
| src/main/java/org/distorted/library/EffectQueueVertex.java | ||
|---|---|---|
| 55 | 55 |
EffectMessage.EFFECT_FINISHED, |
| 56 | 56 |
(mID[i]<<EffectTypes.LENGTH)+EffectTypes.VERTEX.type, |
| 57 | 57 |
mType[i], |
| 58 |
mBitmapID); |
|
| 58 |
mBitmapID, |
|
| 59 |
null); |
|
| 59 | 60 |
|
| 60 | 61 |
if( EffectNames.isUnity(mType[i], mUniforms, NUM_UNIFORMS*i) ) |
| 61 | 62 |
{
|
| src/main/java/org/distorted/library/EffectTypes.java | ||
|---|---|---|
| 10 | 10 |
public enum EffectTypes |
| 11 | 11 |
{
|
| 12 | 12 |
/** |
| 13 |
* Matrix effects - i.e. effect that change the ModelView matrix. Rotations, Moves, Shears, Scales.
|
|
| 13 |
* Effects that change the ModelView matrix: Rotations, Moves, Shears, Scales.
|
|
| 14 | 14 |
*/ |
| 15 | 15 |
MATRIX ( 0x1 ), // we will need to perform bitwise operations on those - so keep the values 1,2,4,8... |
| 16 | 16 |
/** |
| 17 |
* Vertex Effects - i.e. those that get executed in the Vertex shader. Generally various distortions |
|
| 18 |
* of the vertices. |
|
| 17 |
* Effects that get executed in the Vertex shader: various distortions of the vertices. |
|
| 19 | 18 |
*/ |
| 20 | 19 |
VERTEX ( 0x2 ), |
| 21 | 20 |
/** |
| 22 |
* Fragment Effects - executed in the Fragment shader. Changes of color, hue, transparency levels, etc.
|
|
| 21 |
* Effects executed in the Fragment shader: changes of color, hue, transparency levels, etc.
|
|
| 23 | 22 |
*/ |
| 24 | 23 |
FRAGMENT ( 0x4 ), |
| 25 | 24 |
/** |
| 26 |
* effects that did not belong to anywhere else - currently saving the contents of underlying Surface
|
|
| 27 |
* to a PNG or a MP4 file. |
|
| 25 |
* Effects that did not belong to anywhere else - currently only saving the contents of underlying
|
|
| 26 |
* Surface to a PNG or a MP4 file.
|
|
| 28 | 27 |
*/ |
| 29 | 28 |
OTHER ( 0x8 ); |
| 30 | 29 |
|
| ... | ... | |
| 54 | 53 |
maxtable[3] = 5; // Max 5 OTHER Effects |
| 55 | 54 |
} |
| 56 | 55 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 57 |
} |
|
| 58 |
|
|
| 56 |
} |
|
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!!