mirror of
https://github.com/joel16/NX-Shell.git
synced 2025-02-17 02:29:02 +00:00
textures: Remove libnsgif and use gif_lib for loading gifs
This commit is contained in:
parent
0117ae3ac6
commit
05eb58cf48
6
Makefile
6
Makefile
@ -39,9 +39,9 @@ include $(DEVKITPRO)/libnx/switch_rules
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := libs/imgui libs/imgui/misc/freetype libs/libnsbmp libs/libnsgif source source/imgui_nx source/popups source/tabs
|
||||
SOURCES := libs/imgui libs/imgui/misc/freetype libs/libnsbmp source source/imgui_nx source/popups source/tabs
|
||||
DATA := data
|
||||
INCLUDES := include include/imgui_nx libs/imgui libs/imgui/misc/freetype libs/libnsbmp libs/libnsgif libs/
|
||||
INCLUDES := include include/imgui_nx libs/imgui libs/imgui/misc/freetype libs/libnsbmp libs/
|
||||
ROMFS := res
|
||||
|
||||
# Output folders for autogenerated files in romfs
|
||||
@ -75,7 +75,7 @@ CXXFLAGS := $(CFLAGS) -std=gnu++17 -fno-exceptions -fno-rtti
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := `curl-config --libs` `freetype-config --libs` -lturbojpeg -ljpeg -lpng -lwebp -ljansson \
|
||||
LIBS := `curl-config --libs` `freetype-config --libs` -lgif -lturbojpeg -ljpeg -lpng -lwebp -ljansson \
|
||||
-lglad -lEGL -lglapi -ldrm_nouveau -lnx -lm -lz
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
@ -21,4 +21,3 @@ NX Shell is a multi-purpose file manager for the Nintendo Switch that aims towar
|
||||
- **Preetisketch** for the banner.
|
||||
- **Dear ImGui developers and contributors** for the GUI.
|
||||
- **devkitPro maintainers and contributors** for libnx, devkitA64, and many other packages used by this project.
|
||||
- **mtheall/averne** for imgui::deko3d and imgui::nx used by this project.
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
|
||||
#include "imgui.h"
|
||||
#include "textures.hpp"
|
||||
|
||||
enum WINDOW_STATES {
|
||||
WINDOW_STATE_FILEBROWSER = 0,
|
||||
@ -37,6 +37,9 @@ typedef struct {
|
||||
WindowCheckboxData checkbox_data;
|
||||
s64 used_storage = 0;
|
||||
s64 total_storage = 0;
|
||||
std::vector<Tex> textures;
|
||||
long unsigned int frame_count = 0;
|
||||
float zoom_factor = 1.0f;
|
||||
} WindowData;
|
||||
|
||||
extern WindowData data;
|
||||
@ -47,6 +50,9 @@ namespace FileBrowser {
|
||||
}
|
||||
|
||||
namespace Windows {
|
||||
void SetupWindow(void);
|
||||
void ExitWindow(void);
|
||||
void ResetCheckbox(WindowData &data);
|
||||
void MainWindow(WindowData &data, u64 &key, bool progress);
|
||||
void ImageViewer(void);
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
Copyright (C) 2004 Richard Wilson
|
||||
Copyright (C) 2008 Sean Fox
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
File diff suppressed because it is too large
Load Diff
@ -1,191 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004 Richard Wilson <richard.wilson@netsurf-browser.org>
|
||||
* Copyright 2008 Sean Fox <dyntryx@gmail.com>
|
||||
*
|
||||
* This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/
|
||||
* Licenced under the MIT License,
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Interface to progressive animated GIF file decoding.
|
||||
*/
|
||||
|
||||
#ifndef _LIBNSGIF_H_
|
||||
#define _LIBNSGIF_H_
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/* Error return values */
|
||||
typedef enum {
|
||||
GIF_WORKING = 1,
|
||||
GIF_OK = 0,
|
||||
GIF_INSUFFICIENT_FRAME_DATA = -1,
|
||||
GIF_FRAME_DATA_ERROR = -2,
|
||||
GIF_INSUFFICIENT_DATA = -3,
|
||||
GIF_DATA_ERROR = -4,
|
||||
GIF_INSUFFICIENT_MEMORY = -5,
|
||||
GIF_FRAME_NO_DISPLAY = -6,
|
||||
GIF_END_OF_FRAME = -7
|
||||
} gif_result;
|
||||
|
||||
/** GIF frame data */
|
||||
typedef struct gif_frame {
|
||||
/** whether the frame should be displayed/animated */
|
||||
bool display;
|
||||
/** delay (in cs) before animating the frame */
|
||||
unsigned int frame_delay;
|
||||
|
||||
/* Internal members are listed below */
|
||||
|
||||
/** offset (in bytes) to the GIF frame data */
|
||||
unsigned int frame_pointer;
|
||||
/** whether the frame has previously been used */
|
||||
bool virgin;
|
||||
/** whether the frame is totally opaque */
|
||||
bool opaque;
|
||||
/** whether a forcable screen redraw is required */
|
||||
bool redraw_required;
|
||||
/** how the previous frame should be disposed; affects plotting */
|
||||
unsigned char disposal_method;
|
||||
/** whether we acknoledge transparency */
|
||||
bool transparency;
|
||||
/** the index designating a transparent pixel */
|
||||
unsigned char transparency_index;
|
||||
/** x co-ordinate of redraw rectangle */
|
||||
unsigned int redraw_x;
|
||||
/** y co-ordinate of redraw rectangle */
|
||||
unsigned int redraw_y;
|
||||
/** width of redraw rectangle */
|
||||
unsigned int redraw_width;
|
||||
/** height of redraw rectangle */
|
||||
unsigned int redraw_height;
|
||||
} gif_frame;
|
||||
|
||||
/* API for Bitmap callbacks */
|
||||
typedef void* (*gif_bitmap_cb_create)(int width, int height);
|
||||
typedef void (*gif_bitmap_cb_destroy)(void *bitmap);
|
||||
typedef unsigned char* (*gif_bitmap_cb_get_buffer)(void *bitmap);
|
||||
typedef void (*gif_bitmap_cb_set_opaque)(void *bitmap, bool opaque);
|
||||
typedef bool (*gif_bitmap_cb_test_opaque)(void *bitmap);
|
||||
typedef void (*gif_bitmap_cb_modified)(void *bitmap);
|
||||
|
||||
/** Bitmap callbacks function table */
|
||||
typedef struct gif_bitmap_callback_vt {
|
||||
/** Create a bitmap. */
|
||||
gif_bitmap_cb_create bitmap_create;
|
||||
/** Free a bitmap. */
|
||||
gif_bitmap_cb_destroy bitmap_destroy;
|
||||
/** Return a pointer to the pixel data in a bitmap. */
|
||||
gif_bitmap_cb_get_buffer bitmap_get_buffer;
|
||||
|
||||
/* Members below are optional */
|
||||
|
||||
/** Sets whether a bitmap should be plotted opaque. */
|
||||
gif_bitmap_cb_set_opaque bitmap_set_opaque;
|
||||
/** Tests whether a bitmap has an opaque alpha channel. */
|
||||
gif_bitmap_cb_test_opaque bitmap_test_opaque;
|
||||
/** The bitmap image has changed, so flush any persistant cache. */
|
||||
gif_bitmap_cb_modified bitmap_modified;
|
||||
} gif_bitmap_callback_vt;
|
||||
|
||||
/** GIF animation data */
|
||||
typedef struct gif_animation {
|
||||
/** LZW decode context */
|
||||
void *lzw_ctx;
|
||||
/** callbacks for bitmap functions */
|
||||
gif_bitmap_callback_vt bitmap_callbacks;
|
||||
/** pointer to GIF data */
|
||||
unsigned char *gif_data;
|
||||
/** width of GIF (may increase during decoding) */
|
||||
unsigned int width;
|
||||
/** heigth of GIF (may increase during decoding) */
|
||||
unsigned int height;
|
||||
/** number of frames decoded */
|
||||
unsigned int frame_count;
|
||||
/** number of frames partially decoded */
|
||||
unsigned int frame_count_partial;
|
||||
/** decoded frames */
|
||||
gif_frame *frames;
|
||||
/** current frame decoded to bitmap */
|
||||
int decoded_frame;
|
||||
/** currently decoded image; stored as bitmap from bitmap_create callback */
|
||||
void *frame_image;
|
||||
/** number of times to loop animation */
|
||||
int loop_count;
|
||||
|
||||
/* Internal members are listed below */
|
||||
|
||||
/** current index into GIF data */
|
||||
unsigned int buffer_position;
|
||||
/** total number of bytes of GIF data available */
|
||||
unsigned int buffer_size;
|
||||
/** current number of frame holders */
|
||||
unsigned int frame_holders;
|
||||
/** index in the colour table for the background colour */
|
||||
unsigned int background_index;
|
||||
/** image aspect ratio (ignored) */
|
||||
unsigned int aspect_ratio;
|
||||
/** size of colour table (in entries) */
|
||||
unsigned int colour_table_size;
|
||||
/** whether the GIF has a global colour table */
|
||||
bool global_colours;
|
||||
/** global colour table */
|
||||
unsigned int *global_colour_table;
|
||||
/** local colour table */
|
||||
unsigned int *local_colour_table;
|
||||
} gif_animation;
|
||||
|
||||
/**
|
||||
* Initialises necessary gif_animation members.
|
||||
*/
|
||||
void gif_create(gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks);
|
||||
|
||||
/**
|
||||
* Initialises any workspace held by the animation and attempts to decode
|
||||
* any information that hasn't already been decoded.
|
||||
* If an error occurs, all previously decoded frames are retained.
|
||||
*
|
||||
* @return Error return value.
|
||||
* - GIF_FRAME_DATA_ERROR for GIF frame data error
|
||||
* - GIF_INSUFFICIENT_FRAME_DATA for insufficient data to process
|
||||
* any more frames
|
||||
* - GIF_INSUFFICIENT_MEMORY for memory error
|
||||
* - GIF_DATA_ERROR for GIF error
|
||||
* - GIF_INSUFFICIENT_DATA for insufficient data to do anything
|
||||
* - GIF_OK for successful decoding
|
||||
* - GIF_WORKING for successful decoding if more frames are expected
|
||||
*/
|
||||
gif_result gif_initialise(gif_animation *gif, size_t size, unsigned char *data);
|
||||
|
||||
/**
|
||||
* Decodes a GIF frame.
|
||||
*
|
||||
* @return Error return value. If a frame does not contain any image data,
|
||||
* GIF_OK is returned and gif->current_error is set to
|
||||
* GIF_FRAME_NO_DISPLAY
|
||||
* - GIF_FRAME_DATA_ERROR for GIF frame data error
|
||||
* - GIF_INSUFFICIENT_FRAME_DATA for insufficient data to complete the frame
|
||||
* - GIF_DATA_ERROR for GIF error (invalid frame header)
|
||||
* - GIF_INSUFFICIENT_DATA for insufficient data to do anything
|
||||
* - GIF_INSUFFICIENT_MEMORY for insufficient memory to process
|
||||
* - GIF_OK for successful decoding
|
||||
*/
|
||||
gif_result gif_decode_frame(gif_animation *gif, unsigned int frame);
|
||||
|
||||
/**
|
||||
* Releases any workspace held by a gif
|
||||
*/
|
||||
void gif_finalise(gif_animation *gif);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,377 +0,0 @@
|
||||
/*
|
||||
* This file is part of NetSurf's LibNSGIF, http://www.netsurf-browser.org/
|
||||
* Licensed under the MIT License,
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* Copyright 2017 Michael Drake <michael.drake@codethink.co.uk>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "lzw.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief LZW decompression (implementation)
|
||||
*
|
||||
* Decoder for GIF LZW data.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Context for reading LZW data.
|
||||
*
|
||||
* LZW data is split over multiple sub-blocks. Each sub-block has a
|
||||
* byte at the start, which says the sub-block size, and then the data.
|
||||
* Zero-size sub-blocks have no data, and the biggest sub-block size is
|
||||
* 255, which means there are 255 bytes of data following the sub-block
|
||||
* size entry.
|
||||
*
|
||||
* Note that an individual LZW code can be split over up to three sub-blocks.
|
||||
*/
|
||||
struct lzw_read_ctx {
|
||||
const uint8_t *data; /**< Pointer to start of input data */
|
||||
uint32_t data_len; /**< Input data length */
|
||||
uint32_t data_sb_next; /**< Offset to sub-block size */
|
||||
|
||||
const uint8_t *sb_data; /**< Pointer to current sub-block in data */
|
||||
uint32_t sb_bit; /**< Current bit offset in sub-block */
|
||||
uint32_t sb_bit_count; /**< Bit count in sub-block */
|
||||
};
|
||||
|
||||
/**
|
||||
* LZW dictionary entry.
|
||||
*
|
||||
* Records in the dictionary are composed of 1 or more entries.
|
||||
* Entries point to previous entries which can be followed to compose
|
||||
* the complete record. To compose the record in reverse order, take
|
||||
* the `last_value` from each entry, and move to the previous entry.
|
||||
* If the previous_entry's index is < the current clear_code, then it
|
||||
* is the last entry in the record.
|
||||
*/
|
||||
struct lzw_dictionary_entry {
|
||||
uint8_t last_value; /**< Last value for record ending at entry. */
|
||||
uint8_t first_value; /**< First value for entry's record. */
|
||||
uint16_t previous_entry; /**< Offset in dictionary to previous entry. */
|
||||
};
|
||||
|
||||
/**
|
||||
* LZW decompression context.
|
||||
*/
|
||||
struct lzw_ctx {
|
||||
/** Input reading context */
|
||||
struct lzw_read_ctx input;
|
||||
|
||||
uint32_t previous_code; /**< Code read from input previously. */
|
||||
uint32_t previous_code_first; /**< First value of previous code. */
|
||||
|
||||
uint32_t initial_code_size; /**< Starting LZW code size. */
|
||||
uint32_t current_code_size; /**< Current LZW code size. */
|
||||
uint32_t current_code_size_max; /**< Max code value for current size. */
|
||||
|
||||
uint32_t clear_code; /**< Special Clear code value */
|
||||
uint32_t eoi_code; /**< Special End of Information code value */
|
||||
|
||||
uint32_t current_entry; /**< Next position in table to fill. */
|
||||
|
||||
/** Output value stack. */
|
||||
uint8_t stack_base[1 << LZW_CODE_MAX];
|
||||
|
||||
/** LZW decode dictionary. Generated during decode. */
|
||||
struct lzw_dictionary_entry table[1 << LZW_CODE_MAX];
|
||||
};
|
||||
|
||||
|
||||
/* Exported function, documented in lzw.h */
|
||||
lzw_result lzw_context_create(struct lzw_ctx **ctx)
|
||||
{
|
||||
struct lzw_ctx *c = malloc(sizeof(*c));
|
||||
if (c == NULL) {
|
||||
return LZW_NO_MEM;
|
||||
}
|
||||
|
||||
*ctx = c;
|
||||
return LZW_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Exported function, documented in lzw.h */
|
||||
void lzw_context_destroy(struct lzw_ctx *ctx)
|
||||
{
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Advance the context to the next sub-block in the input data.
|
||||
*
|
||||
* \param[in] ctx LZW reading context, updated on success.
|
||||
* \return LZW_OK or LZW_OK_EOD on success, appropriate error otherwise.
|
||||
*/
|
||||
static lzw_result lzw__block_advance(struct lzw_read_ctx *ctx)
|
||||
{
|
||||
uint32_t block_size;
|
||||
uint32_t next_block_pos = ctx->data_sb_next;
|
||||
const uint8_t *data_next = ctx->data + next_block_pos;
|
||||
|
||||
if (next_block_pos >= ctx->data_len) {
|
||||
return LZW_NO_DATA;
|
||||
}
|
||||
|
||||
block_size = *data_next;
|
||||
|
||||
if ((next_block_pos + block_size) >= ctx->data_len) {
|
||||
return LZW_NO_DATA;
|
||||
}
|
||||
|
||||
ctx->sb_bit = 0;
|
||||
ctx->sb_bit_count = block_size * 8;
|
||||
|
||||
if (block_size == 0) {
|
||||
ctx->data_sb_next += 1;
|
||||
return LZW_OK_EOD;
|
||||
}
|
||||
|
||||
ctx->sb_data = data_next + 1;
|
||||
ctx->data_sb_next += block_size + 1;
|
||||
|
||||
return LZW_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the next LZW code of given size from the raw input data.
|
||||
*
|
||||
* Reads codes from the input data stream coping with GIF data sub-blocks.
|
||||
*
|
||||
* \param[in] ctx LZW reading context, updated.
|
||||
* \param[in] code_size Size of LZW code to get from data.
|
||||
* \param[out] code_out Returns an LZW code on success.
|
||||
* \return LZW_OK or LZW_OK_EOD on success, appropriate error otherwise.
|
||||
*/
|
||||
static inline lzw_result lzw__next_code(
|
||||
struct lzw_read_ctx *ctx,
|
||||
uint8_t code_size,
|
||||
uint32_t *code_out)
|
||||
{
|
||||
uint32_t code = 0;
|
||||
uint8_t current_bit = ctx->sb_bit & 0x7;
|
||||
uint8_t byte_advance = (current_bit + code_size) >> 3;
|
||||
|
||||
assert(byte_advance <= 2);
|
||||
|
||||
if (ctx->sb_bit + code_size <= ctx->sb_bit_count) {
|
||||
/* Fast path: code fully inside this sub-block */
|
||||
const uint8_t *data = ctx->sb_data + (ctx->sb_bit >> 3);
|
||||
switch (byte_advance) {
|
||||
case 2: code |= data[2] << 16; /* Fall through */
|
||||
case 1: code |= data[1] << 8; /* Fall through */
|
||||
case 0: code |= data[0] << 0;
|
||||
}
|
||||
ctx->sb_bit += code_size;
|
||||
} else {
|
||||
/* Slow path: code spans sub-blocks */
|
||||
uint8_t byte = 0;
|
||||
uint8_t bits_remaining_0 = (code_size < (8 - current_bit)) ?
|
||||
code_size : (8 - current_bit);
|
||||
uint8_t bits_remaining_1 = code_size - bits_remaining_0;
|
||||
uint8_t bits_used[3] = {
|
||||
[0] = bits_remaining_0,
|
||||
[1] = bits_remaining_1 < 8 ? bits_remaining_1 : 8,
|
||||
[2] = bits_remaining_1 - 8,
|
||||
};
|
||||
|
||||
while (true) {
|
||||
const uint8_t *data = ctx->sb_data;
|
||||
lzw_result res;
|
||||
|
||||
/* Get any data from end of this sub-block */
|
||||
while (byte <= byte_advance &&
|
||||
ctx->sb_bit < ctx->sb_bit_count) {
|
||||
code |= data[ctx->sb_bit >> 3] << (byte << 3);
|
||||
ctx->sb_bit += bits_used[byte];
|
||||
byte++;
|
||||
}
|
||||
|
||||
/* Check if we have all we need */
|
||||
if (byte > byte_advance) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Move to next sub-block */
|
||||
res = lzw__block_advance(ctx);
|
||||
if (res != LZW_OK) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*code_out = (code >> current_bit) & ((1 << code_size) - 1);
|
||||
return LZW_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clear LZW code dictionary.
|
||||
*
|
||||
* \param[in] ctx LZW reading context, updated.
|
||||
* \param[out] stack_pos_out Returns current stack position.
|
||||
* \return LZW_OK or error code.
|
||||
*/
|
||||
static lzw_result lzw__clear_codes(
|
||||
struct lzw_ctx *ctx,
|
||||
const uint8_t ** const stack_pos_out)
|
||||
{
|
||||
uint32_t code;
|
||||
uint8_t *stack_pos;
|
||||
|
||||
/* Reset dictionary building context */
|
||||
ctx->current_code_size = ctx->initial_code_size + 1;
|
||||
ctx->current_code_size_max = (1 << ctx->current_code_size) - 1;;
|
||||
ctx->current_entry = (1 << ctx->initial_code_size) + 2;
|
||||
|
||||
/* There might be a sequence of clear codes, so process them all */
|
||||
do {
|
||||
lzw_result res = lzw__next_code(&ctx->input,
|
||||
ctx->current_code_size, &code);
|
||||
if (res != LZW_OK) {
|
||||
return res;
|
||||
}
|
||||
} while (code == ctx->clear_code);
|
||||
|
||||
/* The initial code must be from the initial dictionary. */
|
||||
if (code > ctx->clear_code) {
|
||||
return LZW_BAD_ICODE;
|
||||
}
|
||||
|
||||
/* Record this initial code as "previous" code, needed during decode. */
|
||||
ctx->previous_code = code;
|
||||
ctx->previous_code_first = code;
|
||||
|
||||
/* Reset the stack, and add first non-clear code added as first item. */
|
||||
stack_pos = ctx->stack_base;
|
||||
*stack_pos++ = code;
|
||||
|
||||
*stack_pos_out = stack_pos;
|
||||
return LZW_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Exported function, documented in lzw.h */
|
||||
lzw_result lzw_decode_init(
|
||||
struct lzw_ctx *ctx,
|
||||
const uint8_t *compressed_data,
|
||||
uint32_t compressed_data_len,
|
||||
uint32_t compressed_data_pos,
|
||||
uint8_t code_size,
|
||||
const uint8_t ** const stack_base_out,
|
||||
const uint8_t ** const stack_pos_out)
|
||||
{
|
||||
struct lzw_dictionary_entry *table = ctx->table;
|
||||
|
||||
/* Initialise the input reading context */
|
||||
ctx->input.data = compressed_data;
|
||||
ctx->input.data_len = compressed_data_len;
|
||||
ctx->input.data_sb_next = compressed_data_pos;
|
||||
|
||||
ctx->input.sb_bit = 0;
|
||||
ctx->input.sb_bit_count = 0;
|
||||
|
||||
/* Initialise the dictionary building context */
|
||||
ctx->initial_code_size = code_size;
|
||||
|
||||
ctx->clear_code = (1 << code_size) + 0;
|
||||
ctx->eoi_code = (1 << code_size) + 1;
|
||||
|
||||
/* Initialise the standard dictionary entries */
|
||||
for (uint32_t i = 0; i < ctx->clear_code; ++i) {
|
||||
table[i].first_value = i;
|
||||
table[i].last_value = i;
|
||||
}
|
||||
|
||||
*stack_base_out = ctx->stack_base;
|
||||
return lzw__clear_codes(ctx, stack_pos_out);
|
||||
}
|
||||
|
||||
|
||||
/* Exported function, documented in lzw.h */
|
||||
lzw_result lzw_decode(struct lzw_ctx *ctx,
|
||||
const uint8_t ** const stack_pos_out)
|
||||
{
|
||||
lzw_result res;
|
||||
uint32_t code_new;
|
||||
uint32_t code_out;
|
||||
uint8_t last_value;
|
||||
uint8_t *stack_pos = ctx->stack_base;
|
||||
uint32_t clear_code = ctx->clear_code;
|
||||
uint32_t current_entry = ctx->current_entry;
|
||||
struct lzw_dictionary_entry * const table = ctx->table;
|
||||
|
||||
/* Get a new code from the input */
|
||||
res = lzw__next_code(&ctx->input, ctx->current_code_size, &code_new);
|
||||
if (res != LZW_OK) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Handle the new code */
|
||||
if (code_new == clear_code) {
|
||||
/* Got Clear code */
|
||||
return lzw__clear_codes(ctx, stack_pos_out);
|
||||
|
||||
} else if (code_new == ctx->eoi_code) {
|
||||
/* Got End of Information code */
|
||||
return LZW_EOI_CODE;
|
||||
|
||||
} else if (code_new > current_entry) {
|
||||
/* Code is invalid */
|
||||
return LZW_BAD_CODE;
|
||||
|
||||
} else if (code_new < current_entry) {
|
||||
/* Code is in table */
|
||||
code_out = code_new;
|
||||
last_value = table[code_new].first_value;
|
||||
} else {
|
||||
/* Code not in table */
|
||||
*stack_pos++ = ctx->previous_code_first;
|
||||
code_out = ctx->previous_code;
|
||||
last_value = ctx->previous_code_first;
|
||||
}
|
||||
|
||||
/* Add to the dictionary, only if there's space */
|
||||
if (current_entry < (1 << LZW_CODE_MAX)) {
|
||||
struct lzw_dictionary_entry *entry = table + current_entry;
|
||||
entry->last_value = last_value;
|
||||
entry->first_value = ctx->previous_code_first;
|
||||
entry->previous_entry = ctx->previous_code;
|
||||
ctx->current_entry++;
|
||||
}
|
||||
|
||||
/* Ensure code size is increased, if needed. */
|
||||
if (current_entry == ctx->current_code_size_max) {
|
||||
if (ctx->current_code_size < LZW_CODE_MAX) {
|
||||
ctx->current_code_size++;
|
||||
ctx->current_code_size_max =
|
||||
(1 << ctx->current_code_size) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store details of this code as "previous code" to the context. */
|
||||
ctx->previous_code_first = table[code_new].first_value;
|
||||
ctx->previous_code = code_new;
|
||||
|
||||
/* Put rest of data for this code on output stack.
|
||||
* Note, in the case of "code not in table", the last entry of the
|
||||
* current code has already been placed on the stack above. */
|
||||
while (code_out > clear_code) {
|
||||
struct lzw_dictionary_entry *entry = table + code_out;
|
||||
*stack_pos++ = entry->last_value;
|
||||
code_out = entry->previous_entry;
|
||||
}
|
||||
*stack_pos++ = table[code_out].last_value;
|
||||
|
||||
*stack_pos_out = stack_pos;
|
||||
return LZW_OK;
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* This file is part of NetSurf's LibNSGIF, http://www.netsurf-browser.org/
|
||||
* Licensed under the MIT License,
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* Copyright 2017 Michael Drake <michael.drake@codethink.co.uk>
|
||||
*/
|
||||
|
||||
#ifndef LZW_H_
|
||||
#define LZW_H_
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief LZW decompression (interface)
|
||||
*
|
||||
* Decoder for GIF LZW data.
|
||||
*/
|
||||
|
||||
|
||||
/** Maximum LZW code size in bits */
|
||||
#define LZW_CODE_MAX 12
|
||||
|
||||
|
||||
/* Declare lzw internal context structure */
|
||||
struct lzw_ctx;
|
||||
|
||||
|
||||
/** LZW decoding response codes */
|
||||
typedef enum lzw_result {
|
||||
LZW_OK, /**< Success */
|
||||
LZW_OK_EOD, /**< Success; reached zero-length sub-block */
|
||||
LZW_NO_MEM, /**< Error: Out of memory */
|
||||
LZW_NO_DATA, /**< Error: Out of data */
|
||||
LZW_EOI_CODE, /**< Error: End of Information code */
|
||||
LZW_BAD_ICODE, /**< Error: Bad initial LZW code */
|
||||
LZW_BAD_CODE, /**< Error: Bad LZW code */
|
||||
} lzw_result;
|
||||
|
||||
|
||||
/**
|
||||
* Create an LZW decompression context.
|
||||
*
|
||||
* \param[out] ctx Returns an LZW decompression context. Caller owned,
|
||||
* free with lzw_context_destroy().
|
||||
* \return LZW_OK on success, or appropriate error code otherwise.
|
||||
*/
|
||||
lzw_result lzw_context_create(
|
||||
struct lzw_ctx **ctx);
|
||||
|
||||
/**
|
||||
* Destroy an LZW decompression context.
|
||||
*
|
||||
* \param[in] ctx The LZW decompression context to destroy.
|
||||
*/
|
||||
void lzw_context_destroy(
|
||||
struct lzw_ctx *ctx);
|
||||
|
||||
/**
|
||||
* Initialise an LZW decompression context for decoding.
|
||||
*
|
||||
* Caller owns neither `stack_base_out` or `stack_pos_out`.
|
||||
*
|
||||
* \param[in] ctx The LZW decompression context to initialise.
|
||||
* \param[in] compressed_data The compressed data.
|
||||
* \param[in] compressed_data_len Byte length of compressed data.
|
||||
* \param[in] compressed_data_pos Start position in data. Must be position
|
||||
* of a size byte at sub-block start.
|
||||
* \param[in] code_size The initial LZW code size to use.
|
||||
* \param[out] stack_base_out Returns base of decompressed data stack.
|
||||
* \param[out] stack_pos_out Returns current stack position.
|
||||
* There are `stack_pos_out - stack_base_out`
|
||||
* current stack entries.
|
||||
* \return LZW_OK on success, or appropriate error code otherwise.
|
||||
*/
|
||||
lzw_result lzw_decode_init(
|
||||
struct lzw_ctx *ctx,
|
||||
const uint8_t *compressed_data,
|
||||
uint32_t compressed_data_len,
|
||||
uint32_t compressed_data_pos,
|
||||
uint8_t code_size,
|
||||
const uint8_t ** const stack_base_out,
|
||||
const uint8_t ** const stack_pos_out);
|
||||
|
||||
/**
|
||||
* Fill the LZW stack with decompressed data
|
||||
*
|
||||
* Ensure anything on the stack is used before calling this, as anything
|
||||
* on the stack before this call will be trampled.
|
||||
*
|
||||
* Caller does not own `stack_pos_out`.
|
||||
*
|
||||
* \param[in] ctx LZW reading context, updated.
|
||||
* \param[out] stack_pos_out Returns current stack position.
|
||||
* Use with `stack_base_out` value from previous
|
||||
* lzw_decode_init() call.
|
||||
* There are `stack_pos_out - stack_base_out`
|
||||
* current stack entries.
|
||||
* \return LZW_OK on success, or appropriate error code otherwise.
|
||||
*/
|
||||
lzw_result lzw_decode(
|
||||
struct lzw_ctx *ctx,
|
||||
const uint8_t ** const stack_pos_out);
|
||||
|
||||
|
||||
#endif
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright 2003 James Bursa <bursa@users.sourceforge.net>
|
||||
* Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
|
||||
*
|
||||
* This file is part of NetSurf, http://www.netsurf-browser.org/
|
||||
* Licenced under the MIT License,
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef _LIBNSGIF_LOG_H_
|
||||
#define _LIBNSGIF_LOG_H_
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define LOG(x) ((void) 0)
|
||||
#else
|
||||
# define LOG(x) do { fprintf(stderr, x), fputc('\n', stderr); } while (0)
|
||||
#endif /* NDEBUG */
|
||||
|
||||
#endif /* _LIBNSGIF_LOG_H_ */
|
37
source/image.cpp
Normal file
37
source/image.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include "config.hpp"
|
||||
#include "gui.hpp"
|
||||
#include "imgui.h"
|
||||
#include "windows.hpp"
|
||||
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#include "imgui_internal.h"
|
||||
|
||||
namespace Windows {
|
||||
void ImageViewer(void) {
|
||||
Windows::SetupWindow();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||
ImGuiWindowFlags_ filename_flag = !cfg.image_filename? ImGuiWindowFlags_NoTitleBar : ImGuiWindowFlags_None;
|
||||
|
||||
if (ImGui::Begin(data.entries[data.selected].name, nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | filename_flag)) {
|
||||
if (((data.textures[0].width * data.zoom_factor) <= 1280) && ((data.textures[0].height * data.zoom_factor) <= 720))
|
||||
ImGui::SetCursorPos((ImGui::GetWindowSize() - ImVec2((data.textures[0].width * data.zoom_factor), (data.textures[0].height * data.zoom_factor))) * 0.5f);
|
||||
|
||||
if (data.textures.size() > 1) {
|
||||
svcSleepThread(data.textures[data.frame_count].delay);
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(data.textures[data.frame_count].id), (ImVec2((data.textures[data.frame_count].width * data.zoom_factor),
|
||||
(data.textures[data.frame_count].height * data.zoom_factor))));
|
||||
data.frame_count++;
|
||||
|
||||
// Reset frame counter
|
||||
if (data.frame_count == data.textures.size() - 1)
|
||||
data.frame_count = 0;
|
||||
}
|
||||
else
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(data.textures[0].id), ImVec2((data.textures[0].width * data.zoom_factor), (data.textures[0].height * data.zoom_factor)));
|
||||
}
|
||||
|
||||
Windows::ExitWindow();
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
}
|
@ -173,7 +173,19 @@ namespace Tabs {
|
||||
sorts_specs->SpecsDirty = true;
|
||||
}
|
||||
else {
|
||||
|
||||
char path[FS_MAX_PATH + 1];
|
||||
|
||||
switch (file_type) {
|
||||
case FileTypeImage:
|
||||
if ((std::snprintf(path, FS_MAX_PATH, "%s/%s", cfg.cwd, data.entries[i].name)) > 0) {
|
||||
Textures::LoadImageFile(path, data.textures);
|
||||
data.state = WINDOW_STATE_IMAGEVIEWER;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
// BMP
|
||||
#include <libnsbmp.h>
|
||||
#include "libnsbmp.h"
|
||||
|
||||
// BMP
|
||||
#include "libnsgif.h"
|
||||
// GIF
|
||||
#include <gif_lib.h>
|
||||
|
||||
// JPEG
|
||||
#include <turbojpeg.h>
|
||||
@ -21,7 +22,7 @@
|
||||
#define STBI_ONLY_PNM
|
||||
#define STBI_ONLY_PSD
|
||||
#define STBI_ONLY_TGA
|
||||
#include <stb_image.h>
|
||||
#include "stb_image.h"
|
||||
|
||||
// PNG
|
||||
#include <png.h>
|
||||
@ -66,40 +67,6 @@ namespace BMP {
|
||||
}
|
||||
}
|
||||
|
||||
namespace GIF {
|
||||
static void *bitmap_create(int width, int height) {
|
||||
/* ensure a stupidly large bitmap is not created */
|
||||
if ((static_cast<long long>(width) * static_cast<long long>(height)) > (MAX_IMAGE_BYTES/BYTES_PER_PIXEL))
|
||||
return nullptr;
|
||||
|
||||
return std::calloc(width * height, BYTES_PER_PIXEL);
|
||||
}
|
||||
|
||||
static void bitmap_set_opaque([[maybe_unused]] void *bitmap, [[maybe_unused]] bool opaque) {
|
||||
assert(bitmap);
|
||||
}
|
||||
|
||||
static bool bitmap_test_opaque([[maybe_unused]] void *bitmap) {
|
||||
assert(bitmap);
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned char *bitmap_get_buffer(void *bitmap) {
|
||||
assert(bitmap);
|
||||
return static_cast<unsigned char *>(bitmap);
|
||||
}
|
||||
|
||||
static void bitmap_destroy(void *bitmap) {
|
||||
assert(bitmap);
|
||||
std::free(bitmap);
|
||||
}
|
||||
|
||||
static void bitmap_modified([[maybe_unused]] void *bitmap) {
|
||||
assert(bitmap);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Textures {
|
||||
typedef enum ImageType {
|
||||
ImageTypeBMP,
|
||||
@ -144,7 +111,7 @@ namespace Textures {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool LoadImage(unsigned char *data, GLint format, Tex &texture) {
|
||||
static bool Create(unsigned char *data, GLint format, Tex &texture) {
|
||||
glGenTextures(1, &texture.id);
|
||||
glBindTexture(GL_TEXTURE_2D, texture.id);
|
||||
|
||||
@ -175,7 +142,7 @@ namespace Textures {
|
||||
if (buffer != nullptr && png_image_finish_read(&image, nullptr, buffer, 0, nullptr) != 0) {
|
||||
texture.width = image.width;
|
||||
texture.height = image.height;
|
||||
ret = Textures::LoadImage(buffer, GL_RGBA, texture);
|
||||
ret = Textures::Create(buffer, GL_RGBA, texture);
|
||||
delete[] buffer;
|
||||
png_image_free(&image);
|
||||
}
|
||||
@ -224,67 +191,106 @@ namespace Textures {
|
||||
|
||||
texture.width = bmp.width;
|
||||
texture.height = bmp.height;
|
||||
bool ret = LoadImage(static_cast<unsigned char *>(bmp.bitmap), GL_RGBA, texture);
|
||||
bool ret = Create(static_cast<unsigned char *>(bmp.bitmap), GL_RGBA, texture);
|
||||
bmp_finalise(&bmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool LoadImageGIF(unsigned char **data, s64 &size, std::vector<Tex> &textures) {
|
||||
gif_bitmap_callback_vt bitmap_callbacks = {
|
||||
GIF::bitmap_create,
|
||||
GIF::bitmap_destroy,
|
||||
GIF::bitmap_get_buffer,
|
||||
GIF::bitmap_set_opaque,
|
||||
GIF::bitmap_test_opaque,
|
||||
GIF::bitmap_modified
|
||||
};
|
||||
|
||||
static bool LoadImageGIF(const std::string &path, std::vector<Tex> &textures) {
|
||||
bool ret = false;
|
||||
gif_animation gif;
|
||||
gif_result code = GIF_OK;
|
||||
gif_create(&gif, &bitmap_callbacks);
|
||||
int error = 0;
|
||||
GifFileType *gif = DGifOpenFileName(path.c_str(), &error);
|
||||
|
||||
if (!gif) {
|
||||
Log::Error("DGifOpenFileName failed: %d\n", error);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (DGifSlurp(gif) != GIF_OK) {
|
||||
Log::Error("DGifSlurp failed: %d\n", gif->Error);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (gif->ImageCount <= 0) {
|
||||
Log::Error("Gif does not contain any images.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
do {
|
||||
code = gif_initialise(&gif, size, *data);
|
||||
if (code != GIF_OK && code != GIF_WORKING) {
|
||||
Log::Error("gif_initialise failed: %d\n", code);
|
||||
gif_finalise(&gif);
|
||||
return ret;
|
||||
}
|
||||
} while (code != GIF_OK);
|
||||
textures.resize(gif->ImageCount);
|
||||
|
||||
bool gif_is_animated = gif.frame_count > 1;
|
||||
// seiken's example code from:
|
||||
// https://forums.somethingawful.com/showthread.php?threadid=2773485&userid=0&perpage=40&pagenumber=487#post465199820
|
||||
textures[0].width = gif->SWidth;
|
||||
textures[0].height = gif->SHeight;
|
||||
std::unique_ptr<u32[]> pixels(new u32[textures[0].width * textures[0].height]);
|
||||
|
||||
if (gif_is_animated) {
|
||||
textures.resize(gif.frame_count);
|
||||
for (int i = 0; i < textures[0].width * textures[0].height; ++i)
|
||||
pixels[i] = gif->SBackGroundColor;
|
||||
|
||||
for (unsigned int i = 0; i < gif.frame_count; i++) {
|
||||
code = gif_decode_frame(&gif, i);
|
||||
if (code != GIF_OK) {
|
||||
Log::Error("gif_decode_frame failed: %d\n", code);
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < gif->ImageCount; ++i) {
|
||||
const SavedImage &frame = gif->SavedImages[i];
|
||||
bool transparency = false;
|
||||
unsigned char transparency_byte = 0;
|
||||
|
||||
// Delay time in hundredths of a second.
|
||||
int delay_time = 1;
|
||||
for (int j = 0; j < frame.ExtensionBlockCount; ++j) {
|
||||
const ExtensionBlock &block = frame.ExtensionBlocks[j];
|
||||
|
||||
textures[i].width = gif.width;
|
||||
textures[i].height = gif.height;
|
||||
textures[i].delay = gif.frames->frame_delay;
|
||||
ret = Textures::LoadImage(static_cast<unsigned char *>(gif.frame_image), GL_RGBA, textures[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
code = gif_decode_frame(&gif, 0);
|
||||
if (code != GIF_OK) {
|
||||
Log::Error("gif_decode_frame failed: %d\n", code);
|
||||
return false;
|
||||
if (block.Function != GRAPHICS_EXT_FUNC_CODE)
|
||||
continue;
|
||||
|
||||
// Here's the metadata for this frame.
|
||||
char dispose = (block.Bytes[0] >> 2) & 7;
|
||||
transparency = block.Bytes[0] & 1;
|
||||
delay_time = block.Bytes[1] + (block.Bytes[2] << 8);
|
||||
transparency_byte = block.Bytes[3];
|
||||
|
||||
if (dispose == 2) {
|
||||
// Clear the canvas.
|
||||
for (int k = 0; k < textures[0].width * textures[0].height; ++k)
|
||||
pixels[k] = gif->SBackGroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
textures[0].width = gif.width;
|
||||
textures[0].height = gif.height;
|
||||
ret = Textures::LoadImage(static_cast<unsigned char *>(gif.frame_image), GL_RGBA, textures[0]);
|
||||
// Colour map for this frame.
|
||||
ColorMapObject *map = frame.ImageDesc.ColorMap ? frame.ImageDesc.ColorMap : gif->SColorMap;
|
||||
|
||||
// Region this frame draws to.
|
||||
int fw = frame.ImageDesc.Width;
|
||||
int fh = frame.ImageDesc.Height;
|
||||
int fl = frame.ImageDesc.Left;
|
||||
int ft = frame.ImageDesc.Top;
|
||||
|
||||
for (int y = 0; y < std::min(textures[0].height, fh); ++y) {
|
||||
for (int x = 0; x < std::min(textures[0].width, fw); ++x) {
|
||||
unsigned char byte = frame.RasterBits[x + y * fw];
|
||||
|
||||
// Transparent pixel.
|
||||
if (transparency && byte == transparency_byte)
|
||||
continue;
|
||||
|
||||
// Draw to canvas.
|
||||
const GifColorType &c = map->Colors[byte];
|
||||
pixels[fl + x + (ft + y) * textures[0].width] = c.Red | (c.Green << 8) | (c.Blue << 16) | (0xff << 24);
|
||||
}
|
||||
}
|
||||
|
||||
textures[i].delay = delay_time * 10000000;
|
||||
textures[i].width = textures[0].width;
|
||||
textures[i].height = textures[0].height;
|
||||
|
||||
// Here's the actual frame, pixels.get() is now a pointer to the 32-bit RGBA
|
||||
// data for this frame you might expect.
|
||||
ret = Textures::Create(reinterpret_cast<unsigned char*>(pixels.get()), GL_RGBA, textures[i]);
|
||||
}
|
||||
|
||||
gif_finalise(&gif);
|
||||
return ret;
|
||||
if (DGifCloseFile(gif, &error) != GIF_OK) {
|
||||
Log::Error("DGifCloseFile failed: %d\n", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadImageJPEG(unsigned char **data, s64 &size, Tex &texture) {
|
||||
@ -293,7 +299,7 @@ namespace Textures {
|
||||
tjDecompressHeader2(jpeg, *data, size, &texture.width, &texture.height, &jpegsubsamp);
|
||||
unsigned char *buffer = new unsigned char[texture.width * texture.height * 3];
|
||||
tjDecompress2(jpeg, *data, size, buffer, texture.width, 0, texture.height, TJPF_RGB, TJFLAG_FASTDCT);
|
||||
bool ret = LoadImage(buffer, GL_RGB, texture);
|
||||
bool ret = Create(buffer, GL_RGB, texture);
|
||||
tjDestroy(jpeg);
|
||||
delete[] buffer;
|
||||
return ret;
|
||||
@ -301,7 +307,7 @@ namespace Textures {
|
||||
|
||||
static bool LoadImageOther(unsigned char **data, s64 &size, Tex &texture) {
|
||||
unsigned char *image = stbi_load_from_memory(*data, size, &texture.width, &texture.height, nullptr, STBI_rgb_alpha);
|
||||
bool ret = Textures::LoadImage(image, GL_RGBA, texture);
|
||||
bool ret = Textures::Create(image, GL_RGBA, texture);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -319,7 +325,7 @@ namespace Textures {
|
||||
if (buffer != nullptr && png_image_finish_read(&image, nullptr, buffer, 0, nullptr) != 0) {
|
||||
texture.width = image.width;
|
||||
texture.height = image.height;
|
||||
ret = Textures::LoadImage(buffer, GL_RGBA, texture);
|
||||
ret = Textures::Create(buffer, GL_RGBA, texture);
|
||||
delete[] buffer;
|
||||
png_image_free(&image);
|
||||
}
|
||||
@ -336,7 +342,7 @@ namespace Textures {
|
||||
|
||||
static bool LoadImageWEBP(unsigned char **data, s64 &size, Tex &texture) {
|
||||
*data = WebPDecodeRGBA(*data, size, &texture.width, &texture.height);
|
||||
bool ret = Textures::LoadImage(*data, GL_RGBA, texture);
|
||||
bool ret = Textures::Create(*data, GL_RGBA, texture);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -359,45 +365,47 @@ namespace Textures {
|
||||
|
||||
bool LoadImageFile(const char path[FS_MAX_PATH], std::vector<Tex> &textures) {
|
||||
bool ret = false;
|
||||
unsigned char *data = nullptr;
|
||||
s64 size = 0;
|
||||
|
||||
if (R_FAILED(Textures::ReadFile(path, &data, size))) {
|
||||
delete[] data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Resize to 1 initially. If the file is a GIF it will be resized accordingly.
|
||||
textures.resize(1);
|
||||
|
||||
ImageType type = GetImageType(path);
|
||||
switch(type) {
|
||||
case ImageTypeBMP:
|
||||
ret = Textures::LoadImageBMP(&data, size, textures[0]);
|
||||
break;
|
||||
ImageType type = Textures::GetImageType(path);
|
||||
|
||||
case ImageTypeGIF:
|
||||
ret = Textures::LoadImageGIF(&data, size, textures);
|
||||
break;
|
||||
if (type == ImageTypeGIF)
|
||||
ret = Textures::LoadImageGIF(path, textures);
|
||||
else {
|
||||
unsigned char *data = nullptr;
|
||||
s64 size = 0;
|
||||
|
||||
case ImageTypeJPEG:
|
||||
ret = Textures::LoadImageJPEG(&data, size, textures[0]);
|
||||
break;
|
||||
if (R_FAILED(Textures::ReadFile(path, &data, size))) {
|
||||
delete[] data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
case ImageTypePNG:
|
||||
ret = Textures::LoadImagePNG(&data, size, textures[0]);
|
||||
break;
|
||||
switch(type) {
|
||||
case ImageTypeBMP:
|
||||
ret = Textures::LoadImageBMP(&data, size, textures[0]);
|
||||
break;
|
||||
|
||||
case ImageTypeJPEG:
|
||||
ret = Textures::LoadImageJPEG(&data, size, textures[0]);
|
||||
break;
|
||||
|
||||
case ImageTypePNG:
|
||||
ret = Textures::LoadImagePNG(&data, size, textures[0]);
|
||||
break;
|
||||
|
||||
case ImageTypeWEBP:
|
||||
ret = Textures::LoadImageWEBP(&data, size, textures[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = Textures::LoadImageOther(&data, size, textures[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
case ImageTypeWEBP:
|
||||
ret = Textures::LoadImageWEBP(&data, size, textures[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = Textures::LoadImageOther(&data, size, textures[0]);
|
||||
break;
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -8,13 +8,13 @@
|
||||
#include "windows.hpp"
|
||||
|
||||
namespace Windows {
|
||||
static void SetupWindow(void) {
|
||||
void SetupWindow(void) {
|
||||
ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiCond_Once);
|
||||
ImGui::SetNextWindowSize(ImVec2(1280.0f, 720.0f), ImGuiCond_Once);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
};
|
||||
|
||||
static void ExitWindow(void) {
|
||||
void ExitWindow(void) {
|
||||
ImGui::End();
|
||||
ImGui::PopStyleVar();
|
||||
};
|
||||
@ -55,6 +55,10 @@ namespace Windows {
|
||||
Popups::DeletePopup(data);
|
||||
break;
|
||||
|
||||
case WINDOW_STATE_IMAGEVIEWER:
|
||||
Windows::ImageViewer();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -76,6 +80,7 @@ namespace Windows {
|
||||
if (key & HidNpadButton_B) {
|
||||
switch(data.state) {
|
||||
case WINDOW_STATE_OPTIONS:
|
||||
case WINDOW_STATE_IMAGEVIEWER:
|
||||
data.state = WINDOW_STATE_FILEBROWSER;
|
||||
break;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user