/* VitaShell Copyright (C) 2015-2018, TheFloW This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "main.h" #include "browser.h" #include "archive.h" #include "photo.h" #include "file.h" #include "theme.h" #include "utils.h" static vita2d_texture *loadImage(const char *file, int type, char *buffer) { vita2d_texture *tex = NULL; if (isInArchive()) { int size = 0; if (isInArchive()) { size = ReadArchiveFile(file, buffer, BIG_BUFFER_SIZE); } else { size = ReadFile(file, buffer, BIG_BUFFER_SIZE); } if (size <= 0) { return NULL; } switch (type) { case FILE_TYPE_BMP: tex = vita2d_load_BMP_buffer(buffer); break; case FILE_TYPE_PNG: tex = vita2d_load_PNG_buffer(buffer); break; case FILE_TYPE_JPEG: tex = vita2d_load_JPEG_buffer(buffer, size); break; } } else { switch (type) { case FILE_TYPE_BMP: tex = vita2d_load_BMP_file(file); break; case FILE_TYPE_PNG: tex = vita2d_load_PNG_file(file); break; case FILE_TYPE_JPEG: tex = vita2d_load_JPEG_file(file); break; } } // Set bilinear filter if (tex) vita2d_texture_set_filters(tex, SCE_GXM_TEXTURE_FILTER_LINEAR, SCE_GXM_TEXTURE_FILTER_LINEAR); return tex; } static int isHorizontal(float rad) { return ((int)sinf(rad) == 0) ? 1 : 0; } static void photoMode(float *zoom, float width, float height, float rad, int mode) { int horizontal = isHorizontal(rad); float h = horizontal ? height : width; float w = horizontal ? width : height; switch (mode) { case MODE_CUSTOM: break; case MODE_PERFECT: // this is only used for showing image the first time if (h > SCREEN_HEIGHT) { // first priority, fit height *zoom = SCREEN_HEIGHT / h; } else if (w > SCREEN_WIDTH) { // second priority, fit screen *zoom = SCREEN_WIDTH / w; } else { // otherwise, original size *zoom = 1.0f; } break; case MODE_ORIGINAL: *zoom = 1.0f; break; case MODE_FIT_HEIGHT: *zoom = SCREEN_HEIGHT / h; break; case MODE_FIT_WIDTH: *zoom = SCREEN_WIDTH / w; break; } } static int getNextZoomMode(float *zoom, float width, float height, float rad, int mode) { float next_zoom = ZOOM_MAX, smallest_zoom = ZOOM_MAX;; int next_mode = MODE_ORIGINAL, smallest_mode = MODE_ORIGINAL; int i = 0; while (i < 3) { if (mode == MODE_CUSTOM || mode == MODE_PERFECT || mode == MODE_FIT_WIDTH) { mode = MODE_ORIGINAL; } else { mode++; } float new_zoom = 0.0f; photoMode(&new_zoom, width, height, rad, mode); if (new_zoom < smallest_zoom) { smallest_zoom = new_zoom; smallest_mode = mode; } if (new_zoom > *zoom && new_zoom < next_zoom) { next_zoom = new_zoom; next_mode = mode; } i++; } // Get smallest then if (next_zoom == ZOOM_MAX) { next_zoom = smallest_zoom; next_mode = smallest_mode; } *zoom = next_zoom; return next_mode; } static void resetImageInfo(vita2d_texture *tex, float *width, float *height, float *x, float *y, float *rad, float *zoom, int *mode, uint64_t *time) { *width = vita2d_texture_get_width(tex); *height = vita2d_texture_get_height(tex); *x = *width/2.0f; *y = *height/2.0f; *rad = 0; *zoom = 1.0f; *mode = MODE_PERFECT; photoMode(zoom, *width, *height, *rad, *mode); *time = 0; } int photoViewer(const char *file, int type, FileList *list, FileListEntry *entry, int *base_pos, int *rel_pos) { char *buffer = memalign(4096, BIG_BUFFER_SIZE); if (!buffer) return VITASHELL_ERROR_NO_MEMORY; vita2d_texture *tex = loadImage(file, type, buffer); if (!tex) { free(buffer); return VITASHELL_ERROR_NO_MEMORY; } // Variables float width = 0.0f, height = 0.0f, x = 0.0f, y = 0.0f, rad = 0.0f, zoom = 1.0f; int mode = MODE_PERFECT; uint64_t time = 0; // Reset image resetImageInfo(tex, &width, &height, &x, &y, &rad, &zoom, &mode, &time); while (1) { readPad(); // Cancel if (pressed_pad[PAD_CANCEL]) { break; } // Previous/next image. if (pressed_pad[PAD_LEFT] || pressed_pad[PAD_RIGHT]) { int available = 0; int old_base_pos = *base_pos; int old_rel_pos = *rel_pos; FileListEntry *old_entry = entry; int previous = pressed_pad[PAD_LEFT]; while (previous ? entry->previous : entry->next) { entry = previous ? entry->previous : entry->next; if (previous) { if (*rel_pos > 0) { (*rel_pos)--; } else if (*base_pos > 0) { (*base_pos)--; } } else { if ((*rel_pos + 1) < list->length) { if ((*rel_pos + 1) < MAX_POSITION) { (*rel_pos)++; } else if ((*base_pos + *rel_pos + 1) < list->length) { (*base_pos)++; } } } if (!entry->is_folder) { char path[MAX_PATH_LENGTH]; snprintf(path, MAX_PATH_LENGTH, "%s%s", list->path, entry->name); int type = getFileType(path); if (type == FILE_TYPE_BMP || type == FILE_TYPE_JPEG || type == FILE_TYPE_PNG) { vita2d_wait_rendering_done(); vita2d_free_texture(tex); tex = loadImage(path, type, buffer); if (!tex) { free(buffer); return VITASHELL_ERROR_NO_MEMORY; } // Reset image resetImageInfo(tex, &width, &height, &x, &y, &rad, &zoom, &mode, &time); available = 1; break; } } } if (!available) { *base_pos = old_base_pos; *rel_pos = old_rel_pos; entry = old_entry; } } // Photo mode if (pressed_pad[PAD_ENTER]) { time = sceKernelGetProcessTimeWide(); x = width / 2.0f; y = height / 2.0f; // Find next mode mode = getNextZoomMode(&zoom, width, height, rad, mode); } // Rotate if (pressed_pad[PAD_LTRIGGER]) { rad -= M_PI_2; if (rad < 0) rad += M_TWOPI; photoMode(&zoom, width, height, rad, mode); } else if (pressed_pad[PAD_RTRIGGER]) { rad += M_PI_2; if (rad >= M_TWOPI) rad -= M_TWOPI; photoMode(&zoom, width, height, rad, mode); } // Zoom if (current_pad[PAD_RIGHT_ANALOG_DOWN]) { time = sceKernelGetProcessTimeWide(); mode = MODE_CUSTOM; zoom /= ZOOM_FACTOR; } else if (current_pad[PAD_RIGHT_ANALOG_UP]) { time = sceKernelGetProcessTimeWide(); mode = MODE_CUSTOM; zoom *= ZOOM_FACTOR; } if (zoom < ZOOM_MIN) { zoom = ZOOM_MIN; } if (zoom > ZOOM_MAX) { zoom = ZOOM_MAX; } // Move if (pad.lx < (ANALOG_CENTER - ANALOG_SENSITIVITY) || pad.lx > (ANALOG_CENTER + ANALOG_SENSITIVITY)) { float d = ((pad.lx - ANALOG_CENTER) / MOVE_DIVISION) / zoom; if (isHorizontal(rad)) { x += cosf(rad) * d; } else { y += -sinf(rad) * d; } } if (pad.ly < (ANALOG_CENTER - ANALOG_SENSITIVITY) || pad.ly > (ANALOG_CENTER + ANALOG_SENSITIVITY)) { float d = ((pad.ly - ANALOG_CENTER) / MOVE_DIVISION) / zoom; if (isHorizontal(rad)) { y += cosf(rad) * d; } else { x += sinf(rad) * d; } } // Limit int horizontal = isHorizontal(rad); float w = horizontal ? SCREEN_HALF_WIDTH : SCREEN_HALF_HEIGHT; float h = horizontal ? SCREEN_HALF_HEIGHT : SCREEN_HALF_WIDTH; if ((zoom * width) > 2.0f * w) { if (x < (w / zoom)) { x = w / zoom; } else if (x > (width - w / zoom)) { x = width - w / zoom; } } else { x = width / 2.0f; } if ((zoom * height) > 2.0f * h) { if (y < (h / zoom)) { y = h / zoom; } else if (y > (height - h / zoom)) { y = height - h/zoom; } } else { y = height / 2.0f; } // Start drawing startDrawing(bg_photo_image); // Photo vita2d_draw_texture_scale_rotate_hotspot(tex, SCREEN_HALF_WIDTH, SCREEN_HALF_HEIGHT, zoom, zoom, rad, x, y); // Zoom text if ((sceKernelGetProcessTimeWide() - time) < ZOOM_TEXT_TIME) pgf_draw_textf(SHELL_MARGIN_X, SCREEN_HEIGHT - 3.0f * SHELL_MARGIN_Y, PHOTO_ZOOM_COLOR, "%.0f%%", zoom * 100.0f); // End drawing endDrawing(); } vita2d_wait_rendering_done(); vita2d_free_texture(tex); free(buffer); return 0; }