|
This thread is locked; no one can reply to it. |
1
2
|
Shifting Bitmaps |
knackname
Member #17,105
August 2019
|
Is there a way I could redraw a bitmap onto itself, just shifted x pixels in one direction? I'm working on a system for rendering a hexagonal tile map and I want to render each row of tiles as it's own image. when I move to far to the left I wand all the bitmaps to shift their image 1 tile distance to the right and redraw the now missing tile to the left. I could just allocate a new bitmap and switch them out but is there any way I could avoid that and just copy a bitmaps image to itself but offset? |
Chris Katko
Member #1,881
January 2002
|
There might be a way to do that but first I have to ask, do you actually NEED to store copies of bitmaps? Why can't you just draw them all to the screen every frame? That kind of stuff was useful in the 80's, not so much today except in the most niche of cases. So if it's for performance reasons (and not some actual geometric requirement to physically create the image you want) I would leave that out completely. Usually you only keep copies of bitmaps if, during your graphics pipeline, you need intermediate results for later stages. It comes into play with lots of shader stuff. But as for physically moving a bitmap, the only real way involves getting a much bigger bitmap and only drawing a portion of it like a "viewport" or "window" (allegro calls them sub bitmaps) into the parent bitmap. You could also try tot use a shader to map old coordinates to new ones (apply a "transformation"). But that'll also use a second copy. But RAM is cheap, and blitting a texture (even with shading/colors/alpha) that's already in VRAM is practically a zero instruction operation. So again, unless you're doing something incredibly niche and tricky, you're probably over-thinking it. Just draw all tiles, every frame, with a offset_x and offset_y for the "scrolling" by subtracting offset_x and offset_y from the end coordinates. And don't draw tiles that are completely off the screen. -----sig: |
knackname
Member #17,105
August 2019
|
It unfortunately is for performance reasons. I tried just drawing the map every frame but the performance was horrible. I already have a buffer bitmap for resizing the display and another buffer bitmap for the map so I can scale it to zoom in and out. I may be doing things completely wrong in that department which could be my issue but with the added strain drawing the map each frame became too much and the program slowed to a crawl. I'm drawing tiles to a map bitmap that's being scaled and drawn to a buffer bitmap that's being scaled and drawn to the display. The map isn't just a simple one image per tile either, each tile is a range of 1-25 separate images drawn at twice 1080p so I can zoom out to 0.5. And there's around 100-250 individual tiles on screen at a time. It's a quite a lot. If you have any idea on how I could improve my scaling I'd love to hear them. I had a version of the program written in c working fine before I added the buffers for resizing the display and scaling the map. My current version is in c++. If you want to look over the code I'm using to do it I could send you a file but I don't want to take up too much of your time. For now I think I'll just attempt the copy over to a new bitmap and swap them method. Even if it's not necessary in the long run I don't think it'll hurt anything. |
bamccaig
Member #7,536
July 2006
|
There are some very smart people around here. Share the code if you can. It's a lot more efficient if you just attach or embed it or link to it or something instead of individual people having to request it. If the code is "proprietary" and you can't/won't share it then I guess do what you have to do. There's a good chance what you're trying to do isn't unique, and it has been done hundreds of times, and somebody here might already know of a solution to it. Don't worry about taking up anybody's time. These days the message boards are slow around here. The people left sticking around that actually program with (or directly on) Allegro will probably be amused by your problem. If somebody helps it is because they chose to, not because you burdened them with it. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
MikiZX
Member #17,092
June 2019
|
Just a thought... cannot really help in better way as I am completely new to A5, is it possible that one of your destination bitmaps (scaling buffer, the one you draw your scaled graphics to) is a memory bitmap? Not sure if this can help in any way. |
knackname
Member #17,105
August 2019
|
I'll look at it, thanks for the suggestion |
Edgar Reynaldo
Major Reynaldo
May 2007
|
knackname said: I'm drawing tiles to a map bitmap that's being scaled and drawn to a buffer bitmap that's being scaled and drawn to the display. The map isn't just a simple one image per tile either, each tile is a range of 1-25 separate images drawn at twice 1080p so I can zoom out to 0.5. And there's around 100-250 individual tiles on screen at a time. It's a quite a lot. Drawing WIDTH x 2160 x (1-25) * (100-250) is a massive amount of drawing. My first guess would be to use mipmaps but without seeing code and resources I can't guess very well. Can you make a 7z of your project or is it just too big? Allegr.cc's attachments are limited to 10MB so you might have to upload it somewhere else. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
knackname
Member #17,105
August 2019
|
I tried cutting out the map bitmap and just resizing each tile individually and drawing it to the screen. It means I can't rotate the entire map like I wanted but it has improved performance dramatically. Now I'm having issues where display events are being delayed. When the map is being drawn it doesn't detect the window being resized or the close button being pressed. It seems like I may be overloading the queue if that's a possibility? Maybe? I don't know. I uploaded the current version of the project to a google drive, here's a link: https://drive.google.com/file/d/1bJ7gqKppjJfSjg_nYwgQizA8IJDR5Pu7/view?usp=sharing the game loop is in SCENE_MANAGER.cpp, the function is mapView If anyone know how to fix it I'd be grateful. And If anyone sees any other questionable code in there let me know, I'm still pretty knew at this. The file is in visual studio 2019 but you should be able to take the .h, .cpp and assets folder and open it up in whatever you use *edit: |
MikiZX
Member #17,092
June 2019
|
I haven't tried compiling the code though quick-looking at the source I possibly see one thing that appears a bit odd to me (since this is not my source code likely it is my understanding which is off so please be patient). As for the events queue, it is something that I yet have to learn about ... |
knackname
Member #17,105
August 2019
|
I was avoiding storing the tilesheets in memory (I was trying to do what Chris Katko suggested but I probably misinterpreted it) by loading and unloading them each time I needed to redraw the map. I just tried loaded them only when initially creating the map object and It improved dramatically. No issues with the display events not being detected. Thanks a lot MikiZX! also the mapOrientation is always set to north at the moment. Eventually I'll have it so that the user can change the direction from which the map is drawn That's fixed but If anyone sees anything odd in the code I'm still all ears. And if anyone knows a way I could still be drawing the tiles to a separate bitmap so I can rotate the whole thing let me know. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
You can achieve everything you want with transforms alone. I simply draw the same shape at specified offsets over and over and I have no problems. Mind you I don't draw any TILES, only hexagons (filled or outlined). Let me download your code and get back to you. Ooh, big download... EDIT My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
knackname
Member #17,105
August 2019
|
It may, but I just started coding last year and VS is what my university uses. What do you recommend? |
Edgar Reynaldo
Major Reynaldo
May 2007
|
I'm a snob, but I recommend Code::Blocks nightlies and MinGW-W64. But beneath that you should really learn CMake. Because then you could make VS solutions or CB projects from a simple CMakeLists.txt file and CMake. First, I haven't even looked at any of your files yet, and all you really needed to share was the files contained in this zip. It's 275KB. Your download was 275MB. That's 1000:1 the size it needed to be. This is why you don't learn real coding at a university. But in reality it is only that size because you included nuget binaries for allegro and its deps. That took up the most size. I don't need those. I'll get back to you once I get it compiling and such. Edgar My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
knackname
Member #17,105
August 2019
|
Noted. With that in mind here's the current project after implementing what MikiZX suggested. https://www.allegro.cc/files/download-attachment/?area=forum%20post&id=1043516 |
Edgar Reynaldo
Major Reynaldo
May 2007
|
It was pretty easy to compile your code. A few minor mistakes, and one bigger problem - you can't quit. Other than that, it ran fine? My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
knackname
Member #17,105
August 2019
|
What are the minor mistakes? You should be able to quit by closing the display. That works on my end. If you hit the close button on the display the displayManager.update() method should set the sceneID to 0 which ends the game loop. For the mapView function it's on lines 331-338 (in SCENE_MANAGER.cpp). And you said I can rotate the whole map image by using transformations? how does that work. At the beginning of this process the whole thing was a laggy mess but with the suggestions I've already gotten I was able to improve it dramatically already. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Here's a diff for you to look at of the minor changes I made. Note, I am just looking at the code now. Those were the only changes I made to get it to compile without any warnings. Always turn on all warnings. EDIT1 EDIT2 MySpecialClass.hpp #ifndef MySpecialClass_HPP #define MySpecialClass_HPP /// declarations go here extern const int ZERO; class MySpecialClass { //... }; #endif // MySpecialClass_HPP Then you put the definitions in their own source module, as you have been. EDIT3 This : //header #include "MAP_OBJECT.h" //construct MAP_OBJECT::MAP_OBJECT(int seed_input, int size_input, bool biomeToggle_input[], mapTile** tiles_ptr_input, MOUSE_MANAGER* mouseManager_input, KEYBOARD_MANAGER* keyboardManager_input, keyBinding* keybind_ptr) { Should be something more like this (most consoles wrap at 80 columns) : //header #include "MAP_OBJECT.h" //construct MAP_OBJECT::MAP_OBJECT(int seed_input, int size_input, bool biomeToggle_input[], mapTile** tiles_ptr_input, MOUSE_MANAGER* mouseManager_input, KEYBOARD_MANAGER* keyboardManager_input, keyBinding* keybind_ptr) { See how much easier that is to read? EDIT4 You can achieve everything you want with an extruded 3D hexagon, al_draw_prim and an ALLEGRO_TRANSFORM. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Chris Katko
Member #1,881
January 2002
|
I don't have a rig to test this game on ATM, but has anyone thrown it into a profiler and tested where the 90% of cpu time is spent? -----sig: |
MikiZX
Member #17,092
June 2019
|
I haven't got to actually running the code yet but what Chris suggests made me lookup a short tutorial for Visual Studio regarding the profiling - new knowledge for me. I don't know if this can help knackname: EDIT: Actually I wanted to try the profiling tools and got to trying knackname's code. Though please bear in mind that this is my first ever profiling session and I am not very familiar with Allegro5 internals - I am likely wrong about this. I find that in EDIT2: knackname, now that I can see your engine in action I could suggest possible improvement though it might be difficult to implement - you will see. The suggestion is that when it comes to drawing stacked towers of tiles you might actually consider starting your drawing loop of a single tower at a value depending on how high the tower "in front" (one closer to the player) is. So if you have one tower obscuring over half of the tower that is behind it - there is no need to draw the tower that is behind completely - you can draw only the visible part. This should reduce overdraw which might further improve the performance. Optional (if you have the time and energy): Extra optional: Though keep in mind that it is easy to be carried away when adding new features to your program so being realistic about the available time and energy you have is always a good call. I think that it is better to complete your program even if it is not completely optimized than to try optimizing everything and ending up with a program that is only half of what you wanted it to be. |
knackname
Member #17,105
August 2019
|
Thanks Edger for the formatting advise, I'll work on implementing that. With this project I wanted specifically to keep it 2d but I may try 3d at some point in the future. MikiZX what is VBO? What does that stand for? I'm planning on drawing a sprite for each tile in either 4 or 6 directions and using that as a method to rotate the map. I'll read out of the array backwards or forwards in a dimension to essentially rotate it. I don't know a good way to read out the data from a 2d array to have it match 6 directions though so I'm leaning towards just the 4 at the moment. I wanted to rotate the map image just for effect so that It spins a little before all the graphics switch orientation and it settles back into place if that makes sense. I'm not looking for a full 3d rotation. |
Chris Katko
Member #1,881
January 2002
|
knackname said: MikiZX what is VBO? What does that stand for? Vertex buffer object. Videocards are fast but the BUS that connects the CPU to them is super slow (relatively speaking) and becomes a huge bottleneck. So all modern cards use batches of operations instead of commanding individual operations. A "display list" is one way, a VBO is another way. A display list is a batch of commands (drawing, coloring, flipping, whatever), and vertex Buffer objects, IIRC, are just an array color, position and texture data. But before you get to stuff like that that gives you an extra % speedup, make sure you've fixed the core algorithm of what you're doing--because if that's wrong, you're just wasting time optimizing something that's inherently slow because you chose a really slow way to do something. In 99% of games with 2-D graphics, if it's slow (even in 1080p) you're probably doing something fundamentally wrong. There are TONS of "bullet hell" games that are likely drawing way more than you are and aren't doing any kind of special tricks to accomplish it. (With 4K, the raw screen area does add up quicker, but it's still correct for general cases.) -----sig: |
MikiZX
Member #17,092
June 2019
|
Yeah, VBO is just an array of points(vertices) where each point can hold information regarding its x,y,z coordinates, color, texture coordinates or more. These points are used to define a triangle (so 3 points are required to define a triangle and the points can be shared between triangles). Anyway, this is an option - if you are doing 2d view then move to VBOs can also be done once your program is complete and working. If you are even considering VBOs then the best you could do at the moment is to create a test project just to understand and test the VBOs out. There are examples in Allegro5 that cover the use of VBOs and I believe GitHub will have 3rd party example or two - you could start with https://www.allegro.cc/manual/5/al_draw_indexed_prim . p.s. rotating the view by, for example, 90 degrees would, I believe, require of you to recreate all of the VBOs though this might be fast enough. EDIT: At the moment I am trashing your source code trying to move it to VBO and am learning in the process. Actually what I have written above about uploading the VBO only once - it seems I was wrong, the VBO needs to be uploaded each time you wish to draw it. |
knackname
Member #17,105
August 2019
|
I figured out what was happening when Edgar couldn't close the game. When the FPS is too high it takes longer than one frame for the program to draw everything and it skips by the display events in the queue. How do I fix this? I guess I could make a second queue just for the FPS timer separate from the one handling display events? |
MikiZX
Member #17,092
June 2019
|
I cannot really help with events. But as far VBO are concerned I think I got it working (though it will need slight polishing). If you do go about testing this please make sure to have a backup of you actual project before copying these files. You will have to excuse my C++ knowledge which is likely not up to level, as I only know C. If you manage to get it working on your end and if you are interested how it works please let me know your questions. |
knackname
Member #17,105
August 2019
|
I tried completely removing the timer from the event queue and It still doesn't work. The program can't keep up with all the drawing 60 times a second and the longer it runs the more and more the draw calls build up. I'll work on optimizing the draw, but now it looks like I need to be dynamically setting my frame-rate to match how long it takes to draw a frame Update: Update 2: |
|
1
2
|