Project

General

Profile

« Previous | Next » 

Revision c6e1c219

Added by Leszek Koltunski over 8 years ago

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!!

View differences:

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