Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Resolution Independence Results in Pixel Misplacement

This thread is locked; no one can reply to it. rss feed Print
Resolution Independence Results in Pixel Misplacement
Eric Johnson
Member #14,841
January 2013
avatar

I stumbled across a neat artical on the wiki regarding resolution independence. I went about implementing it into my current project, but it resulted in deformed and misplaced pixels.

#SelectExpand
1void RenderPhase(void) { 2 3 if (running_ && al_is_event_queue_empty(event_queue_)) { 4 5 render_ = false; 6 7 int screenWidth = display_width_; 8 int screenHeight = display_height_; 9 10 int windowWidth = al_get_display_width(display_); 11 int windowHeight = al_get_display_height(display_); 12 13 int sx = windowWidth / screenWidth; 14 int sy = windowHeight / screenHeight; 15 int scale = std::min(sx, sy); 16 17 int scaleW = screenWidth * scale; 18 int scaleH = screenHeight * scale; 19 int scaleX = (windowWidth - scaleW) / 2; 20 int scaleY = (windowHeight - scaleH) / 2; 21 22 al_set_target_bitmap(buffer); 23 al_clear_to_color(al_map_rgb(0, 0, 0)); 24 25 Object.Render(); 26 27 al_flip_display(); 28 29 al_set_target_backbuffer(display_); 30 al_clear_to_color(al_map_rgb(0, 0, 0)); 31 al_draw_scaled_bitmap(buffer, 0, 0, screenWidth, screenHeight, scaleX, scaleY, scaleW, scaleH, 0); 32 } 33} 34 35void Object::Render(void) { 36 37 static float s_ticks = 0; 38 39 // Throw tiles into buffer 40 al_hold_bitmap_drawing(true); 41 42 for (int y = 0; y < height_; y++) { 43 44 for (int x = 0; x < width_; x++) { 45 46 // Get the current tile 47 stringstream current_tile(tiles_[x][y]); 48 49 // Split the current tile into its axes 50 while (getline(current_tile, axes_, 'x')) { 51 52 static int s_ticks = 0; 53 54 if (s_ticks % 2) { 55 56 // Get the Y axis 57 axis_[k_y_] = atoi(axes_.c_str()); 58 } 59 else { 60 61 // Get the X axis 62 axis_[k_x_] = atoi(axes_.c_str()); 63 } 64 65 s_ticks++; 66 } 67 68 // Clear the current tile for the next cycle 69 current_tile.str(""); 70 71 // Draw the appropriate tile 72 al_draw_bitmap_region(bitmap_, 8 * axis_[k_x_], 9 * axis_[k_y_], 8, 9, 8 * x - s_ticks, 9 * y - s_ticks, 0); 73 } 74 } 75 76 // Release buffer 77 al_hold_bitmap_drawing(false); 78 79 // Simulates camera movement 80 s_ticks += 0.5; 81}

I've attached two images to demonstrate what I'm talking about. The first image is of the resolution independence, and the second of a generic transformation. As you can see, things look quite out of place in the first image, but are fine in the second. Am I implementing the technique incorrectly? What may be the cause of this?

Thank you for your time.

Trent Gamblin
Member #261
April 2000
avatar

You can do the same thing with a transformation, but I'm not feeling generous enough to do it for you. :P

(hint: it involves a translation and a scale)

Eric Johnson
Member #14,841
January 2013
avatar

Hey Trent. Thanks for the quick reply. I completely understand; programming wouldn't be any fun if everything were hand-fed. :P Back to the drawing board!

Edit
Check it out! It works quite well on several resolutions and is much faster than the prior technique! Also, prior to landing on the wiki link, I had no prior knowledge of std::min... I've previously made my own min-like function, but it was rubbish in comparison. Ha ha.

#SelectExpand
1void RenderPhase(void) { 2 3 if (running_ && al_is_event_queue_empty(event_queue_)) { 4 5 render_ = false; 6 7 // Draw stuff here 8 9 int scale = min(al_get_display_width(display_) / display_width_, al_get_display_height(display_) / display_height_); 10 int placement_x = (al_get_display_width(display_) - (display_width_ * scale)) / 2; 11 int placement_y = (al_get_display_height(display_) - (display_height_ * scale)) / 2; 12 13 ALLEGRO_TRANSFORM transform; 14 15 al_identity_transform(&transform); 16 al_scale_transform(&transform, scale, scale); 17 al_translate_transform(&transform, placement_x, placement_y); 18 al_use_transform(&transform); 19 20 al_flip_display(); 21 al_clear_to_color(al_map_rgb(0, 0, 0)); 22 } 23}

beoran
Member #12,636
March 2011

I also tried Sheegoth's approach, but I draw 4 black bars around my screen in stead of filling it, so my messy out-of-screen tile map drawing gets camouflaged. :p The the nice thing about it, though is that it seems that allegro automagically also scales and adjusts the mouse inputs as well? So I don't have to change anything about my input system, and can keep pretending thoughout all my code that the screen is 640x480 (my chosen virtual resolution)?

Arvidsson
Member #4,603
May 2004

In your first example you are flipping the display before actually drawing the buffer bitmap.

In your second example, the transformation only needs to be applied once. Not every frame. Unless the user can manually resize the window of course.

Eric Johnson
Member #14,841
January 2013
avatar

Arvidsson said:

In your first example you are flipping the display before actually drawing the buffer bitmap.In your second example, the transformation only needs to be applied once. Not every frame. Unless the user can manually resize the window of course.

I also tried flipping the display after drawing the buffer bitmap, but I was still left with issues for some reason. Also, I didn't know that about the transformation; that's good to know.

What I have now seems to work out quite nicely for the most part, but I'm having strange 1/4 pixel misplacements on 800x600 resolutions. It may only be on my computer (I've had display issues elsewhere before). No issues on my native resolution though (1600x900).

Kris Asick
Member #1,424
July 2001

I'm doing resolution independence with my current game project and I can give you some pointers to ensure you end up with the best looking graphics possible and the least amount of pixel inaccuracies:

1. Make sure your entire game looks good at 640x480, then upscale your assets to look even better at higher resolutions. If you design your game to look good at 1920x1080 and downscale, you'll get horrible aliasing all over the place. :P

2. ONLY scale in predictable increments that ensure that lines thin enough to take up a single pixel at 640x480 will always be at least a full pixel thick at higher resolutions. My game supports manually being set to various scaling settings, but automatically, it will choose a scaling factor that is a multiple of 0.25, with 0.5 being the factor for 640x480 resolution. The reason for this is to ensure that small changes in resolution don't cause huge changes in graphics quality. For instance, going from 640x480 to 800x600 isn't a big enough change that you really need to increase the size of everything proportionately to look decent, so the better thing to do is to keep the 640x480 scale and just give the player more viewing space.

3. Give every object (including cameras) two different positional values: Its actual position in world space, and its rendering position. When you prep to render, calculate these positions so that they line up perfectly with your scaling factor. This is actually something I struggled with and used a lot of trial and error to figure out, so I'm not entirely sure how to do it properly, just that I eventually got the math working! ::)

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Eric Johnson
Member #14,841
January 2013
avatar

I'm doing resolution independence with my current game project and I can give you some pointers to ensure you end up with the best looking graphics possible and the least amount of pixel inaccuracies:

1. Make sure your entire game looks good at 640x480, then upscale your assets to look even better at higher resolutions. If you design your game to look good at 1920x1080 and downscale, you'll get horrible aliasing all over the place. :P

2. ONLY scale in predictable increments that ensure that lines thin enough to take up a single pixel at 640x480 will always be at least a full pixel thick at higher resolutions. My game supports manually being set to various scaling settings, but automatically, it will choose a scaling factor that is a multiple of 0.25, with 0.5 being the factor for 640x480 resolution. The reason for this is to ensure that small changes in resolution don't cause huge changes in graphics quality. For instance, going from 640x480 to 800x600 isn't a big enough change that you really need to increase the size of everything proportionately to look decent, so the better thing to do is to keep the 640x480 scale and just give the player more viewing space.

3. Give every object (including cameras) two different positional values: Its actual position in world space, and its rendering position. When you prep to render, calculate these positions so that they line up perfectly with your scaling factor. This is actually something I struggled with and used a lot of trial and error to figure out, so I'm not entirely sure how to do it properly, just that I eventually got the math working! ::)

Nicely written, Kris; I appreciate the fine details.

Quote:

I'm not entirely sure how to do it properly, just that I eventually got the math working!

A short while ago (perhaps a month or so) I had attempted a similar technique to your third point, but I had used faulty math, and as a result the entire render phase was all out of whack! :o

Go to: