Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (522)
Games in Android Showcase (127)
games submitted by our members
Games in WIP (590)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: 1 [2]
  ignore  |  Print  
  VBO performance  (Read 2608 times)
0 Members and 1 Guest are viewing this topic.
Offline opiop65

JGO Kernel


Medals: 159
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #30 - Posted 2014-03-10 20:06:20 »

I can only imagine why you would need 10K sprites visible at one time! I would think a few hundred would be a lot already.

Offline theagentd

« JGO Bitwise Duke »


Medals: 361
Projects: 2
Exp: 8 years



« Reply #31 - Posted 2014-03-10 20:07:05 »

I can only imagine why you would need 10K sprites visible at one time! I would think a few hundred would be a lot already.
Anything with particle effects? Come on, it's easy to get to 10K sprites.

Myomyomyo.
Offline opiop65

JGO Kernel


Medals: 159
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #32 - Posted 2014-03-10 20:10:42 »

I have never managed to reach that many. That would probably look very cool though, all those particles floating around!

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline princec

« JGO Spiffy Duke »


Medals: 421
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #33 - Posted 2014-03-10 20:44:01 »

Well, when the battlefield is zoomed out, there are 1,000 units on each side alone. Each unit is made up from 3 sprites (a shadow, a body, and some lights). There's 6,000 sprites.

Each unit then starts shooting... that's a sprite per bullet. And we haven't even done any particles yet!

... and this is without rendering any terrain sprites like trees, rocks, buildings, etc. yet either.

Cas Smiley

Offline opiop65

JGO Kernel


Medals: 159
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #34 - Posted 2014-03-10 20:44:59 »

Ah I see, that makes much more sense now Smiley

I could definitely see how that could get very... complicated very quickly!

Offline trollwarrior1
« Reply #35 - Posted 2014-03-10 20:50:43 »

Its kinda interesting..
I have done my spritebatch with glvertexattribpointer and with custom attributes and the performance is worse than immediate mode by 10 fps or so.(really small difference)
Give us frame times in milliseconds. Comparing FPS values like that says absolutely nothing. For all we know, the difference could be 11 ---> 1 FPS or 10000 ---> 9990 FPS. The first one is a huge difference while the second one might as well be a random spike 0.1 millisecond spike.

Does that mean that VBO is faster than glvertexattribpointer?
These two are not mutually exclusive. You can use glVertex
AttribPointer() to refer to data in a VBO or pass in a ***Buffer directly with data.

Ow cmon... You know what I meant.. I meant its really almost very small.. Was like 1500 and dropped to 1490
Offline gouessej
« Reply #36 - Posted 2014-03-10 22:12:14 »

No. We have already said that filling a buffer object and sending it to the GPU every frame is far less efficient than immediate mode. Like I said, use vertex arrays or stop worrying about deprecated functions and use immediate mode.
I agree with Kappa and I disagree with you. VBOs are in the worst case as slow as vertex arrays, for example on their very early implementations (ARB VBOs in OpenGL 1.3 graphics cards like mine). VBOs are the way to go if you want to support at least OpenGL 1.5. If you want to support OpenGL 1.2, you can use a second code path relying on vertex arrays. When I render my MD3 models in immediate mode, the frame rate is lower than with vertex arrays and VBOs whereas I modify the data every frame. I can hardly find a particular case justifying the use of the immediate mode and some APIs provide a way of emulating it with VBOs, it's nice to quickly port some very old code (just as a temporary solution).

Offline opiop65

JGO Kernel


Medals: 159
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #37 - Posted 2014-03-10 22:14:34 »

gouessej, see above where I specifically said I wasn't supporting the use of old deprecated functions, I just don't get ticked off when people do use them.

Offline gouessej
« Reply #38 - Posted 2014-03-12 22:54:06 »

opiop65, the retained mode and the immediate mode were both already in OpenGL 1.2. The choice of VBOs (or not) is mostly independent from the choice of the fixed pipeline or the programmable pipeline.

Offline StumpyStrust
« Reply #39 - Posted 2014-03-13 18:10:32 »

Tip on answering questions about opengl: Unless you REALLY know what you are talking about, do not say anything as you may confuse the person asking the question more then they already are.

Simple: Fixed Function/immediate mode should never be used. Especially because you can toss together a vertex array batcher for many types of data in a matter of minutes. The performance gain is at least an order of 10.



@pricec
I think you are hitting fillrate issues more than anything else. Even on lowend POS systems I can very easily get 10k+ sprites going at it. Problem is fillrate....its always fillrate.
I am sure you are doing culling when a sprite is outside the camera. Could use polygon meshes instead of quads/triangles_strips. Reduce overdraw via less composited stuff. Instead have the shadow part of the sprite or something similar. Just tossing ideas out.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline opiop65

JGO Kernel


Medals: 159
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #40 - Posted 2014-03-13 18:56:08 »

Most people associate immediate mode with the fixed function pipeline, that's what I was talking about... Sorry OP and everyone else.

Offline princec

« JGO Spiffy Duke »


Medals: 421
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #41 - Posted 2014-03-13 19:42:49 »

@princec
I think you are hitting fillrate issues more than anything else. Even on lowend POS systems I can very easily get 10k+ sprites going at it. Problem is fillrate....its always fillrate.
I am sure you are doing culling when a sprite is outside the camera. Could use polygon meshes instead of quads/triangles_strips. Reduce overdraw via less composited stuff. Instead have the shadow part of the sprite or something similar. Just tossing ideas out.
No, it's not that. There is virtually no overdraw, and most sprites are culled before they get written out. I'm barely touching the fillrate of the card (which is a GTX280 on my development machine - 5 years old but still pretty hot). The cost is almost entirely due to transforming and writing sprite data out to VBOs, which I've just multithreaded which has given me a tidy speed increase Smiley Various incantations involving glMapBufferRange flags give serious speed increases too.

Cas Smiley

Offline StumpyStrust
« Reply #42 - Posted 2014-03-13 20:56:29 »

That is so odd. On my laptops integrated gpu (first gen i5) I can push into 50K+ easily at solid 60. This is without any game logic so there is that but I would think that it wouldn't vary that much. I am sure your sprite batcher is more complicated then mine but it makes me wonder why it would be the bottle neck.



PS. multithreading...nice job man.

Offline princec

« JGO Spiffy Duke »


Medals: 421
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #43 - Posted 2014-03-13 21:06:39 »

Well, here's the code to write just one sprite:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
   public void writeSprite(Sprite sprite, Matrix4f transform, FloatBuffer vertexBuf) {
      SpriteImage image = sprite.getImage();

      final float tx0 = image.tx0;
      final float tx1 = image.tx1;
      final float ty0 = image.ty0;
      final float ty1 = image.ty1;

      final float xscale = sprite.xscale;
      final float yscale = sprite.yscale;

      int alpha = (int) ((sprite.alpha * sprite.masterAlpha) * BattleRenderingConstants.ALPHA_DIV);
      boolean flipped = sprite.isFlipped();
      boolean mirrored = sprite.isMirrored();

      Sprite parent = sprite.getParent();
      for (Sprite p = parent; p != null; p = p.getParent()) {
         flipped ^= p.isFlipped();
         mirrored ^= p.isMirrored();
         alpha = (int) ((alpha * p.alpha * p.masterAlpha) * BattleRenderingConstants.ALPHA_DIV * BattleRenderingConstants.ALPHA_DIV);
      }
      final float x = sprite.x + (mirrored ? -sprite.ox : sprite.ox);
      final float y = sprite.y + (flipped ? -sprite.oy : sprite.oy);

      // First scale then rotate coordinates
      float scaledx0 = mirrored ? (image.ow - image.ox - image.w - image.hotspotx) * xscale : (image.ox - image.hotspotx) * xscale;
      float scaledy0 = flipped ? (image.oh - image.oy - image.h - image.hotspoty) * yscale : (image.oy - image.hotspoty) * yscale;
      float scaledx1 = mirrored ? (image.ow - image.hotspotx - image.ox) * xscale : (image.ox + image.w - image.hotspotx) * xscale;
      float scaledy1 = flipped ? (image.oh - image.hotspoty - image.oy) * yscale : (image.oy + image.h - image.hotspoty) * yscale;

      final float angle = (float) toRadians(mirrored ? -sprite.angle : sprite.angle);
      final float cos = (float) Math.cos(angle);
      final float sin = (float) Math.sin(angle);

      final float cosx0 = cos * scaledx0;
      final float siny0 = sin * scaledy0;
      final float cosx1 = cos * scaledx1;
      final float siny1 = sin * scaledy1;
      final float sinx0 = sin * scaledx0;
      final float cosy0 = cos * scaledy0;
      final float sinx1 = sin * scaledx1;
      final float cosy1 = cos * scaledy1;

      final float txA = mirrored ? tx1 : tx0;
      final float tyA = flipped ? ty0 : ty1;
      final float txB = mirrored ? tx0 : tx1;
      final float tyB = flipped ? ty1 : ty0;

      final float x0, y0, x1, y1, x2, y2, x3, y3;
      if (parent != null) {
         Vector4f temp = TEMP.get(), dest = DEST.get();
         temp.x = (cosx0 - siny0) + x;
         temp.y = (sinx0 + cosy0) + y;
         transform(transform, temp, dest);
         x0 = dest.x;
         y0 = dest.y;

         temp.x = (cosx1 - siny0) + x;
         temp.y = (sinx1 + cosy0) + y;
         transform(transform, temp, dest);
         x1 = dest.x;
         y1 = dest.y;

         temp.x = (cosx1 - siny1) + x;
         temp.y = (sinx1 + cosy1) + y;
         transform(transform, temp, dest);
         x2 = dest.x;
         y2 = dest.y;

         temp.x = (cosx0 - siny1) + x;
         temp.y = (sinx0 + cosy1) + y;
         transform(transform, temp, dest);
         x3 = dest.x;
         y3 = dest.y;

      } else {
         x0 = (cosx0 - siny0) + x;
         y0 = (sinx0 + cosy0) + y;
         x1 = (cosx1 - siny0) + x;
         y1 = (sinx1 + cosy0) + y;
         x2 = (cosx1 - siny1) + x;
         y2 = (sinx1 + cosy1) + y;
         x3 = (cosx0 - siny1) + x;
         y3 = (sinx0 + cosy1) + y;
      }

      float z = image.z;
      float m = mirrored ? -1.0f : 1.0f;

      vertexBuf.put(x0);
      vertexBuf.put(y0);
      vertexBuf.put(y0 - sprite.y);
      vertexBuf.put(txA);
      vertexBuf.put(tyA);
      vertexBuf.put(z);
      writeColor(sprite.color00, alpha, vertexBuf);
      vertexBuf.put(mode);
      vertexBuf.put(sprite.custom00);
      vertexBuf.put(sprite.custom01);
      vertexBuf.put(m);
      vertexBuf.put(angle);

      vertexBuf.put(x1);
      vertexBuf.put(y1);
      vertexBuf.put(y1 - sprite.y);
      vertexBuf.put(txB);
      vertexBuf.put(tyA);
      vertexBuf.put(z);
      writeColor(sprite.color10, alpha, vertexBuf);
      vertexBuf.put(mode);
      vertexBuf.put(sprite.custom00);
      vertexBuf.put(sprite.custom01);
      vertexBuf.put(m);
      vertexBuf.put(angle);

      vertexBuf.put(x2);
      vertexBuf.put(y2);
      vertexBuf.put(y2 - sprite.y);
      vertexBuf.put(txB);
      vertexBuf.put(tyB);
      vertexBuf.put(z);
      writeColor(sprite.color11, alpha, vertexBuf);
      vertexBuf.put(mode);
      vertexBuf.put(sprite.custom00);
      vertexBuf.put(sprite.custom01);
      vertexBuf.put(m);
      vertexBuf.put(angle);

      vertexBuf.put(x3);
      vertexBuf.put(y3);
      vertexBuf.put(y3 - sprite.y);
      vertexBuf.put(txA);
      vertexBuf.put(tyB);
      vertexBuf.put(z);
      writeColor(sprite.color01, alpha, vertexBuf);
      vertexBuf.put(mode);
      vertexBuf.put(sprite.custom00);
      vertexBuf.put(sprite.custom01);
      vertexBuf.put(m);
      vertexBuf.put(angle);
   }

   @Override
   public void writeColor(int color, int alpha, FloatBuffer dest) {
      float alpha00 = ((color >> 24) & 0xFF) * alpha * BattleRenderingConstants.ALPHA_DIV;
      float preMultAlpha00 = alpha00 * BattleRenderingConstants.ALPHA_DIV;
      if (glowing && !isBaking()) {
         dest.put(Float.intBitsToFloat(((int) ((color & 0xFF) * preMultAlpha00)) | ((int) (((color >> 8) & 0xFF) * preMultAlpha00) << 8) | ((int) (((color >> 16) & 0xFF) * preMultAlpha00) << 16)));
      } else {
         dest.put(Float.intBitsToFloat(((int) ((color & 0xFF) * preMultAlpha00)) | ((int) (((color >> 8) & 0xFF) * preMultAlpha00) << 8) | ((int) (((color >> 16) & 0xFF) * preMultAlpha00) << 16) | ((int) alpha00) << 24));
      }
   }


I have to do that 20,000 times in 17ms... after I've figured out which order to draw them in!

The other huge speedup I've managed is by putting the game logic in - wait for it - a separate thread. This is both more difficult and easier than it looks, though it helps that this particular game is designed around doing something like this. The game logic thread only needs to be interrupted for a very short time whilst sprite parameters are updated so the logic thread is usually well utilised.

Cas Smiley

Offline StumpyStrust
« Reply #44 - Posted 2014-03-13 21:26:25 »

Anyway you could move some stuff such as rotation to a shader? May speed things up. Looks similar to what I used which I posted in I think the tutorials section. It is not using a VBO but the built in VA. I have since changed it to use a single interleaved buffer but still use the built in VA.

Offline princec

« JGO Spiffy Duke »


Medals: 421
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #45 - Posted 2014-03-14 09:16:06 »

I would do but it's not the whole story, and besides, the rotation is just a few multiplies... to get the shader to do it I'd have to pass in a whole bunch of extra data to the VBO instead. Here's the method that calls writeSprite:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
185  
186  
187  
188  
189  
190  
191  
192  
193  
194  
195  
196  
197  
198  
199  
200  
201  
202  
203  
204  
205  
206  
207  
208  
209  
210  
211  
212  
213  
214  
215  
216  
217  
218  
219  
220  
221  
222  
223  
224  
225  
226  
227  
228  
229  
230  
231  
232  
233  
234  
      public void addRoot(Sprite sprite, Style useStyle, Context context) {
         // First flatten the entire hierarchy into an array
         int hierarchySize = 1;
         int idx = 0;
         context.hierarchy[0] = sprite;
         while (idx < hierarchySize) {
            Sprite s = context.hierarchy[idx++];
            Sprite[] children = s.getChildren();
            if (children == null) {
               continue;
            }
            for (int i = 0, n = s.getNumChildren(); i < n; i++) {
               Sprite child = children[i];
               if (!child.isVisible()) {
                  continue;
               }

               Style childUseStyle = child.getRenderStyle();
               if (childUseStyle == null) {
                  continue;
               }
               context.hierarchy[hierarchySize++] = child;
            }
         }

         // Now sort it by order. The number of elements is so tiny that we will use GnomeSort as it's super cache friendly
         // and not too slow for small sizes.
         GnomeSort.sort(context.hierarchy, 0, hierarchySize, ORDER_COMPARATOR);

         // Now draw the sprites, but don't write data to the vertex buffers; just freeze it.
         add(sprite, useStyle, DrawMode.BUFFER, context);

         // And now draw the sprites in the order we want them drawn, using frozen data
         for (int i = 0; i < hierarchySize; i++) {
            Sprite s = context.hierarchy[i];
            add(s, s.getRenderStyle(), DrawMode.OUTPUT, context);
         }
      }

      private void checkStartNewState(Sprite sprite, Style useStyle) {
         boolean needToStartNewState = false;

         assert useStyle != null;

         if (currentRun == null) {
            needToStartNewState = true;
         } else if (currentStyle == null) {
            needToStartNewState = true;
         } else if (useStyle.getStyleID() != currentStyle.getStyleID()) {
            needToStartNewState = true;
         } else {
            SpriteImage img = sprite.image;
            if (img != null) {
               for (int i = 0, n = useStyle.getNumTextures(); i < n; i++) {
                  if (img.texture.length > i) {
                     GLBaseTexture tex = img.texture[i];
                     if (tex != null && currentTexture[i] != tex) {
                        needToStartNewState = true;
                        break;
                     }
                  }
               }
            }
         }

         if (needToStartNewState) {
            // Changed state. Start new state.
            int currentVertexOffset = currentRun == null ? 0 : currentRun.vertexOffset;
            int currentIndexOffset = currentRun == null ? 0 : currentRun.indexOffset;
            nextStateRun();
            currentRun.style = useStyle;
            SpriteImage img = sprite.image;
            if (img != null) {
               for (int i = 0, n = useStyle.getNumTextures(); i < n; i++) {
                  if (i >= img.texture.length) {
                     break;
                  }
                  GLBaseTexture tex = img.texture[i];
                  if (img.texture.length > i && tex != null) {
                     currentTexture[i] = tex;
                     currentRun.texture[i] = tex;
                  }
               }
            }

            // If we've got a different stride, we need to start a new offset
            if (currentStride != useStyle.getVertexStride()) {
               currentStride = useStyle.getVertexStride();
               currentRun.startIndex = indexCursor = 0;
               currentRun.endIndex = 0;
               currentRun.startVertex = vertexCursor = 0;
               currentRun.endVertex = 0;
               currentRun.vertexOffset = vertexPosition * 4;
               currentRun.indexOffset = mappedIndices.position() * 4;
            } else {
               // Same stride as before, so continue using same stuff
               currentRun.startIndex = indexCursor;
               currentRun.endIndex = indexCursor;
               currentRun.startVertex = vertexCursor;
               currentRun.endVertex = vertexCursor;
               currentRun.vertexOffset = currentVertexOffset;
               currentRun.indexOffset = currentIndexOffset;
            }

            currentStyle = useStyle;
         }
      }

      public void add(Sprite sprite, Style useStyle, DrawMode mode, Context context) {
         if (mode != DrawMode.BUFFER) {
            // System.out.println("Position at " + vertexPosition + " for sprite " + System.identityHashCode(sprite) + " (base: " + baseVertexOffset + ")");
            checkStartNewState(sprite, useStyle);
         }

         boolean frozen = sprite.isFrozen();
         ByteBuffer raw = sprite.getRaw();
         FloatBuffer vertexBuf = mappedVertices;
         int startPosition = vertexPosition;
         vertexBuf.position(startPosition);
         int vertexStride = useStyle.getVertexStride();
         if (frozen) {
            if (raw == null) {
               raw = ByteBuffer.allocate(vertexStride * 4).order(ByteOrder.nativeOrder());
               sprite.setRaw(raw);
               frozen = false; // cause calcs to be made and raw to be written to
            } else {
               if (mode != DrawMode.BUFFER) {
                  raw = sprite.getRaw();
                  raw.limit(vertexStride * 4).rewind();
                  rawVertices.limit((startPosition + vertexStride) << 2).position(startPosition << 2);
                  rawVertices.put(raw);
               }
            }
         } else if (mode == DrawMode.BUFFER) {
            if (raw == null) {
               raw = ByteBuffer.allocate(vertexStride * 4).order(ByteOrder.nativeOrder());
               sprite.setRaw(raw);
            }
         }

         if (mode == DrawMode.OUTPUT) {
            raw = sprite.getRaw();
            raw.limit(vertexStride * 4).rewind();
            rawVertices.limit((startPosition + vertexStride) << 2).position(startPosition << 2);
            rawVertices.put(raw);
         } else if (!frozen) {
            if (raw != null) {
               raw.rewind();
               vertexBuf = raw.asFloatBuffer();
            }

            useStyle.writeSprite(sprite, context.stack[context.stackDepth], vertexBuf);

            if (raw != null && mode != DrawMode.BUFFER) {
               raw.rewind();
               rawVertices.limit((startPosition + vertexStride) << 2).position(startPosition << 2);
               rawVertices.put(raw);
            }
         }

         if (mode != DrawMode.BUFFER) {
            // Write indices: need 6, for two triangles
            IntBuffer indexBuf = mappedIndices;
            int vx = vertexCursor;
            indexBuf.put(vx + 0);
            indexBuf.put(vx + 1);
            indexBuf.put(vx + 2);
            indexBuf.put(vx + 0);
            indexBuf.put(vx + 2);
            indexBuf.put(vx + 3);

            indexCursor += 6;
            vertexPosition += vertexStride;
            vertexCursor += 4;
            currentRun.endIndex += 6;
            currentRun.endVertex += 4;
         }

         if (mode != DrawMode.BUFFER) {
            return;
         }

         Sprite[] children = sprite.getChildren();
         if (children != null) {
            context.stackDepth++;

            boolean mirrored = sprite.isMirrored();
            boolean flipped = sprite.isFlipped();
            Sprite parent = sprite.getParent();
            while (parent != null) {
               mirrored ^= parent.isMirrored();
               flipped ^= parent.isFlipped();
               parent = parent.getParent();
            }
            float ox = mirrored ? -sprite.ox : sprite.ox;
            float oy = flipped ? -sprite.oy : sprite.oy;
            context.stack[context.stackDepth].load(context.stack[context.stackDepth - 1]);
            context.temp_vec3.set(sprite.x + ox, sprite.y + oy, 0.0f);
            context.stack[context.stackDepth].translate(context.temp_vec3);

            float angle = sprite.angle;
            if (angle != 0.0f) {
               if (mirrored) {
                  angle = -angle;
               }
               context.stack[context.stackDepth].rotate((float) Math.toRadians(angle), ROTATE_VEC);
            }
            if (sprite.xscale != 1.0f || sprite.yscale != 1.0f) {
               context.temp_vec3.set(sprite.xscale, sprite.yscale, 0.0f);
               context.stack[context.stackDepth].scale(context.temp_vec3);
            }

            for (int i = 0, n = sprite.getNumChildren(); i < n; i++) {
               Sprite child = children[i];
               if (!child.isVisible()) {
                  continue;
               }

               Style childUseStyle = child.getRenderStyle();
               if (childUseStyle == null) {
                  continue;
               }

               if (childUseStyle.getRenderSprite()) {
                  add(child, childUseStyle, DrawMode.BUFFER, context);
               } else {
                  assert false : "Not yet implemented properly"; // We need to apply the current transform to the geometry...
                                                                 // hmmm
               }
            }

            context.stackDepth--;
         }
      }


Because our sprites exist in hierarchies we have two ways to add sprites to the scene; as the root of a hierarchy, or as a plain sprite. When you start adding child sprites there's a cumulative transform applied. Note also how at that point I'm tracking GL state changes to build up batches.

Cas Smiley

Pages: 1 [2]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

trollwarrior1 (29 views)
2014-11-22 12:13:56

xFryIx (71 views)
2014-11-13 12:34:49

digdugdiggy (50 views)
2014-11-12 21:11:50

digdugdiggy (44 views)
2014-11-12 21:10:15

digdugdiggy (38 views)
2014-11-12 21:09:33

kovacsa (62 views)
2014-11-07 19:57:14

TehJavaDev (67 views)
2014-11-03 22:04:50

BurntPizza (64 views)
2014-11-03 18:54:52

moogie (80 views)
2014-11-03 06:22:04

CopyableCougar4 (80 views)
2014-11-01 23:36:41
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!