rgk Posted January 19, 2017 Share Posted January 19, 2017 So one major optimization issue I have is that I update a bitmap and I have huge bitmaps, originally 4800 wide by 2100 high. ( Currently shrinking them to optimize because of update() ) Bullets remove chunks of ground, so I can't really call it less. The update function completely recreates all of that data. https://github.com/photonstorm/phaser/blob/v2.6.2/src/gameobjects/BitmapData.js#L596 Using the x, y, width and height forgets all the other data besides what is inside that. Does anyone know of any way of only updating a small portion of it while still keeping the rest of the array intact? I've been looking into it for quite some time with little luck. Link to comment Share on other sites More sharing options...
Fatalist Posted January 19, 2017 Share Posted January 19, 2017 Create a smaller ImageData, update it and the copy its data pixel-by-pixel to the main ImageData. Link to comment Share on other sites More sharing options...
rgk Posted January 19, 2017 Author Share Posted January 19, 2017 @Fatalist How would I do that? I'm having a hard time figuring out where to update this data in the array. Link to comment Share on other sites More sharing options...
phreaknation Posted January 19, 2017 Share Posted January 19, 2017 47 minutes ago, rgk said: @Fatalist How would I do that? I'm having a hard time figuring out where to update this data in the array. Using Fatalist's suggestion you should think of it as a grid and each part as coordinates. That will help you along Link to comment Share on other sites More sharing options...
Fatalist Posted January 19, 2017 Share Posted January 19, 2017 1 hour ago, rgk said: How would I do that? I'm having a hard time figuring out where to update this data in the array. The pixels array is one-dimensional, so to get to pixel [x, y] you need the element at: y * width + x Have not tested it, but this should work: function copyBitmapData(source, dest, x, y) { var sourcePixels = new Uint32Array(source.data.buffer), destPixels = new Uint32Array(dest.data.buffer); for (var i = 0; i < source.height; i++) { var destRowStart = (y + i) * dest.width + x; for (var j = 0; j < source.width; j++) { var pixel = sourcePixels[i * source.width + j]; destPixels[destRowStart + j] = pixel; } } } Link to comment Share on other sites More sharing options...
mattstyles Posted January 19, 2017 Share Posted January 19, 2017 You can get smarter than direct array access to make things a little more intuitive for you as developer. Take a look at ndarray, specifically array shifting to cut out part of the structure, this is one of the exact use-cases for the module. It's been a while since I mucked around with this stuff, but BitmapData is a load of ClampedUint8's right? Infact, I don't think it matters, you just create an ndarray based on the entire bitmap data, then use .lo and .hi to cut out a portion to create a shifted view of that array you can then manipulate: // Using pixels as its easier to manipulate, .data might suit better var image = ndarray(bitmapData.pixels, [4800, 2100]) var chunk = image.lo(400,400).hi(200,200) for (let i = 0; i < chunk.length; i += 4) { // Specify red (this might be how you do it, can't remember) // just saw this is wrong! haha, you'll get some colour though! let value = (255 << 24) | (255 << 16) | (0 << 8) | 0 // Set it to red chunk.set(x, value) } Chunk uses the same data structure as image and bitmapData so you're not duplicating arrays (memory), this does require you to keep track of it all and make sure you're not mutating the wrong underlying structure, but, well, yay javascript. edit: 3 hours ago, rgk said: I'm having a hard time figuring out where to update this data in the array. Just saw that, have you seen this? I checked the Phaser docs and BitmapData helpfully gives you both the Uint8Clamped view into the image data and the Uint32 view, the clamped view groups up pixels into 4 components, rgba, whereas the Uint32 grouped those into one 32-bit component (rather than 4 8-bit components, hence why they are known as views on to the same piece of memory). If you're having trouble updating the data in the array it could be you're using BitmapData.data which gives you the clamped Uint8, you might be expecting each array entry to represent a colour (e.g. 0xff0033ff) but it does not, the Uint32 version however, works exactly like this. Again, if you use ndarray because of the way it represents the data internally it is quite easy to use either structure and provide different ways of entering the data, e.g. if you change the stride you effectively change how it iterates over the structure, so you could use the Uint8Clamped views and change the stride to only target the alpha, then when you iterate through using `ndarray.get(0)`, `ndarray.get(1)`, etc you'd only get the 8 bits referring to alpha. All quite fun if thats your bag. Link to comment Share on other sites More sharing options...
rgk Posted January 19, 2017 Author Share Posted January 19, 2017 @Fatalist Thank you, that got me moving in the right direction. Problem is if I set dest.pixels to destPixels, nothing happens. Do I also have to update other values like the buffer? this.bmd.copy(this.level, 1200, 1200, 100, 100, 0, 0); // This grabs an obvious square for testing. this.bmd.update(); this.level.copy(this.bmd, 0, 0, 100, 100, bullet.x - 50, bullet.y - 50); this.copyBitmapData(this.bmd, this.level, bullet.x - 50, bullet.y - 50); The copy back visually updates it but getPixel doesn't pickup on the changes, obviously doing a this.level.update does the trick after the copy. @mattstyles That is a very cool library (I'm going to be using it to handle huge arrays in the future), I'm looking to do it as lightweight as possible for the sake of putting it back in Phaser. I am sure someone can use an optimized way to update large bitmaps. Link to comment Share on other sites More sharing options...
Fatalist Posted January 19, 2017 Share Posted January 19, 2017 1 hour ago, rgk said: Problem is if I set dest.pixels to destPixels, nothing happens. You don't need to set it, they point to the same data anyway. In fact, you don't need destPixels/sourcePixels at all, just use .pixels property instead. Put this after copyBitmapData to see where do the pixels actually change: this.level.context.putImageData(this.level.imageData, 0, 0); Link to comment Share on other sites More sharing options...
rgk Posted January 20, 2017 Author Share Posted January 20, 2017 @Fatalist Nothing changes, actually doing putImageData removes any visual change caused by the copy. I am assuming changing pixels isn't updating imageData? Link to comment Share on other sites More sharing options...
rgk Posted January 20, 2017 Author Share Posted January 20, 2017 I forgot to Math.floor() the bullet.x and bullet.y values, and it works! Obvious issues are you can't use getPixel, only getPixel32 because of what they access, I am going to be trying to add this to phaser and I will make sure to give you credit @Fatalist Link to comment Share on other sites More sharing options...
Fatalist Posted January 20, 2017 Share Posted January 20, 2017 Great! Can't wait to see your game 9 hours ago, rgk said: Obvious issues are you can't use getPixel, getPixel should work too, it's the same data under the hood. Link to comment Share on other sites More sharing options...
rgk Posted January 20, 2017 Author Share Posted January 20, 2017 @Fatalist I had to change all the use I had of getPixel to getPixel32, because I oddly enough used both in two different situations and only getPixel32 worked properly. I don't alter the buffer, I switched to the .pixels property directly. Also here is the initial pull request, it needs some work though. https://github.com/photonstorm/phaser-ce/pull/12 Edit: Which I just sent over a PR to fix those doc issues and changed the method scope. Link to comment Share on other sites More sharing options...
Fatalist Posted January 20, 2017 Share Posted January 20, 2017 Nice. Another thing that would be useful(and more straightforward in your case too), is to have an optional boolean parameter in BitmapData.update that tells it to not discard old data and just update the specified rectangle. rgk 1 Link to comment Share on other sites More sharing options...
Recommended Posts