-
-
Save mmozeiko/c9ecb8b206c245198f0a5aedc21f5a64 to your computer and use it in GitHub Desktop.
SDL2 demo to show panning & zooming implementation
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 "SDL.h" | |
#include <stdlib.h> | |
#define LINE_COUNT 256 | |
typedef struct | |
{ | |
float x1, y1; | |
float x2, y2; | |
} line; | |
static line lines[LINE_COUNT]; | |
static int rnd(int min, int max) | |
{ | |
// not uniform, but meh... | |
return min + rand() % (max - min); | |
} | |
typedef float matrix[6]; | |
// sets matrix to identity | |
static void mat_identity(matrix m) | |
{ | |
m[0] = m[3] = 1.f; | |
m[1] = m[2] = m[4] = m[5] = 0.f; | |
} | |
// multiplies matrix m with translation matrix for [x,y] vector | |
static void mat_translate(matrix m, float x, float y) | |
{ | |
m[4] += m[0] * x + m[2] * y; | |
m[5] += m[1] * x + m[3] * y; | |
} | |
// multiplies matrix m with scaling matrix for [x,y] | |
static void mat_scale(matrix m, float x, float y) | |
{ | |
m[0] *= x; | |
m[3] *= y; | |
} | |
// transforms vector [x,y] by matrix | |
static void mat_transform(matrix m, float* x, float* y) | |
{ | |
float x1 = m[0] * *x + m[2] * *y + m[4]; | |
float y1 = m[1] * *x + m[3] * *y + m[5]; | |
*x = x1; | |
*y = y1; | |
} | |
int main(int argc, char* argv[]) | |
{ | |
SDL_Init(SDL_INIT_VIDEO); | |
SDL_Window* window = SDL_CreateWindow("test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_RESIZABLE); | |
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); | |
for (int i=0; i<LINE_COUNT; i++) | |
{ | |
lines[i].x1 = rnd(-1000, 1000); | |
lines[i].y1 = rnd(-1000, 1000); | |
lines[i].x2 = rnd(-1000, 1000); | |
lines[i].y2 = rnd(-1000, 1000); | |
} | |
// initial position & scale | |
float posx = 0; | |
float posy = 0; | |
float scale = 1; | |
int panning = 0; | |
for (;;) | |
{ | |
// point that stays the same when zooming | |
float centerx, centery; | |
#if 1 | |
// use center of window | |
{ | |
int w, h; | |
SDL_GetWindowSize(window, &w, &h); | |
centerx = w/2.f; | |
centery = h/2.f; | |
} | |
#else | |
// use mouse position | |
{ | |
int x, y; | |
SDL_GetMouseState(&x, &y); | |
centerx = x; | |
centery = y; | |
} | |
#endif | |
SDL_Event ev; | |
if (SDL_PollEvent(&ev)) | |
{ | |
if (ev.type == SDL_QUIT) | |
{ | |
break; | |
} | |
else if (ev.type == SDL_MOUSEBUTTONDOWN) | |
{ | |
if (ev.button.button == SDL_BUTTON_LEFT) | |
{ | |
panning = 1; | |
SDL_CaptureMouse(1); | |
} | |
} | |
else if (ev.type == SDL_MOUSEBUTTONUP) | |
{ | |
if (ev.button.button == SDL_BUTTON_LEFT) | |
{ | |
panning = 0; | |
SDL_CaptureMouse(0); | |
} | |
} | |
else if (ev.type == SDL_MOUSEMOTION) | |
{ | |
if (panning) | |
{ | |
// x and y is in pixels | |
posx += ev.motion.xrel; | |
posy += ev.motion.yrel; | |
} | |
} | |
else if (ev.type == SDL_MOUSEWHEEL) | |
{ | |
float dscale = ev.wheel.y / 20.f; | |
float newscale = scale + dscale; | |
// clamp scale to [0.1 .. 5.0] interval | |
if (newscale >= 0.1f && newscale <= 5.f) | |
{ | |
float t = newscale / scale; | |
matrix m; | |
mat_identity(m); | |
mat_translate(m, centerx, centery); | |
mat_scale(m, t, t); | |
mat_translate(m, -centerx, -centery); | |
mat_transform(m, &posx, &posy); | |
scale = newscale; | |
} | |
} | |
continue; | |
} | |
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); | |
SDL_RenderClear(renderer); | |
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); | |
matrix m; | |
mat_identity(m); | |
mat_translate(m, posx, posy); | |
mat_scale(m, scale, scale); | |
for (int i=0; i<LINE_COUNT; i++) | |
{ | |
const line* l = lines + i; | |
float x1 = l->x1; | |
float y1 = l->y1; | |
float x2 = l->x2; | |
float y2 = l->y2; | |
mat_transform(m, &x1, &y1); | |
mat_transform(m, &x2, &y2); | |
SDL_RenderDrawLine(renderer, (int)x1, (int)y1, (int)x2, (int)y2); | |
} | |
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); | |
SDL_Rect center = { (int)centerx - 2, (int)centery, 4, 4 }; | |
SDL_RenderDrawRect(renderer, ¢er); | |
SDL_RenderPresent(renderer); | |
} | |
SDL_DestroyRenderer(renderer); | |
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