Revision c204c69d
Added by Leszek Koltunski almost 9 years ago
| src/main/java/org/distorted/library/Distorted.java | ||
|---|---|---|
| 138 | 138 |
DistortedNode.onDestroy(); |
| 139 | 139 |
EffectQueue.onDestroy(); |
| 140 | 140 |
DistortedEffects.onDestroy(); |
| 141 |
DistortedAttachDaemon.onDestroy(); |
|
| 141 | 142 |
EffectMessageSender.stopSending(); |
| 142 | 143 |
|
| 143 | 144 |
mInitialized = false; |
| src/main/java/org/distorted/library/DistortedAttachDaemon.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.library; |
|
| 21 |
|
|
| 22 |
import java.util.ArrayList; |
|
| 23 |
|
|
| 24 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 25 |
/** |
|
| 26 |
* This static class handles changing topology of a Tree in a safe way. I.e. if one wants to |
|
| 27 |
* attach() a new Node somewhere in the Tree, we cannot simply attach it mid-render (detach() is |
|
| 28 |
* even worse!). What we do instead is mark that this job will have to be done and actually do it |
|
| 29 |
* just before the next render. That's what this Daemon does. |
|
| 30 |
*/ |
|
| 31 |
class DistortedAttachDaemon |
|
| 32 |
{
|
|
| 33 |
private static final int ATTACH = 0; // |
|
| 34 |
private static final int DETACH = 1; // types of jobs that the Daemon can do |
|
| 35 |
private static final int DETACHALL = 2; // |
|
| 36 |
|
|
| 37 |
private static class Job |
|
| 38 |
{
|
|
| 39 |
int type; |
|
| 40 |
DistortedAttacheable attacheable; |
|
| 41 |
DistortedNode object; |
|
| 42 |
|
|
| 43 |
Job(int t, DistortedAttacheable a, DistortedNode o) |
|
| 44 |
{
|
|
| 45 |
type = t; |
|
| 46 |
attacheable = a; |
|
| 47 |
object = o; |
|
| 48 |
} |
|
| 49 |
} |
|
| 50 |
|
|
| 51 |
private static ArrayList<Job> mJobs = new ArrayList<>(); |
|
| 52 |
|
|
| 53 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 54 |
|
|
| 55 |
private DistortedAttachDaemon() |
|
| 56 |
{
|
|
| 57 |
|
|
| 58 |
} |
|
| 59 |
|
|
| 60 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 61 |
|
|
| 62 |
static boolean toDo() |
|
| 63 |
{
|
|
| 64 |
int num = mJobs.size(); |
|
| 65 |
Job job; |
|
| 66 |
|
|
| 67 |
for(int i=0; i<num; i++) |
|
| 68 |
{
|
|
| 69 |
job = mJobs.remove(0); |
|
| 70 |
|
|
| 71 |
switch(job.type) |
|
| 72 |
{
|
|
| 73 |
case ATTACH : job.attacheable.attachNow(job.object); |
|
| 74 |
break; |
|
| 75 |
case DETACH : job.attacheable.detachNow(job.object); |
|
| 76 |
break; |
|
| 77 |
case DETACHALL: job.attacheable.detachAllNow() ; |
|
| 78 |
break; |
|
| 79 |
default : android.util.Log.e("AttachDaemon", "what?");
|
|
| 80 |
} |
|
| 81 |
} |
|
| 82 |
|
|
| 83 |
return ( num>0 ); |
|
| 84 |
} |
|
| 85 |
|
|
| 86 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 87 |
|
|
| 88 |
static void attach(DistortedAttacheable a, DistortedNode n) |
|
| 89 |
{
|
|
| 90 |
mJobs.add(new Job(ATTACH,a,n)); |
|
| 91 |
} |
|
| 92 |
|
|
| 93 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 94 |
|
|
| 95 |
static void detach(DistortedAttacheable a, DistortedNode n) |
|
| 96 |
{
|
|
| 97 |
mJobs.add(new Job(DETACH,a,n)); |
|
| 98 |
} |
|
| 99 |
|
|
| 100 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 101 |
|
|
| 102 |
static void detachAll(DistortedAttacheable a) |
|
| 103 |
{
|
|
| 104 |
mJobs.add(new Job(DETACHALL,a,null)); |
|
| 105 |
} |
|
| 106 |
|
|
| 107 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 108 |
|
|
| 109 |
static void onDestroy() |
|
| 110 |
{
|
|
| 111 |
mJobs.clear(); |
|
| 112 |
} |
|
| 113 |
} |
|
| src/main/java/org/distorted/library/DistortedAttacheable.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.library; |
|
| 21 |
|
|
| 22 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 23 |
/** |
|
| 24 |
* Package-private interface implemented by all objects to which one can attach a Tree-like structure |
|
| 25 |
* of DistortedNodes. (Currently: DistortedNode itself and DistortedOutputSurface). |
|
| 26 |
* <p> |
|
| 27 |
* All the methods below are really meant to be package-local; and this interface should really be a |
|
| 28 |
* package-local class which other classes would extend (but that's impossible because OutputSurface |
|
| 29 |
* already extends other class). |
|
| 30 |
*/ |
|
| 31 |
interface DistortedAttacheable |
|
| 32 |
{
|
|
| 33 |
void attachNow(DistortedNode n); |
|
| 34 |
void detachNow(DistortedNode n); |
|
| 35 |
void detachAllNow(); |
|
| 36 |
} |
|
| src/main/java/org/distorted/library/DistortedNode.java | ||
|---|---|---|
| 27 | 27 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 28 | 28 |
/** |
| 29 | 29 |
* Class which represents a Node in a Tree of (InputSurface,Mesh,Effects) triplets. |
| 30 |
*
|
|
| 30 |
* <p>
|
|
| 31 | 31 |
* Having organized such sets into a Tree, we can then render any Node to any OutputSurface. |
| 32 | 32 |
* That recursively renders the set held in the Node and all its children. |
| 33 |
* <p> |
|
| 34 |
* The class takes special care to only render identical sub-trees once. Each Node holds a reference |
|
| 35 |
* to sub-class 'NodeData'. Two identical sub-trees attached at different points of the main tree |
|
| 36 |
* will point to the same NodeData; only the first of this is rendered (when mData.numRendered==0). |
|
| 33 | 37 |
*/ |
| 34 |
public class DistortedNode |
|
| 38 |
public class DistortedNode implements DistortedAttacheable
|
|
| 35 | 39 |
{
|
| 36 | 40 |
private static HashMap<ArrayList<Long>,NodeData> mMapNodeID = new HashMap<>(); |
| 37 | 41 |
private static long mNextNodeID =0; |
| ... | ... | |
| 41 | 45 |
private DistortedInputSurface mSurface; |
| 42 | 46 |
private NodeData mData; |
| 43 | 47 |
|
| 44 |
private DistortedNode mParent; |
|
| 45 | 48 |
private ArrayList<DistortedNode> mChildren; |
| 46 | 49 |
private int[] mNumChildren; // ==mChildren.length(), but we only create mChildren if the first one gets added |
| 47 | 50 |
|
| ... | ... | |
| 58 | 61 |
numPointingNodes= 1; |
| 59 | 62 |
numRendered = 0; |
| 60 | 63 |
mFBO = null; |
| 61 |
|
|
| 62 |
android.util.Log.e("DistortedNode", "new NodeData");
|
|
| 63 | 64 |
} |
| 64 | 65 |
} |
| 65 | 66 |
|
| ... | ... | |
| 71 | 72 |
mMapNodeID.clear(); |
| 72 | 73 |
} |
| 73 | 74 |
|
| 74 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 75 |
// tree isomorphism |
|
| 76 |
|
|
| 77 |
private void RecomputeNodeID(ArrayList<Long> prev) |
|
| 78 |
{
|
|
| 79 |
ArrayList<Long> curr = generateIDList(); |
|
| 80 |
|
|
| 81 |
if( mParent==null ) |
|
| 82 |
{
|
|
| 83 |
adjustNodeData(prev,curr); |
|
| 84 |
} |
|
| 85 |
else |
|
| 86 |
{
|
|
| 87 |
ArrayList<Long> parentPrev = mParent.generateIDList(); |
|
| 88 |
adjustNodeData(prev,curr); |
|
| 89 |
mParent.RecomputeNodeID(parentPrev); |
|
| 90 |
} |
|
| 91 |
} |
|
| 92 |
|
|
| 93 | 75 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 94 | 76 |
|
| 95 | 77 |
private ArrayList<Long> generateIDList() |
| ... | ... | |
| 108 | 90 |
return ret; |
| 109 | 91 |
} |
| 110 | 92 |
|
| 111 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 112 |
|
|
| 113 |
private void adjustNodeData(ArrayList<Long> oldList, ArrayList<Long> newList) |
|
| 114 |
{
|
|
| 115 |
boolean otherNodesPoint = (mData.numPointingNodes>1); |
|
| 116 |
|
|
| 117 |
if( otherNodesPoint ) mData.numPointingNodes--; |
|
| 118 |
else mMapNodeID.remove(oldList); |
|
| 119 |
|
|
| 120 |
NodeData newData = mMapNodeID.get(newList); |
|
| 121 |
|
|
| 122 |
if( newData==null ) |
|
| 123 |
{
|
|
| 124 |
if( otherNodesPoint ) mData = new NodeData(++mNextNodeID); |
|
| 125 |
else mData.ID = ++mNextNodeID; // numPointingNodes must be 1 already |
|
| 126 |
|
|
| 127 |
if( newList.size()>1 ) |
|
| 128 |
{
|
|
| 129 |
if( mData.mFBO ==null ) |
|
| 130 |
{
|
|
| 131 |
android.util.Log.e("DistortedNode", "creating a new FBO");
|
|
| 132 |
|
|
| 133 |
mData.mFBO = new DistortedFramebuffer(mSurface.getWidth(), mSurface.getHeight()); |
|
| 134 |
} |
|
| 135 |
} |
|
| 136 |
else |
|
| 137 |
{
|
|
| 138 |
if( mData.mFBO !=null ) |
|
| 139 |
{
|
|
| 140 |
android.util.Log.e("DistortedNode", "marking FBO for deletion and setting it to NULL");
|
|
| 141 |
|
|
| 142 |
mData.mFBO.markForDeletion(); |
|
| 143 |
mData.mFBO = null; |
|
| 144 |
} |
|
| 145 |
else |
|
| 146 |
{
|
|
| 147 |
android.util.Log.e("DistortedNode", "adjustNodeData: impossible situation??");
|
|
| 148 |
} |
|
| 149 |
} |
|
| 150 |
|
|
| 151 |
mMapNodeID.put(newList, mData); |
|
| 152 |
} |
|
| 153 |
else |
|
| 154 |
{
|
|
| 155 |
newData.numPointingNodes++; |
|
| 156 |
mData = newData; |
|
| 157 |
} |
|
| 158 |
} |
|
| 159 |
|
|
| 160 | 93 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 161 | 94 |
// this will be called on startup and every time OpenGL context has been lost |
| 162 | 95 |
|
| ... | ... | |
| 174 | 107 |
|
| 175 | 108 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 176 | 109 |
// Debug - print all the Node IDs |
| 177 |
/* |
|
| 110 |
|
|
| 178 | 111 |
void debug(int depth) |
| 179 | 112 |
{
|
| 180 | 113 |
String tmp=""; |
| 181 | 114 |
int i; |
| 182 | 115 |
|
| 183 | 116 |
for(i=0; i<depth; i++) tmp +=" "; |
| 184 |
tmp += (mData.ID+" (nodes: "+mData.numPointingNodes+")");
|
|
| 117 |
tmp += ("NodeID="+mData.ID+" (nodes pointing: "+mData.numPointingNodes+" surfaceID="+mSurface.getID()+")");
|
|
| 185 | 118 |
|
| 186 | 119 |
android.util.Log.e("NODE", tmp);
|
| 187 | 120 |
|
| ... | ... | |
| 199 | 132 |
for(ArrayList<Long> key: mMapNodeID.keySet()) |
| 200 | 133 |
{
|
| 201 | 134 |
tmp = mMapNodeID.get(key); |
| 135 |
android.util.Log.e("NODE", "NodeID: "+tmp.ID+" <-- "+key);
|
|
| 136 |
} |
|
| 137 |
} |
|
| 138 |
|
|
| 139 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 140 |
|
|
| 141 |
void treeIsomorphism() |
|
| 142 |
{
|
|
| 143 |
android.util.Log.e("NODE", "begin treeIso for Node Surface ID="+mSurface.getID());
|
|
| 144 |
debug(0); |
|
| 145 |
debugMap(); |
|
| 146 |
android.util.Log.e("NODE", "begin treeIso for Node Surface ID="+mSurface.getID());
|
|
| 147 |
|
|
| 148 |
ArrayList<Long> oldList = generateIDList(); |
|
| 149 |
|
|
| 150 |
for(int i=0; i<mNumChildren[0]; i++) |
|
| 151 |
{
|
|
| 152 |
mChildren.get(i).treeIsomorphism(); |
|
| 153 |
} |
|
| 154 |
|
|
| 155 |
ArrayList<Long> newList = generateIDList(); |
|
| 156 |
NodeData newData = mMapNodeID.get(newList); |
|
| 157 |
|
|
| 158 |
if( newData==null ) |
|
| 159 |
{
|
|
| 160 |
android.util.Log.d("NODE", " inserted newData to map, newList="+newList);
|
|
| 161 |
|
|
| 162 |
|
|
| 163 |
newData = new NodeData(++mNextNodeID); |
|
| 164 |
mMapNodeID.put(newList,newData); |
|
| 165 |
debugMap(); |
|
| 166 |
} |
|
| 167 |
else if( newData.ID != mData.ID ) |
|
| 168 |
{
|
|
| 169 |
newData.numPointingNodes++; |
|
| 170 |
} |
|
| 171 |
|
|
| 172 |
if( newData.ID != mData.ID ) |
|
| 173 |
{
|
|
| 174 |
boolean fboUsed = false; |
|
| 175 |
|
|
| 176 |
if( mNumChildren[0]>0 && newData.mFBO==null ) |
|
| 177 |
{
|
|
| 178 |
if( mData.mFBO!=null ) |
|
| 179 |
{
|
|
| 180 |
newData.mFBO = mData.mFBO; |
|
| 181 |
fboUsed = true; |
|
| 182 |
} |
|
| 183 |
else |
|
| 184 |
{
|
|
| 185 |
newData.mFBO = new DistortedFramebuffer(mSurface.getWidth(),mSurface.getHeight()); |
|
| 186 |
} |
|
| 187 |
} |
|
| 188 |
if( mNumChildren[0]==0 && newData.mFBO!=null ) |
|
| 189 |
{
|
|
| 190 |
newData.mFBO.markForDeletion(); |
|
| 191 |
newData.mFBO = null; |
|
| 192 |
} |
|
| 193 |
|
|
| 194 |
if( --mData.numPointingNodes==0 ) |
|
| 195 |
{
|
|
| 196 |
android.util.Log.d("NODE", " removed oldData to map, oldList="+oldList);
|
|
| 197 |
|
|
| 202 | 198 |
|
| 203 |
android.util.Log.e("NODE", "key="+key+" NodeID: "+tmp.ID);
|
|
| 199 |
mMapNodeID.remove(oldList); |
|
| 200 |
debugMap(); |
|
| 201 |
|
|
| 202 |
if( !fboUsed && mData.mFBO!=null ) |
|
| 203 |
{
|
|
| 204 |
mData.mFBO.markForDeletion(); |
|
| 205 |
mData.mFBO = null; |
|
| 206 |
} |
|
| 207 |
} |
|
| 208 |
|
|
| 209 |
mData = newData; |
|
| 204 | 210 |
} |
| 211 |
|
|
| 212 |
android.util.Log.e("NODE", "end treeIso for Node SurfaceID="+mSurface.getID()+" newList="+newList);
|
|
| 213 |
debug(0); |
|
| 214 |
debugMap(); |
|
| 215 |
android.util.Log.e("NODE", "end treeIso for Node SurfaceID="+mSurface.getID()+" newList="+newList);
|
|
| 205 | 216 |
} |
| 206 |
*/ |
|
| 217 |
|
|
| 207 | 218 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 208 | 219 |
|
| 209 | 220 |
void drawRecursive(long currTime, DistortedOutputSurface surface) |
| ... | ... | |
| 256 | 267 |
mSurface = surface; |
| 257 | 268 |
mEffects = effects; |
| 258 | 269 |
mMesh = mesh; |
| 259 |
mParent = null; |
|
| 260 | 270 |
mChildren = null; |
| 261 | 271 |
mNumChildren = new int[1]; |
| 262 | 272 |
mNumChildren[0]= 0; |
| ... | ... | |
| 289 | 299 |
*/ |
| 290 | 300 |
public DistortedNode(DistortedNode node, int flags) |
| 291 | 301 |
{
|
| 292 |
mParent = null; |
|
| 293 | 302 |
mEffects= new DistortedEffects(node.mEffects,flags); |
| 294 | 303 |
mMesh = node.mMesh; |
| 295 | 304 |
|
| ... | ... | |
| 314 | 323 |
} |
| 315 | 324 |
if( (flags & Distorted.CLONE_CHILDREN) != 0 ) |
| 316 | 325 |
{
|
| 326 |
if( node.mChildren==null ) // do NOT copy over the NULL! |
|
| 327 |
{
|
|
| 328 |
node.mChildren = new ArrayList<>(2); |
|
| 329 |
} |
|
| 330 |
|
|
| 317 | 331 |
mChildren = node.mChildren; |
| 318 | 332 |
mNumChildren = node.mNumChildren; |
| 319 | 333 |
} |
| ... | ... | |
| 338 | 352 |
mMapNodeID.put(list, mData); |
| 339 | 353 |
} |
| 340 | 354 |
} |
| 341 |
|
|
| 355 |
|
|
| 342 | 356 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 343 | 357 |
/** |
| 344 | 358 |
* Adds a new child to the last position in the list of our Node's children. |
| 345 |
* |
|
| 359 |
* <p> |
|
| 360 |
* We cannot do this mid-render - actual attachment will be done just before the next render, by the |
|
| 361 |
* DistortedAttachDeamon (by calling attachNow()) |
|
| 362 |
* |
|
| 346 | 363 |
* @param node The new Node to add. |
| 347 | 364 |
*/ |
| 348 |
public synchronized void attach(DistortedNode node)
|
|
| 365 |
public void attach(DistortedNode node) |
|
| 349 | 366 |
{
|
| 350 |
ArrayList<Long> prev = generateIDList(); |
|
| 351 |
|
|
| 352 |
if( mChildren==null ) mChildren = new ArrayList<>(2); |
|
| 353 |
|
|
| 354 |
android.util.Log.e("DistortedNode", "ATTACH1");
|
|
| 355 |
|
|
| 356 |
|
|
| 357 |
node.mParent = this; |
|
| 358 |
mChildren.add(node); |
|
| 359 |
mNumChildren[0]++; |
|
| 360 |
|
|
| 361 |
RecomputeNodeID(prev); |
|
| 367 |
DistortedAttachDaemon.attach(this,node); |
|
| 362 | 368 |
} |
| 363 |
|
|
| 369 |
|
|
| 364 | 370 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 365 | 371 |
/** |
| 366 | 372 |
* Adds a new child to the last position in the list of our Node's children. |
| 367 |
* |
|
| 373 |
* <p> |
|
| 374 |
* We cannot do this mid-render - actual attachment will be done just before the next render, by the |
|
| 375 |
* DistortedAttachDeamon (by calling attachNow()) |
|
| 376 |
* |
|
| 368 | 377 |
* @param surface InputSurface to initialize our child Node with. |
| 369 | 378 |
* @param effects DistortedEffects to initialize our child Node with. |
| 370 | 379 |
* @param mesh MeshObject to initialize our child Node with. |
| 371 | 380 |
* @return the newly constructed child Node, or null if we couldn't allocate resources. |
| 372 | 381 |
*/ |
| 373 |
public synchronized DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
|
|
| 382 |
public DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh) |
|
| 374 | 383 |
{
|
| 375 |
ArrayList<Long> prev = generateIDList(); |
|
| 376 |
|
|
| 377 |
android.util.Log.e("DistortedNode", "ATTACH2");
|
|
| 384 |
DistortedNode node = new DistortedNode(surface,effects,mesh); |
|
| 385 |
DistortedAttachDaemon.attach(this,node); |
|
| 386 |
return node; |
|
| 387 |
} |
|
| 378 | 388 |
|
| 389 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 390 |
/** |
|
| 391 |
* This is not really part of the public API. Has to be public only because it is a part of the |
|
| 392 |
* DistortedAttacheable interface, which should really be a class that we extend here instead but |
|
| 393 |
* Java has no multiple inheritance. |
|
| 394 |
* |
|
| 395 |
* @param node The new Node to add. |
|
| 396 |
*/ |
|
| 397 |
public void attachNow(DistortedNode node) |
|
| 398 |
{
|
|
| 379 | 399 |
if( mChildren==null ) mChildren = new ArrayList<>(2); |
| 380 |
DistortedNode node = new DistortedNode(surface,effects,mesh); |
|
| 381 |
node.mParent = this; |
|
| 400 |
|
|
| 382 | 401 |
mChildren.add(node); |
| 383 | 402 |
mNumChildren[0]++; |
| 384 |
|
|
| 385 |
RecomputeNodeID(prev); |
|
| 386 |
|
|
| 387 |
return node; |
|
| 388 | 403 |
} |
| 389 |
|
|
| 404 |
|
|
| 390 | 405 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 391 | 406 |
/** |
| 392 | 407 |
* Removes the first occurrence of a specified child from the list of children of our Node. |
| 393 |
* |
|
| 408 |
* <p> |
|
| 409 |
* We cannot do this mid-render - actual detachment will be done just before the next render, by the |
|
| 410 |
* DistortedAttachDeamon (by calling detachNow()) |
|
| 411 |
* |
|
| 394 | 412 |
* @param node The Node to remove. |
| 395 |
* @return <code>true</code> if the child was successfully removed. |
|
| 396 | 413 |
*/ |
| 397 |
public synchronized boolean detach(DistortedNode node)
|
|
| 414 |
public void detach(DistortedNode node)
|
|
| 398 | 415 |
{
|
| 399 |
if( mNumChildren[0]>0 ) |
|
| 400 |
{
|
|
| 401 |
ArrayList<Long> prev = generateIDList(); |
|
| 402 |
|
|
| 403 |
if( mChildren.remove(node) ) |
|
| 404 |
{
|
|
| 405 |
android.util.Log.e("DistortedNode", "DETACH1");
|
|
| 406 |
|
|
| 407 |
node.mParent = null; |
|
| 408 |
mNumChildren[0]--; |
|
| 409 |
|
|
| 410 |
RecomputeNodeID(prev); |
|
| 411 |
|
|
| 412 |
return true; |
|
| 413 |
} |
|
| 414 |
} |
|
| 415 |
|
|
| 416 |
return false; |
|
| 416 |
DistortedAttachDaemon.detach(this,node); |
|
| 417 | 417 |
} |
| 418 | 418 |
|
| 419 | 419 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| ... | ... | |
| 422 | 422 |
* <p> |
| 423 | 423 |
* A bit questionable method as there can be many different Nodes attached as children, some |
| 424 | 424 |
* of them having the same Effects but - for instance - different Mesh. Use with care. |
| 425 |
* <p> |
|
| 426 |
* We cannot do this mid-render - actual detachment will be done just before the next render, by the |
|
| 427 |
* DistortedAttachDeamon (by calling detachNow()) |
|
| 425 | 428 |
* |
| 426 | 429 |
* @param effects DistortedEffects to remove. |
| 427 |
* @return <code>true</code> if the child was successfully removed. |
|
| 428 | 430 |
*/ |
| 429 |
public synchronized boolean detach(DistortedEffects effects)
|
|
| 431 |
public void detach(DistortedEffects effects)
|
|
| 430 | 432 |
{
|
| 431 | 433 |
long id = effects.getID(); |
| 432 | 434 |
DistortedNode node; |
| ... | ... | |
| 437 | 439 |
|
| 438 | 440 |
if( node.mEffects.getID()==id ) |
| 439 | 441 |
{
|
| 440 |
android.util.Log.e("DistortedNode", "DETACH2");
|
|
| 441 |
|
|
| 442 |
|
|
| 443 |
ArrayList<Long> prev = generateIDList(); |
|
| 444 |
|
|
| 445 |
node.mParent = null; |
|
| 446 |
mChildren.remove(i); |
|
| 447 |
mNumChildren[0]--; |
|
| 448 |
|
|
| 449 |
RecomputeNodeID(prev); |
|
| 450 |
|
|
| 451 |
return true; |
|
| 442 |
DistortedAttachDaemon.detach(this,node); |
|
| 443 |
break; |
|
| 452 | 444 |
} |
| 453 | 445 |
} |
| 454 |
|
|
| 455 |
return false; |
|
| 456 | 446 |
} |
| 457 | 447 |
|
| 458 | 448 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 459 | 449 |
/** |
| 460 |
* Removes all children Nodes. |
|
| 450 |
* This is not really part of the public API. Has to be public only because it is a part of the |
|
| 451 |
* DistortedAttacheable interface, which should really be a class that we extend here instead but |
|
| 452 |
* Java has no multiple inheritance. |
|
| 453 |
* |
|
| 454 |
* @param node The Node to remove. |
|
| 461 | 455 |
*/ |
| 462 |
public synchronized void detachAll()
|
|
| 456 |
public void detachNow(DistortedNode node)
|
|
| 463 | 457 |
{
|
| 464 |
for(int i=0; i<mNumChildren[0]; i++)
|
|
| 458 |
if( mNumChildren[0]>0 && mChildren.remove(node) )
|
|
| 465 | 459 |
{
|
| 466 |
mChildren.get(i).mParent = null;
|
|
| 460 |
mNumChildren[0]--;
|
|
| 467 | 461 |
} |
| 468 |
|
|
| 462 |
} |
|
| 463 |
|
|
| 464 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 465 |
/** |
|
| 466 |
* Removes all children Nodes. |
|
| 467 |
* <p> |
|
| 468 |
* We cannot do this mid-render - actual detachment will be done just before the next render, by the |
|
| 469 |
* DistortedAttachDeamon (by calling detachAllNow()) |
|
| 470 |
*/ |
|
| 471 |
public void detachAll() |
|
| 472 |
{
|
|
| 473 |
DistortedAttachDaemon.detachAll(this); |
|
| 474 |
} |
|
| 475 |
|
|
| 476 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 477 |
/** |
|
| 478 |
* This is not really part of the public API. Has to be public only because it is a part of the |
|
| 479 |
* DistortedAttacheable interface, which should really be a class that we extend here instead but |
|
| 480 |
* Java has no multiple inheritance. |
|
| 481 |
*/ |
|
| 482 |
public void detachAllNow() |
|
| 483 |
{
|
|
| 469 | 484 |
if( mNumChildren[0]>0 ) |
| 470 | 485 |
{
|
| 471 |
ArrayList<Long> prev = generateIDList(); |
|
| 472 |
|
|
| 473 | 486 |
mNumChildren[0] = 0; |
| 474 | 487 |
mChildren.clear(); |
| 475 |
RecomputeNodeID(prev); |
|
| 476 | 488 |
} |
| 477 | 489 |
} |
| 478 | 490 |
|
| src/main/java/org/distorted/library/DistortedOutputSurface.java | ||
|---|---|---|
| 24 | 24 |
|
| 25 | 25 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 26 | 26 |
|
| 27 |
abstract class DistortedOutputSurface extends DistortedSurface |
|
| 27 |
abstract class DistortedOutputSurface extends DistortedSurface implements DistortedAttacheable
|
|
| 28 | 28 |
{
|
| 29 | 29 |
private ArrayList<DistortedNode> mChildren; |
| 30 | 30 |
private int mNumChildren; // ==mChildren.length(), but we only create mChildren if the first one gets added |
| ... | ... | |
| 99 | 99 |
*/ |
| 100 | 100 |
public void render(long time) |
| 101 | 101 |
{
|
| 102 |
// change tree topology (attach and detach children) |
|
| 103 |
// create and delete all underlying OpenGL resources |
|
| 104 |
// Watch out: FIRST change topology, only then deal |
|
| 105 |
// with OpenGL resources. That's because changing Tree |
|
| 106 |
// can result in additional Framebuffers that would need |
|
| 107 |
// to be created immediately, before the calls to drawRecursive() |
|
| 108 |
|
|
| 109 |
if( DistortedAttachDaemon.toDo() ) |
|
| 110 |
{
|
|
| 111 |
for(int i=0; i<mNumChildren; i++) |
|
| 112 |
{
|
|
| 113 |
mChildren.get(i).treeIsomorphism(); |
|
| 114 |
} |
|
| 115 |
} |
|
| 116 |
|
|
| 102 | 117 |
toDo(); |
| 103 | 118 |
|
| 104 | 119 |
for(int i=0; i<mNumChildren; i++) |
| ... | ... | |
| 159 | 174 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 160 | 175 |
/** |
| 161 | 176 |
* Adds a new child to the last position in the list of our Surface's children. |
| 177 |
* <p> |
|
| 178 |
* We cannot do this mid-render - actual attachment will be done just before the next render, by the |
|
| 179 |
* DistortedAttachDeamon (by calling attachNow()) |
|
| 162 | 180 |
* |
| 163 | 181 |
* @param node The new Node to add. |
| 164 | 182 |
*/ |
| 165 |
public synchronized void attach(DistortedNode node)
|
|
| 183 |
public void attach(DistortedNode node) |
|
| 166 | 184 |
{
|
| 167 |
if( mChildren==null ) mChildren = new ArrayList<>(2); |
|
| 168 |
mChildren.add(node); |
|
| 169 |
mNumChildren++; |
|
| 185 |
DistortedAttachDaemon.attach(this,node); |
|
| 170 | 186 |
} |
| 171 | 187 |
|
| 172 | 188 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 173 | 189 |
/** |
| 174 | 190 |
* Adds a new child to the last position in the list of our Surface's children. |
| 191 |
* <p> |
|
| 192 |
* We cannot do this mid-render - actual attachment will be done just before the next render, by the |
|
| 193 |
* DistortedAttachDeamon (by calling attachNow()) |
|
| 175 | 194 |
* |
| 176 | 195 |
* @param surface InputSurface to initialize our child Node with. |
| 177 | 196 |
* @param effects DistortedEffects to initialize our child Node with. |
| 178 | 197 |
* @param mesh MeshObject to initialize our child Node with. |
| 179 | 198 |
* @return the newly constructed child Node, or null if we couldn't allocate resources. |
| 180 | 199 |
*/ |
| 181 |
public synchronized DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
|
|
| 200 |
public DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh) |
|
| 182 | 201 |
{
|
| 183 |
if( mChildren==null ) mChildren = new ArrayList<>(2); |
|
| 184 | 202 |
DistortedNode node = new DistortedNode(surface,effects,mesh); |
| 203 |
DistortedAttachDaemon.attach(this,node); |
|
| 204 |
return node; |
|
| 205 |
} |
|
| 206 |
|
|
| 207 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 208 |
/** |
|
| 209 |
* This is not really part of the public API. Has to be public only because it is a part of the |
|
| 210 |
* DistortedAttacheable interface, which should really be a class that we extend here instead but |
|
| 211 |
* Java has no multiple inheritance. |
|
| 212 |
* |
|
| 213 |
* @param node new Node to add. |
|
| 214 |
*/ |
|
| 215 |
public void attachNow(DistortedNode node) |
|
| 216 |
{
|
|
| 217 |
if( mChildren==null ) mChildren = new ArrayList<>(2); |
|
| 185 | 218 |
mChildren.add(node); |
| 186 | 219 |
mNumChildren++; |
| 187 |
|
|
| 188 |
return node; |
|
| 189 | 220 |
} |
| 190 | 221 |
|
| 191 | 222 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 192 | 223 |
/** |
| 193 | 224 |
* Removes the first occurrence of a specified child from the list of children of our Surface. |
| 225 |
* <p> |
|
| 226 |
* We cannot do this mid-render - actual attachment will be done just before the next render, by the |
|
| 227 |
* DistortedAttachDeamon (by calling detachNow()) |
|
| 228 |
* |
|
| 229 |
* @param node The Node to remove. |
|
| 230 |
*/ |
|
| 231 |
public void detach(DistortedNode node) |
|
| 232 |
{
|
|
| 233 |
DistortedAttachDaemon.detach(this,node); |
|
| 234 |
} |
|
| 235 |
|
|
| 236 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 237 |
/** |
|
| 238 |
* This is not really part of the public API. Has to be public only because it is a part of the |
|
| 239 |
* DistortedAttacheable interface, which should really be a class that we extend here instead but |
|
| 240 |
* Java has no multiple inheritance. |
|
| 194 | 241 |
* |
| 195 | 242 |
* @param node The Node to remove. |
| 196 |
* @return <code>true</code> if the child was successfully removed. |
|
| 197 | 243 |
*/ |
| 198 |
public synchronized boolean detach(DistortedNode node)
|
|
| 244 |
public void detachNow(DistortedNode node)
|
|
| 199 | 245 |
{
|
| 200 | 246 |
if( mNumChildren>0 && mChildren.remove(node) ) |
| 201 | 247 |
{
|
| 202 | 248 |
mNumChildren--; |
| 203 |
return true; |
|
| 204 | 249 |
} |
| 205 |
|
|
| 206 |
return false; |
|
| 207 | 250 |
} |
| 208 | 251 |
|
| 209 | 252 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| 210 | 253 |
/** |
| 211 | 254 |
* Removes all children Nodes. |
| 255 |
* <p> |
|
| 256 |
* We cannot do this mid-render - actual attachment will be done just before the next render, by the |
|
| 257 |
* DistortedAttachDeamon (by calling detachAllNow()) |
|
| 258 |
*/ |
|
| 259 |
public void detachAll() |
|
| 260 |
{
|
|
| 261 |
DistortedAttachDaemon.detachAll(this); |
|
| 262 |
} |
|
| 263 |
|
|
| 264 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
| 265 |
/** |
|
| 266 |
* This is not really part of the public API. Has to be public only because it is a part of the |
|
| 267 |
* DistortedAttacheable interface, which should really be a class that we extend here instead but |
|
| 268 |
* Java has no multiple inheritance. |
|
| 212 | 269 |
*/ |
| 213 |
public synchronized void detachAll()
|
|
| 270 |
public void detachAllNow()
|
|
| 214 | 271 |
{
|
| 215 | 272 |
if( mNumChildren>0 ) |
| 216 | 273 |
{
|
| src/main/java/org/distorted/library/DistortedSurface.java | ||
|---|---|---|
| 38 | 38 |
private static boolean mToDo = false; |
| 39 | 39 |
private static LinkedList<DistortedSurface> mDoneList = new LinkedList<>(); |
| 40 | 40 |
private static LinkedList<DistortedSurface> mToDoList = new LinkedList<>(); |
| 41 |
private static long mNextID = 0; |
|
| 41 | 42 |
|
| 43 |
private long mID; |
|
| 42 | 44 |
private boolean mMarked; |
| 43 | 45 |
int[] mColorH = new int[1]; |
| 44 | 46 |
int mSizeX, mSizeY; // in screen space |
| ... | ... | |
| 100 | 102 |
} |
| 101 | 103 |
|
| 102 | 104 |
mToDo = true; |
| 105 |
mNextID = 0; |
|
| 103 | 106 |
} |
| 104 | 107 |
|
| 105 | 108 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
| ... | ... | |
| 121 | 124 |
mSizeY = height; |
| 122 | 125 |
mColorH[0]= color; |
| 123 | 126 |
mMarked = false; |
| 127 |
mID = mNextID++; |
|
| 124 | 128 |
|
| 125 | 129 |
if( color!=DONT_CREATE ) |
| 126 | 130 |
{
|
| ... | ... | |
| 152 | 156 |
*/ |
| 153 | 157 |
public long getID() |
| 154 | 158 |
{
|
| 155 |
return mColorH[0];
|
|
| 159 |
return mID;
|
|
| 156 | 160 |
} |
| 157 | 161 |
|
| 158 | 162 |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
Also available in: Unified diff
New, cleaner way to create/destroy DistortedSurfaces.
Serious regression in StarWars (crashes!). Looks like the Node's internal FBO is being deleted and not re-created in time.