orangeduck / Corange

Pure C Game Engine
http://www.youtube.com/watch?v=482GxqTWXtA
Other
1.78k stars 199 forks source link

bug in "image_rotate_inplace()" function #74

Closed d4v3y5c0n3s closed 2 years ago

d4v3y5c0n3s commented 2 years ago

https://github.com/orangeduck/Corange/blob/9a7372d660dc469965297aea6935a85279a7b6f7/src/assets/image.c#L212

Because this line sets the "repeat_type" of "i" to "IMAGE_REPEAT_BLACK" it causes the calls to "image_set()" here to not modify the image.

Let me know if you'd like me to provide anything I might've missed.

blogdron commented 2 years ago

NoTaBuG? =)

It seems to me that this is not a bug, when we rotate the image, for example, in GIMP, the edges of the image do not spread further along the canvas, the same is true here.

For example, if I want to take two images, rotate them and put one on top of the other, I will get one image with partially overlapping parts, but if I get out of UV bounds, then I will get an always filled image and I can’t complete the task above. Of course, I might want to rotate the image with a different UV out-of-bounds handling method for example for working with tiles (tile atlas for example).

This function does exactly what it should, and it just turns the image.

    image * c1 = image_tga_load_file("./assets/c6.tga");
    image_rotate_inplace(c1,0.5);
    image_tga_save_file(c1,"./out.tga");

original origin

result
result

if set repeat_type by default (just delete swap repeat options)

- i->repeat_type = IMAGE_REPEAT_BLACK;
- i->repeat_type = repeat;

we have this result new_result

Everything seems to be good! Considering that our picture is tiled and can be repeated But what if we return a simple, non-repeating image?

This is what will happen. non-repeat Pay attention to the corners It seems to me good behavior for this function to prevent this

So if someone needs it, he will simply duplicate this function in this form.

void image_rotate_inplace_sampled(image* i, float amount,int repeat_type) {

  image* j = image_blank(i->height, i->width);
  int repeat = i->repeat_type;
  i->repeat_type = repeat_type;

  for (int x = 0; x < i->width; x++)
  for (int y = 0; y < i->height; y++) {
    float u = ((float)x / i->width)  - 0.5;
    float v = ((float)y / i->height) - 0.5;
    vec2 uv = mat2_mul_vec2(mat2_rotation(amount), vec2_new(u, v));
    uv = vec2_add(uv, vec2_new(0.5, 0.5));
    image_set(j, x, y, image_sample(i, uv));
  }

  i->repeat_type = repeat;
  image_data_swap((void**)&i->data, (void**)&j->data);
  image_del(j);

}

And it will use such a function to get, for example, such a result

image_rotate_inplace_sampled(img, 0.5,IMAGE_REPEAT_CLAMP);

CLAMP

You may notice flaws in other repetition modes. It might be worth investigating and fixing this, at least CLAMP (the bottom of the image is incorrect).

=)

d4v3y5c0n3s commented 2 years ago

Yea, on closer inspection I see that you are right, it's working fine. I didn't look close enough at the math and in particular the "image_data_swap()" line. Thank you for explaining how this works 😄