0

Objectives

  • To make health-bar perform insanely faster while updating the bar width.
  • To maintain its quality while scaling (pixel to meter ratio).

Currently I am using libgdx Pixmap to create an health bar, but when I change the drawLine parameters to new value then suddenly still there's no changes. In the bellow code is my current working code, I'm not sure if this is the sufficient way of drawing Pixmap dynamically.

// This code is working when written all in update method

Pixmap frame = new Pixmap(32, 3, Pixmap.Format.RGBA8888);
frame.drawRectangle(...);
frame.drawLine(...);

Texture texture = new Texture(frame);
frame.dispose();

batch.begin();
batch.draw(texture ...);
batch.end();

Sample healthbar

enter image description here

ronscript
  • 397
  • 1
  • 8
  • 33
  • Are you calling all of them in render() ? – Deniz Yılmaz Aug 11 '16 at 17:20
  • yes its working properly when I called all of them, but is there a way not to call them all? – ronscript Aug 11 '16 at 17:22
  • First of all you dont need actually create pixmap for this purpose. Secondly maybe you can create pixmap field in class but i just wanted the learn you did or not :) By the way are you changing pixmap color while drawing line and rectangle. – Deniz Yılmaz Aug 11 '16 at 17:28
  • I'm changing the line width while drawing its texture. – ronscript Aug 11 '16 at 17:29
  • Can you change pixmap color by pixmap.setColor(...) between draw rectangle and line.Of course change color to back after draw line. Your code looks okey to me.Also seeing parameters for line and rectangle would be better. – Deniz Yılmaz Aug 11 '16 at 17:32
  • You should not be creating new Pixmaps and Textures in your render loop. Allocate once and reuse. And if you aren't disposing them before losing the reference, you're leaking all of their memory. That said, if you are simply drawing rectangles and lines, ShapeRenderer would be way faster than Pixmap. – Tenfour04 Aug 11 '16 at 18:07

1 Answers1

5

You shouldn't be using Pixmap for that (as general rule of thumb: if you think you need to use Pixmap for something then you are likely wrong). A Pixmap is used to load, store or manipulate the image data in CPU memory: RAM. Manipulating image data in CPU memory is relatively slow and the resulting data can't be used to render on the screen with e.g. SpriteBatch.

For that you need to upload (copy) the data from CPU memory to GPU memory: VRAM. A Texture is used to represent the image data in VRAM. So, indeed, you could do that by creating a Texture out of it. Alternatively you could reuse an existing texture by calling the texture.load(pixmap) method. However, uploading image data from RAM to VRAM is also relatively slow.

So, instead of manipulating the image data on CPU and then copying it to GPU, you're better of to use the GPU directly to achieve what you want. You didn't provide enough information about what you actually want to achieve, but here are a few options that could help you get started.

  1. Draw only a portion of the full bar. Let's say you have an image in your atlas that represents the full health bar and you want to render only a portion of it, representing the actual health: batch.draw(region.getTexture(), x, y, width * health, height, region.getU(), region.getV(), region.getU() + health * (region.getU2() - region.getU()), region.getV2()); (here x, y, width and height are the location and size of bar in your world coordinates and health is the normalized health ranging from 0 to 1).
  2. Scale a TextureRegion to the size of the bar. Let's say your health bar is fully opaque or only with an outerline, then you can use a single pixel TextureRegion and scale it to be the size you want: barch.draw(region, x, y, width * health, height);
  3. Use a nine-patch.
  4. Use ShapeRenderer, which provides practically the same and more drawing functionality as Pixmap does, but instead does it directly using the GPU.
Xoppa
  • 7,983
  • 1
  • 23
  • 34
  • Which one do you recommend that most In terms of performance? – ronscript Aug 11 '16 at 18:27
  • 1
    That depends on your other code. If you are already using `ShapeRenderer` anyway then you might as well use it for this as well. If you use `SpriteBatch` however, then usually strechting a (single pixel) `TextureRegion` is better performing (note that you can use a single white pixel, because you can color it with SpriteBatch to whatever color you want). Either way, it probably never will be a noticeable performance difference. – Xoppa Aug 11 '16 at 18:30
  • Currently I'm using ECS framework and already created a versatile systems , so I could use any of the choices you made and also my game art designs is made of pixel art. Which one suits the best for my game? – ronscript Aug 11 '16 at 18:32
  • I wouldn't use option 1 for such simple bar, because that takes the most space in the atlas. Nine-patch is also not really necesarry for such simple bar. Personally I probably would use the single white texel approach, because a health bar is usually part of the UI and the UI is usually implemented using scene2d and that fits nice for a custom Actor. Scene2d implies using SpriteBatch, so that rules out ShapeRenderer. – Xoppa Aug 11 '16 at 19:28
  • Bam! that's what I need to hear from you `Scene2d` – ronscript Aug 11 '16 at 20:39
  • im thinking of using `Scene2d` and `TextureRegion`, do you think it would be better? – ronscript Aug 11 '16 at 21:00
  • Sure, using scene2d for UI is very common, although that has nothing to do with the actual rendering. This is beyond the scope of your original question though, so perhaps ask a new question if you have a new question. – Xoppa Aug 11 '16 at 21:15
  • Ive created another question http://stackoverflow.com/questions/38907063/how-to-create-a-pixel-size-health-bar-using-scene2d – ronscript Aug 11 '16 at 22:28
  • @ronscript Can you help me in this question please? [stackoverflow.com/questions/42130408/pixmaps-and-performance-libgdx] – Niranjana Feb 09 '17 at 07:35