about summary refs log blame commit diff
path: root/main.c
blob: 898aace4cc86d754f35be4a76c80cc1160fff5d6 (plain) (tree)






































































































































































































                                                                                                                           
/*
    OSXIV - Overly Simple X Image Viewer
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

#define DEBUG 0

int main(int argc, char** argv);
int render(double zoom, double move_x, double move_y);
int handle_events();
void cleanup();

#define DBG(fmt, ...) do { if (DEBUG) printf(fmt, __VA_ARGS__); } while (0)

SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
SDL_Texture *texture = NULL;

int main(int argc, char** argv)
{
    if(argc < 2)
    {
        fprintf(stderr, "Please provide a filename (or '-' to read from stdin).\n");
        return 1;
    }

    if(strcmp(argv[1], "-") && access(argv[1], F_OK ) == -1)
    {
        fprintf(stderr, "Filename doesnt exist.\n");
        return 1;
    }

    SDL_Init(SDL_INIT_VIDEO);
    IMG_Init(IMG_INIT_PNG);

    atexit(cleanup);

    char* windowtitle = malloc(sizeof(char) * (9 + strlen(strcmp(argv[1], "-") ? argv[1] : "stdin"))); // +9 bcz "OSXIV - "
    sprintf(windowtitle, "OSXIV - %s", strcmp(argv[1], "-") ? argv[1] : "stdin");

    SDL_DisplayMode dm;
    SDL_GetCurrentDisplayMode(0, &dm);

    window = SDL_CreateWindow(
            windowtitle,
            SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED,
            dm.w / 2, //w
            dm.h / 2, //h
            SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
        );

    free(windowtitle);

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE);

    SDL_RWops* img;
    if(!strcmp(argv[1], "-"))
        img = SDL_RWFromFP(stdin, 0);
    else
        img = SDL_RWFromFile(argv[1], "rb");
    texture = IMG_LoadTexture_RW(renderer, img, 0);
    if(!texture)
    {
        SDL_FreeRW(img);
        fprintf(stderr, "Problem while loading the image: (%s).\n", argv[1]);
        return 1;
    }

    SDL_FreeRW(img);

    if(handle_events())
    {
        fprintf(stderr, "Event handling exception.\n");
        return 1;
    }

    return 0;
}

int render(double zoom, double move_x, double move_y)
{
    SDL_Rect src = {0};
    SDL_Rect dst = {0};
    int screen_h, screen_w;

    SDL_RenderClear(renderer);
    SDL_QueryTexture(texture, NULL, NULL, &src.w , &src.h);

    DBG("\nsrc w: %d h: %d x: %d y: %d\n", src.w, src.h, src.x, src.y);

    SDL_GetWindowSize(window, &dst.w, &dst.h);
    screen_h = dst.h;
    screen_w = dst.w;

    DBG("scr w: %d h: %d\n", screen_w, screen_h);

    /* APPLY ZOOM */
    dst.h *= zoom;
    dst.w *= zoom;

    DBG("zoom: %f\n", zoom);

    /* REVERT IMAGE FILL */
    double ratio = (double) src.w / src.h;
    if(dst.h >= dst.w / ratio)
        dst.h = dst.w / ratio;
    else
        dst.w = ratio * dst.h;

    /* CENTER IN SCREEN */
    dst.x = (screen_w - dst.w) / 2;
    dst.y = (screen_h - dst.h) / 2;

    DBG("dst w: %d h: %d x: %d y: %d\n\n", dst.w, dst.h, dst.x, dst.y);

    /* APPLY MOVE */
    dst.x -= move_x * dst.w;
    dst.y -= move_y * dst.h;

    DBG("Moved by x_perc: %f y_perc: %f\n", move_x, move_y);

    SDL_RenderCopy(renderer, texture, &src, &dst);
    SDL_RenderPresent(renderer);

    return 0;
}

int handle_events()
{
    SDL_Event event;

    double zoom_multiplier = 0.1; // 10%
    double move_multipler = 0.1; // 10%

    double zoom = 1.0; // 100% initially
    double move_x = 0.0; // initial x pos (centered)
    double move_y = 0.0; // initial y pos (centered)

    while(SDL_WaitEvent(&event))
    {
        //DBG("Event: 0x%x\n", event.type);
        switch(event.type)
        {
            case SDL_KEYDOWN:
                switch(event.key.keysym.sym)
                {
                    case '+': // zoom in
                    case 61: // +
                        zoom += zoom_multiplier;
                        render(zoom, move_x, move_y);
                        break;
                    case '-': // zoom out
                        zoom -= zoom - zoom_multiplier < 0 ? 0 : zoom_multiplier;
                        render(zoom, move_x, move_y);
                        break;
                    case 1073741906: // up arrow - move up
                        move_y -= move_multipler / zoom;
                        render(zoom, move_x, move_y);
                        break;
                    case 1073741905: // down arrow - move down
                        move_y += move_multipler / zoom;
                        render(zoom, move_x, move_y);
                        break;
                    case 1073741904: // left arrow - move left
                        move_x -= move_multipler / zoom;
                        render(zoom, move_x, move_y);
                        break;
                    case 1073741903: // right arrow - move right
                        move_x += move_multipler / zoom;
                        render(zoom, move_x, move_y);
                        break;
                    case 'q':
                        exit(0);
                }
                break;
             case SDL_WINDOWEVENT:
                render(zoom, move_x, move_y);
                break;
            case SDL_QUIT:
                exit(0);
        }
    }

    return 1;
}

void cleanup()
{
    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    IMG_Quit();
    SDL_Quit();
}