Port plugin to Aroma

This commit is contained in:
Maschell 2020-12-11 16:41:37 +01:00
parent 539e06b46c
commit 425c52add3
34 changed files with 1104 additions and 4292 deletions

67
.clang-format Normal file
View File

@ -0,0 +1,67 @@
# Generated from CLion C/C++ Code Style settings
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
AlignOperands: Align
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Always
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: Yes
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: true
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
ColumnLimit: 0
CompactNamespaces: false
ContinuationIndentWidth: 8
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PointerAlignment: Right
ReflowComments: false
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 4
UseTab: Never

72
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,72 @@
name: CI-Release
on:
push:
branches:
- master
jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src
build-binary:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v2
- name: create version.h
run: |
git_hash=$(git rev-parse --short "$GITHUB_SHA")
cat <<EOF > ./src/version.h
#pragma once
#define VERSION_EXTRA " (nightly-$git_hash)"
EOF
- name: build binary
run: |
docker build . -t builder
docker run --rm -v ${PWD}:/project builder make
- uses: actions/upload-artifact@master
with:
name: binary
path: "*.wps"
deploy-binary:
needs: build-binary
runs-on: ubuntu-22.04
steps:
- name: Get environment variables
id: get_repository_name
run: |
echo REPOSITORY_NAME=$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}' | sed -e "s/:refs//") >> $GITHUB_ENV
echo DATETIME=$(echo $(date '+%Y%m%d-%H%M%S')) >> $GITHUB_ENV
- uses: actions/download-artifact@master
with:
name: binary
- name: zip artifact
run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip *.wps
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
release_name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
draft: false
prerelease: true
body: |
Not a stable release:
${{ github.event.head_commit.message }}
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
asset_name: ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
asset_content_type: application/zip

32
.github/workflows/pr.yml vendored Normal file
View File

@ -0,0 +1,32 @@
name: CI-PR
on: [pull_request]
jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src
build-binary:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v2
- name: create version.h
run: |
git_hash=$(git rev-parse --short "${{ github.event.pull_request.head.sha }}")
cat <<EOF > ./src/version.h
#pragma once
#define VERSION_EXTRA " (nightly-$git_hash)"
EOF
- name: build binary
run: |
docker build . -t builder
docker run --rm -v ${PWD}:/project builder make
- uses: actions/upload-artifact@master
with:
name: binary
path: "*.wps"

5
.gitignore vendored
View File

@ -1,2 +1,7 @@
build/* build/*
*.mod *.mod
cmake-build-debug/
.idea/
*.wps
*.elf
CMakeLists.txt

View File

@ -1,31 +0,0 @@
sudo: required
branches:
only:
- master
services:
- docker
addons:
apt:
packages:
- p7zip-full
before_script:
- docker build . -t screenshot-builder
script:
- docker run -it --rm -v ${PWD}:/project screenshot-builder make
before_deploy:
- cd $TRAVIS_BUILD_DIR/
- mkdir -p "wiiu/plugins"
- commit="$(git rev-parse --short=7 HEAD)"
- find -type f -name "*.mod" | xargs -i cp {} wiiu/plugins
- zip -r screenshot_wups_nightly_$commit.zip wiiu
- git config --local user.name "Maschell"
- git config --local user.email "Maschell@gmx.de"
- git tag "ScreenshotWUPS-$(date +'%Y%m%d%H%M%S')-$(git log --format=%h -1)"
deploy:
provider: releases
skip_cleanup: true
api_key:
secure: HU3Ymp5pGjTj4z59sFAkDc02WhQol+CER9UTEpvLjLuklzbguuSc6rtnorA+krWBJvk1+Gl50JqlhhI9HuauU/oTvNQLah3DC29aDmxAHFQ7fk5FDap+BBYTkb7CKPI5l1k4GRqK3EwKQMJ2L+/BdwraLHazLbU22OPPYSZvrsGBej3Nvdg6C6QcwYN3E2nO5lbxnclag+6MduKKfyvd7zA/llexrZXYC71HskEcRHIX/ol5l3yiR9L/0LcGU1hn63+O6wdC58+RxuvfRE8Zj/O853yWmAs4ltUBsFstDMvzmw9aYlN0bK8nvYvv1oBOR4ql4aPwkaEjAUzEorIBIFn8gSSdHNM5QmW+Zf+nPdIQVpS4EsDZbvM7QoptdgOuZVk7MnTVKg/7vZVDI7IMm3T/GleuwsvKs6+/jPjEhvslyKLKRaQGREGPCtAkPbDn9S8eVyhgkqQk1g5+O0RA6t9FmiOS+QPyhjSyqGPaHXQvsiN2PmGnE1YbjqUBBoy2tly4TUb+M/gGYDipKyCuQiqCpp04GYmIIHjxpIZOTZGA/klUODKTBG6DOnVNBqsYBpSwO9PIYO+gPWWBXzRF4A2/fB2TuAWVSB3FZ/Ml7AVZWXcU8l84uhKmLNJ+oeXDDDcrt4iAvjfoiWWATD0WEoZgiFDQ98nM6EqgRMQ4f1Q=
file: screenshot_wups_nightly_$commit.zip
on:
repo: Maschell/ScreenshotWUPS

View File

@ -1,6 +1,6 @@
FROM wups/core-with-wut:0.1 FROM wiiuenv/devkitppc:20220917
# Get dependencies COPY --from=wiiuenv/wiiupluginsystem:20220904 /artifacts $DEVKITPRO
COPY --from=wiiuwut/libutils:0.1 /artifacts $WUT_ROOT COPY --from=wiiuenv/libmappedmemory:20220904 /artifacts $DEVKITPRO
WORKDIR project WORKDIR project

353
Makefile
View File

@ -1,300 +1,147 @@
# You probably never need to adjust this Makefile. #-------------------------------------------------------------------------------
# All changes can be done in the makefile.mk
#---------------------------------------------------------------------------------
# Clear the implicit built in rules
#---------------------------------------------------------------------------------
.SUFFIXES: .SUFFIXES:
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPPC)),)
$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=<path to>devkitPPC")
endif
ifeq ($(strip $(DEVKITPRO)),) ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPRO") $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif endif
export PATH := $(DEVKITPPC)/bin:$(PORTLIBS)/bin:$(PATH) TOPDIR ?= $(CURDIR)
export PORTLIBS := $(DEVKITPRO)/portlibs/ppc
export WUPSDIR := $(DEVKITPRO)/wups
export GCC_VER := $(shell $(DEVKITPPC)/bin/powerpc-eabi-gcc -dumpversion)
PREFIX := powerpc-eabi- include $(DEVKITPRO)/wups/share/wups_rules
export AS := $(PREFIX)as WUT_ROOT := $(DEVKITPRO)/wut
export CC := $(PREFIX)gcc WUMS_ROOT := $(DEVKITPRO)/wums
export CXX := $(PREFIX)g++
export LD := $(PREFIX)ld
export AR := $(PREFIX)ar
export OBJCOPY := $(PREFIX)objcopy
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# TARGET is the name of the output # TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed # BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code # SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files # DATA is a list of directories containing data files
#--------------------------------------------------------------------------------- # INCLUDES is a list of directories containing header files
TARGET := $(notdir $(CURDIR)) #-------------------------------------------------------------------------------
TARGET := screenshot
BUILD := build BUILD := build
SOURCES := src src/utils src/fs
DATA := data
INCLUDES := src
ifeq ($(notdir $(CURDIR)),$(BUILD)) #-------------------------------------------------------------------------------
include ../makefile.mk
else
include makefile.mk
endif
include $(WUPSDIR)/plugin_makefile.mk
#MAP ?= $(TARGET:.mod=.map)
#---------------------------------------------------------------------------------
# options for code generation # options for code generation
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
CFLAGS := -Wall -O2 -ffunction-sections \
$(MACHDEP)
# -Os: optimise size CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__
# -Wall: generate lots of warnings
# -D__wiiu__: define the symbol __wiiu__ (used in some headers)
# -mcpu=750: enable processor specific compilation
# -meabi: enable eabi specific compilation
# -mhard-float: enable hardware floating point instructions
# -nostartfiles: Do not use the standard system startup files when linking
# -ffunction-sections: split up functions so linker can garbage collect
# -fdata-sections: split up data so linker can garbage collect
COMMON_CFLAGS := -Os -Wall -mcpu=750 -meabi -mhard-float -D__WIIU__ -nostartfiles -ffunction-sections -fdata-sections -Wl,-q $(COMMON_CFLAGS)
# -x c: compile as c code CXXFLAGS := $(CFLAGS)
# -std=c11: use the c11 standard
CFLAGS := $(COMMON_CFLAGS) -x c -std=gnu11 $(CFLAGS)
# -x c: compile as c++ code ASFLAGS := -g $(ARCH)
# -std=gnu++11: use the c++11 standard LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libmappedmemory.ld $(WUPSSPECS)
CXXFLAGS := $(COMMON_CFLAGS) -x c++ -std=gnu++11 $(CXXFLAGS)
ifeq ($(DO_LOGGING), 1) ifeq ($(DEBUG),1)
CFLAGS += -D__LOGGING__ CXXFLAGS += -DDEBUG -g
CXXFLAGS += -D__LOGGING__ CFLAGS += -DDEBUG -g
endif endif
#--------------------------------------------------------------------------------- ifeq ($(DEBUG),VERBOSE)
# any extra ld flags CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
#-------------------------------------------------------------------------------- CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
# --gc-sections: remove unneeded symbols
# -Map: generate a map file
LDFLAGS += -Wl,-Map,$(notdir $@).map,--gc-sections
#---------------------------------------------------------------------------------
Q := @
MAKEFLAGS += --no-print-directory
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS +=
#
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS +=
NEEDS_WUT := 0
ifeq ($(WUT_ENABLE_CPP), 1)
WUT_ENABLE_NEWLIB := 1
LDFLAGS += -Wl,-whole-archive,-lwutstdc++,-no-whole-archive
NEEDS_WUT := 1
endif endif
ifeq ($(WUT_ENABLE_NEWLIB), 1) LIBS := -lwups -lwut -lgd -lpng -ljpeg -lz -lmappedmemory
LDFLAGS += -Wl,-whole-archive,-lwutnewlib,-no-whole-archive
NEEDS_WUT := 1
endif
ifeq ($(WUT_DEFAULT_MALLOC), 1) #-------------------------------------------------------------------------------
LDFLAGS += -Wl,-whole-archive,-lwutmalloc,-no-whole-archive # list of directories containing libraries, this must be the top level
NEEDS_WUT := 1 # containing include and lib
endif #-------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(WUPS_ROOT) $(WUT_ROOT) $(WUMS_ROOT)
ifeq ($(NEEDS_WUT), 1) #-------------------------------------------------------------------------------
ifeq ($(strip $(WUT_ROOT)),)
$(error "Please set WUT_ROOT in your environment. export WUT_ROOT=<path to>wut)
endif
CFLAGS += -D__WUT__
CXXFLAGS += -D__WUT__
endif
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional # no real need to edit anything past this point unless you need to add additional
# rules for different file extensions # rules for different file extensions
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR))) ifneq ($(BUILD),$(notdir $(CURDIR)))
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
export PROJECTDIR := $(CURDIR)
export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
#---------------------------------------------------------------------------------
# automatically build a list of object files for our project
#---------------------------------------------------------------------------------
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
TTFFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.ttf)))
PNGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.png)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
export REAL_LD := $(CC)
else
export REAL_LD := $(CXX)
endif
export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \
$(sFILES:.s=.o) $(SFILES:.S=.o) \
$(PNGFILES:.png=.png.o) $(addsuffix .o,$(BINFILES))
#---------------------------------------------------------------------------------
# build a list of include paths
#---------------------------------------------------------------------------------
export INCLUDE_FULL += $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
$(EXTERNAL_INCLUDE)
#---------------------------------------------------------------------------------
# build a list of library paths
#---------------------------------------------------------------------------------
export LIBPATHS_FULL += $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \
$(EXTERNAL_LIBPATHS)
export OUTPUT := $(CURDIR)/$(TARGET) export OUTPUT := $(CURDIR)/$(TARGET)
.PHONY: $(BUILD) clean install export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#-------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#-------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#-------------------------------------------------------------------------------
export LD := $(CC)
#-------------------------------------------------------------------------------
else
#-------------------------------------------------------------------------------
export LD := $(CXX)
#-------------------------------------------------------------------------------
endif
#-------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#-------------------------------------------------------------------------------
all: $(BUILD)
#---------------------------------------------------------------------------------
$(BUILD): $(BUILD):
@[ -d $@ ] || mkdir -p $@ @$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD))
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
clean: clean:
@echo clean ... @echo clean ...
@rm -fr $(BUILD) $(OUTPUT).mod $(OUTPUT) @rm -fr $(BUILD) $(TARGET).wps $(TARGET).elf
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
else else
.PHONY: all
DEPENDS := $(OFILES:.o=.d) DEPENDS := $(OFILES:.o=.d)
THIS_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) #-------------------------------------------------------------------------------
# main targets
#-------------------------------------------------------------------------------
all : $(OUTPUT).wps
############################################################################### $(OUTPUT).wps : $(OUTPUT).elf
# Rule to make everything. $(OUTPUT).elf : $(OFILES)
PHONY += all
all : $(OUTPUT) $(OFILES_SRC) : $(HFILES_BIN)
###############################################################################
# Special build rules
#-------------------------------------------------------------------------------
# Rule to make the module file. # you need a rule like this for each extension you use as binary data
$(OUTPUT) : $(OFILES) #-------------------------------------------------------------------------------
@echo "linking ... " $@ %.bin.o %_bin.h : %.bin
@$(REAL_LD) $(OFILES) $(LDFLAGS) $(LIBS) $(LIBPATHS_FULL) -o $@ #-------------------------------------------------------------------------------
###############################################################################
# Standard build rules
#---------------------------------------------------------------------------------
%.a:
#---------------------------------------------------------------------------------
@echo $(notdir $@)
@rm -f $@
@$(AR) -rc $@ $^
#---------------------------------------------------------------------------------
%.o: %.cpp
@echo $(notdir $<) @echo $(notdir $<)
@$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(INCLUDE_FULL) -c $< -o $@ $(ERROR_FILTER) @$(bin2o)
#---------------------------------------------------------------------------------
%.o: %.c
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(INCLUDE_FULL) -c $< -o $@ $(ERROR_FILTER)
#---------------------------------------------------------------------------------
%.o: %.S
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(INCLUDE_FULL) -c $< -o $@ $(ERROR_FILTER)
#---------------------------------------------------------------------------------
%.png.o : %.png
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.jpg.o : %.jpg
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.ttf.o : %.ttf
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.bin.o : %.bin
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.wav.o : %.wav
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.mp3.o : %.mp3
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.ogg.o : %.ogg
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
###############################################################################
# Assembly listing rules
# Rule to make assembly listing.
PHONY += list
list : $(LIST)
# Rule to make the listing file.
%.list : $(TARGET)
$(LOG)
-$Qmkdir -p $(dir $@)
$Q$(OBJDUMP) -d $< > $@
###############################################################################
# Clean rule
# Rule to clean files.
PHONY += clean
clean :
$Qrm -rf $(wildcard $(BUILD) $(BIN))
###############################################################################
# Phony targets
.PHONY : $(PHONY)
-include $(DEPENDS) -include $(DEPENDS)
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
endif endif
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------

View File

@ -1,39 +1,52 @@
# Screenshot tool [![Build Status](https://api.travis-ci.org/Maschell/ScreenshotWUPS.svg?branch=master)](https://travis-ci.org/Maschell/ScreenshotWUPS) # Screenshot Plugin
This is just a simple plugin that takes screenshot of the TV and DRC screen. The screenshot will saved on the sd card in the folder "sd:/wiiu/screenshots/" This is just a simple plugin that takes screenshot of the TV and DRC screen.
The screenshot will be saved on the SD card in the folder `sd:/wiiu/screenshots`
## Wii U Plugin System ## Installation
This is a plugin for the [Wii U Plugin System (WUPS)](https://github.com/Maschell/WiiUPluginSystem/). To be able to use this plugin you have to place the resulting `.mod` file into the following folder: (`[ENVIRONMENT]` is a placeholder for the actual environment name.)
``` 1. Copy the file `screenshot.wps` into `sd:/wiiu/environments/[ENVIRONMENT]/plugins`.
sd:/wiiu/plugins 2. Requires the [WiiUPluginLoaderBackend](https://github.com/wiiu-env/WiiUPluginLoaderBackend) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
``` 3. Requires the [MemoryMappingModule](https://github.com/wiiu-env/MemoryMappingModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
When the file is placed on the SDCard you can load it with [plugin loader](https://github.com/Maschell/WiiUPluginSystem/).
## Usage
Press ZL + L + ZR + R on the gamepad to take a screenshot.
Via the plugin config menu (press L, DPAD Down and Minus on the gamepad) you can configure the plugin. The available options are the following:
- **Settings**:
- Enabled: (Default is true)
- Enables or disables the screenshot plugin.
- Output format: (Default is JPEG)
- Determines which file is used. Currently saving screens as .jpg, .png and .bmp is supported.
- Screen: (Default is TV and Gamepad)
- Determines from which screen a screenshot should be taken. Possible options: TV & Gamepad, TV only, Gamepad only.
- JPEG quality: (Default is 90)
- Determines the quality when saving as JPEG. Lowest possible quality is 10, highest 100.
## Building ## Building
For building you need: For building you need:
- [wups](https://github.com/Maschell/WiiUPluginSystem) - [wups](https://github.com/wiiu-env/WiiUPluginSystem)
- [wut](https://github.com/decaf-emu/wut) - [wut](https://github.com/decaf-emu/wut)
- [libutilswut](https://github.com/Maschell/libutils/tree/wut) (WUT version) for common functions. - [libmappedmemory](https://github.com/wiiu-env/libmappedmemory)
- PPC versions of zlib, libgd, libpng, libjpeg (install via `pacman -Syu ppc-zlib ppc-libgd ppc-libpng ppc-libjpeg-turbo`)
Install them (in this order) according to their README's. Don't forget the dependencies of the libs itself. ## Building using the Dockerfile
Other external libraries are already located in the `libs` folder.
- libjpeg
- libturbojpeg
### Building using the Dockerfile
It's possible to use a docker image for building. This way you don't need anything installed on your host system. It's possible to use a docker image for building. This way you don't need anything installed on your host system.
``` ```
# Build docker image (only needed once # Build docker image (only needed once)
docker build . -t screenshot-builder docker build . -t screenshot-plugin-builder
# make # make
docker run -it --rm -v ${PWD}:/project screenshot-builder make docker run -it --rm -v ${PWD}:/project screenshot-plugin-builder make
# make clean # make clean
docker run -it --rm -v ${PWD}:/project screenshot-builder make clean docker run -it --rm -v ${PWD}:/project screenshot-plugin-builder make clean
``` ```
## Format the code via docker
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src -i`

View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="ScreenshotPlugin" />
<Option makefile_is_custom="1" />
<Option pch_mode="2" />
<Option compiler="ppc-gcc" />
<Build>
<Target title="Debug">
<Option output="bin/Debug/ScreenshotPlugin" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/" />
<Option type="1" />
<Option compiler="ppc-gcc" />
<Compiler>
<Add option="-g" />
</Compiler>
<MakeCommands>
<Build command="make -j8" />
<CompileFile command="$make -f $makefile $file" />
<Clean command="make clean" />
<DistClean command="$make -f $makefile distclean$target" />
<AskRebuildNeeded command="$make -q -f $makefile $target" />
<SilentBuild command="make -j8 &gt; $(CMD_NULL)" />
</MakeCommands>
</Target>
<Target title="Release">
<Option output="bin/Release/ScreenshotPlugin" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/" />
<Option type="1" />
<Option compiler="ppc-gcc" />
<Compiler>
<Add option="-O2" />
</Compiler>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
</Compiler>
<Extensions>
<code_completion />
<envvars />
<debugger />
<lib_finder disable_auto="1" />
</Extensions>
</Project>
</CodeBlocks_project_file>

View File

@ -1,74 +0,0 @@
/* jconfig.h. Generated from jconfig.h.in by configure. */
/* Version ID for the JPEG library.
* Might be useful for tests like "#if JPEG_LIB_VERSION >= 60".
*/
#define JPEG_LIB_VERSION 62
/* libjpeg-turbo version */
#define LIBJPEG_TURBO_VERSION 1.5.3
/* libjpeg-turbo version in integer form */
#define LIBJPEG_TURBO_VERSION_NUMBER 1005003
/* Support arithmetic encoding */
#define C_ARITH_CODING_SUPPORTED 1
/* Support arithmetic decoding */
#define D_ARITH_CODING_SUPPORTED 1
/*
* Define BITS_IN_JSAMPLE as either
* 8 for 8-bit sample values (the usual setting)
* 12 for 12-bit sample values
* Only 8 and 12 are legal data precisions for lossy JPEG according to the
* JPEG standard, and the IJG code does not support anything else!
* We do not support run-time selection of data precision, sorry.
*/
#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */
/* Define to 1 if you have the <locale.h> header file. */
#define HAVE_LOCALE_H 1
/* Define to 1 if you have the <stddef.h> header file. */
#define HAVE_STDDEF_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if the system has the type `unsigned char'. */
#define HAVE_UNSIGNED_CHAR 1
/* Define to 1 if the system has the type `unsigned short'. */
#define HAVE_UNSIGNED_SHORT 1
/* Compiler does not support pointers to undefined structures. */
/* #undef INCOMPLETE_TYPES_BROKEN */
/* Support in-memory source/destination managers */
#define MEM_SRCDST_SUPPORTED 1
/* Define if you have BSD-like bzero and bcopy in <strings.h> rather than
memset/memcpy in <string.h>. */
/* #undef NEED_BSD_STRINGS */
/* Define if you need to include <sys/types.h> to get size_t. */
#define NEED_SYS_TYPES_H 1
/* Define if your (broken) compiler shifts signed values as if they were
unsigned. */
/* #undef RIGHT_SHIFT_IS_UNSIGNED */
/* Use accelerated SIMD routines. */
/* #undef WITH_SIMD */
/* Define to 1 if type `char' is unsigned and you are not using gcc. */
#ifndef __CHAR_UNSIGNED__
/* # undef __CHAR_UNSIGNED__ */
#endif
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */

View File

@ -1,317 +0,0 @@
/*
* jerror.h
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1997, Thomas G. Lane.
* Modified 1997-2009 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright (C) 2014, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file defines the error and message codes for the JPEG library.
* Edit this file to add new codes, or to translate the message strings to
* some other language.
* A set of error-reporting macros are defined too. Some applications using
* the JPEG library may wish to include this file to get the error codes
* and/or the macros.
*/
/*
* To define the enum list of message codes, include this file without
* defining macro JMESSAGE. To create a message string table, include it
* again with a suitable JMESSAGE definition (see jerror.c for an example).
*/
#ifndef JMESSAGE
#ifndef JERROR_H
/* First time through, define the enum list */
#define JMAKE_ENUM_LIST
#else
/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */
#define JMESSAGE(code,string)
#endif /* JERROR_H */
#endif /* JMESSAGE */
#ifdef JMAKE_ENUM_LIST
typedef enum {
#define JMESSAGE(code,string) code ,
#endif /* JMAKE_ENUM_LIST */
JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */
/* For maintenance convenience, list is alphabetical by message code name */
#if JPEG_LIB_VERSION < 70
JMESSAGE(JERR_ARITH_NOTIMPL,
"Sorry, arithmetic coding is not implemented")
#endif
JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix")
JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix")
JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode")
JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
#if JPEG_LIB_VERSION >= 70
JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request")
#endif
JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range")
JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported")
#if JPEG_LIB_VERSION >= 70
JMESSAGE(JERR_BAD_DROP_SAMPLING,
"Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c")
#endif
JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition")
JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace")
JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace")
JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length")
JMESSAGE(JERR_BAD_LIB_VERSION,
"Wrong JPEG library version: library is %d, caller expects %d")
JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan")
JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d")
JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d")
JMESSAGE(JERR_BAD_PROGRESSION,
"Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d")
JMESSAGE(JERR_BAD_PROG_SCRIPT,
"Invalid progressive parameters at scan script entry %d")
JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors")
JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d")
JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d")
JMESSAGE(JERR_BAD_STRUCT_SIZE,
"JPEG parameter struct mismatch: library thinks size is %u, caller expects %u")
JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access")
JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small")
JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here")
JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet")
JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d")
JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request")
JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d")
JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x")
JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d")
JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d")
JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)")
JMESSAGE(JERR_EMS_READ, "Read from EMS failed")
JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed")
JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan")
JMESSAGE(JERR_FILE_READ, "Input file read error")
JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?")
JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet")
JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow")
JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry")
JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels")
JMESSAGE(JERR_INPUT_EMPTY, "Empty input file")
JMESSAGE(JERR_INPUT_EOF, "Premature end of input file")
JMESSAGE(JERR_MISMATCHED_QUANT_TABLE,
"Cannot transcode due to multiple use of quantization table %d")
JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data")
JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change")
JMESSAGE(JERR_NOTIMPL, "Not implemented yet")
JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time")
#if JPEG_LIB_VERSION >= 70
JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined")
#endif
JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported")
JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined")
JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image")
JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined")
JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x")
JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)")
JMESSAGE(JERR_QUANT_COMPONENTS,
"Cannot quantize more than %d color components")
JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors")
JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors")
JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers")
JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker")
JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x")
JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers")
JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF")
JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s")
JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file")
JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file")
JMESSAGE(JERR_TFILE_WRITE,
"Write failed on temporary file --- out of disk space?")
JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines")
JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x")
JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up")
JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation")
JMESSAGE(JERR_XMS_READ, "Read from XMS failed")
JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed")
JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT_SHORT)
JMESSAGE(JMSG_VERSION, JVERSION)
JMESSAGE(JTRC_16BIT_TABLES,
"Caution: quantization tables are too coarse for baseline JPEG")
JMESSAGE(JTRC_ADOBE,
"Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d")
JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u")
JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u")
JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x")
JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x")
JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d")
JMESSAGE(JTRC_DRI, "Define Restart Interval %u")
JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u")
JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u")
JMESSAGE(JTRC_EOI, "End Of Image")
JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d")
JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d")
JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE,
"Warning: thumbnail image size does not match data length %u")
JMESSAGE(JTRC_JFIF_EXTENSION,
"JFIF extension marker: type 0x%02x, length %u")
JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image")
JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u")
JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x")
JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u")
JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors")
JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors")
JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization")
JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d")
JMESSAGE(JTRC_RST, "RST%d")
JMESSAGE(JTRC_SMOOTH_NOTIMPL,
"Smoothing not supported with nonstandard sampling ratios")
JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d")
JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d")
JMESSAGE(JTRC_SOI, "Start of Image")
JMESSAGE(JTRC_SOS, "Start Of Scan: %d components")
JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d")
JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d")
JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s")
JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s")
JMESSAGE(JTRC_THUMB_JPEG,
"JFIF extension marker: JPEG-compressed thumbnail image, length %u")
JMESSAGE(JTRC_THUMB_PALETTE,
"JFIF extension marker: palette thumbnail image, length %u")
JMESSAGE(JTRC_THUMB_RGB,
"JFIF extension marker: RGB thumbnail image, length %u")
JMESSAGE(JTRC_UNKNOWN_IDS,
"Unrecognized component IDs %d %d %d, assuming YCbCr")
JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u")
JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u")
JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d")
#if JPEG_LIB_VERSION >= 70
JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code")
#endif
JMESSAGE(JWRN_BOGUS_PROGRESSION,
"Inconsistent progression sequence for component %d coefficient %d")
JMESSAGE(JWRN_EXTRANEOUS_DATA,
"Corrupt JPEG data: %u extraneous bytes before marker 0x%02x")
JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment")
JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code")
JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d")
JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file")
JMESSAGE(JWRN_MUST_RESYNC,
"Corrupt JPEG data: found marker 0x%02x instead of RST%d")
JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG")
JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines")
#if JPEG_LIB_VERSION < 70
JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request")
#if defined(C_ARITH_CODING_SUPPORTED) || defined(D_ARITH_CODING_SUPPORTED)
JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined")
JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code")
#endif
#endif
#ifdef JMAKE_ENUM_LIST
JMSG_LASTMSGCODE
} J_MESSAGE_CODE;
#undef JMAKE_ENUM_LIST
#endif /* JMAKE_ENUM_LIST */
/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */
#undef JMESSAGE
#ifndef JERROR_H
#define JERROR_H
/* Macros to simplify using the error and trace message stuff */
/* The first parameter is either type of cinfo pointer */
/* Fatal errors (print message and exit) */
#define ERREXIT(cinfo,code) \
((cinfo)->err->msg_code = (code), \
(*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
#define ERREXIT1(cinfo,code,p1) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
#define ERREXIT2(cinfo,code,p1,p2) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(cinfo)->err->msg_parm.i[1] = (p2), \
(*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
#define ERREXIT3(cinfo,code,p1,p2,p3) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(cinfo)->err->msg_parm.i[1] = (p2), \
(cinfo)->err->msg_parm.i[2] = (p3), \
(*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(cinfo)->err->msg_parm.i[1] = (p2), \
(cinfo)->err->msg_parm.i[2] = (p3), \
(cinfo)->err->msg_parm.i[3] = (p4), \
(*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
#define ERREXITS(cinfo,code,str) \
((cinfo)->err->msg_code = (code), \
strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
(*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
#define MAKESTMT(stuff) do { stuff } while (0)
/* Nonfatal errors (we can keep going, but the data is probably corrupt) */
#define WARNMS(cinfo,code) \
((cinfo)->err->msg_code = (code), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
#define WARNMS1(cinfo,code,p1) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
#define WARNMS2(cinfo,code,p1,p2) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(cinfo)->err->msg_parm.i[1] = (p2), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
/* Informational/debugging messages */
#define TRACEMS(cinfo,lvl,code) \
((cinfo)->err->msg_code = (code), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
#define TRACEMS1(cinfo,lvl,code,p1) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
#define TRACEMS2(cinfo,lvl,code,p1,p2) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(cinfo)->err->msg_parm.i[1] = (p2), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \
MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
_mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \
(cinfo)->err->msg_code = (code); \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \
MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
_mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
(cinfo)->err->msg_code = (code); \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \
MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
_mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
_mp[4] = (p5); \
(cinfo)->err->msg_code = (code); \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \
MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
_mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
_mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \
(cinfo)->err->msg_code = (code); \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
#define TRACEMSS(cinfo,lvl,code,str) \
((cinfo)->err->msg_code = (code), \
strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
#endif /* JERROR_H */

View File

@ -1,421 +0,0 @@
/*
* jmorecfg.h
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 1997-2009 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright (C) 2009, 2011, 2014-2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains additional configuration options that customize the
* JPEG software for special applications or support machine-dependent
* optimizations. Most users will not need to touch this file.
*/
/*
* Maximum number of components (color channels) allowed in JPEG image.
* To meet the letter of the JPEG spec, set this to 255. However, darn
* few applications need more than 4 channels (maybe 5 for CMYK + alpha
* mask). We recommend 10 as a reasonable compromise; use 4 if you are
* really short on memory. (Each allowed component costs a hundred or so
* bytes of storage, whether actually used in an image or not.)
*/
#define MAX_COMPONENTS 10 /* maximum number of image components */
/*
* Basic data types.
* You may need to change these if you have a machine with unusual data
* type sizes; for example, "char" not 8 bits, "short" not 16 bits,
* or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits,
* but it had better be at least 16.
*/
/* Representation of a single sample (pixel element value).
* We frequently allocate large arrays of these, so it's important to keep
* them small. But if you have memory to burn and access to char or short
* arrays is very slow on your hardware, you might want to change these.
*/
#if BITS_IN_JSAMPLE == 8
/* JSAMPLE should be the smallest type that will hold the values 0..255.
* You can use a signed char by having GETJSAMPLE mask it with 0xFF.
*/
#ifdef HAVE_UNSIGNED_CHAR
typedef unsigned char JSAMPLE;
#define GETJSAMPLE(value) ((int) (value))
#else /* not HAVE_UNSIGNED_CHAR */
typedef char JSAMPLE;
#ifdef __CHAR_UNSIGNED__
#define GETJSAMPLE(value) ((int) (value))
#else
#define GETJSAMPLE(value) ((int) (value) & 0xFF)
#endif /* __CHAR_UNSIGNED__ */
#endif /* HAVE_UNSIGNED_CHAR */
#define MAXJSAMPLE 255
#define CENTERJSAMPLE 128
#endif /* BITS_IN_JSAMPLE == 8 */
#if BITS_IN_JSAMPLE == 12
/* JSAMPLE should be the smallest type that will hold the values 0..4095.
* On nearly all machines "short" will do nicely.
*/
typedef short JSAMPLE;
#define GETJSAMPLE(value) ((int) (value))
#define MAXJSAMPLE 4095
#define CENTERJSAMPLE 2048
#endif /* BITS_IN_JSAMPLE == 12 */
/* Representation of a DCT frequency coefficient.
* This should be a signed value of at least 16 bits; "short" is usually OK.
* Again, we allocate large arrays of these, but you can change to int
* if you have memory to burn and "short" is really slow.
*/
typedef short JCOEF;
/* Compressed datastreams are represented as arrays of JOCTET.
* These must be EXACTLY 8 bits wide, at least once they are written to
* external storage. Note that when using the stdio data source/destination
* managers, this is also the data type passed to fread/fwrite.
*/
#ifdef HAVE_UNSIGNED_CHAR
typedef unsigned char JOCTET;
#define GETJOCTET(value) (value)
#else /* not HAVE_UNSIGNED_CHAR */
typedef char JOCTET;
#ifdef __CHAR_UNSIGNED__
#define GETJOCTET(value) (value)
#else
#define GETJOCTET(value) ((value) & 0xFF)
#endif /* __CHAR_UNSIGNED__ */
#endif /* HAVE_UNSIGNED_CHAR */
/* These typedefs are used for various table entries and so forth.
* They must be at least as wide as specified; but making them too big
* won't cost a huge amount of memory, so we don't provide special
* extraction code like we did for JSAMPLE. (In other words, these
* typedefs live at a different point on the speed/space tradeoff curve.)
*/
/* UINT8 must hold at least the values 0..255. */
#ifdef HAVE_UNSIGNED_CHAR
typedef unsigned char UINT8;
#else /* not HAVE_UNSIGNED_CHAR */
#ifdef __CHAR_UNSIGNED__
typedef char UINT8;
#else /* not __CHAR_UNSIGNED__ */
typedef short UINT8;
#endif /* __CHAR_UNSIGNED__ */
#endif /* HAVE_UNSIGNED_CHAR */
/* UINT16 must hold at least the values 0..65535. */
#ifdef HAVE_UNSIGNED_SHORT
typedef unsigned short UINT16;
#else /* not HAVE_UNSIGNED_SHORT */
typedef unsigned int UINT16;
#endif /* HAVE_UNSIGNED_SHORT */
/* INT16 must hold at least the values -32768..32767. */
#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */
typedef short INT16;
#endif
/* INT32 must hold at least signed 32-bit values.
*
* NOTE: The INT32 typedef dates back to libjpeg v5 (1994.) Integers were
* sometimes 16-bit back then (MS-DOS), which is why INT32 is typedef'd to
* long. It also wasn't common (or at least as common) in 1994 for INT32 to be
* defined by platform headers. Since then, however, INT32 is defined in
* several other common places:
*
* Xmd.h (X11 header) typedefs INT32 to int on 64-bit platforms and long on
* 32-bit platforms (i.e always a 32-bit signed type.)
*
* basetsd.h (Win32 header) typedefs INT32 to int (always a 32-bit signed type
* on modern platforms.)
*
* qglobal.h (Qt header) typedefs INT32 to int (always a 32-bit signed type on
* modern platforms.)
*
* This is a recipe for conflict, since "long" and "int" aren't always
* compatible types. Since the definition of INT32 has technically been part
* of the libjpeg API for more than 20 years, we can't remove it, but we do not
* use it internally any longer. We instead define a separate type (JLONG)
* for internal use, which ensures that internal behavior will always be the
* same regardless of any external headers that may be included.
*/
#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */
#ifndef _BASETSD_H_ /* Microsoft defines it in basetsd.h */
#ifndef _BASETSD_H /* MinGW is slightly different */
#ifndef QGLOBAL_H /* Qt defines it in qglobal.h */
typedef long INT32;
#endif
#endif
#endif
#endif
/* Datatype used for image dimensions. The JPEG standard only supports
* images up to 64K*64K due to 16-bit fields in SOF markers. Therefore
* "unsigned int" is sufficient on all machines. However, if you need to
* handle larger images and you don't mind deviating from the spec, you
* can change this datatype. (Note that changing this datatype will
* potentially require modifying the SIMD code. The x86-64 SIMD extensions,
* in particular, assume a 32-bit JDIMENSION.)
*/
typedef unsigned int JDIMENSION;
#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */
/* These macros are used in all function definitions and extern declarations.
* You could modify them if you need to change function linkage conventions;
* in particular, you'll need to do that to make the library a Windows DLL.
* Another application is to make all functions global for use with debuggers
* or code profilers that require it.
*/
/* a function called through method pointers: */
#define METHODDEF(type) static type
/* a function used only in its module: */
#define LOCAL(type) static type
/* a function referenced thru EXTERNs: */
#define GLOBAL(type) type
/* a reference to a GLOBAL function: */
#define EXTERN(type) extern type
/* Originally, this macro was used as a way of defining function prototypes
* for both modern compilers as well as older compilers that did not support
* prototype parameters. libjpeg-turbo has never supported these older,
* non-ANSI compilers, but the macro is still included because there is some
* software out there that uses it.
*/
#define JMETHOD(type,methodname,arglist) type (*methodname) arglist
/* libjpeg-turbo no longer supports platforms that have far symbols (MS-DOS),
* but again, some software relies on this macro.
*/
#undef FAR
#define FAR
/*
* On a few systems, type boolean and/or its values FALSE, TRUE may appear
* in standard header files. Or you may have conflicts with application-
* specific header files that you want to include together with these files.
* Defining HAVE_BOOLEAN before including jpeglib.h should make it work.
*/
#ifndef HAVE_BOOLEAN
typedef int boolean;
#endif
#ifndef FALSE /* in case these macros already exist */
#define FALSE 0 /* values of boolean */
#endif
#ifndef TRUE
#define TRUE 1
#endif
/*
* The remaining options affect code selection within the JPEG library,
* but they don't need to be visible to most applications using the library.
* To minimize application namespace pollution, the symbols won't be
* defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined.
*/
#ifdef JPEG_INTERNALS
#define JPEG_INTERNAL_OPTIONS
#endif
#ifdef JPEG_INTERNAL_OPTIONS
/*
* These defines indicate whether to include various optional functions.
* Undefining some of these symbols will produce a smaller but less capable
* library. Note that you can leave certain source files out of the
* compilation/linking process if you've #undef'd the corresponding symbols.
* (You may HAVE to do that if your compiler doesn't like null source files.)
*/
/* Capability options common to encoder and decoder: */
#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */
#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */
#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */
/* Encoder capability options: */
#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */
/* Note: if you selected 12-bit data precision, it is dangerous to turn off
* ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit
* precision, so jchuff.c normally uses entropy optimization to compute
* usable tables for higher precision. If you don't want to do optimization,
* you'll have to supply different default Huffman tables.
* The exact same statements apply for progressive JPEG: the default tables
* don't work for progressive mode. (This may get fixed, however.)
*/
#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */
/* Decoder capability options: */
#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */
#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */
#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */
#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */
#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */
#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */
#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */
/* more capability options later, no doubt */
/*
* The RGB_RED, RGB_GREEN, RGB_BLUE, and RGB_PIXELSIZE macros are a vestigial
* feature of libjpeg. The idea was that, if an application developer needed
* to compress from/decompress to a BGR/BGRX/RGBX/XBGR/XRGB buffer, they could
* change these macros, rebuild libjpeg, and link their application statically
* with it. In reality, few people ever did this, because there were some
* severe restrictions involved (cjpeg and djpeg no longer worked properly,
* compressing/decompressing RGB JPEGs no longer worked properly, and the color
* quantizer wouldn't work with pixel sizes other than 3.) Further, since all
* of the O/S-supplied versions of libjpeg were built with the default values
* of RGB_RED, RGB_GREEN, RGB_BLUE, and RGB_PIXELSIZE, many applications have
* come to regard these values as immutable.
*
* The libjpeg-turbo colorspace extensions provide a much cleaner way of
* compressing from/decompressing to buffers with arbitrary component orders
* and pixel sizes. Thus, we do not support changing the values of RGB_RED,
* RGB_GREEN, RGB_BLUE, or RGB_PIXELSIZE. In addition to the restrictions
* listed above, changing these values will also break the SIMD extensions and
* the regression tests.
*/
#define RGB_RED 0 /* Offset of Red in an RGB scanline element */
#define RGB_GREEN 1 /* Offset of Green */
#define RGB_BLUE 2 /* Offset of Blue */
#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */
#define JPEG_NUMCS 17
#define EXT_RGB_RED 0
#define EXT_RGB_GREEN 1
#define EXT_RGB_BLUE 2
#define EXT_RGB_PIXELSIZE 3
#define EXT_RGBX_RED 0
#define EXT_RGBX_GREEN 1
#define EXT_RGBX_BLUE 2
#define EXT_RGBX_PIXELSIZE 4
#define EXT_BGR_RED 2
#define EXT_BGR_GREEN 1
#define EXT_BGR_BLUE 0
#define EXT_BGR_PIXELSIZE 3
#define EXT_BGRX_RED 2
#define EXT_BGRX_GREEN 1
#define EXT_BGRX_BLUE 0
#define EXT_BGRX_PIXELSIZE 4
#define EXT_XBGR_RED 3
#define EXT_XBGR_GREEN 2
#define EXT_XBGR_BLUE 1
#define EXT_XBGR_PIXELSIZE 4
#define EXT_XRGB_RED 1
#define EXT_XRGB_GREEN 2
#define EXT_XRGB_BLUE 3
#define EXT_XRGB_PIXELSIZE 4
static const int rgb_red[JPEG_NUMCS] = {
-1, -1, RGB_RED, -1, -1, -1, EXT_RGB_RED, EXT_RGBX_RED,
EXT_BGR_RED, EXT_BGRX_RED, EXT_XBGR_RED, EXT_XRGB_RED,
EXT_RGBX_RED, EXT_BGRX_RED, EXT_XBGR_RED, EXT_XRGB_RED,
-1
};
static const int rgb_green[JPEG_NUMCS] = {
-1, -1, RGB_GREEN, -1, -1, -1, EXT_RGB_GREEN, EXT_RGBX_GREEN,
EXT_BGR_GREEN, EXT_BGRX_GREEN, EXT_XBGR_GREEN, EXT_XRGB_GREEN,
EXT_RGBX_GREEN, EXT_BGRX_GREEN, EXT_XBGR_GREEN, EXT_XRGB_GREEN,
-1
};
static const int rgb_blue[JPEG_NUMCS] = {
-1, -1, RGB_BLUE, -1, -1, -1, EXT_RGB_BLUE, EXT_RGBX_BLUE,
EXT_BGR_BLUE, EXT_BGRX_BLUE, EXT_XBGR_BLUE, EXT_XRGB_BLUE,
EXT_RGBX_BLUE, EXT_BGRX_BLUE, EXT_XBGR_BLUE, EXT_XRGB_BLUE,
-1
};
static const int rgb_pixelsize[JPEG_NUMCS] = {
-1, -1, RGB_PIXELSIZE, -1, -1, -1, EXT_RGB_PIXELSIZE, EXT_RGBX_PIXELSIZE,
EXT_BGR_PIXELSIZE, EXT_BGRX_PIXELSIZE, EXT_XBGR_PIXELSIZE, EXT_XRGB_PIXELSIZE,
EXT_RGBX_PIXELSIZE, EXT_BGRX_PIXELSIZE, EXT_XBGR_PIXELSIZE, EXT_XRGB_PIXELSIZE,
-1
};
/* Definitions for speed-related optimizations. */
/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying
* two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER
* as short on such a machine. MULTIPLIER must be at least 16 bits wide.
*/
#ifndef MULTIPLIER
#ifndef WITH_SIMD
#define MULTIPLIER int /* type for fastest integer multiply */
#else
#define MULTIPLIER short /* prefer 16-bit with SIMD for parellelism */
#endif
#endif
/* FAST_FLOAT should be either float or double, whichever is done faster
* by your compiler. (Note that this type is only used in the floating point
* DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.)
*/
#ifndef FAST_FLOAT
#define FAST_FLOAT float
#endif
#endif /* JPEG_INTERNAL_OPTIONS */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -1,64 +0,0 @@
# Compiling the projects with libutils logging code?
DO_LOGGING := 1
# Links against the wut implementation of newlib, this is useful for using any function
# from the C standard library
WUT_ENABLE_NEWLIB := 0
# Links against the wut implementation of stdcpp, this is useful for using any function
# from the C++ standard library. This will enable WUT_ENABLE_NEWLIB if you have not already done so.
WUT_ENABLE_CPP := 0
# By default newlib will allocate 90% of the default heap for use with sbrk & malloc,
# if this is unacceptable to you then you should use this as it replaces the newlib
# malloc functions which ones which redirect to the CafeOS default heap functions
# such as MEMAllocFromDefaultHeap.
WUT_DEFAULT_MALLOC := 1
# Target filename
TARGET := screenshot.mod
# Source directories
SOURCES := src/
# Data directories
DATA :=
# Include directories
INCLUDES := src
#---------------------------------------------------------------------------------
# options for code generation and linking
#---------------------------------------------------------------------------------
# Extra C AND C++ compiler flags
COMMON_CFLAGS :=
# Extra C compiler flags
CFLAGS :=
# Extra C++ compiler flags
CXXFLAGS :=
# Extra linking flags for all linking steps
LDFLAGS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(WUPSDIR) $(WUT_ROOT) $(CURDIR)/libs
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lwups -lutilswut -lcoreinit -lturbojpeg -lgx2 -lvpad -lnsysnet
#---------------------------------------------------------------------------------
# Will be added to the final lib paths
# example:
# -L$C:/library1/lib
#---------------------------------------------------------------------------------
EXTERNAL_LIBPATHS :=
#---------------------------------------------------------------------------------
# Will be added to the final include paths
# -IC:/library1/include
#---------------------------------------------------------------------------------
EXTERNAL_INCLUDE := -I$(WUT_ROOT)/include/libutilswut

View File

@ -1,17 +0,0 @@
#include "JpegInformation.h"
#include <malloc.h>
JpegInformation::JpegInformation(tjhandle handle, uint8_t* jpegBuf, uint64_t jpegSize)
{
this->buffer = jpegBuf;
this->size = jpegSize;
this->handle = handle;
}
JpegInformation::~JpegInformation()
{
if(this->buffer) {
free(this->buffer);
}
tjDestroy(this->handle);
}

View File

@ -1,26 +0,0 @@
#ifndef JPEGINFORMATION_H
#define JPEGINFORMATION_H
#include <stdint.h>
#include <turbojpeg.h>
class JpegInformation {
public:
JpegInformation(tjhandle handle, uint8_t* jpegBuf, uint64_t jpegSize);
virtual ~JpegInformation();
uint8_t * getBuffer() {
return buffer;
};
uint64_t getSize() {
return size;
};
private:
uint8_t* buffer;
uint64_t size;
tjhandle handle;
};
#endif // JPEGINFORMATION_H

View File

@ -1,6 +1,15 @@
#ifndef COMMON_H_ #pragma once
#define COMMON_H_
#define WIIU_SCREENSHOT_PATH "sd:/wiiu/screenshots/" #define WIIU_SCREENSHOT_PATH "fs:/vol/external01/wiiu/screenshots/"
#endif // COMMON_H_ typedef enum {
IMAGE_OUTPUT_FORMAT_JPEG = 0,
IMAGE_OUTPUT_FORMAT_PNG = 1,
IMAGE_OUTPUT_FORMAT_BMP = 2,
} ImageOutputFormatEnum;
typedef enum {
IMAGE_SOURCE_TV_AND_DRC = 0,
IMAGE_SOURCE_TV = 1,
IMAGE_SOURCE_DRC = 2,
} ImageSourceEnum;

76
src/fs/FSUtils.cpp Normal file
View File

@ -0,0 +1,76 @@
#include "fs/FSUtils.h"
#include <cstdio>
#include <cstring>
#include <fcntl.h>
int32_t FSUtils::CheckFile(const char *filepath) {
if (!filepath)
return 0;
struct stat filestat;
char dirnoslash[strlen(filepath) + 2];
snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath);
while (dirnoslash[strlen(dirnoslash) - 1] == '/')
dirnoslash[strlen(dirnoslash) - 1] = '\0';
char *notRoot = strrchr(dirnoslash, '/');
if (!notRoot) {
strcat(dirnoslash, "/");
}
if (stat(dirnoslash, &filestat) == 0)
return 1;
return 0;
}
int32_t FSUtils::CreateSubfolder(const char *fullpath) {
if (!fullpath) {
return 0;
}
int32_t result = 0;
char dirnoslash[strlen(fullpath) + 1];
strcpy(dirnoslash, fullpath);
int32_t pos = strlen(dirnoslash) - 1;
while (dirnoslash[pos] == '/') {
dirnoslash[pos] = '\0';
pos--;
}
if (CheckFile(dirnoslash)) {
return 1;
} else {
char parentpath[strlen(dirnoslash) + 2];
strcpy(parentpath, dirnoslash);
char *ptr = strrchr(parentpath, '/');
if (!ptr) {
//! Device root directory (must be with '/')
strcat(parentpath, "/");
struct stat filestat;
if (stat(parentpath, &filestat) == 0)
return 1;
return 0;
}
ptr++;
ptr[0] = '\0';
result = CreateSubfolder(parentpath);
}
if (!result)
return 0;
if (mkdir(dirnoslash, 0777) == -1) {
return 0;
}
return 1;
}

11
src/fs/FSUtils.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include <wut_types.h>
class FSUtils {
public:
//! todo: C++ class
static int32_t CreateSubfolder(const char *fullpath);
static int32_t CheckFile(const char *filepath);
};

View File

@ -1,61 +1,99 @@
#include <wups.h>
#include <utils/logger.h>
#include <vpad/input.h>
#include <gx2/surface.h>
#include <coreinit/time.h>
#include <utils/StringTools.h>
#include <fs/FSUtils.h>
#include "common.h" #include "common.h"
#include "screenshot_utils.h" #include "fs/FSUtils.h"
#include "retain_vars.hpp" #include "retain_vars.hpp"
#include "screenshot_utils.h"
#include "utils/StringTools.h"
#include "utils/logger.h"
#include <coreinit/time.h>
#include <coreinit/title.h>
#include <gx2/surface.h>
#include <vpad/input.h>
#include <wups.h>
static bool takeScreenshotTV __attribute__((section(".data"))) = false; static bool takeScreenshotTV = false;
static bool takeScreenshotDRC __attribute__((section(".data"))) = false; static bool takeScreenshotDRC = false;
static uint8_t screenshotCooldown __attribute__((section(".data"))) = 0; static uint8_t screenshotCoolDown = 0;
static uint32_t counter __attribute__((section(".data"))) = 0;
DECL_FUNCTION(int32_t, VPADRead, VPADChan chan, VPADStatus *buffer, uint32_t buffer_size, VPADReadError *error) { DECL_FUNCTION(int32_t, VPADRead, VPADChan chan, VPADStatus *buffer, uint32_t buffer_size, VPADReadError *error) {
int32_t result = real_VPADRead(chan, buffer, buffer_size, error); VPADReadError real_error;
int32_t result = real_VPADRead(chan, buffer, buffer_size, &real_error);
if(result > 0 && *error == VPAD_READ_SUCCESS && (buffer[0].hold == gButtonCombo) && screenshotCooldown == 0 && OSIsHomeButtonMenuEnabled()) { if (gEnabled) {
counter++; if (result > 0 && real_error == VPAD_READ_SUCCESS && (buffer[0].hold == gButtonCombo) && screenshotCoolDown == 0 && OSIsHomeButtonMenuEnabled()) {
takeScreenshotTV = true; takeScreenshotTV = gImageSource == IMAGE_SOURCE_TV_AND_DRC || gImageSource == IMAGE_SOURCE_TV;
takeScreenshotDRC = true; takeScreenshotDRC = gImageSource == IMAGE_SOURCE_TV_AND_DRC || gImageSource == IMAGE_SOURCE_DRC;
screenshotCooldown = 0x3C; screenshotCoolDown = 60;
}
if (screenshotCoolDown > 0) {
screenshotCoolDown--;
} }
if(screenshotCooldown > 0) {
screenshotCooldown--;
} }
if (error) {
*error = real_error;
}
return result; return result;
} }
DECL_FUNCTION(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, int32_t scan_target) { DECL_FUNCTION(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, GX2ScanTarget scan_target) {
if((takeScreenshotTV || takeScreenshotDRC) && gAppStatus == WUPS_APP_STATUS_FOREGROUND) { if ((takeScreenshotTV || takeScreenshotDRC)) {
OSCalendarTime output; OSCalendarTime output;
OSTicksToCalendarTime(OSGetTime(), &output); OSTicksToCalendarTime(OSGetTime(), &output);
char buffer[255] = {0}; std::string buffer = string_format("%s%016llX", WIIU_SCREENSHOT_PATH, OSGetTitleID());
snprintf(buffer,254,"%s%04ld-%02ld-%02ld/",WIIU_SCREENSHOT_PATH,output.tm_year,output.tm_mon,output.tm_mday); if (!gShortNameEn.empty()) {
buffer += string_format(" (%s)", gShortNameEn.c_str());
FSUtils::CreateSubfolder(buffer);
snprintf(buffer,254,"%s%04ld-%02ld-%02ld/%04ld-%02ld-%02ld_%02ld.%02ld.%02ld_",
WIIU_SCREENSHOT_PATH,output.tm_year,output.tm_mon,output.tm_mday,output.tm_year,output.tm_mon,output.tm_mday,output.tm_hour,output.tm_min,output.tm_sec);
if(scan_target == 1 && colorBuffer != NULL && takeScreenshotTV && gAppStatus == WUPS_APP_STATUS_FOREGROUND) {
DEBUG_FUNCTION_LINE("Lets take a screenshot from TV. Source format: %d \n",colorBuffer->surface.format);
takeScreenshot((GX2ColorBuffer *)colorBuffer, StringTools::strfmt("%sTV.jpg",buffer).c_str());
takeScreenshotTV = false;
} }
if(scan_target == 4 && colorBuffer != NULL && takeScreenshotDRC && gAppStatus == WUPS_APP_STATUS_FOREGROUND) { buffer += string_format("/%04d-%02d-%02d/", output.tm_year, output.tm_mon + 1, output.tm_mday);
DEBUG_FUNCTION_LINE("Lets take a screenshot from DRC. Source format: %d \n",colorBuffer->surface.format);
takeScreenshot((GX2ColorBuffer *)colorBuffer, StringTools::strfmt("%sDRC.jpg",buffer).c_str()); bool dirExists = true;
auto dir = opendir(buffer.c_str());
if (dir) {
closedir(dir);
} else {
if (!FSUtils::CreateSubfolder(buffer.c_str())) {
DEBUG_FUNCTION_LINE_ERR("Failed to create dir: %s", buffer.c_str());
dirExists = false;
}
}
if (dirExists) {
buffer = string_format("%s%04d-%02d-%02d_%02d.%02d.%02d_",
buffer.c_str(), output.tm_year, output.tm_mon + 1,
output.tm_mday, output.tm_hour, output.tm_min, output.tm_sec);
if (scan_target == GX2_SCAN_TARGET_TV && colorBuffer != nullptr && takeScreenshotTV) {
DEBUG_FUNCTION_LINE("Lets take a screenshot from TV.");
takeScreenshot((GX2ColorBuffer *) colorBuffer, buffer, scan_target, gTVSurfaceFormat, gOutputFormat, gQuality);
takeScreenshotTV = false;
} else if (scan_target == GX2_SCAN_TARGET_DRC0 && colorBuffer != nullptr && takeScreenshotDRC) {
DEBUG_FUNCTION_LINE("Lets take a screenshot from DRC.");
takeScreenshot((GX2ColorBuffer *) colorBuffer, buffer, scan_target, gDRCSurfaceFormat, gOutputFormat, gQuality);
takeScreenshotDRC = false;
}
} else {
takeScreenshotTV = false;
takeScreenshotDRC = false; takeScreenshotDRC = false;
} }
} }
real_GX2CopyColorBufferToScanBuffer(colorBuffer,scan_target); real_GX2CopyColorBufferToScanBuffer(colorBuffer, scan_target);
}
DECL_FUNCTION(void, GX2SetTVBuffer, void *buffer, uint32_t buffer_size, int32_t tv_render_mode, GX2SurfaceFormat surface_format, GX2BufferingMode buffering_mode) {
DEBUG_FUNCTION_LINE_VERBOSE("Set TV Buffer format to 0x%08X", surface_format);
gTVSurfaceFormat = surface_format;
return real_GX2SetTVBuffer(buffer, buffer_size, tv_render_mode, surface_format, buffering_mode);
}
DECL_FUNCTION(void, GX2SetDRCBuffer, void *buffer, uint32_t buffer_size, uint32_t drc_mode, GX2SurfaceFormat surface_format, GX2BufferingMode buffering_mode) {
DEBUG_FUNCTION_LINE_VERBOSE("Set DRC Buffer format to 0x%08X", surface_format);
gDRCSurfaceFormat = surface_format;
return real_GX2SetDRCBuffer(buffer, buffer_size, drc_mode, surface_format, buffering_mode);
} }
WUPS_MUST_REPLACE(VPADRead, WUPS_LOADER_LIBRARY_VPAD, VPADRead); WUPS_MUST_REPLACE(VPADRead, WUPS_LOADER_LIBRARY_VPAD, VPADRead);
WUPS_MUST_REPLACE(GX2CopyColorBufferToScanBuffer, WUPS_LOADER_LIBRARY_GX2, GX2CopyColorBufferToScanBuffer); WUPS_MUST_REPLACE(GX2CopyColorBufferToScanBuffer, WUPS_LOADER_LIBRARY_GX2, GX2CopyColorBufferToScanBuffer);
WUPS_MUST_REPLACE(GX2SetTVBuffer, WUPS_LOADER_LIBRARY_GX2, GX2SetTVBuffer);
WUPS_MUST_REPLACE(GX2SetDRCBuffer, WUPS_LOADER_LIBRARY_GX2, GX2SetDRCBuffer);

View File

@ -1,155 +1,254 @@
#include <wups.h> #include "main.h"
#include <malloc.h>
#include <vector>
#include <string>
#include <string.h>
#include <dirent.h>
#include <coreinit/cache.h>
#include <coreinit/thread.h>
#include <coreinit/time.h>
#include <coreinit/screen.h>
#include <vpad/input.h>
#include <nsysnet/socket.h>
#include <utils/logger.h>
#include "retain_vars.hpp" #include "retain_vars.hpp"
#include "utils/logger.h"
#include <coreinit/cache.h>
#include <coreinit/title.h>
#include <malloc.h>
#include <nn/acp.h>
#include <string>
#include <vpad/input.h>
#include <wups.h>
#include <wups/config/WUPSConfigItemBoolean.h>
#include <wups/config/WUPSConfigItemIntegerRange.h>
#include <wups/config/WUPSConfigItemMultipleValues.h>
// Mandatory plugin information. // Mandatory plugin information.
WUPS_PLUGIN_NAME("Screenshot tool"); WUPS_PLUGIN_NAME("Screenshot plugin");
WUPS_PLUGIN_DESCRIPTION("This plugin allows you to make screenshots that will be saved to the sd card"); WUPS_PLUGIN_DESCRIPTION("This plugin allows you to make screenshots that will be saved to the sd card");
WUPS_PLUGIN_VERSION("v0.1"); WUPS_PLUGIN_VERSION(VERSION_FULL);
WUPS_PLUGIN_AUTHOR("Maschell"); WUPS_PLUGIN_AUTHOR("Maschell");
WUPS_PLUGIN_LICENSE("GPL"); WUPS_PLUGIN_LICENSE("GPL");
// FS Access // FS Access
WUPS_FS_ACCESS() WUPS_USE_WUT_DEVOPTAB();
uint32_t SplashScreen(int32_t time,int32_t combotime); WUPS_USE_STORAGE("screenshot_plugin");
#define ENABLED_CONFIG_STRING "enabled"
#define FORMAT_CONFIG_STRING "format"
#define QUALITY_CONFIG_STRING "quality"
#define SCREEN_CONFIG_STRING "screen"
// Gets called once the loader exists. // Gets called once the loader exists.
INITIALIZE_PLUGIN() { INITIALIZE_PLUGIN() {
socket_lib_init(); initLogging();
gButtonCombo = VPAD_BUTTON_R | VPAD_BUTTON_L | VPAD_BUTTON_ZR | VPAD_BUTTON_ZL;
OSMemoryBarrier();
log_init(); // Open storage to read values
WUPSStorageError storageRes = WUPS_OpenStorage();
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to open storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
} else {
// Try to get value from storage
if ((storageRes = WUPS_GetInt(nullptr, ENABLED_CONFIG_STRING, reinterpret_cast<int32_t *>(&gEnabled))) == WUPS_STORAGE_ERROR_NOT_FOUND) {
// Add the value to the storage if it's missing.
if (WUPS_StoreBool(nullptr, ENABLED_CONFIG_STRING, gEnabled) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to store value");
}
} else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to get value %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
}
// Try to get value from storage
if ((storageRes = WUPS_GetInt(nullptr, FORMAT_CONFIG_STRING, reinterpret_cast<int32_t *>(&gOutputFormat))) == WUPS_STORAGE_ERROR_NOT_FOUND) {
// Add the value to the storage if it's missing.
if (WUPS_StoreBool(nullptr, FORMAT_CONFIG_STRING, gOutputFormat) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to store value");
}
} else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to get value %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
}
uint32_t res = SplashScreen(10,2); // Try to get value from storage
if ((storageRes = WUPS_GetInt(nullptr, QUALITY_CONFIG_STRING, reinterpret_cast<int32_t *>(&gQuality))) == WUPS_STORAGE_ERROR_NOT_FOUND) {
// Add the value to the storage if it's missing.
if (WUPS_StoreInt(nullptr, QUALITY_CONFIG_STRING, (int32_t) gQuality) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to store value");
}
} else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to get value %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
}
gButtonCombo = res; // Try to get value from storage
ICInvalidateRange((void*)(&gButtonCombo), 4); if ((storageRes = WUPS_GetInt(nullptr, SCREEN_CONFIG_STRING, reinterpret_cast<int32_t *>(&gImageSource))) == WUPS_STORAGE_ERROR_NOT_FOUND) {
DCFlushRange((void*)(&gButtonCombo), 4); // Add the value to the storage if it's missing.
if (WUPS_StoreInt(nullptr, SCREEN_CONFIG_STRING, (int32_t) gImageSource) != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to store value");
}
} else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to get value %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
}
// Close storage
if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to close storage");
}
}
if (gOutputFormat >= 3) {
gOutputFormat = IMAGE_OUTPUT_FORMAT_JPEG;
}
if (gQuality < 10) {
gQuality = 10;
} else if (gQuality > 100) {
gQuality = 100;
}
}
void formatChanged(ConfigItemMultipleValues *item, uint32_t newValue) {
DEBUG_FUNCTION_LINE("New value in %s changed: %d", item->configID, newValue);
gOutputFormat = (ImageOutputFormatEnum) newValue;
if (gOutputFormat >= 3) {
gOutputFormat = IMAGE_OUTPUT_FORMAT_JPEG;
}
WUPS_StoreInt(nullptr, item->configID, (int32_t) newValue);
}
void imageSourceChanged(ConfigItemMultipleValues *item, uint32_t newValue) {
DEBUG_FUNCTION_LINE("New value in %s changed: %d", item->configID, newValue);
gImageSource = (ImageSourceEnum) newValue;
if (gImageSource >= 3) {
gImageSource = IMAGE_SOURCE_TV_AND_DRC;
}
WUPS_StoreInt(nullptr, item->configID, (int32_t) newValue);
}
void qualityChanged(ConfigItemIntegerRange *item, int32_t newValue) {
DEBUG_FUNCTION_LINE("New quality: %d", newValue);
gQuality = (ImageOutputFormatEnum) newValue;
if (gQuality < 10) {
gQuality = 10;
} else if (gQuality > 100) {
gQuality = 100;
}
WUPS_StoreInt(nullptr, QUALITY_CONFIG_STRING, (int32_t) gQuality);
}
void enabledChanged(ConfigItemBoolean *item, bool newValue) {
DEBUG_FUNCTION_LINE("gEnabled new value: %d", newValue);
gEnabled = (ImageOutputFormatEnum) newValue;
WUPS_StoreBool(nullptr, ENABLED_CONFIG_STRING, gEnabled);
}
WUPS_GET_CONFIG() {
// We open the storage, so we can persist the configuration the user did.
if (WUPS_OpenStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to open storage");
return 0;
}
WUPSConfigHandle config;
WUPSConfig_CreateHandled(&config, "Screenshot plugin");
WUPSConfigCategoryHandle setting;
WUPSConfig_AddCategoryByNameHandled(config, "Settings", &setting);
WUPSConfigItemBoolean_AddToCategoryHandled(config, setting, ENABLED_CONFIG_STRING, "Enabled", gEnabled, &enabledChanged);
ConfigItemMultipleValuesPair fileFormat[3];
fileFormat[0].value = IMAGE_OUTPUT_FORMAT_JPEG;
fileFormat[0].valueName = (char *) "JPEG";
fileFormat[1].value = IMAGE_OUTPUT_FORMAT_PNG;
fileFormat[1].valueName = (char *) "PNG";
fileFormat[2].value = IMAGE_OUTPUT_FORMAT_BMP;
fileFormat[2].valueName = (char *) "BMP";
uint32_t defaultIndex = 0;
uint32_t curIndex = 0;
for (auto &cur : fileFormat) {
if (cur.value == gOutputFormat) {
defaultIndex = curIndex;
break;
}
curIndex++;
}
WUPSConfigItemMultipleValues_AddToCategoryHandled(config, setting, FORMAT_CONFIG_STRING, "Output format", defaultIndex, fileFormat,
sizeof(fileFormat) / sizeof(fileFormat[0]), &formatChanged);
ConfigItemMultipleValuesPair source[3];
source[0].value = IMAGE_SOURCE_TV_AND_DRC;
source[0].valueName = (char *) "TV & Gamepad";
source[1].value = IMAGE_SOURCE_TV;
source[1].valueName = (char *) "TV only";
source[2].value = IMAGE_SOURCE_DRC;
source[2].valueName = (char *) "Gamepad only";
defaultIndex = 0;
curIndex = 0;
for (auto &cur : source) {
if (cur.value == gImageSource) {
defaultIndex = curIndex;
break;
}
curIndex++;
}
WUPSConfigItemMultipleValues_AddToCategoryHandled(config, setting, SCREEN_CONFIG_STRING, "Screen", defaultIndex, source,
sizeof(source) / sizeof(source[0]), &imageSourceChanged);
WUPSConfigItemIntegerRange_AddToCategoryHandled(config, setting, QUALITY_CONFIG_STRING, "JPEG quality", gQuality, 10, 100, &qualityChanged);
return config;
}
WUPS_CONFIG_CLOSED() {
// Save all changes
if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to close storage");
}
} }
// Called whenever an application was started. // Called whenever an application was started.
ON_APPLICATION_START(my_args) { ON_APPLICATION_START() {
socket_lib_init(); initLogging();
log_init(); ACPInitialize();
auto *metaXml = (ACPMetaXml *) memalign(0x40, sizeof(ACPMetaXml));
gAppStatus = WUPS_APP_STATUS_FOREGROUND; if (ACPGetTitleMetaXml(OSGetTitleID(), metaXml) == ACP_RESULT_SUCCESS) {
gShortNameEn = metaXml->shortname_en;
log_init(); std::string illegalChars = "\\/:?\"<>|@=;`_^][";
} for (auto it = gShortNameEn.begin(); it < gShortNameEn.end(); ++it) {
if (*it < '0' || *it > 'z') {
ON_APP_STATUS_CHANGED(status) { *it = ' ';
gAppStatus = status;
}
#define FPS 60
uint32_t SplashScreen(int32_t time,int32_t combotime) {
uint32_t result = VPAD_BUTTON_R | VPAD_BUTTON_L | VPAD_BUTTON_ZR | VPAD_BUTTON_ZL;
// Init screen
OSScreenInit();
uint32_t screen_buf0_size = OSScreenGetBufferSizeEx(SCREEN_TV);
uint32_t screen_buf1_size = OSScreenGetBufferSizeEx(SCREEN_DRC);
uint32_t * screenbuffer0 = (uint32_t*)memalign(0x100, screen_buf0_size);
uint32_t * screenbuffer1 = (uint32_t*)memalign(0x100, screen_buf1_size);
if(screenbuffer0 == NULL || screenbuffer1 == NULL) {
if(screenbuffer0 != NULL) {
free(screenbuffer0);
} }
if(screenbuffer1 != NULL) {
free(screenbuffer1);
} }
return result; for (auto it = gShortNameEn.begin(); it < gShortNameEn.end(); ++it) {
bool found = illegalChars.find(*it) != std::string::npos;
if (found) {
*it = ' ';
} }
OSScreenSetBufferEx(SCREEN_TV, (void *)screenbuffer0);
OSScreenSetBufferEx(SCREEN_DRC, (void *)screenbuffer1);
OSScreenEnableEx(SCREEN_TV, 1);
OSScreenEnableEx(SCREEN_DRC, 1);
// Clear screens
OSScreenClearBufferEx(SCREEN_TV, 0);
OSScreenClearBufferEx(SCREEN_DRC, 0);
// Flip buffers
OSScreenFlipBuffersEx(SCREEN_TV);
OSScreenFlipBuffersEx(SCREEN_DRC);
OSScreenClearBufferEx(SCREEN_TV, 0);
OSScreenClearBufferEx(SCREEN_DRC, 0);
std::vector<std::string> strings;
strings.push_back("Screenshot tool 0.1 - by Maschell.");
strings.push_back("");
strings.push_back("");
strings.push_back("Press the combo you want to use for making screenshots now");
strings.push_back("for 2 seconds.");
strings.push_back(" ");
strings.push_back("Otherwise the default combo (L+R+ZR+ZL button) will be used");
strings.push_back("in 10 seconds.");
strings.push_back(" ");
strings.push_back("Press the TV buttons to exit with the default combo.");
uint8_t pos = 0;
for (std::vector<std::string>::iterator it = strings.begin() ; it != strings.end(); ++it) {
OSScreenPutFontEx(SCREEN_TV, 0, pos, (*it).c_str());
OSScreenPutFontEx(SCREEN_DRC, 0, pos, (*it).c_str());
pos++;
} }
uint32_t length = gShortNameEn.length();
OSScreenFlipBuffersEx(SCREEN_TV); for (uint32_t i = 1; i < length; ++i) {
OSScreenFlipBuffersEx(SCREEN_DRC); if (gShortNameEn[i - 1] == ' ' && gShortNameEn[i] == ' ') {
gShortNameEn.erase(i, 1);
int32_t tickswait = time * FPS * 16; i--;
length--;
int32_t sleepingtime = 16;
int32_t times = tickswait/16;
int32_t i=0;
VPADStatus vpad_data;
VPADReadError error;
uint32_t last = 0xFFFFFFFF;
int32_t timer = 0;
while(i<times) {
VPADRead(VPAD_CHAN_0, &vpad_data, 1, &error);
if(vpad_data.trigger == VPAD_BUTTON_TV) {
break;
} }
if(last == vpad_data.hold && last != 0) { }
timer++; if (gShortNameEn.size() == 1 && gShortNameEn[0] == ' ') {
gShortNameEn.clear();
} else { } else {
last = vpad_data.hold; DEBUG_FUNCTION_LINE("Detected name as \"%s\"", gShortNameEn.c_str());
timer = 0;
} }
if(timer >= combotime*FPS) { } else {
result = vpad_data.hold; gShortNameEn.clear();
break;
} }
i++; }
OSSleepTicks(OSMicrosecondsToTicks(sleepingtime*1000));
} ON_APPLICATION_REQUESTS_EXIT() {
deinitLogging();
if(screenbuffer0 != NULL) {
free(screenbuffer0);
}
if(screenbuffer1 != NULL) {
free(screenbuffer1);
}
return result;
} }

5
src/main.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include "version.h"
#define VERSION "v0.1"
#define VERSION_FULL VERSION VERSION_EXTRA

View File

@ -1,3 +1,10 @@
#include "retain_vars.hpp" #include "retain_vars.hpp"
wups_loader_app_status_t gAppStatus __attribute__((section(".data"))) = WUPS_APP_STATUS_UNKNOWN; #include <string>
uint32_t gButtonCombo __attribute__((section(".data"))) = 0; GX2SurfaceFormat gTVSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8;
GX2SurfaceFormat gDRCSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8;
ImageSourceEnum gImageSource = IMAGE_SOURCE_TV_AND_DRC;
bool gEnabled = true;
uint32_t gButtonCombo = 0;
int32_t gQuality = 90;
ImageOutputFormatEnum gOutputFormat = IMAGE_OUTPUT_FORMAT_JPEG;
std::string gShortNameEn;

View File

@ -1,9 +1,14 @@
#ifndef _RETAINS_VARS_H_ #pragma once
#define _RETAINS_VARS_H_ #include "common.h"
#include <gx2/surface.h>
#include <string>
#include <wups.h> #include <wups.h>
extern wups_loader_app_status_t gAppStatus; extern bool gEnabled;
extern ImageSourceEnum gImageSource;
extern GX2SurfaceFormat gTVSurfaceFormat;
extern GX2SurfaceFormat gDRCSurfaceFormat;
extern uint32_t gButtonCombo; extern uint32_t gButtonCombo;
extern int32_t gQuality;
#endif // _RETAINS_VARS_H_ extern ImageOutputFormatEnum gOutputFormat;
extern std::string gShortNameEn;

View File

@ -1,75 +1,111 @@
#include "screenshot_utils.h" #include "screenshot_utils.h"
#include "common.h"
#include <fs/FSUtils.h> #include "utils/utils.h"
#include <malloc.h> #include <gd.h>
#include <coreinit/cache.h>
#include <gx2/event.h> #include <gx2/event.h>
#include <gx2/surface.h>
#include <gx2/mem.h> #include <gx2/mem.h>
#include <memory/mappedmemory.h>
#include <valarray>
uint8_t RGBComponentToSRGB[] = {0x00, 0x0C, 0x15, 0x1C, 0x21, 0x26, 0x2A, 0x2E, 0x31, 0x34, 0x37, 0x3A, 0x3D, 0x3F, 0x42, 0x44,
0x46, 0x49, 0x4B, 0x4D, 0x4F, 0x51, 0x52, 0x54, 0x56, 0x58, 0x59, 0x5B, 0x5D, 0x5E, 0x60, 0x61,
0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76,
0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA1, 0xA2, 0xA3, 0xA4,
0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA8, 0xA9, 0xAA, 0xAB, 0xAB, 0xAC, 0xAD, 0xAE, 0xAE, 0xAF, 0xB0,
0xB0, 0xB1, 0xB2, 0xB3, 0xB3, 0xB4, 0xB5, 0xB5, 0xB6, 0xB7, 0xB7, 0xB8, 0xB9, 0xB9, 0xBA, 0xBB,
0xBB, 0xBC, 0xBD, 0xBD, 0xBE, 0xBF, 0xBF, 0xC0, 0xC1, 0xC1, 0xC2, 0xC2, 0xC3, 0xC4, 0xC4, 0xC5,
0xC5, 0xC6, 0xC7, 0xC7, 0xC8, 0xC9, 0xC9, 0xCA, 0xCA, 0xCB, 0xCC, 0xCC, 0xCD, 0xCD, 0xCE, 0xCE,
0xCF, 0xD0, 0xD0, 0xD1, 0xD1, 0xD2, 0xD2, 0xD3, 0xD4, 0xD4, 0xD5, 0xD5, 0xD6, 0xD6, 0xD7, 0xD7,
0xD8, 0xD9, 0xD9, 0xDA, 0xDA, 0xDB, 0xDB, 0xDC, 0xDC, 0xDD, 0xDD, 0xDE, 0xDE, 0xDF, 0xDF, 0xE0,
0xE1, 0xE1, 0xE2, 0xE2, 0xE3, 0xE3, 0xE4, 0xE4, 0xE5, 0xE5, 0xE6, 0xE6, 0xE7, 0xE7, 0xE8, 0xE8,
0xE9, 0xE9, 0xEA, 0xEA, 0xEB, 0xEB, 0xEC, 0xEC, 0xED, 0xED, 0xED, 0xEE, 0xEE, 0xEF, 0xEF, 0xF0,
0xF0, 0xF1, 0xF1, 0xF2, 0xF2, 0xF3, 0xF3, 0xF4, 0xF4, 0xF5, 0xF5, 0xF5, 0xF6, 0xF6, 0xF7, 0xF7,
0xF8, 0xF8, 0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE};
#ifdef __cplusplus bool saveTextureAsPicture(const std::string &path, uint8_t *sourceBuffer, uint32_t width, uint32_t height, uint32_t pitch, GX2SurfaceFormat format, ImageOutputFormatEnum outputFormat, bool convertRGBtoSRGB, int quality) {
extern "C" { if (sourceBuffer == nullptr) {
#endif DEBUG_FUNCTION_LINE_ERR("sourceBuffer is nullptr");
return false;
void
GX2ResolveAAColorBuffer(const GX2ColorBuffer * srcColorBuffer,
GX2Surface * dstSurface,
uint32_t dstMip,
uint32_t dstSlice);
#ifdef __cplusplus
}
#endif
JpegInformation * convertToJpeg(uint8_t * sourceBuffer, uint32_t width, uint32_t height, uint32_t pitch, uint32_t format, int32_t quality) {
if(sourceBuffer == NULL) {
DEBUG_FUNCTION_LINE("path or buffer NULL\n");
return NULL;
} }
if(( format != GX2_SURFACE_FORMAT_SRGB_R8_G8_B8_A8 && if (format != GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8) {
format != GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8)) { DEBUG_FUNCTION_LINE_ERR("Surface format 0x%08X not supported", format);
DEBUG_FUNCTION_LINE("Format not supported\n"); return false;
return NULL;
} }
tjhandle handle = tjInitCompress(); if (quality < 10) {
quality = 10;
if(handle == NULL) { } else if (quality > 100) {
const char *err = (const char *) tjGetErrorStr(); quality = 100;
DEBUG_FUNCTION_LINE("TJ Error: %s UNABLE TO INIT TJ Compressor Object\n",err);
return NULL;
} }
int32_t jpegQual = quality; auto res = false;
int32_t nbands = 4;
int32_t flags = 0;
unsigned char* jpegBuf = NULL;
int32_t pixelFormat = TJPF_GRAY; gdImagePtr im = gdImageCreateTrueColor((int) width, (int) height);
int32_t jpegSubsamp = TJSAMP_GRAY; if (!im) {
if(nbands == 4) { DEBUG_FUNCTION_LINE_ERR("Failed to create gdImage with dimension: %d x %d", width, height);
pixelFormat = TJPF_RGBA; return false;
jpegSubsamp = TJSAMP_411;
}
unsigned long jpegSize = 0;
int32_t tj_stat = tjCompress2( handle, sourceBuffer, width, pitch * nbands, height, pixelFormat, &(jpegBuf), &jpegSize, jpegSubsamp, jpegQual, flags);
if(tj_stat != 0) {
const char *err = (const char *) tjGetErrorStr();
DEBUG_FUNCTION_LINE("TurboJPEG Error: %s UNABLE TO COMPRESS JPEG IMAGE\n", err);
tjDestroy(handle);
} else {
DEBUG_FUNCTION_LINE("Success! %08X %08X\n",jpegBuf, jpegSize);
return new JpegInformation(handle, jpegBuf, jpegSize);
} }
return NULL; gdImageFill(im, 0, 0, gdImageColorAllocate(im, 255, 255, 255));
auto *buffer = (uint32_t *) sourceBuffer;
for (uint32_t y = 0; y < height; ++y) {
for (uint32_t x = 0; x < width; ++x) {
uint32_t pixel = buffer[(y * pitch) + x];
uint8_t r = (pixel >> 24) & 0xFF;
uint8_t g = (pixel >> 16) & 0xFF;
uint8_t b = (pixel >> 8) & 0xFF;
if (convertRGBtoSRGB) {
r = RGBComponentToSRGB[r];
g = RGBComponentToSRGB[g];
b = RGBComponentToSRGB[b];
}
auto color = gdImageColorAllocate(im, r, g, b);
gdImageSetPixel(im, (int) x, (int) y, color);
}
}
FILE *file = fopen(path.c_str(), "wb");
if (file) {
setvbuf(file, nullptr, _IOFBF, 512 * 1024);
res = true;
DEBUG_FUNCTION_LINE("Saving screenshot as %s", path.c_str());
switch (outputFormat) {
case IMAGE_OUTPUT_FORMAT_JPEG: {
gdImageJpeg(im, file, (int32_t) quality);
break;
}
case IMAGE_OUTPUT_FORMAT_PNG: {
gdImagePngEx(im, file, -1);
break;
}
case IMAGE_OUTPUT_FORMAT_BMP:
gdImageBmp(im, file, -1);
break;
default:
DEBUG_FUNCTION_LINE_ERR("Invalid output format");
res = false;
break;
}
// Close file
fclose(file);
}
gdImageDestroy(im);
return res;
} }
bool copyBuffer(GX2ColorBuffer * sourceBuffer, GX2ColorBuffer * targetBuffer, uint32_t targetWidth, uint32_t targetHeight) { static bool copyBuffer(GX2ColorBuffer *sourceBuffer, GX2ColorBuffer *targetBuffer, uint32_t targetWidth, uint32_t targetHeight) {
// Making sure the buffers are not NULL // Making sure the buffers are not nullptr
if (sourceBuffer != NULL && targetBuffer != NULL) { if (sourceBuffer != nullptr && targetBuffer != nullptr) {
uint32_t depth = 1; uint32_t depth = 1;
targetBuffer->surface.use = (GX2SurfaceUse) (GX2_SURFACE_USE_COLOR_BUFFER | GX2_SURFACE_USE_TEXTURE); targetBuffer->surface.use = (GX2SurfaceUse) (GX2_SURFACE_USE_COLOR_BUFFER | GX2_SURFACE_USE_TEXTURE);
targetBuffer->surface.dim = GX2_SURFACE_DIM_TEXTURE_2D; targetBuffer->surface.dim = GX2_SURFACE_DIM_TEXTURE_2D;
@ -88,15 +124,15 @@ bool copyBuffer(GX2ColorBuffer * sourceBuffer, GX2ColorBuffer * targetBuffer, ui
targetBuffer->surface.pitch = 0; targetBuffer->surface.pitch = 0;
uint32_t i; uint32_t i;
for(i = 0; i < 13; i++) { for (i = 0; i < 13; i++) {
targetBuffer->surface.mipLevelOffset[i] = 0; targetBuffer->surface.mipLevelOffset[i] = 0;
} }
targetBuffer->viewMip = 0; targetBuffer->viewMip = 0;
targetBuffer->viewFirstSlice = 0; targetBuffer->viewFirstSlice = 0;
targetBuffer->viewNumSlices = depth; targetBuffer->viewNumSlices = depth;
targetBuffer->aaBuffer = NULL; targetBuffer->aaBuffer = nullptr;
targetBuffer->aaSize = 0; targetBuffer->aaSize = 0;
for(i = 0; i < 5; i++){ for (i = 0; i < 5; i++) {
targetBuffer->regs[i] = 0; targetBuffer->regs[i] = 0;
} }
@ -104,12 +140,11 @@ bool copyBuffer(GX2ColorBuffer * sourceBuffer, GX2ColorBuffer * targetBuffer, ui
GX2InitColorBufferRegs(targetBuffer); GX2InitColorBufferRegs(targetBuffer);
// Let's allocate the memory. // Let's allocate the memory.
targetBuffer->surface.image = memalign(targetBuffer->surface.alignment,targetBuffer->surface.imageSize); targetBuffer->surface.image = MEMAllocFromMappedMemoryForGX2Ex(targetBuffer->surface.imageSize, targetBuffer->surface.alignment);
if(targetBuffer->surface.image == NULL) { if (targetBuffer->surface.image == nullptr) {
DEBUG_FUNCTION_LINE("failed to allocate memory.\n"); DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the surface image");
return false; return false;
} }
DEBUG_FUNCTION_LINE("Allocated image data buffer. data %08X size %08X \n",targetBuffer->surface.image,targetBuffer->surface.imageSize);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU, targetBuffer->surface.image, targetBuffer->surface.imageSize); GX2Invalidate(GX2_INVALIDATE_MODE_CPU, targetBuffer->surface.image, targetBuffer->surface.imageSize);
if (sourceBuffer->surface.aa == GX2_AA_MODE1X) { if (sourceBuffer->surface.aa == GX2_AA_MODE1X) {
@ -125,70 +160,102 @@ bool copyBuffer(GX2ColorBuffer * sourceBuffer, GX2ColorBuffer * targetBuffer, ui
tempSurface.aa = GX2_AA_MODE1X; tempSurface.aa = GX2_AA_MODE1X;
GX2CalcSurfaceSizeAndAlignment(&tempSurface); GX2CalcSurfaceSizeAndAlignment(&tempSurface);
tempSurface.image = memalign(tempSurface.alignment,tempSurface.imageSize); tempSurface.image = MEMAllocFromMappedMemoryForGX2Ex(tempSurface.imageSize, tempSurface.alignment);
if(tempSurface.image == NULL) { if (tempSurface.image == nullptr) {
DEBUG_FUNCTION_LINE("failed to allocate data AA.\n"); DEBUG_FUNCTION_LINE_ERR("failed to allocate data for resolving AA");
if(targetBuffer->surface.image != NULL) { if (targetBuffer->surface.image != nullptr) {
free(targetBuffer->surface.image); MEMFreeToMappedMemory(targetBuffer->surface.image);
targetBuffer->surface.image = NULL; targetBuffer->surface.image = nullptr;
} }
return false; return false;
} }
GX2ResolveAAColorBuffer(sourceBuffer,&tempSurface, 0, 0); GX2ResolveAAColorBuffer(sourceBuffer, &tempSurface, 0, 0);
GX2CopySurface(&tempSurface, 0, 0,&targetBuffer->surface, 0, 0); GX2CopySurface(&tempSurface, 0, 0, &targetBuffer->surface, 0, 0);
// Sync CPU and GPU // Sync CPU and GPU
GX2DrawDone(); GX2DrawDone();
if(tempSurface.image != NULL) { if (tempSurface.image != nullptr) {
free(tempSurface.image); MEMFreeToMappedMemory(tempSurface.image);
tempSurface.image = NULL; tempSurface.image = nullptr;
} }
} }
return true; return true;
} else { } else {
DEBUG_FUNCTION_LINE("Couldn't copy buffer, pointer was NULL\n"); DEBUG_FUNCTION_LINE_ERR("Couldn't copy buffer, pointer was nullptr");
return false; return false;
} }
} }
bool takeScreenshot(GX2ColorBuffer *srcBuffer,const char * path) { bool takeScreenshot(GX2ColorBuffer *srcBuffer, const std::string &path, GX2ScanTarget scanTarget, GX2SurfaceFormat outputBufferSurfaceFormat, ImageOutputFormatEnum outputFormat, int quality) {
if(srcBuffer == NULL) { if (srcBuffer == nullptr) {
DEBUG_FUNCTION_LINE_ERR("Source buffer was NULL");
return false; return false;
} }
DEBUG_FUNCTION_LINE("Taking screenshot. %s\n",path);
GX2ColorBuffer colorBuffer; GX2ColorBuffer colorBuffer;
GX2ColorBuffer * saveBuffer = NULL; GX2ColorBuffer *saveBuffer = nullptr;
// keep dimensions // keep dimensions
uint32_t width = srcBuffer->surface.width; uint32_t width = srcBuffer->surface.width;
uint32_t height = srcBuffer->surface.height; uint32_t height = srcBuffer->surface.height;
bool valid = false; std::string fullPath = path;
bool cancel = false;
bool low_memory = false;
do {
// At first we need to copy the buffer to fit our resolution.
if(saveBuffer == NULL) {
do {
valid = copyBuffer(srcBuffer,&colorBuffer,width,height);
// If the copying failed, we don't have enough memory. Let's decrease the resolution.
if(!valid) {
low_memory = true;
if(height >= 1080) { if (scanTarget == GX2_SCAN_TARGET_DRC) {
fullPath += "DRC";
} else if (scanTarget == GX2_SCAN_TARGET_TV) {
fullPath += "TV";
} else if (scanTarget == GX2_SCAN_TARGET_DRC1) {
fullPath += "DRC2";
} else {
DEBUG_FUNCTION_LINE_ERR("Invalid scanTarget %d", scanTarget);
return false;
}
switch (outputFormat) {
case IMAGE_OUTPUT_FORMAT_JPEG:
fullPath += ".jpg";
break;
case IMAGE_OUTPUT_FORMAT_PNG:
fullPath += ".png";
break;
case IMAGE_OUTPUT_FORMAT_BMP:
fullPath += ".bmp";
break;
default:
DEBUG_FUNCTION_LINE_WARN("Invalid output format, use jpeg instead");
fullPath += ".jpg";
break;
}
bool convertRGBToSRGB = false;
if ((outputBufferSurfaceFormat & 0x400)) {
DEBUG_FUNCTION_LINE_VERBOSE("Images needs to be converted to SRGB");
convertRGBToSRGB = true;
}
bool valid;
bool cancel = false;
do {
// At first, we need to copy the buffer to fit our resolution.
if (saveBuffer == nullptr) {
do {
valid = copyBuffer(srcBuffer, &colorBuffer, width, height);
// If the copying failed, we don't have enough memory. Let's decrease the resolution.
if (!valid) {
if (height >= 1080) {
width = 1280; width = 1280;
height = 720; height = 720;
DEBUG_FUNCTION_LINE("Switching to 720p.\n"); DEBUG_FUNCTION_LINE("Switching to 720p.");
} else if(height >= 720) { } else if (height >= 720) {
width = 854; width = 854;
height = 480; height = 480;
DEBUG_FUNCTION_LINE("Switching to 480p.\n"); DEBUG_FUNCTION_LINE("Switching to 480p.");
} else if(height >= 480) { } else if (height >= 480) {
width = 640; width = 640;
height = 360; height = 360;
DEBUG_FUNCTION_LINE("Switching to 360p.\n"); DEBUG_FUNCTION_LINE("Switching to 360p.");
} else { } else {
// Cancel the screenshot if the resolution would be too low. // Cancel the screenshot if the resolution would be too low.
cancel = true; cancel = true;
@ -198,65 +265,53 @@ bool takeScreenshot(GX2ColorBuffer *srcBuffer,const char * path) {
// On success save the pointer. // On success save the pointer.
saveBuffer = &colorBuffer; saveBuffer = &colorBuffer;
} }
} while(!valid); } while (!valid);
} }
// Check if we should proceed // Check if we should proceed
if(cancel) { if (cancel) {
// Free the memory on error. // Free the memory on error.
if(colorBuffer.surface.image != NULL) { if (colorBuffer.surface.image != nullptr) {
free(colorBuffer.surface.image); MEMFreeToMappedMemory(colorBuffer.surface.image);
colorBuffer.surface.image = NULL; colorBuffer.surface.image = nullptr;
} }
return false; return false;
} }
// Flush out destinations caches // Flush out destinations caches
GX2Invalidate(GX2_INVALIDATE_MODE_COLOR_BUFFER, colorBuffer.surface.image,colorBuffer.surface.imageSize); GX2Invalidate(GX2_INVALIDATE_MODE_COLOR_BUFFER, colorBuffer.surface.image, colorBuffer.surface.imageSize);
// Wait for GPU to finish // Wait for GPU to finish
GX2DrawDone(); GX2DrawDone();
DEBUG_FUNCTION_LINE("Trying to save.\n"); valid = saveTextureAsPicture(fullPath, (uint8_t *) saveBuffer->surface.image, width, height, saveBuffer->surface.pitch, saveBuffer->surface.format, outputFormat, convertRGBToSRGB, quality);
JpegInformation * jpegResult = convertToJpeg((uint8_t *) saveBuffer->surface.image,width,height,saveBuffer->surface.pitch,saveBuffer->surface.format, 95);
if(jpegResult != NULL) {
DEBUG_FUNCTION_LINE("Encoded file as JPEG. size = %lld.\n", jpegResult->getSize());
DCFlushRange(jpegResult->getBuffer(), jpegResult->getSize());
valid = FSUtils::saveBufferToFile(path, (void *) jpegResult->getBuffer(), jpegResult->getSize());
if(!valid) {
DEBUG_FUNCTION_LINE("Failed to save buffer to %s \n",path);
}
delete jpegResult;
}
// Free the colorbuffer copy. // Free the colorbuffer copy.
if(colorBuffer.surface.image != NULL) { if (colorBuffer.surface.image != nullptr) {
free(colorBuffer.surface.image); MEMFreeToMappedMemory(colorBuffer.surface.image);
colorBuffer.surface.image = NULL; colorBuffer.surface.image = nullptr;
saveBuffer = NULL; saveBuffer = nullptr;
} }
// When taking the screenshot failed, decrease the resolution again ~. // When taking the screenshot failed, decrease the resolution again ~.
if(!valid) { if (!valid) {
low_memory = true; if (height >= 1080) {
if(height >= 1080) {
width = 1280; width = 1280;
height = 720; height = 720;
DEBUG_FUNCTION_LINE("Switching to 720p.\n"); DEBUG_FUNCTION_LINE("Switching to 720p.");
} else if(height >= 720) { } else if (height >= 720) {
width = 854; width = 854;
height = 480; height = 480;
DEBUG_FUNCTION_LINE("Switching to 480p.\n"); DEBUG_FUNCTION_LINE("Switching to 480p.");
} else if(height >= 480) { } else if (height >= 480) {
width = 640; width = 640;
height = 360; height = 360;
DEBUG_FUNCTION_LINE("Switching to 360p.\n"); DEBUG_FUNCTION_LINE("Switching to 360p.");
} else { } else {
return false; return false;
} }
} }
} while(!valid); } while (!valid);
return true; return true;
} }

View File

@ -1,14 +1,13 @@
#ifndef _SCREENSHOT_UTILS_H_ #pragma once
#define _SCREENSHOT_UTILS_H_
#include "common.h"
#include "utils/logger.h"
#include <gx2/surface.h> #include <gx2/surface.h>
#include <utils/logger.h> #include <memory>
#include "JpegInformation.h" #include <optional>
#include <string>
JpegInformation * convertToJpeg(uint8_t * sourceBuffer, uint32_t width, uint32_t height, uint32_t pitch, uint32_t format, int32_t quality); bool saveTextureAsPicture(const std::string &path, uint8_t *sourceBuffer, uint32_t width, uint32_t height, uint32_t pitch, GX2SurfaceFormat format, ImageOutputFormatEnum outputFormat, bool convertRGBtoSRGB, int quality);
bool copyBuffer(GX2ColorBuffer * sourceBuffer, GX2ColorBuffer * targetBuffer, uint32_t targetWidth, uint32_t targetHeight);
bool takeScreenshot(GX2ColorBuffer *srcBuffer,const char * path); bool takeScreenshot(GX2ColorBuffer *srcBuffer, const std::string &path, GX2ScanTarget scanTarget, GX2SurfaceFormat outputBufferSurfaceFormat, ImageOutputFormatEnum outputFormat, int quality);
#endif

14
src/utils/StringTools.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
template<typename... Args>
std::string string_format(const std::string &format, Args... args) {
int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
auto size = static_cast<size_t>(size_s);
auto buf = std::make_unique<char[]>(size);
std::snprintf(buf.get(), size, format.c_str(), args...);
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}

36
src/utils/logger.c Normal file
View File

@ -0,0 +1,36 @@
#ifdef DEBUG
#include <stdint.h>
#include <whb/log_cafe.h>
#include <whb/log_module.h>
#include <whb/log_udp.h>
uint32_t moduleLogInit = false;
uint32_t cafeLogInit = false;
uint32_t udpLogInit = false;
#endif // DEBUG
void initLogging() {
#ifdef DEBUG
if (!(moduleLogInit = WHBLogModuleInit())) {
cafeLogInit = WHBLogCafeInit();
udpLogInit = WHBLogUdpInit();
}
#endif // DEBUG
}
void deinitLogging() {
#ifdef DEBUG
if (moduleLogInit) {
WHBLogModuleDeinit();
moduleLogInit = false;
}
if (cafeLogInit) {
WHBLogCafeDeinit();
cafeLogInit = false;
}
if (udpLogInit) {
WHBLogUdpDeinit();
udpLogInit = false;
}
#endif // DEBUG
}

72
src/utils/logger.h Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include <coreinit/debug.h>
#include <string.h>
#include <whb/log.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LOG_APP_TYPE "P"
#define LOG_APP_NAME "ScreenshotPlugin"
#define __FILENAME__ ({ \
const char *__filename = __FILE__; \
const char *__pos = strrchr(__filename, '/'); \
if (!__pos) __pos = strrchr(__filename, '\\'); \
__pos ? __pos + 1 : __filename; \
})
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX_DEFAULT(LOG_FUNC, "", "", FMT, ##ARGS)
#define LOG_EX_DEFAULT(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) LOG_EX(__FILENAME__, __FUNCTION__, __LINE__, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ##ARGS)
#define LOG_EX(FILENAME, FUNCTION, LINE, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \
do { \
LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, FILENAME, FUNCTION, LINE, ##ARGS); \
} while (0)
#ifdef DEBUG
#ifdef VERBOSE_DEBUG
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "", "", FMT, ##ARGS);
#else
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0)
#endif
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##WARN ## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS);
#else
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##WARN ## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS);
#endif
void initLogging();
void deinitLogging();
#ifdef __cplusplus
}
#endif

12
src/utils/utils.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <memory>
template<class T, class... Args>
std::unique_ptr<T> make_unique_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
return std::unique_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
}
template<class T, class... Args>
std::shared_ptr<T> make_shared_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
return std::shared_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
}

2
src/version.h Normal file
View File

@ -0,0 +1,2 @@
#pragma once
#define VERSION_EXTRA ""