Created
January 22, 2023 16:13
-
-
Save Leowbattle/f539d9bf667e0ed7d0eaa8464c38d7bd to your computer and use it in GitHub Desktop.
bilinear.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <math.h> | |
#define STB_IMAGE_IMPLEMENTATION | |
#include "stb_image.h" | |
#define STB_IMAGE_WRITE_IMPLEMENTATION | |
#include "stb_image_write.h" | |
#define PI 3.14159 | |
typedef struct { | |
uint8_t r; | |
uint8_t g; | |
uint8_t b; | |
} rgb; | |
typedef struct { | |
float r; | |
float g; | |
float b; | |
} rgbf; | |
float clampf(float x, float a, float b) { | |
if (x < a) { | |
return a; | |
} else if (x > b) { | |
return b; | |
} else { | |
return x; | |
} | |
} | |
float deg2rad(float deg) { | |
return deg * PI / 180; | |
} | |
float fract(float x) { | |
return x - floorf(x); | |
} | |
rgb sample(rgb* data, int w, int h, float u, float v) { | |
// u = clampf(u, 0, 1); | |
// v = clampf(v, 0, 1); | |
u = fract(u); | |
v = fract(v); | |
float U = u * (w - 1); | |
float V = v * (h - 1); | |
rgb tl = data[(int)floorf(V) * w + (int)floorf(U)]; | |
rgb tr = data[(int)floorf(V) * w + (int)ceilf(U)]; | |
rgb bl = data[(int)ceilf(V) * w + (int)floorf(U)]; | |
rgb br = data[(int)ceilf(V) * w + (int)ceilf(U)]; | |
float u2 = U - floorf(U); | |
float v2 = V - floorf(V); | |
rgbf top = { | |
tl.r + u2 * (tr.r - tl.r), | |
tl.g + u2 * (tr.g - tl.g), | |
tl.b + u2 * (tr.b - tl.b), | |
}; | |
rgbf bottom = { | |
bl.r + u2 * (br.r - bl.r), | |
bl.g + u2 * (br.g - bl.g), | |
bl.b + u2 * (br.b - bl.b), | |
}; | |
rgbf c = { | |
top.r + v2 * (bottom.r - top.r), | |
top.g + v2 * (bottom.g - top.g), | |
top.b + v2 * (bottom.b - top.b), | |
}; | |
// return (rgb){ | |
// (uint8_t)(u * 255), | |
// (uint8_t)(v * 255), | |
// (uint8_t)255, | |
// }; | |
return (rgb){ | |
(uint8_t)c.r, | |
(uint8_t)c.g, | |
(uint8_t)c.b, | |
}; | |
} | |
typedef struct { | |
float m[9]; | |
} mat3; | |
typedef struct { | |
float x; | |
float y; | |
} vec2; | |
void mat3_identity(mat3* mat) { | |
*mat = (mat3) { | |
1, 0, 0, | |
0, 1, 0, | |
0, 0, 1, | |
}; | |
} | |
void mat3_scale(mat3* mat, float s) { | |
float* m = mat->m; | |
for (int i = 0; i < 9; i++) { | |
m[i] *= s; | |
} | |
} | |
void mat3_translate(mat3* mat, vec2 v) { | |
float* m = mat->m; | |
m[2] += m[0] * v.x + m[1] * v.y; | |
m[5] += m[3] * v.x + m[4] * v.y; | |
} | |
void mat3_rotate(mat3* mat, float t) { | |
float ct = cosf(t); | |
float st = sinf(t); | |
float* m = mat->m; | |
*mat = (mat3) { | |
m[0] * ct + m[1] * st, | |
m[0] * -st + m[1] * ct, | |
m[2], | |
m[3] * ct + m[4] * st, | |
m[3] * -st + m[4] * ct, | |
m[5], | |
m[6] * ct + m[7] * st, | |
m[6] * -st + m[7] * ct, | |
m[8] | |
}; | |
} | |
int main(int argc, char** argv) { | |
int w; | |
int h; | |
int comp; | |
rgb* in = (rgb*)stbi_load(argv[1], &w, &h, &comp, 3); | |
int size = 256; | |
rgb* data = malloc(size * size * 3); | |
mat3 mat; | |
mat3_identity(&mat); | |
mat3_scale(&mat, 5); | |
mat3_translate(&mat, (vec2){0.5f, 0.5f}); | |
mat3_rotate(&mat, deg2rad(35)); | |
mat3_translate(&mat, (vec2){-0.5f, -0.5f}); | |
printf("%f %f %f\n%f %f %f\n%f %f %f\n", | |
mat.m[0], mat.m[1], mat.m[2], | |
mat.m[3], mat.m[4], mat.m[5], | |
mat.m[6], mat.m[7], mat.m[8]); | |
for (int y = 0; y < size; y++) { | |
float v = (float)y / (size - 1); | |
for (int x = 0; x < size; x++) { | |
float u = (float)x / (size - 1); | |
float U = u * mat.m[0] + v * mat.m[1] + mat.m[2]; | |
float V = u * mat.m[3] + v * mat.m[4] + mat.m[5]; | |
data[y * size + x] = sample(in, w, h, U, V); | |
} | |
} | |
stbi_write_png("out.png", size, size, 3, data, size * 3); | |
stbi_image_free(in); | |
free(data); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment