Skip to content

Instantly share code, notes, and snippets.

@mmozeiko

mmozeiko/test.c Secret

Created Aug 20, 2018
Embed
What would you like to do?
SDL2 demo to show panning & zooming implementation
#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, &center);
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