Skip to content

Instantly share code, notes, and snippets.

@Leowbattle
Created January 22, 2023 16:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Leowbattle/f539d9bf667e0ed7d0eaa8464c38d7bd to your computer and use it in GitHub Desktop.
Save Leowbattle/f539d9bf667e0ed7d0eaa8464c38d7bd to your computer and use it in GitHub Desktop.
bilinear.c
#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