1/*
2 * Copyright (c) 2009-2010 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33package jme3tools.optimize;
34
35import com.jme3.bounding.BoundingBox;
36import com.jme3.renderer.Camera;
37import com.jme3.scene.Geometry;
38import java.util.Set;
39
40public class FastOctnode {
41
42    int offset;
43    int length;
44    FastOctnode child;
45    FastOctnode next;
46
47    private static final BoundingBox tempBox = new BoundingBox();
48
49    public int getSide(){
50        return ((offset & 0xE0000000) >> 29) & 0x7;
51    }
52
53    public void setSide(int side){
54        offset &= 0x1FFFFFFF;
55        offset |= (side << 29);
56    }
57
58    public void setOffset(int offset){
59        if (offset < 0 || offset > 20000000){
60            throw new IllegalArgumentException();
61        }
62
63        this.offset &= 0xE0000000;
64        this.offset |= offset;
65    }
66
67    public int getOffset(){
68        return this.offset & 0x1FFFFFFF;
69    }
70
71    private void generateRenderSetNoCheck(Geometry[] globalGeomList, Set<Geometry> renderSet, Camera cam){
72        if (length != 0){
73            int start = getOffset();
74            int end   = start + length;
75            for (int i = start; i < end; i++){
76                renderSet.add(globalGeomList[i]);
77            }
78        }
79
80        if (child == null)
81            return;
82
83        FastOctnode node = child;
84        while (node != null){
85            node.generateRenderSetNoCheck(globalGeomList, renderSet, cam);
86            node = node.next;
87        }
88    }
89
90    private static void findChildBound(BoundingBox bbox, int side){
91        float extent = bbox.getXExtent() * 0.5f;
92        bbox.getCenter().set(bbox.getCenter().x + extent * Octnode.extentMult[side].x,
93                             bbox.getCenter().y + extent * Octnode.extentMult[side].y,
94                             bbox.getCenter().z + extent * Octnode.extentMult[side].z);
95        bbox.setXExtent(extent);
96        bbox.setYExtent(extent);
97        bbox.setZExtent(extent);
98    }
99
100    public void generateRenderSet(Geometry[] globalGeomList, Set<Geometry> renderSet, Camera cam, BoundingBox parentBox, boolean isRoot){
101        tempBox.setCenter(parentBox.getCenter());
102        tempBox.setXExtent(parentBox.getXExtent());
103        tempBox.setYExtent(parentBox.getYExtent());
104        tempBox.setZExtent(parentBox.getZExtent());
105
106        if (!isRoot){
107            findChildBound(tempBox, getSide());
108        }
109
110        tempBox.setCheckPlane(0);
111        cam.setPlaneState(0);
112        Camera.FrustumIntersect result = cam.contains(tempBox);
113        if (result != Camera.FrustumIntersect.Outside){
114            if (length != 0){
115                int start = getOffset();
116                int end   = start + length;
117                for (int i = start; i < end; i++){
118                    renderSet.add(globalGeomList[i]);
119                }
120            }
121
122            if (child == null)
123                return;
124
125            FastOctnode node = child;
126
127            float x = tempBox.getCenter().x;
128            float y = tempBox.getCenter().y;
129            float z = tempBox.getCenter().z;
130            float ext = tempBox.getXExtent();
131
132            while (node != null){
133                if (result == Camera.FrustumIntersect.Inside){
134                    node.generateRenderSetNoCheck(globalGeomList, renderSet, cam);
135                }else{
136                    node.generateRenderSet(globalGeomList, renderSet, cam, tempBox, false);
137                }
138
139                tempBox.getCenter().set(x,y,z);
140                tempBox.setXExtent(ext);
141                tempBox.setYExtent(ext);
142                tempBox.setZExtent(ext);
143
144                node = node.next;
145            }
146        }
147    }
148
149    @Override
150    public String toString(){
151        return "OCTNode[O=" + getOffset() + ", L=" + length +
152                ", S=" + getSide() + "]";
153    }
154
155    public String toStringVerbose(int indent){
156        String str = "------------------".substring(0,indent) + toString() + "\n";
157        if (child == null)
158            return str;
159
160        FastOctnode children = child;
161        while (children != null){
162            str += children.toStringVerbose(indent+1);
163            children = children.next;
164        }
165
166        return str;
167    }
168
169}
170