Skip to content

Instantly share code, notes, and snippets.

@nandakoryaaa
Last active February 14, 2025 22:44
Show Gist options
  • Save nandakoryaaa/ae872e2ccbfe10c93c7f3a8f207481cc to your computer and use it in GitHub Desktop.
Save nandakoryaaa/ae872e2ccbfe10c93c7f3a8f207481cc to your computer and use it in GitHub Desktop.
Bitmap rotation in C + SDL2 using Bresenham lines
#define SDL_MAIN_HANDLED
#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#define SURF_W 640
#define SURF_H 640
void draw_img_line(
SDL_Surface* surf, uint32_t* img_data, uint16_t img_w,
uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1
) {
int16_t dx = x1 - x0;
int16_t dy = y1 - y0;
uint16_t dist_x = abs(dx);
uint16_t dist_y = abs(dy);
int16_t step_x = dx < 0 ? -1 : 1;
int16_t step_y = dy < 0 ? -surf->pitch / 4 : surf->pitch / 4;
uint16_t dist = dist_y > dist_x ? dist_y : dist_x;
uint32_t* addr = (uint32_t*)(surf->pixels + y0 * surf->pitch + x0 * 4);
uint16_t err_x = 0;
uint16_t err_y = 0;
uint16_t err_img = 0;
for (uint16_t i = 0; i < dist; i++) {
*addr = *img_data;
err_x += dist_x;
err_y += dist_y;
if (err_x >= dist) {
err_x -= dist;
addr += step_x;
*addr = *img_data;
}
if (err_y >= dist) {
err_y -= dist;
addr += step_y;
}
err_img += img_w;
while (err_img >= dist) {
err_img -= dist;
img_data++;
}
}
}
void draw_rotated_img(
SDL_Surface* surf, SDL_Surface* img_surf, uint16_t x, uint16_t y,
uint16_t w, uint16_t h, float rotation
) {
int16_t cx = x + (w >> 1);
int16_t cy = y + (h >> 1);
int16_t x0 = x - cx;
int16_t y0 = y - cy;
int16_t x1 = x0 + w - 1;
int16_t y1 = y0;
int16_t x2 = x0;
int16_t y2 = y0 + h - 1;
float cos_val = cos(rotation);
float sin_val = sin(rotation);
int16_t rx0 = (int16_t) (cos_val * x0 + sin_val * y0);
int16_t ry0 = (int16_t) (cos_val * y0 - sin_val * x0);
int16_t rx1 = (int16_t) (cos_val * x1 + sin_val * y1);
int16_t ry1 = (int16_t) (cos_val * y1 - sin_val * x1);
int16_t rx2 = (int16_t) (cos_val * x2 + sin_val * y2);
int16_t ry2 = (int16_t) (cos_val * y2 - sin_val * x2);
int16_t dx = rx2 - rx0;
int16_t dy = ry2 - ry0;
int16_t step_x = dx < 0 ? -1 : 1;
int16_t step_y = dy < 0 ? -1 : 1;
uint16_t dist_x = abs(dx);
uint16_t dist_y = abs(dy);
uint16_t dist = dist_x > dist_y ? dist_x : dist_y;
uint16_t err_x = 0;
uint16_t err_y = 0;
uint16_t err_img = 0;
rx0 += cx;
ry0 += cy;
rx1 += cx;
ry1 += cy;
uint8_t* img_data = (uint8_t*) img_surf->pixels;
for (uint16_t i = 0; i < dist; i++) {
draw_img_line(surf, (uint32_t*)img_data, img_surf->w, rx0, ry0, rx1, ry1);
err_img += h;
while (err_img >= dist) {
img_data += img_surf->pitch;
err_img -= dist;
}
err_x += dist_x;
err_y += dist_y;
if (err_x >= dist) {
err_x -= dist;
rx0 += step_x;
rx1 += step_x;
}
if (err_y >= dist) {
err_y -= dist;
ry0 += step_y;
ry1 += step_y;
}
}
}
int main(int argc, char* argv[])
{
if (argc < 2) {
printf("Usage: rotate image.bmp\n");
return 1;
}
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow(
"Rotation",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
SURF_W,
SURF_H,
SDL_WINDOW_ALLOW_HIGHDPI
);
if (window == NULL) {
printf("Could not create window: %s\n", SDL_GetError());
return 1;
}
SDL_Surface *bmpSurface = SDL_LoadBMP(argv[1]);
if (!bmpSurface) {
SDL_Quit();
printf("Error: %s\n", SDL_GetError());
return 1;
}
if (bmpSurface->w > 512 || bmpSurface->h > 512 || bmpSurface->w < 32 || bmpSurface->h < 32) {
printf("Image dimensions must be 32..512 pixels\n");
SDL_FreeSurface(bmpSurface);
SDL_Quit();
return 1;
}
SDL_Surface *screenSurface = SDL_GetWindowSurface(window);
SDL_Surface *imgSurface = SDL_ConvertSurface(bmpSurface, screenSurface->format, 0);
SDL_FreeSurface(bmpSurface);
float rot = 0.0;
SDL_Event event;
uint16_t w = imgSurface->w;
uint16_t h = imgSurface->h;
int in_game = 1;
while (in_game) {
SDL_FillRect(screenSurface, NULL, 0);
draw_rotated_img(screenSurface, imgSurface, (SURF_W - w) / 2, (SURF_H - h) / 2, w, h, rot);
rot += M_PI / 180;
if (rot > M_PI * 2) {
rot -= M_PI * 2;
}
SDL_UpdateWindowSurface(window);
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
in_game = 0;
break;
}
}
SDL_Delay(10);
}
SDL_FreeSurface(imgSurface);
SDL_FreeSurface(screenSurface);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment