It works now! ePub files still dont work.

This commit is contained in:
SeanOMik 2019-09-01 16:40:08 -05:00
parent f55236a39b
commit dfed263a85
21 changed files with 744 additions and 444 deletions

View File

@ -3,9 +3,9 @@
This is a project I've haven't worked on for a while and I'm just now getting back to it. This is a Nintendo Switch Homebrew Application and will read ePub files, or eventually, what ever MuPDF supports.
### Current State:
* Crashes your switch.
* ePubs cause a crash, PDFs dont load, idk what happends with other files.
* Just about **ALL** of the code isn't even mine but taken from an old NX-Shell repo.
* Working on redoing the code and making it not crash your switch.
* Working on redoing the code
### TODO:
* Use MuPDF.

Binary file not shown.

View File

@ -1,10 +1,8 @@
#ifndef EBOOK_READER_SDL_HELPER_H
#define EBOOK_READER_SDL_HELPER_H
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
static inline SDL_Color SDL_MakeColour(Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
static inline SDL_Color SDL_MakeColour(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
SDL_Color colour = {r, g, b, a};
return colour;
}
@ -23,15 +21,15 @@ static inline SDL_Color SDL_MakeColour(Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
#define TEXT_MIN_COLOUR_LIGHT SDL_MakeColour(32, 32, 32, 255)
#define TEXT_MIN_COLOUR_DARK SDL_MakeColour(185, 185, 185, 255)
#define BAR_COLOUR SDL_MakeColour(200, 200, 200, 255)
#define PROGRESS_COLOUR SDL_MakeColour(48, 174, 222, 255)
void SDL_ClearScreen(SDL_Renderer *renderer, SDL_Color colour);
void SDL_DrawRect(SDL_Renderer *renderer, int x, int y, int w, int h, SDL_Color colour);
void SDL_DrawCircle(SDL_Renderer *renderer, int x, int y, int r, SDL_Color colour);
void SDL_DrawText(SDL_Surface* window_surface, TTF_Font *font, int x, int y, SDL_Color colour, const char *text);
void SDL_DrawTextf(SDL_Surface* window_surface, TTF_Font *font, int x, int y, SDL_Color colour, const char* text, ...);
void SDL_DrawText(SDL_Renderer *renderer, TTF_Font *font, int x, int y, SDL_Color colour, const char *text);
void SDL_DrawTextf(SDL_Renderer *renderer, TTF_Font *font, int x, int y, SDL_Color colour, const char* text, ...);
void SDL_LoadImage(SDL_Renderer *renderer, SDL_Texture **texture, char *path);
void SDL_LoadImageBuf(SDL_Renderer *renderer, SDL_Texture **texture, void *mem, int size);
void SDL_DrawImage(SDL_Renderer *renderer, SDL_Texture *texture, int x, int y, int w, int h);
void SDL_DrawImage(SDL_Renderer *renderer, SDL_Texture *texture, int x, int y);
void SDL_DrawImageScale(SDL_Renderer *renderer, SDL_Texture *texture, int x, int y, int w, int h);
#endif

View File

@ -4,10 +4,9 @@
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
extern SDL_Renderer* RENDERER;
extern SDL_Window *WINDOW;
extern SDL_Surface *WINDOW_SURFACE;
extern SDL_Renderer *RENDERER;
extern TTF_Font *ARIAL_UNICODE;
extern SDL_Event EVENT;
#endif

View File

@ -2,10 +2,7 @@
#define EBOOK_READER_MENU_BOOK_READER_H
#include <switch.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
//void Menu_OpenBook(SDL_Renderer *renderer, SDL_Surface* window_surface, TTF_Font *font, char *path);
void Menu_OpenBook(char *path);
#endif

View File

@ -1,5 +1,5 @@
#ifndef NX_SHELL_STATUS_BAR_H
#define NX_SHELL_STATUS_BAR_H
#ifndef EBOOK_READER_STATUS_BAR_H
#define EBOOK_READER_STATUS_BAR_H
void StatusBar_DisplayTime(void);

View File

@ -1,171 +0,0 @@
#include "BookReader.hpp"
#include <string>
extern "C" {
#include "SDL_helper.h"
#include "status_bar.h"
//#include "common.h"
//#include "config.h"
}
fz_context *ctx = NULL;
static inline void FreeTextureIfNeeded(SDL_Texture **texture) {
if (texture && *texture) {
SDL_DestroyTexture(*texture);
*texture = NULL;
}
}
BookReader::BookReader(SDL_Renderer *renderer, const char *path) {
RENDERER = renderer;
if (ctx == NULL) {
ctx = fz_new_context(NULL, NULL, 128 << 10);
fz_register_document_handlers(ctx);
}
//doc = fz_open_document(ctx, path);
doc = fz_open_document_with_stream(ctx, path, fz_open_file(ctx, path));
pdf = pdf_specifics(ctx, doc);
pages_count = fz_count_pages(ctx, doc);
SDL_Rect viewport;
SDL_RenderGetViewport(renderer, &viewport);
screen_bounds = fz_make_rect(0, 0, viewport.w, viewport.h);
load_page(0);
}
BookReader::~BookReader() {
fz_drop_document(ctx, doc);
FreeTextureIfNeeded(&page_texture);
}
void BookReader::previous_page() {
load_page(current_page - 1);
}
void BookReader::next_page() {
load_page(current_page + 1);
}
void BookReader::zoom_in() {
set_zoom(zoom + 0.1);
}
void BookReader::zoom_out() {
set_zoom(zoom - 0.1);
}
void BookReader::move_page_up() {
move_page(0, -50);
}
void BookReader::move_page_down() {
move_page(0, 50);
}
void BookReader::move_page_left() {
move_page(-50, 0);
}
void BookReader::move_page_right() {
move_page(50, 0);
}
void BookReader::reset_page() {
page_center = fz_make_point(screen_bounds.x1 / 2, screen_bounds.y1 / 2);
set_zoom(min_zoom);
}
void BookReader::draw(SDL_Surface *window_surface, TTF_Font *font) {
float w = page_bounds.x1 * zoom, h = page_bounds.y1 * zoom;
SDL_Rect rect;
rect.x = page_center.x - w / 2;
rect.y = page_center.y - h / 2;
rect.w = w;
rect.h = h;
SDL_ClearScreen(RENDERER, SDL_MakeColour(33, 39, 43, 255));
SDL_RenderClear(RENDERER);
SDL_RenderCopy(RENDERER, page_texture, NULL, &rect);
//if (--status_bar_visible_counter > 0) {
char title[128];
sprintf(title, "%i/%i, %.2f%%", current_page + 1, pages_count, zoom * 100);
int title_width = 0, title_height = 0;
TTF_SizeText(font, title, &title_width, &title_height);
SDL_Color color = STATUS_BAR_LIGHT;
SDL_DrawRect(RENDERER, 0, 0, 1920, 60, SDL_MakeColour(color.r, color.g, color.b, 128));
SDL_DrawText(window_surface, font, (screen_bounds.x1 - title_width) / 2, (44 - title_height) / 2, WHITE, title);
StatusBar_DisplayTime();
//}
SDL_RenderPresent(RENDERER);
}
void BookReader::load_page(int num) {
current_page = std::min(std::max(0, num), pages_count - 1);
fz_drop_page(ctx, page);
page = fz_load_page(ctx, doc, current_page);
fz_rect bounds;
//fz_bound_page(ctx, page, &bounds);
fz_bound_page(ctx, page);
if (page_bounds.x1 != bounds.x1 || page_bounds.y1 != bounds.y1) {
page_bounds = bounds;
page_center = fz_make_point(screen_bounds.x1 / 2, screen_bounds.y1 / 2);
min_zoom = fmin(screen_bounds.x1 / bounds.x1, screen_bounds.y1 / bounds.y1);
max_zoom = fmax(screen_bounds.x1 / bounds.x1, screen_bounds.y1 / bounds.y1);
zoom = min_zoom;
}
render_page_to_texture();
status_bar_visible_counter = 50;
}
void BookReader::render_page_to_texture() {
FreeTextureIfNeeded(&page_texture);
fz_matrix m = fz_identity;
//fz_scale(&m, zoom, zoom);
fz_scale(zoom, zoom);
fz_pixmap *pix = fz_new_pixmap_from_page_contents(ctx, page, m, fz_device_rgb(ctx), 0);
SDL_Surface *image = SDL_CreateRGBSurfaceFrom(pix->samples, pix->w, pix->h, pix->n * 8, pix->w * pix->n, 0x000000FF, 0x0000FF00, 0x00FF0000, 0);
page_texture = SDL_CreateTextureFromSurface(RENDERER, image);
SDL_FreeSurface(image);
fz_drop_pixmap(ctx, pix);
}
void BookReader::set_zoom(float value) {
value = fmin(fmax(min_zoom, value), max_zoom);
if (value == zoom) return;
zoom = value;
load_page(current_page);
move_page(0, 0);
status_bar_visible_counter = 50;
}
void BookReader::move_page(float x, float y) {
float w = page_bounds.x1 * zoom, h = page_bounds.y1 * zoom;
page_center.x = fmin(fmax(page_center.x + x, w / 2), screen_bounds.x1 - w / 2);
page_center.y = fmin(fmax(page_center.y + y, screen_bounds.y1 - h / 2), h / 2);
}

View File

@ -1,47 +0,0 @@
#ifndef EBOOK_READER_BOOK_READER_HPP
#define EBOOK_READER_BOOK_READER_HPP
#include <mupdf/pdf.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
struct SDL_Texture;
class BookReader {
public:
BookReader(SDL_Renderer *renderer, const char *path);
~BookReader();
void previous_page();
void next_page();
void zoom_in();
void zoom_out();
void move_page_up();
void move_page_down();
void move_page_left();
void move_page_right();
void reset_page();
void draw(SDL_Surface *window_surface, TTF_Font *font);
private:
void load_page(int num);
void render_page_to_texture();
void set_zoom(float value);
void move_page(float x, float y);
fz_document *doc = NULL;
pdf_document *pdf = NULL;
fz_page *page = NULL;
fz_rect page_bounds = fz_empty_rect, screen_bounds = fz_empty_rect;
fz_point page_center = fz_make_point(0, 0);
SDL_Texture *page_texture = NULL;
SDL_Renderer *RENDERER = NULL;
int current_page = -1, pages_count = 0;
float min_zoom = 1, max_zoom = 1, zoom = 1;
int status_bar_visible_counter = 0;
};
#endif

View File

@ -1,46 +1,46 @@
#include "common.h"
#include "SDL_helper.h"
void SDL_ClearScreen(SDL_Renderer *renderer, SDL_Color colour)
{
void SDL_ClearScreen(SDL_Renderer *renderer, SDL_Color colour) {
SDL_SetRenderDrawColor(renderer, colour.r, colour.g, colour.b, colour.a);
SDL_RenderClear(renderer);
}
void SDL_DrawRect(SDL_Renderer *renderer, int x, int y, int w, int h, SDL_Color colour)
{
void SDL_DrawRect(SDL_Renderer *renderer, int x, int y, int w, int h, SDL_Color colour) {
SDL_Rect rect;
rect.x = x; rect.y = y; rect.w = w; rect.h = h;
SDL_SetRenderDrawColor(renderer, colour.r, colour.g, colour.b, colour.a);
SDL_RenderFillRect(renderer, &rect);
SDL_SetRenderDrawColor(RENDERER, colour.r, colour.g, colour.b, colour.a);
SDL_RenderFillRect(RENDERER, &rect);
}
void SDL_DrawCircle(SDL_Renderer *renderer, int x, int y, int r, SDL_Color colour)
{
void SDL_DrawCircle(SDL_Renderer *renderer, int x, int y, int r, SDL_Color colour) {
filledCircleRGBA(renderer, x, y, r, colour.r, colour.g, colour.b, colour.a);
return;
}
void SDL_DrawText(SDL_Surface* window_surface, TTF_Font *font, int x, int y, SDL_Color colour, const char *text)
{
void SDL_DrawText(SDL_Renderer *renderer, TTF_Font *font, int x, int y, SDL_Color colour, const char *text) {
SDL_Surface *surface = TTF_RenderText_Blended_Wrapped(font, text, colour, 1280);
SDL_SetSurfaceAlphaMod(surface, colour.a);
SDL_Rect position = {x, y, surface->w, surface->h};
SDL_BlitSurface(surface, NULL, window_surface, &position);
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_FreeSurface(surface);
SDL_Rect position;
position.x = x; position.y = y;
SDL_QueryTexture(texture, NULL, NULL, &position.w, &position.h);
SDL_RenderCopy(renderer, texture, NULL, &position);
SDL_DestroyTexture(texture);
}
void SDL_DrawTextf(SDL_Surface* window_surface, TTF_Font *font, int x, int y, SDL_Color colour, const char* text, ...)
{
void SDL_DrawTextf(SDL_Renderer *renderer, TTF_Font *font, int x, int y, SDL_Color colour, const char* text, ...) {
char buffer[256];
va_list args;
va_start(args, text);
vsnprintf(buffer, 256, text, args);
SDL_DrawText(window_surface, font, x, y, colour, buffer);
SDL_DrawText(renderer, font, x, y, colour, buffer);
va_end(args);
}
void SDL_LoadImage(SDL_Renderer *renderer, SDL_Texture **texture, char *path)
{
void SDL_LoadImage(SDL_Renderer *renderer, SDL_Texture **texture, char *path) {
SDL_Surface *loaded_surface = NULL;
loaded_surface = IMG_Load(path);
@ -54,24 +54,14 @@ void SDL_LoadImage(SDL_Renderer *renderer, SDL_Texture **texture, char *path)
SDL_FreeSurface(loaded_surface);
}
void SDL_LoadImageBuf(SDL_Renderer *renderer, SDL_Texture **texture, void *mem, int size)
{
SDL_Surface *loaded_surface = NULL;
SDL_RWops *rw = SDL_RWFromMem(mem, size);
loaded_surface = IMG_Load_RW(rw, 1);
if (loaded_surface)
{
Uint32 colorkey = SDL_MapRGB(loaded_surface->format, 0, 0, 0);
SDL_SetColorKey(loaded_surface, SDL_TRUE, colorkey);
*texture = SDL_CreateTextureFromSurface(renderer, loaded_surface);
void SDL_DrawImage(SDL_Renderer *renderer, SDL_Texture *texture, int x, int y) {
SDL_Rect position;
position.x = x; position.y = y;
SDL_QueryTexture(texture, NULL, NULL, &position.w, &position.h);
SDL_RenderCopy(renderer, texture, NULL, &position);
}
SDL_FreeSurface(loaded_surface);
}
void SDL_DrawImage(SDL_Renderer *renderer, SDL_Texture *texture, int x, int y, int w, int h)
{
void SDL_DrawImageScale(SDL_Renderer *renderer, SDL_Texture *texture, int x, int y, int w, int h) {
SDL_Rect position;
position.x = x; position.y = y; position.w = w; position.h = h;
SDL_RenderCopy(renderer, texture, NULL, &position);

View File

@ -76,7 +76,7 @@ void Init_Services() {
// available switch SDL2 video modes :
// 1920 x 1080 @ 32 bpp (SDL_PIXELFORMAT_RGBA8888)
// 1280 x 720 @ 32 bpp (SDL_PIXELFORMAT_RGBA8888)
WINDOW = SDL_CreateWindow("sdl2_gles2", 0, 0, 1920, 1080, 0);
WINDOW = SDL_CreateWindow("sdl2_gles2", 0, 0, 1280, 720, 0);
if (!WINDOW) {
SDL_Log("SDL_CreateWindow: %s\n", SDL_GetError());
Term_Services();
@ -95,7 +95,7 @@ void Init_Services() {
romfsInit();
ARIAL_UNICODE = TTF_OpenFont("romfs:/arial-unicode-ms.ttf", 30);
ARIAL_UNICODE = TTF_OpenFont("romfs:/arial.ttf", 35);
if (!ARIAL_UNICODE) {
Term_Services();
}
@ -122,20 +122,15 @@ int main(int argc, char *argv[]) {
Init_Services();
std::cout << "Opening test.epub" << std::endl;
Menu_OpenBook("/switch/eBookReader/books/test.pdf");
Menu_OpenBook("/switch/eBookReader/books/test.epub");
//Menu_OpenBook("/switch/eBookReader/books/test.epub");
while (run) {
while (SDL_PollEvent(&EVENT)) {
switch (EVENT.type) {
case SDL_JOYAXISMOTION:
SDL_Log("Joystick %d axis %d value: %d\n",
EVENT.jaxis.which,
EVENT.jaxis.axis, EVENT.jaxis.value);
break;
case SDL_JOYBUTTONDOWN:
SDL_Log("Joystick %d button %d down\n",
EVENT.jbutton.which, EVENT.jbutton.button);
// https://github.com/devkitPro/SDL/blob/switch-sdl2/src/joystick/switch/SDL_sysjoystick.c#L52
// seek for joystick #0
if (EVENT.jbutton.which == 0) {
@ -158,56 +153,6 @@ int main(int argc, char *argv[]) {
SDL_RenderPresent(RENDERER);*/
}
/*while (!done) {
while (SDL_PollEvent(&EVENT)) {
switch (EVENT.type) {
case SDL_JOYAXISMOTION:
SDL_Log("Joystick %d axis %d value: %d\n",
EVENT.jaxis.which,
EVENT.jaxis.axis, EVENT.jaxis.value);
break;
case SDL_JOYBUTTONDOWN:
SDL_Log("Joystick %d button %d down\n",
EVENT.jbutton.which, EVENT.jbutton.button);
// https://github.com/devkitPro/SDL/blob/switch-sdl2/src/joystick/switch/SDL_sysjoystick.c#L52
// seek for joystick #0
if (EVENT.jbutton.which == 0) {
if (EVENT.jbutton.button == 0) {
// (A) button down
} else if (EVENT.jbutton.button == 10) {
// (+) button down
done = 1;
}
}
break;
default:
break;
}
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
// fill window bounds
SDL_SetRenderDrawColor(renderer, 111, 111, 111, 255);
SDL_GetWindowSize(window, &w, &h);
SDL_Rect f = {0, 0, w, h};
SDL_RenderFillRect(renderer, &f);
draw_rects(renderer, x, 0);
draw_rects(renderer, x, h - 64);
SDL_RenderPresent(renderer);
x++;
if (x > w - 192) {
x = 0;
}
}*/
//SDL_Renderer *renderer, SDL_Surface* window_surface, TTF_Font *font, char *path
Term_Services();
return 0;
}

View File

@ -1,89 +0,0 @@
#include <iostream>
extern "C" {
#include "menu_book_reader.h"
#include "common.h"
//#include "touch_helper.h"
}
#include "BookReader.hpp"
extern SDL_Renderer* RENDERER;
extern SDL_Window* WINDOW;
extern SDL_Surface* WINDOW_SURFACE;
void Menu_OpenBook(char *path) {
BookReader *reader = new BookReader(RENDERER, path);
/*TouchInfo touchInfo;
Touch_Init(&touchInfo);*/
while(appletMainLoop()) {
reader->draw(WINDOW_SURFACE, ARIAL_UNICODE);
hidScanInput();
//Touch_Process(&touchInfo);
u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);
u64 kHeld = hidKeysHeld(CONTROLLER_P1_AUTO);
if ((kDown & KEY_B) || (kDown & KEY_PLUS)) {
std::cout << "B | PLUS" << std::endl;
break;
}
if ((kDown & KEY_DLEFT) || (kDown & KEY_L)) {
std::cout << "B | LEFT" << std::endl;
reader->previous_page();
}
if ((kDown & KEY_DRIGHT) || (kDown & KEY_R)) {
std::cout << "B | RIGHT" << std::endl;
reader->next_page();
}
if (kDown & KEY_LSTICK) {
std::cout << "B | LEFT STICK KEY" << std::endl;
reader->reset_page();
}
if (kHeld & KEY_DUP) {
std::cout << "B | UP" << std::endl;
reader->zoom_in();
}
if (kHeld & KEY_DDOWN) {
std::cout << "B | DOWN" << std::endl;
reader->zoom_out();
}
if (kHeld & KEY_LSTICK_UP) {
std::cout << "B | LEFT STICK UP" << std::endl;
reader->move_page_up();
}
if (kHeld & KEY_LSTICK_DOWN) {
std::cout << "B | LEFT STICK DOWN" << std::endl;
reader->move_page_down();
}
if (kHeld & KEY_LSTICK_LEFT) {
std::cout << "B | LEFT STICK LEFT" << std::endl;
reader->move_page_left();
}
if (kHeld & KEY_LSTICK_RIGHT) {
std::cout << "B | LEFT STICK RIGHT" << std::endl;
reader->move_page_right();
}
/*if (touchInfo.state == TouchEnded && touchInfo.tapType != TapNone)
{
if (tapped_inside(touchInfo, 0, 0, 120, 720))
reader->previous_page();
else if (tapped_inside(touchInfo, 1160, 0, 1280, 720))
reader->next_page();
}*/
}
delete reader;
}

View File

@ -0,0 +1,183 @@
#include "BookReader.hpp"
#include "PageLayout.hpp"
#include "LandscapePageLayout.hpp"
#include "common.h"
#include <algorithm>
//#include <libconfig.h>
extern "C" {
#include "SDL_helper.h"
#include "status_bar.h"
//#include "config.h"
}
fz_context *ctx = NULL;
/*config_t *config = NULL;
static int load_last_page(const char *book_name) {
if (!config) {
config = (config_t *)malloc(sizeof(config_t));
config_init(config);
config_read_file(config, "/switch/NX-Shell/last_book_pages.cfg");
}
config_setting_t *setting = config_setting_get_member(config_root_setting(config), book_name);
if (setting) {
return config_setting_get_int(setting);
}
return 0;
}
static void save_last_page(const char *book_name, int current_page) {
config_setting_t *setting = config_setting_get_member(config_root_setting(config), book_name);
if (!setting) {
setting = config_setting_add(config_root_setting(config), book_name, CONFIG_TYPE_INT);
}
if (setting) {
config_setting_set_int(setting, current_page);
config_write_file(config, "/switch/NX-Shell/last_book_pages.cfg");
}
}*/
BookReader::BookReader(const char *path) {
if (ctx == NULL) {
ctx = fz_new_context(NULL, NULL, 128 << 10);
fz_register_document_handlers(ctx);
}
book_name = std::string(path).substr(std::string(path).find_last_of("/\\") + 1);
std::string invalid_chars = " :/?#[]@!$&'()*+,;=.";
for (char& c: invalid_chars) {
book_name.erase(std::remove(book_name.begin(), book_name.end(), c), book_name.end());
}
doc = fz_open_document(ctx, path);
//int current_page = load_last_page(book_name.c_str());
int current_page = 0;
switch_current_page_layout(_currentPageLayout, current_page);
if (current_page > 0) {
show_status_bar();
}
}
BookReader::~BookReader() {
fz_drop_document(ctx, doc);
delete layout;
}
void BookReader::previous_page(int n) {
layout->previous_page(n);
show_status_bar();
//save_last_page(book_name.c_str(), layout->current_page());
}
void BookReader::next_page(int n) {
layout->next_page(n);
show_status_bar();
//save_last_page(book_name.c_str(), layout->current_page());
}
void BookReader::zoom_in() {
layout->zoom_in();
show_status_bar();
}
void BookReader::zoom_out() {
layout->zoom_out();
show_status_bar();
}
void BookReader::move_page_up() {
layout->move_up();
}
void BookReader::move_page_down() {
layout->move_down();
}
void BookReader::move_page_left() {
layout->move_left();
}
void BookReader::move_page_right() {
layout->move_right();
}
void BookReader::reset_page() {
layout->reset();
show_status_bar();
}
void BookReader::switch_page_layout() {
switch (_currentPageLayout) {
case BookPageLayoutPortrait:
switch_current_page_layout(BookPageLayoutLandscape, 0);
break;
case BookPageLayoutLandscape:
switch_current_page_layout(BookPageLayoutPortrait, 0);
break;
}
}
void BookReader::draw() {
/*if (config_dark_theme == true)
SDL_ClearScreen(RENDERER, SDL_MakeColour(33, 39, 43, 255));
else */
SDL_ClearScreen(RENDERER, SDL_MakeColour(255, 255, 255, 255));
SDL_RenderClear(RENDERER);
layout->draw_page();
#ifdef __SWITCH__
if (--status_bar_visible_counter > 0) {
char *title = layout->info();
int title_width = 0, title_height = 0;
//TTF_SizeText(Roboto, title, &title_width, &title_height);
TTF_SizeText(ARIAL_UNICODE, title, &title_width, &title_height);
//SDL_Color color = config_dark_theme ? STATUS_BAR_DARK : STATUS_BAR_LIGHT;
SDL_Color color = STATUS_BAR_LIGHT;
SDL_DrawRect(RENDERER, 0, 0, 1280, 40, SDL_MakeColour(color.r, color.g, color.b , 128));
//SDL_DrawText(RENDERER, Roboto, (1280 - title_width) / 2, (44 - title_height) / 2, WHITE, title);
SDL_DrawText(RENDERER, ARIAL_UNICODE, (1280 - title_width) / 2, (44 - title_height) / 2, WHITE, title);
StatusBar_DisplayTime();
}
#endif
SDL_RenderPresent(RENDERER);
}
void BookReader::show_status_bar() {
status_bar_visible_counter = 50;
}
void BookReader::switch_current_page_layout(BookPageLayout bookPageLayout, int current_page) {
if (layout) {
current_page = layout->current_page();
delete layout;
layout = NULL;
}
_currentPageLayout = bookPageLayout;
switch (bookPageLayout) {
case BookPageLayoutPortrait:
layout = new PageLayout(doc, current_page);
break;
case BookPageLayoutLandscape:
layout = new LandscapePageLayout(doc, current_page);
break;
}
}

View File

@ -0,0 +1,52 @@
#ifndef EBOOK_READER_BOOK_READER_HPP
#define EBOOK_READER_BOOK_READER_HPP
#include <mupdf/pdf.h>
#include <string>
#include "PageLayout.hpp"
struct SDL_Texture;
typedef enum
{
BookPageLayoutPortrait,
BookPageLayoutLandscape
} BookPageLayout;
class BookReader
{
public:
BookReader(const char *path);
~BookReader();
void previous_page(int n);
void next_page(int n);
void zoom_in();
void zoom_out();
void move_page_up();
void move_page_down();
void move_page_left();
void move_page_right();
void reset_page();
void switch_page_layout();
void draw();
BookPageLayout currentPageLayout()
{
return _currentPageLayout;
}
private:
void show_status_bar();
void switch_current_page_layout(BookPageLayout bookPageLayout, int current_page);
fz_document *doc = NULL;
int status_bar_visible_counter = 0;
BookPageLayout _currentPageLayout = BookPageLayoutPortrait;
PageLayout *layout = NULL;
std::string book_name;
};
#endif

View File

@ -0,0 +1,40 @@
#include "LandscapePageLayout.hpp"
#include "common.h"
#include <algorithm>
LandscapePageLayout::LandscapePageLayout(fz_document *doc, int current_page):PageLayout(doc, current_page)
{
int w = viewport.w;
viewport.w = viewport.h;
viewport.h = w;
render_page_to_texture(_current_page, true);
reset();
}
void LandscapePageLayout::reset()
{
page_center = fz_make_point(viewport.h / 2, viewport.w / 2);
set_zoom(min_zoom);
};
void LandscapePageLayout::draw_page()
{
float w = page_bounds.x1 * zoom, h = page_bounds.y1 * zoom;
SDL_Rect rect;
rect.y = page_center.y - h / 2;
rect.x = page_center.x - w / 2;
rect.w = w;
rect.h = h;
SDL_RenderCopyEx(RENDERER, page_texture, NULL, &rect, 90, NULL, SDL_FLIP_NONE);
}
void LandscapePageLayout::move_page(float x, float y)
{
float w = page_bounds.x1 * zoom, h = page_bounds.y1 * zoom;
page_center.x = fmin(fmax(page_center.x + y, h / 2), viewport.h - h / 2);
page_center.y = fmin(fmax(page_center.y + x, viewport.w - w / 2), w / 2);
}

View File

@ -0,0 +1,18 @@
#ifndef EBOOK_READER_LANDSCAPE_PAGE_LAYOUT_HPP
#define EBOOK_READER_LANDSCAPE_PAGE_LAYOUT_HPP
#include "PageLayout.hpp"
class LandscapePageLayout: public PageLayout
{
public:
LandscapePageLayout(fz_document *doc, int current_page);
void reset();
void draw_page();
protected:
void move_page(float x, float y);
};
#endif

View File

@ -0,0 +1,127 @@
#include "PageLayout.hpp"
#include "common.h"
#include <algorithm>
PageLayout::PageLayout(fz_document *doc, int current_page):doc(doc),pdf(pdf_specifics(ctx, doc)),pages_count(fz_count_pages(ctx, doc))
{
_current_page = std::min(std::max(0, current_page), pages_count - 1);
SDL_RenderGetViewport(RENDERER, &viewport);
render_page_to_texture(_current_page, false);
}
void PageLayout::previous_page(int n)
{
render_page_to_texture(_current_page - n, false);
}
void PageLayout::next_page(int n)
{
render_page_to_texture(_current_page + n, false);
}
void PageLayout::zoom_in()
{
set_zoom(zoom + 0.1);
};
void PageLayout::zoom_out()
{
set_zoom(zoom - 0.1);
};
void PageLayout::move_up()
{
move_page(0, 50);
};
void PageLayout::move_down()
{
move_page(0, -50);
};
void PageLayout::move_left()
{
move_page(-50, 0);
};
void PageLayout::move_right()
{
move_page(50, 0);
};
void PageLayout::reset()
{
page_center = fz_make_point(viewport.w / 2, viewport.h / 2);
set_zoom(min_zoom);
};
void PageLayout::draw_page()
{
float w = page_bounds.x1 * zoom, h = page_bounds.y1 * zoom;
SDL_Rect rect;
rect.x = page_center.x - w / 2;
rect.y = page_center.y - h / 2;
rect.w = w;
rect.h = h;
SDL_RenderCopy(RENDERER, page_texture, NULL, &rect);
}
char* PageLayout::info()
{
static char title[128];
sprintf(title, "%i/%i, %.2f%%", _current_page + 1, pages_count, zoom * 100);
return title;
}
void PageLayout::render_page_to_texture(int num, bool reset_zoom)
{
FreeTextureIfNeeded(&page_texture);
_current_page = std::min(std::max(0, num), pages_count - 1);
fz_page *page = fz_load_page(ctx, doc, _current_page);
fz_rect bounds = fz_bound_page(ctx, page);
if (page_bounds.x1 != bounds.x1 || page_bounds.y1 != bounds.y1 || reset_zoom)
{
page_bounds = bounds;
page_center = fz_make_point(viewport.w / 2, viewport.h / 2);
min_zoom = fmin(viewport.w / bounds.x1, viewport.h / bounds.y1);
max_zoom = fmax(viewport.w / bounds.x1, viewport.h / bounds.y1);
zoom = min_zoom;
}
fz_pixmap *pix = fz_new_pixmap_from_page_contents(ctx, page, fz_scale(zoom, zoom), fz_device_rgb(ctx), 0);
SDL_Surface *image = SDL_CreateRGBSurfaceFrom(pix->samples, pix->w, pix->h, pix->n * 8, pix->w * pix->n, 0x000000FF, 0x0000FF00, 0x00FF0000, 0);
page_texture = SDL_CreateTextureFromSurface(RENDERER, image);
SDL_FreeSurface(image);
fz_drop_pixmap(ctx, pix);
fz_drop_page(ctx, page);
}
void PageLayout::set_zoom(float value)
{
value = fmin(fmax(min_zoom, value), max_zoom);
if (value == zoom)
return;
zoom = value;
render_page_to_texture(_current_page, false);
move_page(0, 0);
}
void PageLayout::move_page(float x, float y)
{
float w = page_bounds.x1 * zoom, h = page_bounds.y1 * zoom;
page_center.x = fmin(fmax(page_center.x + x, w / 2), viewport.w - w / 2);
page_center.y = fmin(fmax(page_center.y + y, viewport.h - h / 2), h / 2);
}

View File

@ -0,0 +1,58 @@
#ifndef EBOOK_READER_PAGE_LAYOUT_HPP
#define EBOOK_READER_PAGE_LAYOUT_HPP
#include <mupdf/pdf.h>
#include <SDL2/SDL.h>
extern fz_context *ctx;
static inline void FreeTextureIfNeeded(SDL_Texture **texture)
{
if (texture && *texture)
{
SDL_DestroyTexture(*texture);
*texture = NULL;
}
}
class PageLayout
{
public:
PageLayout(fz_document *doc, int current_page);
int current_page()
{
return _current_page;
}
virtual void previous_page(int n);
virtual void next_page(int n);
virtual void zoom_in();
virtual void zoom_out();
virtual void move_up();
virtual void move_down();
virtual void move_left();
virtual void move_right();
virtual void reset();
virtual void draw_page();
virtual char* info();
protected:
virtual void render_page_to_texture(int num, bool reset_zoom);
virtual void set_zoom(float value);
virtual void move_page(float x, float y);
fz_document *doc = NULL;
pdf_document *pdf = NULL;
const int pages_count = 0;
int _current_page = 0;
fz_rect page_bounds = fz_empty_rect;
fz_point page_center = fz_make_point(0, 0);
float min_zoom = 1, max_zoom = 1, zoom = 1;
SDL_Rect viewport;
SDL_Texture *page_texture = NULL;
};
#endif

View File

@ -0,0 +1,121 @@
extern "C" {
#include "menu_book_reader.h"
#include "common.h"
//#include "touch_helper.h"
}
#include "BookReader.hpp"
void Menu_OpenBook(char *path) {
BookReader *reader = new BookReader(path);
/*TouchInfo touchInfo;
Touch_Init(&touchInfo);*/
while(appletMainLoop()) {
reader->draw();
hidScanInput();
//Touch_Process(&touchInfo);
u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);
u64 kHeld = hidKeysHeld(CONTROLLER_P1_AUTO);
if (kDown & KEY_DLEFT) {
if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode()))
reader->previous_page(1);
else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode()))
reader->zoom_out();
} else if (kDown & KEY_DRIGHT) {
if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode()))
reader->next_page(1);
else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode()))
reader->zoom_in();
}
if (kDown & KEY_R) {
reader->next_page(10);
} else if (kDown & KEY_L) {
reader->previous_page(10);
}
if ((kDown & KEY_DUP) || (kHeld & KEY_RSTICK_UP)) {
if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) {
reader->zoom_in();
} else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) {
reader->previous_page(1);
}
//reader->reset_page();
} else if ((kDown & KEY_DDOWN) || (kHeld & KEY_RSTICK_DOWN)) {
if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) {
reader->zoom_out();
} else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) {
reader->next_page(1);
}
//reader->reset_page();
}
if (kHeld & KEY_LSTICK_UP) {
if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) {
reader->move_page_up();
} else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) {
reader->move_page_left();
}
} else if (kHeld & KEY_LSTICK_DOWN) {
if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) {
reader->move_page_down();
} else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) {
reader->move_page_right();
}
} else if (kHeld & KEY_LSTICK_LEFT) {
if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) {
reader->move_page_left();
} else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) {
reader->move_page_up();
}
} else if (kHeld & KEY_LSTICK_RIGHT) {
if (reader->currentPageLayout() == BookPageLayoutPortrait || (!hidGetHandheldMode())) {
reader->move_page_right();
} else if ((reader->currentPageLayout() == BookPageLayoutLandscape) && (hidGetHandheldMode())) {
reader->move_page_down();
}
}
if (kDown & KEY_B) {
break;
}
if (kDown & KEY_LSTICK || kDown & KEY_RSTICK) {
reader->reset_page();
}
if (kDown & KEY_Y) {
reader->switch_page_layout();
}
/*if (touchInfo.state == TouchEnded && touchInfo.tapType != TapNone)
{
float tapRegion = 120;
switch (reader->currentPageLayout())
{
case BookPageLayoutPortrait:
if (tapped_inside(touchInfo, 0, 0, tapRegion, 720))
reader->previous_page(1);
else if (tapped_inside(touchInfo, 1280 - tapRegion, 0, 1280, 720))
reader->next_page(1);
break;
case BookPageLayoutLandscape:
if (tapped_inside(touchInfo, 0, 0, 1280, tapRegion))
reader->previous_page(1);
else if (tapped_inside(touchInfo, 0, 720 - tapRegion, 1280, 720))
reader->next_page(1);
reader->reset_page();
break;
}
}*/
}
delete reader;
}

View File

@ -4,20 +4,21 @@
#include "common.h"
#include "SDL_helper.h"
#include "status_bar.h"
#include "textures.h"
static char *Clock_GetCurrentTime(bool _12hour) {
static char *Clock_GetCurrentTime(void)
{
static char buffer[10];
u64 current_time;
timeGetCurrentTime(TimeType_UserSystemClock, &current_time);
struct tm* time_struct = gmtime((const time_t *)&current_time);
int hours = time_struct->tm_hour;
int minutes = time_struct->tm_min;
int amOrPm = 0;
time_t unixTime = time(NULL);
struct tm* timeStruct = gmtime((const time_t *)&unixTime);
int hours = (timeStruct->tm_hour);
int minutes = timeStruct->tm_min;
bool amOrPm = false;
if (_12hour) {
if (hours < 12)
amOrPm = 1;
amOrPm = true;
if (hours == 0)
hours = 12;
else if (hours > 12)
@ -27,14 +28,92 @@ static char *Clock_GetCurrentTime(bool _12hour) {
snprintf(buffer, 10, "%2i:%02i %s", hours, minutes, amOrPm ? "AM" : "PM");
else
snprintf(buffer, 10, "%2i:%02i %s", hours, minutes, amOrPm ? "AM" : "PM");
}
return buffer;
}
void StatusBar_DisplayTime(void) {
int width = 0, height = 0;
TTF_SizeText(ARIAL_UNICODE, Clock_GetCurrentTime(true), &width, &height);
static void StatusBar_GetBatteryStatus(int x, int y)
{
u32 percent = 0;
ChargerType state;
int width = 0;
char buf[5];
SDL_DrawText(WINDOW_SURFACE, ARIAL_UNICODE, 1900 - width, (40 - height)/2, WHITE, Clock_GetCurrentTime(true));
if (R_FAILED(psmGetChargerType(&state)))
state = 0;
if (R_SUCCEEDED(psmGetBatteryChargePercentage(&percent)))
{
if (percent < 20)
SDL_DrawImage(RENDERER, battery_low, x, 3);
else if ((percent >= 20) && (percent < 30))
{
if (state != 0)
SDL_DrawImage(RENDERER, battery_20_charging, x, 3);
else
SDL_DrawImage(RENDERER, battery_20, x, 3);
}
else if ((percent >= 30) && (percent < 50))
{
if (state != 0)
SDL_DrawImage(RENDERER, battery_50_charging, x, 3);
else
SDL_DrawImage(RENDERER, battery_50, x, 3);
}
else if ((percent >= 50) && (percent < 60))
{
if (state != 0)
SDL_DrawImage(RENDERER, battery_50_charging, x, 3);
else
SDL_DrawImage(RENDERER, battery_50, x, 3);
}
else if ((percent >= 60) && (percent < 80))
{
if (state != 0)
SDL_DrawImage(RENDERER, battery_60_charging, x, 3);
else
SDL_DrawImage(RENDERER, battery_60, x, 3);
}
else if ((percent >= 80) && (percent < 90))
{
if (state != 0)
SDL_DrawImage(RENDERER, battery_80_charging, x, 3);
else
SDL_DrawImage(RENDERER, battery_80, x, 3);
}
else if ((percent >= 90) && (percent < 100))
{
if (state != 0)
SDL_DrawImage(RENDERER, battery_90_charging, x, 3);
else
SDL_DrawImage(RENDERER, battery_90, x, 3);
}
else if (percent == 100)
{
if (state != 0)
SDL_DrawImage(RENDERER, battery_full_charging, x, 3);
else
SDL_DrawImage(RENDERER, battery_full, x, 3);
}
snprintf(buf, 5, "%d%%", percent);
TTF_SizeText(Roboto, buf, &width, NULL);
SDL_DrawText(RENDERER, Roboto, (x - width - 10), y, WHITE, buf);
}
else
{
snprintf(buf, 5, "%d%%", percent);
TTF_SizeText(Roboto, buf, &width, NULL);
SDL_DrawText(RENDERER, Roboto, (x - width - 10), y, WHITE, buf);
SDL_DrawImage(RENDERER, battery_unknown, x, 1);
}
}
void StatusBar_DisplayTime(void)
{
int width = 0, height = 0;
TTF_SizeText(Roboto, Clock_GetCurrentTime(), &width, &height);
StatusBar_GetBatteryStatus(1260 - width - 44, (40 - height) / 2);
SDL_DrawText(RENDERER, Roboto, 1260 - width, (40 - height) / 2, WHITE, Clock_GetCurrentTime());
}