Save-Point
Flipping Images - Printable Version

+- Save-Point (https://www.save-point.org)
+-- Forum: Games Development (https://www.save-point.org/forum-4.html)
+--- Forum: Tutorials (https://www.save-point.org/forum-19.html)
+--- Thread: Flipping Images (/thread-7529.html)



Flipping Images - kyonides - 08-25-2019

Flipping Images
Vertical and Horizontal Flips

I wanted to share some C code with you guys in order to let you learn a bit about low level languages and how they handle image flipping internally. You wouldn't imagine that it could be that simple in the first place because some programming languages posses features others don't.

Let's take a look at two well known languages, C and Ruby. Actually Ruby is a C backed Object Oriented Programming language with other paradigms included as well. Still, anybody that has dealt with Ruby scripts or even RGSS ones would realize how many things seem to be darn easy for anybody to learn. Laughing Sometimes I wonder why most people never touch a script unless its one of the worst like a battle system. It's definitely not the best script to start with. Happy with a sweat Things like something as useful as Ruby's Range class should be a must for any language. Others like Java seem to include that feature already. That's not C's case nonetheless.  Sad

Ruby Range Class
@array[0..3]
Yeah, it's just a number followed by a few dots that later ends with another number. Since version 2.6 you can skip the last argument if you feel like it. Laughing And people don't believe me Ruby is ideal for lazy people.

C Range Function!? Happy with a sweat I'm sorry there's no such a thing. Really! Laughing It has lived for decades and it still doesn't offer us anything like that. Programmers' advice consists of telling you to implement a loop, especially in a helper function. Laughing + Tongue sticking out

Code:
typedef stbi_uc unsigned char;

Code:
// Horizontal Flip by Kyonides Arkanthes shared under GPLv2 or v3
static void stbi_kyon_horizontal_flip(void *image, int w, int h, int bytes_per_pixel)
{
 size_t line_bytes = (size_t)w * bytes_per_pixel;
 stbi_uc temp[line_bytes];
 stbi_uc *bytes = (stbi_uc *)image;
 int lpos, rpos;
 for (int col = 0; col < h; col++) {
   stbi_uc *line = bytes + col * line_bytes;
   memcpy(&temp, line, line_bytes);
   for (int row = 0; row < w; row++) {
     lpos = row * bytes_per_pixel;
     rpos = line_bytes - row * bytes_per_pixel - 1;
     line[lpos] = temp[rpos - 3];
     line[lpos + 1] = temp[rpos - 2];
     line[lpos + 2] = temp[rpos - 1];
     line[lpos + 3] = temp[rpos];
   }
 }
 stbi_kyon_horizontally_flip_on_load = false;
}

I know the code above works because I've included it in my A Short Odyssey Gosu project already. Laughing

Code:
static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
{
 int row;
 size_t bytes_per_row = (size_t)w * bytes_per_pixel;
 stbi_uc temp[2048];
 stbi_uc *bytes = (stbi_uc *)image;
 for (row = 0; row < (h>>1); row++) {
   stbi_uc *row0 = bytes + row * bytes_per_row;
   stbi_uc *row1 = bytes + (h - row - 1) * bytes_per_row;
   // swap row0 with row1
   size_t bytes_left = bytes_per_row;
   while (bytes_left) {
     size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp);
     memcpy(temp, row0, bytes_copy);
     memcpy(row0, row1, bytes_copy);
     memcpy(row1, temp, bytes_copy);
     row0 += bytes_copy;
     row1 += bytes_copy;
     bytes_left -= bytes_copy;
   }
 }
}

Why did I share my code and stb_image.h's? Happy with a sweat Well, it's because it shows you what you can do when you don't count on ranges to save the day. It looks ugly, isn't it? Laughing

As you might ignore Laughing + Tongue sticking out C arrays are weird. You don't look for its first position like in Ruby with something like array[0] but you just type array. Shocked Strange indeed! That's not the end of this spooky tale, guys! Happy with a sweat In order to tell C that you want some index you've got two ways to do that.

Option 1
array[offset + 1]

Option 2
array + offset + 1

Shocked What the hell is that supposed to be!? Happy with a sweat Well, in C you can "add" a position as if array were equal to zero because arrays are pointers and they always reference its first position anyway. And it gets weirder and weirder if you include nested arrays... Confused

Keep in mind that people usually don't pass stuff like C arrays by value but as a pointer or reference. It means you pass a memory direction to the array you've created. It's weird to do the same with other stuff like numbers either integers like 8 or floats like 1.3 also known as double if you require double precision in float computation. You could end up passing a different value, its actual address that might look like 34651468167. Laughing Oh and there's no guarantee it will always be there. Confused Try to place a pixel in such a position and you'll end up with missing pixels letting you think you've got a broken monitor of sorts. Laughing + Tongue sticking out

By the way, don't abuse of the memcpy function that allows you to duplicate any variable's contents and store them in a destination variable. Programmers kind of fear it since it might still come up with some unexpected behavior.

What's the benefit of passing variables by reference? Err, well, you can alter them in a different function without needing to return it at the end of its execution, even if nothing forbids you of doing so if you wanna. Confused

In C and C++ you'll find people setting and getting a variable's value via setter and getter functions. Setters usually are void since you're supposed to know what kind of value you're passing them from the very beginning. Happy with a sweat void means no return value. In this case it's like returning a nil in Ruby except nil is still some value or object for Ruby! Confused Actually a simple return with no argument in Ruby is identical to typing return nil. In C or C++ you make a function not return a thing by typing return; yeah with semicolon included. Fail to add it and the compiler will start screaming at you! Laughing Ruby is really nice indeed!

What's the typedef? Happy with a sweat Err, that's a reserved keyword that tells either C or C++ that your code defines a fictitious type of variable or function named after the first argument that represents the other arguments. It's shorthand for whatever you don't wanna keep typing the whole day. Yeah, it's true! Shocked Even in C or C++ you can be a bit lazy as well. Laughing