mirror of
https://github.com/wiiu-env/NotificationModule.git
synced 2025-01-11 19:09:08 +01:00
First commit
This commit is contained in:
commit
38efe0b15f
67
.clang-format
Normal file
67
.clang-format
Normal 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
|
59
.github/workflows/ci.yml
vendored
Normal file
59
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
name: CI-Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
clang-format:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- 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@v3
|
||||
- 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: "*.wms"
|
||||
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 *.wms
|
||||
- name: Create Release
|
||||
uses: "softprops/action-gh-release@v1"
|
||||
with:
|
||||
tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
|
||||
draft: false
|
||||
prerelease: true
|
||||
generate_release_notes: true
|
||||
name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
|
||||
files: |
|
||||
./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip
|
43
.github/workflows/pr.yml
vendored
Normal file
43
.github/workflows/pr.yml
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
name: CI-PR
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
clang-format:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: clang-format
|
||||
run: |
|
||||
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src
|
||||
check-build-with-logging:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: clang-format
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: build binary with logging
|
||||
run: |
|
||||
docker build . -t builder
|
||||
docker run --rm -v ${PWD}:/project builder make DEBUG=VERBOSE
|
||||
docker run --rm -v ${PWD}:/project builder make clean
|
||||
docker run --rm -v ${PWD}:/project builder make DEBUG=1
|
||||
build-binary:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: clang-format
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- 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: "*.wms"
|
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
*.cbp
|
||||
*.elf
|
||||
*.layout
|
||||
*.rpx
|
||||
build/
|
||||
*.save-failed
|
||||
.idea/
|
||||
cmake-build-debug/
|
||||
CMakeLists.txt
|
||||
*.wms
|
8
Dockerfile
Normal file
8
Dockerfile
Normal file
@ -0,0 +1,8 @@
|
||||
FROM wiiuenv/devkitppc:20221228
|
||||
|
||||
COPY --from=wiiuenv/libnotifications:20230126 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libmappedmemory:20220904 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libfunctionpatcher:20230108 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/wiiumodulesystem:20230106 /artifacts $DEVKITPRO
|
||||
|
||||
WORKDIR project
|
674
LICENSE
Normal file
674
LICENSE
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
150
Makefile
Normal file
150
Makefile
Normal file
@ -0,0 +1,150 @@
|
||||
#-------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
|
||||
include $(DEVKITPRO)/wums/share/wums_rules
|
||||
|
||||
FREETYPE_INCLUDE := $(DEVKITPRO)/portlibs/ppc/include/freetype2
|
||||
PORTLIBS_PPC := $(DEVKITPRO)/portlibs/ppc
|
||||
WUMS_ROOT := $(DEVKITPRO)/wums
|
||||
WUT_ROOT := $(DEVKITPRO)/wut
|
||||
#-------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# DATA is a list of directories containing data files
|
||||
# INCLUDES is a list of directories containing header files
|
||||
#-------------------------------------------------------------------------------
|
||||
TARGET := NotificationModule
|
||||
BUILD := build
|
||||
SOURCES := src src/utils src/gui src/shaders
|
||||
DATA := data
|
||||
INCLUDES := src
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#-------------------------------------------------------------------------------
|
||||
CFLAGS := -Wall -Wextra -O2 -ffunction-sections\
|
||||
$(MACHDEP)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -std=c++20
|
||||
|
||||
ASFLAGS := $(ARCH)
|
||||
LDFLAGS = $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libmappedmemory.ld $(WUMSSPECS)
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CXXFLAGS += -DDEBUG -g
|
||||
CFLAGS += -DDEBUG -g
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG),VERBOSE)
|
||||
CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
endif
|
||||
|
||||
LIBS := -lwums -lwut -lfunctionpatcher -lgd -lz -lmappedmemory
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level
|
||||
# containing include and lib
|
||||
#-------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUMS_ROOT) $(PORTLIBS_PPC)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#-------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
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) -I$(FREETYPE_INCLUDE)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
$(BUILD):
|
||||
@$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD))
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(TARGET).wms $(TARGET).elf
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#-------------------------------------------------------------------------------
|
||||
all : $(OUTPUT).wms
|
||||
|
||||
$(OUTPUT).wms : $(OUTPUT).elf
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#-------------------------------------------------------------------------------
|
||||
%.bin.o %_bin.h : %.bin
|
||||
#-------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
endif
|
||||
#-------------------------------------------------------------------------------
|
39
README.md
Normal file
39
README.md
Normal file
@ -0,0 +1,39 @@
|
||||
[![CI-Release](https://github.com/wiiu-env/NotificationModule/actions/workflows/ci.yml/badge.svg)](https://github.com/wiiu-env/NotificationModule/actions/workflows/ci.yml)
|
||||
|
||||
See [libnotifications](https://github.com/wiiu-env/libnotifications).
|
||||
|
||||
## Usage
|
||||
(`[ENVIRONMENT]` is a placeholder for the actual environment name.)
|
||||
|
||||
1. Copy the file `NotificationModule.wms` into `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
|
||||
2. Requires the [WUMSLoader](https://github.com/wiiu-env/WUMSLoader) in `sd:/wiiu/environments/[ENVIRONMENT]/modules/setup`.
|
||||
|
||||
## Buildflags
|
||||
|
||||
### Logging
|
||||
Building via `make` only logs errors (via OSReport). To enable logging via the [LoggingModule](https://github.com/wiiu-env/LoggingModule) set `DEBUG` to `1` or `VERBOSE`.
|
||||
|
||||
`make` Logs errors only (via OSReport).
|
||||
`make DEBUG=1` Enables information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
|
||||
`make DEBUG=VERBOSE` Enables verbose information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
|
||||
|
||||
If the [LoggingModule](https://github.com/wiiu-env/LoggingModule) is not present, it'll fall back to UDP (Port 4405) and [CafeOS](https://github.com/wiiu-env/USBSerialLoggingModule) logging.
|
||||
|
||||
## 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.
|
||||
|
||||
```
|
||||
# Build docker image (only needed once)
|
||||
docker build . -t notificationmodule-builder
|
||||
|
||||
# make
|
||||
docker run -it --rm -v ${PWD}:/project notificationmodule-builder make
|
||||
|
||||
# make clean
|
||||
docker run -it --rm -v ${PWD}:/project notificationmodule-builder make clean
|
||||
```
|
||||
|
||||
## Format the code via docker
|
||||
|
||||
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src -i`
|
200
src/export.cpp
Normal file
200
src/export.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
#include "gui/Notification.h"
|
||||
#include "retain_vars.hpp"
|
||||
#include "utils/utils.h"
|
||||
#include <memory>
|
||||
#include <notifications/notifications.h>
|
||||
#include <wums.h>
|
||||
|
||||
void ExportCleanUp() {
|
||||
std::lock_guard<std::mutex> lock(gNotificationListMutex);
|
||||
gNotificationList.clear();
|
||||
}
|
||||
|
||||
NotificationModuleStatus NMAddStaticNotification(const char *text,
|
||||
NotificationModuleNotificationType type,
|
||||
float durationBeforeFadeOutInSeconds,
|
||||
float shakeDurationInSeconds,
|
||||
NMColor textColor,
|
||||
NMColor backgroundColor,
|
||||
void (*finishFunc)(NotificationModuleHandle, void *context),
|
||||
void *context) {
|
||||
if (!gOverlayFrame) {
|
||||
return NOTIFICATION_MODULE_RESULT_OVERLAY_NOT_READY;
|
||||
}
|
||||
|
||||
NotificationStatus status;
|
||||
switch (type) {
|
||||
case NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO:
|
||||
status = NOTIFICATION_STATUS_INFO;
|
||||
break;
|
||||
case NOTIFICATION_MODULE_NOTIFICATION_TYPE_ERROR:
|
||||
status = NOTIFICATION_STATUS_ERROR;
|
||||
break;
|
||||
default:
|
||||
return NOTIFICATION_MODULE_RESULT_UNSUPPORTED_TYPE;
|
||||
}
|
||||
auto notification = make_shared_nothrow<Notification>(
|
||||
text,
|
||||
status,
|
||||
durationBeforeFadeOutInSeconds,
|
||||
shakeDurationInSeconds,
|
||||
(GX2Color){textColor.r, textColor.g, textColor.b, textColor.a},
|
||||
(GX2Color){backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a},
|
||||
finishFunc,
|
||||
context);
|
||||
if (!notification) {
|
||||
return NOTIFICATION_MODULE_RESULT_ALLOCATION_FAILED;
|
||||
}
|
||||
|
||||
gOverlayFrame->addNotification(notification);
|
||||
|
||||
return NOTIFICATION_MODULE_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void NMNotificationRemovedFromOverlay(Notification *notification) {
|
||||
if (notification) {
|
||||
auto handle = notification->getHandle();
|
||||
if (!remove_locked_first_if(gNotificationListMutex, gNotificationList, [handle](auto &cur) { return cur->getHandle() == handle; })) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NMNotificationRemovedFromOverlay failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NotificationModuleStatus NMAddDynamicNotification(const char *text,
|
||||
NMColor textColor,
|
||||
NMColor backgroundColor,
|
||||
void (*finishFunc)(NotificationModuleHandle, void *context),
|
||||
void *context,
|
||||
NotificationModuleHandle *outHandle) {
|
||||
if (outHandle == nullptr) {
|
||||
return NOTIFICATION_MODULE_RESULT_INVALID_ARGUMENT;
|
||||
}
|
||||
*outHandle = 0;
|
||||
if (!gOverlayFrame) {
|
||||
return NOTIFICATION_MODULE_RESULT_OVERLAY_NOT_READY;
|
||||
}
|
||||
|
||||
auto notification = make_shared_nothrow<Notification>(
|
||||
text,
|
||||
NOTIFICATION_STATUS_IN_PROGRESS,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(GX2Color){textColor.r, textColor.g, textColor.b, textColor.a},
|
||||
(GX2Color){backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a},
|
||||
finishFunc,
|
||||
context,
|
||||
NMNotificationRemovedFromOverlay);
|
||||
if (!notification) {
|
||||
return NOTIFICATION_MODULE_RESULT_ALLOCATION_FAILED;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(gNotificationListMutex);
|
||||
*outHandle = notification->getHandle();
|
||||
gOverlayFrame->addNotification(notification);
|
||||
gNotificationList.push_front(notification);
|
||||
}
|
||||
|
||||
return NOTIFICATION_MODULE_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
NotificationModuleStatus NMUpdateDynamicNotificationText(NotificationModuleHandle handle,
|
||||
const char *text) {
|
||||
NotificationModuleStatus res = NOTIFICATION_MODULE_RESULT_INVALID_HANDLE;
|
||||
std::lock_guard<std::mutex> lock(gNotificationListMutex);
|
||||
for (auto &cur : gNotificationList) {
|
||||
if (cur->getHandle() == handle) {
|
||||
cur->updateText(text);
|
||||
res = NOTIFICATION_MODULE_RESULT_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NotificationModuleStatus NMUpdateDynamicNotificationBackgroundColor(NotificationModuleHandle handle,
|
||||
NMColor backgroundColor) {
|
||||
NotificationModuleStatus res = NOTIFICATION_MODULE_RESULT_INVALID_HANDLE;
|
||||
std::lock_guard<std::mutex> lock(gNotificationListMutex);
|
||||
for (auto &cur : gNotificationList) {
|
||||
if (cur->getHandle() == handle) {
|
||||
cur->updateBackgroundColor((GX2Color){backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a});
|
||||
res = NOTIFICATION_MODULE_RESULT_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NotificationModuleStatus NMUpdateDynamicNotificationTextColor(NotificationModuleHandle handle,
|
||||
NMColor textColor) {
|
||||
NotificationModuleStatus res = NOTIFICATION_MODULE_RESULT_INVALID_HANDLE;
|
||||
std::lock_guard<std::mutex> lock(gNotificationListMutex);
|
||||
for (auto &cur : gNotificationList) {
|
||||
if (cur->getHandle() == handle) {
|
||||
cur->updateTextColor((GX2Color){textColor.r, textColor.g, textColor.b, textColor.a});
|
||||
res = NOTIFICATION_MODULE_RESULT_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NotificationModuleStatus NMFinishDynamicNotification(NotificationModuleHandle handle,
|
||||
NotificationModuleStatusFinish finishMode,
|
||||
float durationBeforeFadeOutInSeconds,
|
||||
float shakeDurationInSeconds) {
|
||||
NotificationStatus newStatus;
|
||||
switch (finishMode) {
|
||||
case NOTIFICATION_MODULE_STATUS_FINISH:
|
||||
newStatus = NOTIFICATION_STATUS_INFO;
|
||||
break;
|
||||
case NOTIFICATION_MODULE_STATUS_FINISH_WITH_SHAKE:
|
||||
newStatus = NOTIFICATION_STATUS_ERROR;
|
||||
break;
|
||||
default:
|
||||
return NOTIFICATION_MODULE_RESULT_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
NotificationModuleStatus res = NOTIFICATION_MODULE_RESULT_INVALID_HANDLE;
|
||||
std::lock_guard<std::mutex> lock(gNotificationListMutex);
|
||||
for (auto &cur : gNotificationList) {
|
||||
if (cur->getHandle() == handle) {
|
||||
cur->updateStatus(newStatus);
|
||||
cur->updateWaitDuration(durationBeforeFadeOutInSeconds);
|
||||
cur->updateShakeDuration(shakeDurationInSeconds);
|
||||
res = NOTIFICATION_MODULE_RESULT_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NotificationModuleStatus NMIsOverlayReady(bool *outIsReady) {
|
||||
if (outIsReady == nullptr) {
|
||||
return NOTIFICATION_MODULE_RESULT_INVALID_ARGUMENT;
|
||||
}
|
||||
if (gOverlayFrame == nullptr) {
|
||||
*outIsReady = false;
|
||||
} else {
|
||||
*outIsReady = true;
|
||||
}
|
||||
return NOTIFICATION_MODULE_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
NotificationModuleStatus NMGetVersion(NotificationModuleAPIVersion *outVersion) {
|
||||
if (outVersion == nullptr) {
|
||||
return NOTIFICATION_MODULE_RESULT_INVALID_ARGUMENT;
|
||||
}
|
||||
*outVersion = 1;
|
||||
return NOTIFICATION_MODULE_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
WUMS_EXPORT_FUNCTION(NMAddDynamicNotification);
|
||||
WUMS_EXPORT_FUNCTION(NMAddStaticNotification);
|
||||
WUMS_EXPORT_FUNCTION(NMUpdateDynamicNotificationText);
|
||||
WUMS_EXPORT_FUNCTION(NMUpdateDynamicNotificationBackgroundColor);
|
||||
WUMS_EXPORT_FUNCTION(NMUpdateDynamicNotificationTextColor);
|
||||
WUMS_EXPORT_FUNCTION(NMFinishDynamicNotification);
|
||||
WUMS_EXPORT_FUNCTION(NMIsOverlayReady);
|
||||
WUMS_EXPORT_FUNCTION(NMGetVersion);
|
3
src/export.h
Normal file
3
src/export.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void ExportCleanUp();
|
164
src/function_patches.cpp
Normal file
164
src/function_patches.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
#include "retain_vars.hpp"
|
||||
#include "shaders/ColorShader.h"
|
||||
#include "shaders/Texture2DShader.h"
|
||||
#include <function_patcher/fpatching_defines.h>
|
||||
#include <gx2/state.h>
|
||||
|
||||
bool drawScreenshotSavedTexture(const GX2ColorBuffer *colorBuffer, GX2ScanTarget scan_target);
|
||||
|
||||
GX2ColorBuffer lastTVColorBuffer;
|
||||
GX2ColorBuffer lastDRCColorBuffer;
|
||||
DECL_FUNCTION(void, GX2GetCurrentScanBuffer, GX2ScanTarget scanTarget, GX2ColorBuffer *cb) {
|
||||
real_GX2GetCurrentScanBuffer(scanTarget, cb);
|
||||
if (scanTarget == GX2_SCAN_TARGET_TV) {
|
||||
memcpy(&lastTVColorBuffer, cb, sizeof(GX2ColorBuffer));
|
||||
} else {
|
||||
memcpy(&lastDRCColorBuffer, cb, sizeof(GX2ColorBuffer));
|
||||
}
|
||||
}
|
||||
|
||||
DECL_FUNCTION(void, GX2SetContextState, GX2ContextState *curContext) {
|
||||
real_GX2SetContextState(curContext);
|
||||
|
||||
gOriginalContextState = curContext;
|
||||
}
|
||||
|
||||
DECL_FUNCTION(void, GX2SetupContextStateEx, GX2ContextState *state, BOOL unk1) {
|
||||
real_GX2SetupContextStateEx(state, unk1);
|
||||
gOriginalContextState = state;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("gOriginalContextState = %08X", state);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void drawIntoColorBuffer(const GX2ColorBuffer *colorBuffer, OverlayFrame *overlayFrame, GX2ScanTarget scan_target) {
|
||||
real_GX2SetContextState(gContextState);
|
||||
|
||||
GX2SetDefaultState();
|
||||
|
||||
GX2SetColorBuffer((GX2ColorBuffer *) colorBuffer, GX2_RENDER_TARGET_0);
|
||||
GX2SetViewport(0.0f, 0.0f, colorBuffer->surface.width, colorBuffer->surface.height, 0.0f, 1.0f);
|
||||
GX2SetScissor(0, 0, colorBuffer->surface.width, colorBuffer->surface.height);
|
||||
|
||||
GX2SetDepthOnlyControl(GX2_FALSE, GX2_FALSE, GX2_COMPARE_FUNC_NEVER);
|
||||
GX2SetAlphaTest(GX2_TRUE, GX2_COMPARE_FUNC_GREATER, 0.0f);
|
||||
GX2SetColorControl(GX2_LOGIC_OP_COPY, GX2_ENABLE, GX2_DISABLE, GX2_ENABLE);
|
||||
auto outputFormat = scan_target ? gTVSurfaceFormat : gDRCSurfaceFormat;
|
||||
overlayFrame->draw(outputFormat & 0x400);
|
||||
GX2Flush();
|
||||
|
||||
real_GX2SetContextState(gOriginalContextState);
|
||||
}
|
||||
|
||||
|
||||
void drawScreenshotSavedTexture2(GX2ColorBuffer *colorBuffer, GX2ScanTarget scan_target) {
|
||||
if (gOverlayFrame->empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
drawIntoColorBuffer(colorBuffer, gOverlayFrame, scan_target);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, GX2ScanTarget scan_target) {
|
||||
gDrawReady = true;
|
||||
if (drawScreenshotSavedTexture(colorBuffer, scan_target)) {
|
||||
// if it returns true we don't need to call GX2CopyColorBufferToScanBuffer
|
||||
return;
|
||||
}
|
||||
|
||||
real_GX2CopyColorBufferToScanBuffer(colorBuffer, scan_target);
|
||||
}
|
||||
|
||||
bool drawScreenshotSavedTexture(const GX2ColorBuffer *colorBuffer, GX2ScanTarget scan_target) {
|
||||
if (gOverlayFrame->empty()) {
|
||||
return false;
|
||||
}
|
||||
GX2ColorBuffer cb;
|
||||
GX2InitColorBuffer(&cb,
|
||||
colorBuffer->surface.dim,
|
||||
colorBuffer->surface.width,
|
||||
colorBuffer->surface.height,
|
||||
colorBuffer->surface.depth,
|
||||
colorBuffer->surface.format,
|
||||
colorBuffer->surface.aa,
|
||||
colorBuffer->surface.tileMode,
|
||||
colorBuffer->surface.swizzle,
|
||||
colorBuffer->aaBuffer,
|
||||
colorBuffer->aaSize);
|
||||
|
||||
cb.surface.image = colorBuffer->surface.image;
|
||||
|
||||
drawIntoColorBuffer(&cb, gOverlayFrame, scan_target);
|
||||
|
||||
real_GX2CopyColorBufferToScanBuffer(&cb, scan_target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DECL_FUNCTION(void, GX2Init, uint32_t attributes) {
|
||||
real_GX2Init(attributes);
|
||||
if (!gOverlayInitDone) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Init Overlay");
|
||||
gOverlayFrame = new (std::nothrow) OverlayFrame(1280.0f, 720.0f);
|
||||
if (!gOverlayFrame) {
|
||||
OSFatal("Failed to alloc gOverlayFrame");
|
||||
}
|
||||
|
||||
// Allocate shader.
|
||||
ColorShader::instance();
|
||||
Texture2DShader::instance();
|
||||
|
||||
// has been allocated in WUMS INIT
|
||||
if (!gContextState) {
|
||||
OSFatal("Failed to alloc gContextState");
|
||||
}
|
||||
real_GX2SetupContextStateEx(gContextState, GX2_TRUE);
|
||||
DCInvalidateRange(gContextState, sizeof(GX2ContextState)); // Important!
|
||||
gOverlayInitDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
DECL_FUNCTION(void, GX2MarkScanBufferCopied, GX2ScanTarget scan_target) {
|
||||
gDrawReady = true;
|
||||
if (scan_target == GX2_SCAN_TARGET_TV) {
|
||||
drawScreenshotSavedTexture2(&lastTVColorBuffer, scan_target);
|
||||
} else {
|
||||
drawScreenshotSavedTexture2(&lastDRCColorBuffer, scan_target);
|
||||
}
|
||||
|
||||
real_GX2MarkScanBufferCopied(scan_target);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(void, GX2SwapScanBuffers, void) {
|
||||
if (gDrawReady && !gOverlayFrame->empty()) {
|
||||
gOverlayFrame->process();
|
||||
gOverlayFrame->updateEffects();
|
||||
}
|
||||
real_GX2SwapScanBuffers();
|
||||
}
|
||||
|
||||
function_replacement_data_t function_replacements[] = {
|
||||
REPLACE_FUNCTION(GX2GetCurrentScanBuffer, LIBRARY_GX2, GX2GetCurrentScanBuffer),
|
||||
REPLACE_FUNCTION(GX2SetContextState, LIBRARY_GX2, GX2SetContextState),
|
||||
REPLACE_FUNCTION(GX2SetupContextStateEx, LIBRARY_GX2, GX2SetupContextStateEx),
|
||||
REPLACE_FUNCTION(GX2SetTVBuffer, LIBRARY_GX2, GX2SetTVBuffer),
|
||||
REPLACE_FUNCTION(GX2SetDRCBuffer, LIBRARY_GX2, GX2SetDRCBuffer),
|
||||
REPLACE_FUNCTION(GX2CopyColorBufferToScanBuffer, LIBRARY_GX2, GX2CopyColorBufferToScanBuffer),
|
||||
REPLACE_FUNCTION(GX2Init, LIBRARY_GX2, GX2Init),
|
||||
REPLACE_FUNCTION(GX2MarkScanBufferCopied, LIBRARY_GX2, GX2MarkScanBufferCopied),
|
||||
REPLACE_FUNCTION(GX2SwapScanBuffers, LIBRARY_GX2, GX2SwapScanBuffers),
|
||||
};
|
||||
|
||||
uint32_t function_replacements_size = sizeof(function_replacements) / sizeof(function_replacement_data_t);
|
7
src/function_patches.h
Normal file
7
src/function_patches.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <function_patcher/fpatching_defines.h>
|
||||
|
||||
extern function_replacement_data_t function_replacements[];
|
||||
extern uint32_t function_replacements_size;
|
333
src/gui/GuiElement.cpp
Normal file
333
src/gui/GuiElement.cpp
Normal file
@ -0,0 +1,333 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#include "GuiElement.h"
|
||||
#include <coreinit/time.h>
|
||||
|
||||
//! TODO remove this!
|
||||
static int32_t screenwidth = 1280;
|
||||
static int32_t screenheight = 720;
|
||||
|
||||
/**
|
||||
* Constructor for the Object class.
|
||||
*/
|
||||
GuiElement::GuiElement() {
|
||||
xoffset = 0.0f;
|
||||
yoffset = 0.0f;
|
||||
zoffset = 0.0f;
|
||||
width = 0.0f;
|
||||
height = 0.0f;
|
||||
alpha = 1.0f;
|
||||
scaleX = 1.0f;
|
||||
scaleY = 1.0f;
|
||||
scaleZ = 1.0f;
|
||||
for (int32_t i = 0; i < 5; i++) {
|
||||
state[i] = STATE_DEFAULT;
|
||||
}
|
||||
stateChan = -1;
|
||||
parentElement = NULL;
|
||||
rumble = true;
|
||||
selectable = false;
|
||||
clickable = false;
|
||||
holdable = false;
|
||||
drawOverOnlyWhenSelected = false;
|
||||
visible = true;
|
||||
yoffsetDyn = 0;
|
||||
xoffsetDyn = 0;
|
||||
alphaDyn = -1;
|
||||
scaleDyn = 1;
|
||||
effects = EFFECT_NONE;
|
||||
effectAmount = 0;
|
||||
effectTarget = 0;
|
||||
effectsOver = EFFECT_NONE;
|
||||
effectAmountOver = 0;
|
||||
effectTargetOver = 0;
|
||||
angle = 0.0f;
|
||||
angleDyn = 0;
|
||||
effectShakeFrame = 0;
|
||||
effectTargetInMS = 0;
|
||||
|
||||
// default alignment - align to top left
|
||||
alignment = (ALIGN_CENTERED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the left position of the GuiElement.
|
||||
* @see SetLeft()
|
||||
* @return Left position in pixel.
|
||||
*/
|
||||
float GuiElement::getLeft() {
|
||||
float pWidth = 0;
|
||||
float pLeft = 0;
|
||||
float pScaleX = 1.0f;
|
||||
|
||||
if (parentElement) {
|
||||
pWidth = parentElement->getWidth();
|
||||
pLeft = parentElement->getLeft();
|
||||
pScaleX = parentElement->getScaleX();
|
||||
}
|
||||
|
||||
pLeft += xoffsetDyn;
|
||||
|
||||
float x = pLeft;
|
||||
|
||||
//! TODO: the conversion from int to float and back to int is bad for performance, change that
|
||||
if (alignment & ALIGN_CENTER) {
|
||||
x = pLeft + pWidth * 0.5f * pScaleX - width * 0.5f * getScaleX();
|
||||
} else if (alignment & ALIGN_RIGHT) {
|
||||
x = pLeft + pWidth * pScaleX - width * getScaleX();
|
||||
}
|
||||
|
||||
return x + xoffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the top position of the GuiElement.
|
||||
* @see SetTop()
|
||||
* @return Top position in pixel.
|
||||
*/
|
||||
float GuiElement::getTop() {
|
||||
float pHeight = 0;
|
||||
float pTop = 0;
|
||||
float pScaleY = 1.0f;
|
||||
|
||||
if (parentElement) {
|
||||
pHeight = parentElement->getHeight();
|
||||
pTop = parentElement->getTop();
|
||||
pScaleY = parentElement->getScaleY();
|
||||
}
|
||||
|
||||
pTop += yoffsetDyn;
|
||||
|
||||
float y = pTop;
|
||||
|
||||
//! TODO: the conversion from int to float and back to int is bad for performance, change that
|
||||
if (alignment & ALIGN_MIDDLE) {
|
||||
y = pTop + pHeight * 0.5f * pScaleY - getHeight() * 0.5f * getScaleY();
|
||||
} else if (alignment & ALIGN_BOTTOM) {
|
||||
y = pTop + pHeight * pScaleY - getHeight() * getScaleY();
|
||||
}
|
||||
|
||||
return y + yoffset;
|
||||
}
|
||||
|
||||
void GuiElement::setEffect(int32_t eff, int32_t amount, int32_t target) {
|
||||
if (eff & EFFECT_SLIDE_IN) {
|
||||
// these calculations overcompensate a little
|
||||
if (eff & EFFECT_SLIDE_TOP) {
|
||||
if (eff & EFFECT_SLIDE_FROM) {
|
||||
yoffsetDyn = (int32_t) -getHeight() * scaleY;
|
||||
} else {
|
||||
yoffsetDyn = -screenheight;
|
||||
}
|
||||
} else if (eff & EFFECT_SLIDE_LEFT) {
|
||||
if (eff & EFFECT_SLIDE_FROM) {
|
||||
xoffsetDyn = (int32_t) -getWidth() * scaleX;
|
||||
} else {
|
||||
xoffsetDyn = -screenwidth;
|
||||
}
|
||||
} else if (eff & EFFECT_SLIDE_BOTTOM) {
|
||||
if (eff & EFFECT_SLIDE_FROM) {
|
||||
yoffsetDyn = (int32_t) getHeight() * scaleY;
|
||||
} else {
|
||||
yoffsetDyn = screenheight;
|
||||
}
|
||||
} else if (eff & EFFECT_SLIDE_RIGHT) {
|
||||
if (eff & EFFECT_SLIDE_FROM) {
|
||||
xoffsetDyn = (int32_t) getWidth() * scaleX;
|
||||
} else {
|
||||
xoffsetDyn = screenwidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((eff & EFFECT_FADE) && amount > 0) {
|
||||
alphaDyn = 0;
|
||||
} else if ((eff & EFFECT_FADE) && amount < 0) {
|
||||
alphaDyn = alpha;
|
||||
}
|
||||
effects |= eff;
|
||||
effectAmount = amount;
|
||||
effectTarget = target;
|
||||
}
|
||||
|
||||
//!Sets an effect to be enabled on wiimote cursor over
|
||||
//!\param e Effect to enable
|
||||
//!\param a Amount of the effect (usage varies on effect)
|
||||
//!\param t Target amount of the effect (usage varies on effect)
|
||||
void GuiElement::setEffectOnOver(int32_t e, int32_t a, int32_t t) {
|
||||
effectsOver |= e;
|
||||
effectAmountOver = a;
|
||||
effectTargetOver = t;
|
||||
}
|
||||
|
||||
void GuiElement::resetEffects() {
|
||||
yoffsetDyn = 0;
|
||||
xoffsetDyn = 0;
|
||||
alphaDyn = -1;
|
||||
scaleDyn = 1;
|
||||
angleDyn = 0;
|
||||
effectShakeFrame = 0;
|
||||
effectTargetInMS = 0;
|
||||
effects = EFFECT_NONE;
|
||||
effectAmount = 0;
|
||||
effectTarget = 0;
|
||||
effectsOver = EFFECT_NONE;
|
||||
effectAmountOver = 0;
|
||||
effectTargetOver = 0;
|
||||
}
|
||||
|
||||
void GuiElement::updateEffects() {
|
||||
if (!this->isVisible() && parentElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (effects & (EFFECT_SLIDE_IN | EFFECT_SLIDE_OUT | EFFECT_SLIDE_FROM)) {
|
||||
if (effects & EFFECT_SLIDE_IN) {
|
||||
if (effects & EFFECT_SLIDE_LEFT) {
|
||||
xoffsetDyn += effectAmount;
|
||||
|
||||
if (xoffsetDyn >= 0) {
|
||||
xoffsetDyn = 0;
|
||||
effects = 0;
|
||||
effectFinished(this);
|
||||
}
|
||||
} else if (effects & EFFECT_SLIDE_RIGHT) {
|
||||
xoffsetDyn -= effectAmount;
|
||||
|
||||
if (xoffsetDyn <= 0) {
|
||||
xoffsetDyn = 0;
|
||||
effects = 0;
|
||||
effectFinished(this);
|
||||
}
|
||||
} else if (effects & EFFECT_SLIDE_TOP) {
|
||||
yoffsetDyn += effectAmount;
|
||||
|
||||
if (yoffsetDyn >= 0) {
|
||||
yoffsetDyn = 0;
|
||||
effects = 0;
|
||||
effectFinished(this);
|
||||
}
|
||||
} else if (effects & EFFECT_SLIDE_BOTTOM) {
|
||||
yoffsetDyn -= effectAmount;
|
||||
|
||||
if (yoffsetDyn <= 0) {
|
||||
yoffsetDyn = 0;
|
||||
effects = 0;
|
||||
effectFinished(this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (effects & EFFECT_SLIDE_LEFT) {
|
||||
xoffsetDyn -= effectAmount;
|
||||
if (xoffsetDyn <= -screenwidth) {
|
||||
effects = 0; // shut off effect
|
||||
effectFinished(this);
|
||||
} else if ((effects & EFFECT_SLIDE_FROM) && xoffsetDyn <= -(getWidth() + xoffset)) {
|
||||
effects = 0; // shut off effect
|
||||
effectFinished(this);
|
||||
}
|
||||
} else if (effects & EFFECT_SLIDE_RIGHT) {
|
||||
xoffsetDyn += effectAmount;
|
||||
|
||||
if (xoffsetDyn >= screenwidth) {
|
||||
effects = 0; // shut off effect
|
||||
effectFinished(this);
|
||||
} else if ((effects & EFFECT_SLIDE_FROM) && xoffsetDyn >= getWidth() * scaleX) {
|
||||
effects = 0; // shut off effect
|
||||
effectFinished(this);
|
||||
}
|
||||
} else if (effects & EFFECT_SLIDE_TOP) {
|
||||
yoffsetDyn -= effectAmount;
|
||||
|
||||
if (yoffsetDyn <= -screenheight) {
|
||||
effects = 0; // shut off effect
|
||||
effectFinished(this);
|
||||
} else if ((effects & EFFECT_SLIDE_FROM) && yoffsetDyn <= -getHeight()) {
|
||||
effects = 0; // shut off effect
|
||||
effectFinished(this);
|
||||
}
|
||||
} else if (effects & EFFECT_SLIDE_BOTTOM) {
|
||||
yoffsetDyn += effectAmount;
|
||||
|
||||
if (yoffsetDyn >= screenheight) {
|
||||
effects = 0; // shut off effect
|
||||
effectFinished(this);
|
||||
} else if ((effects & EFFECT_SLIDE_FROM) && yoffsetDyn >= getHeight()) {
|
||||
effects = 0; // shut off effect
|
||||
effectFinished(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (effects & EFFECT_FADE) {
|
||||
alphaDyn += effectAmount * (1.0f / 255.0f);
|
||||
|
||||
if (effectAmount < 0 && alphaDyn <= 0) {
|
||||
alphaDyn = 0;
|
||||
effects = 0; // shut off effect
|
||||
effectFinished(this);
|
||||
} else if (effectAmount > 0 && alphaDyn >= alpha) {
|
||||
alphaDyn = alpha;
|
||||
effects = 0; // shut off effect
|
||||
effectFinished(this);
|
||||
}
|
||||
} else if (effects & EFFECT_SCALE) {
|
||||
scaleDyn += effectAmount * 0.01f;
|
||||
|
||||
if ((effectAmount < 0 && scaleDyn <= (effectTarget * 0.01f)) || (effectAmount > 0 && scaleDyn >= (effectTarget * 0.01f))) {
|
||||
scaleDyn = effectTarget * 0.01f;
|
||||
effects = 0; // shut off effect
|
||||
effectFinished(this);
|
||||
}
|
||||
} else if (effects & EFFECT_SHAKE) {
|
||||
if (effectShakeFrame == 0) {
|
||||
effectTargetInMS = OSTicksToMilliseconds(OSGetSystemTime()) + effectTarget;
|
||||
}
|
||||
uint32_t frame = ++effectShakeFrame % 10;
|
||||
|
||||
if (frame <= 1) {
|
||||
angleDyn = 0.0f;
|
||||
xoffsetDyn = 0;
|
||||
yoffsetDyn = 0;
|
||||
} else if (frame == 3) {
|
||||
angleDyn = -0.3f;
|
||||
xoffsetDyn = -1;
|
||||
yoffsetDyn = -2;
|
||||
} else if (frame == 5) {
|
||||
angleDyn = 0.3f;
|
||||
xoffsetDyn = -1;
|
||||
yoffsetDyn = 0;
|
||||
} else if (frame == 7) {
|
||||
angleDyn = 0.0f;
|
||||
xoffsetDyn = 0;
|
||||
yoffsetDyn = 1;
|
||||
} else if (frame == 9) {
|
||||
angleDyn = -0.3f;
|
||||
xoffsetDyn = 1;
|
||||
yoffsetDyn = -1;
|
||||
}
|
||||
|
||||
if (OSTicksToMilliseconds(OSGetSystemTime()) > effectTargetInMS) {
|
||||
angleDyn = 0.0f;
|
||||
xoffsetDyn = 0.0f;
|
||||
yoffsetDyn = 0.0f;
|
||||
effects = 0; // shut off effect
|
||||
effectShakeFrame = 0;
|
||||
effectTarget = 0;
|
||||
effectTargetInMS = 0;
|
||||
effectFinished(this);
|
||||
}
|
||||
}
|
||||
}
|
630
src/gui/GuiElement.h
Normal file
630
src/gui/GuiElement.h
Normal file
@ -0,0 +1,630 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "shaders/gx2_ext.h"
|
||||
#include "sigslot.h"
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <wchar.h>
|
||||
#pragma GCC diagnostic ignored "-Wvolatile"
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
|
||||
enum {
|
||||
EFFECT_NONE = 0x00,
|
||||
EFFECT_SLIDE_TOP = 0x01,
|
||||
EFFECT_SLIDE_BOTTOM = 0x02,
|
||||
EFFECT_SLIDE_RIGHT = 0x04,
|
||||
EFFECT_SLIDE_LEFT = 0x08,
|
||||
EFFECT_SLIDE_IN = 0x10,
|
||||
EFFECT_SLIDE_OUT = 0x20,
|
||||
EFFECT_SLIDE_FROM = 0x40,
|
||||
EFFECT_FADE = 0x80,
|
||||
EFFECT_SCALE = 0x100,
|
||||
EFFECT_COLOR_TRANSITION = 0x200,
|
||||
EFFECT_SHAKE = 0x400,
|
||||
};
|
||||
|
||||
enum {
|
||||
ALIGN_LEFT = 0x01,
|
||||
ALIGN_CENTER = 0x02,
|
||||
ALIGN_RIGHT = 0x04,
|
||||
ALIGN_TOP = 0x10,
|
||||
ALIGN_MIDDLE = 0x20,
|
||||
ALIGN_BOTTOM = 0x40,
|
||||
ALIGN_TOP_LEFT = ALIGN_LEFT | ALIGN_TOP,
|
||||
ALIGN_TOP_CENTER = ALIGN_CENTER | ALIGN_TOP,
|
||||
ALIGN_TOP_RIGHT = ALIGN_RIGHT | ALIGN_TOP,
|
||||
ALIGN_CENTERED = ALIGN_CENTER | ALIGN_MIDDLE,
|
||||
};
|
||||
|
||||
//!Forward declaration
|
||||
class GuiController;
|
||||
|
||||
|
||||
//!Primary GUI class. Most other classes inherit from this class.
|
||||
class GuiElement {
|
||||
public:
|
||||
//!Constructor
|
||||
GuiElement();
|
||||
|
||||
//!Destructor
|
||||
virtual ~GuiElement() {}
|
||||
|
||||
//!Set the element's parent
|
||||
//!\param e Pointer to parent element
|
||||
virtual void setParent(GuiElement *e) {
|
||||
parentElement = e;
|
||||
}
|
||||
|
||||
//!Gets the element's parent
|
||||
//!\return Pointer to parent element
|
||||
virtual GuiElement *getParent() {
|
||||
return parentElement;
|
||||
}
|
||||
|
||||
//!Gets the current leftmost coordinate of the element
|
||||
//!Considers horizontal alignment, x offset, width, and parent element's GetLeft() / GetWidth() values
|
||||
//!\return left coordinate
|
||||
virtual float getLeft();
|
||||
|
||||
//!Gets the current topmost coordinate of the element
|
||||
//!Considers vertical alignment, y offset, height, and parent element's GetTop() / GetHeight() values
|
||||
//!\return top coordinate
|
||||
virtual float getTop();
|
||||
|
||||
//!Gets the current Z coordinate of the element
|
||||
//!\return Z coordinate
|
||||
virtual float getDepth() {
|
||||
float zParent = 0.0f;
|
||||
|
||||
if (parentElement) {
|
||||
zParent = parentElement->getDepth();
|
||||
}
|
||||
|
||||
return zParent + zoffset;
|
||||
}
|
||||
|
||||
virtual float getCenterX(void) {
|
||||
float pCenterX = 0.0f;
|
||||
|
||||
if (parentElement) {
|
||||
pCenterX = parentElement->getCenterX();
|
||||
}
|
||||
|
||||
pCenterX += xoffset + xoffsetDyn;
|
||||
|
||||
if (alignment & ALIGN_LEFT) {
|
||||
float pWidth = 0.0f;
|
||||
float pScale = 0.0f;
|
||||
|
||||
if (parentElement) {
|
||||
pWidth = parentElement->getWidth();
|
||||
pScale = parentElement->getScaleX();
|
||||
}
|
||||
|
||||
pCenterX -= pWidth * 0.5f * pScale - width * 0.5f * getScaleX();
|
||||
} else if (alignment & ALIGN_RIGHT) {
|
||||
float pWidth = 0.0f;
|
||||
float pScale = 0.0f;
|
||||
|
||||
if (parentElement) {
|
||||
pWidth = parentElement->getWidth();
|
||||
pScale = parentElement->getScaleX();
|
||||
}
|
||||
|
||||
pCenterX += pWidth * 0.5f * pScale - width * 0.5f * getScaleX();
|
||||
}
|
||||
return pCenterX;
|
||||
}
|
||||
|
||||
virtual float getCenterY(void) {
|
||||
float pCenterY = 0.0f;
|
||||
|
||||
if (parentElement) {
|
||||
pCenterY = parentElement->getCenterY();
|
||||
}
|
||||
|
||||
pCenterY += yoffset + yoffsetDyn;
|
||||
|
||||
if (alignment & ALIGN_TOP) {
|
||||
float pHeight = 0.0f;
|
||||
float pScale = 0.0f;
|
||||
|
||||
if (parentElement) {
|
||||
pHeight = parentElement->getHeight();
|
||||
pScale = parentElement->getScaleY();
|
||||
}
|
||||
|
||||
pCenterY += pHeight * 0.5f * pScale - getHeight() * 0.5f * getScaleY();
|
||||
} else if (alignment & ALIGN_BOTTOM) {
|
||||
float pHeight = 0.0f;
|
||||
float pScale = 0.0f;
|
||||
|
||||
if (parentElement) {
|
||||
pHeight = parentElement->getHeight();
|
||||
pScale = parentElement->getScaleY();
|
||||
}
|
||||
|
||||
pCenterY -= pHeight * 0.5f * pScale - getHeight() * 0.5f * getScaleY();
|
||||
}
|
||||
return pCenterY;
|
||||
}
|
||||
|
||||
//!Gets elements xoffset
|
||||
virtual float getOffsetX() {
|
||||
return xoffset;
|
||||
}
|
||||
|
||||
//!Gets elements yoffset
|
||||
virtual float getOffsetY() {
|
||||
return yoffset;
|
||||
}
|
||||
|
||||
//!Gets the current width of the element. Does not currently consider the scale
|
||||
//!\return width
|
||||
virtual float getWidth() {
|
||||
return width;
|
||||
};
|
||||
|
||||
//!Gets the height of the element. Does not currently consider the scale
|
||||
//!\return height
|
||||
virtual float getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
//!Sets the size (width/height) of the element
|
||||
//!\param w Width of element
|
||||
//!\param h Height of element
|
||||
virtual void setSize(float w, float h) {
|
||||
width = w;
|
||||
height = h;
|
||||
}
|
||||
|
||||
//!Sets the element's visibility
|
||||
//!\param v Visibility (true = visible)
|
||||
virtual void setVisible(bool v) {
|
||||
visible = v;
|
||||
visibleChanged(this, v);
|
||||
}
|
||||
|
||||
//!Checks whether or not the element is visible
|
||||
//!\return true if visible, false otherwise
|
||||
virtual bool isVisible() const {
|
||||
return !isStateSet(STATE_HIDDEN) && visible;
|
||||
};
|
||||
|
||||
//!Checks whether or not the element is selectable
|
||||
//!\return true if selectable, false otherwise
|
||||
virtual bool isSelectable() {
|
||||
return !isStateSet(STATE_DISABLED) && selectable;
|
||||
}
|
||||
|
||||
virtual bool isDrawOverOnlyWhenSelected() {
|
||||
return drawOverOnlyWhenSelected;
|
||||
}
|
||||
|
||||
virtual void setdrawOverOnlyWhenSelected(bool s) {
|
||||
drawOverOnlyWhenSelected = s;
|
||||
}
|
||||
|
||||
//!Checks whether or not the element is clickable
|
||||
//!\return true if clickable, false otherwise
|
||||
virtual bool isClickable() {
|
||||
return !isStateSet(STATE_DISABLED) && clickable;
|
||||
}
|
||||
|
||||
//!Checks whether or not the element is holdable
|
||||
//!\return true if holdable, false otherwise
|
||||
virtual bool isHoldable() {
|
||||
return !isStateSet(STATE_DISABLED) && holdable;
|
||||
}
|
||||
|
||||
//!Sets whether or not the element is selectable
|
||||
//!\param s Selectable
|
||||
virtual void setSelectable(bool s) {
|
||||
selectable = s;
|
||||
}
|
||||
|
||||
//!Sets whether or not the element is clickable
|
||||
//!\param c Clickable
|
||||
virtual void setClickable(bool c) {
|
||||
clickable = c;
|
||||
}
|
||||
|
||||
//!Sets whether or not the element is holdable
|
||||
//!\param c Holdable
|
||||
virtual void setHoldable(bool d) {
|
||||
holdable = d;
|
||||
}
|
||||
|
||||
//!Sets the element's state
|
||||
//!\param s State (STATE_DEFAULT, STATE_SELECTED, STATE_CLICKED, STATE_DISABLED)
|
||||
//!\param c Controller channel (0-3, -1 = none)
|
||||
virtual void setState(int32_t s, int32_t c = -1) {
|
||||
if (c >= 0 && c < 5) {
|
||||
state[c] |= s;
|
||||
} else {
|
||||
for (int32_t i = 0; i < 5; i++) {
|
||||
state[i] |= s;
|
||||
}
|
||||
}
|
||||
stateChan = c;
|
||||
stateChanged(this, s, c);
|
||||
}
|
||||
|
||||
virtual void clearState(int32_t s, int32_t c = -1) {
|
||||
if (c >= 0 && c < 5) {
|
||||
state[c] &= ~s;
|
||||
} else {
|
||||
for (int32_t i = 0; i < 5; i++) {
|
||||
state[i] &= ~s;
|
||||
}
|
||||
}
|
||||
stateChan = c;
|
||||
stateChanged(this, s, c);
|
||||
}
|
||||
|
||||
virtual bool isStateSet(int32_t s, int32_t c = -1) const {
|
||||
if (c >= 0 && c < 5) {
|
||||
return (state[c] & s) != 0;
|
||||
} else {
|
||||
for (int32_t i = 0; i < 5; i++) {
|
||||
if ((state[i] & s) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//!Gets the element's current state
|
||||
//!\return state
|
||||
virtual int32_t getState(int32_t c = 0) {
|
||||
return state[c];
|
||||
};
|
||||
|
||||
//!Gets the controller channel that last changed the element's state
|
||||
//!\return Channel number (0-3, -1 = no channel)
|
||||
virtual int32_t getStateChan() {
|
||||
return stateChan;
|
||||
};
|
||||
|
||||
//!Resets the element's state to STATE_DEFAULT
|
||||
virtual void resetState() {
|
||||
for (int32_t i = 0; i < 5; i++) {
|
||||
state[i] = STATE_DEFAULT;
|
||||
}
|
||||
stateChan = -1;
|
||||
}
|
||||
|
||||
//!Sets the element's alpha value
|
||||
//!\param a alpha value
|
||||
virtual void setAlpha(float a) {
|
||||
alpha = a;
|
||||
}
|
||||
|
||||
//!Gets the element's alpha value
|
||||
//!Considers alpha, alphaDyn, and the parent element's getAlpha() value
|
||||
//!\return alpha
|
||||
virtual float getAlpha() {
|
||||
float a;
|
||||
|
||||
if (alphaDyn >= 0) {
|
||||
a = alphaDyn;
|
||||
} else {
|
||||
a = alpha;
|
||||
}
|
||||
|
||||
if (parentElement) {
|
||||
a = (a * parentElement->getAlpha());
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
//!Sets the element's scale
|
||||
//!\param s scale (1 is 100%)
|
||||
virtual void setScale(float s) {
|
||||
scaleX = s;
|
||||
scaleY = s;
|
||||
scaleZ = s;
|
||||
}
|
||||
|
||||
//!Sets the element's scale
|
||||
//!\param s scale (1 is 100%)
|
||||
virtual void setScaleX(float s) {
|
||||
scaleX = s;
|
||||
}
|
||||
|
||||
//!Sets the element's scale
|
||||
//!\param s scale (1 is 100%)
|
||||
virtual void setScaleY(float s) {
|
||||
scaleY = s;
|
||||
}
|
||||
|
||||
//!Sets the element's scale
|
||||
//!\param s scale (1 is 100%)
|
||||
virtual void setScaleZ(float s) {
|
||||
scaleZ = s;
|
||||
}
|
||||
|
||||
//!Gets the element's current scale
|
||||
//!Considers scale, scaleDyn, and the parent element's getScale() value
|
||||
virtual float getScale() {
|
||||
float s = 0.5f * (scaleX + scaleY) * scaleDyn;
|
||||
|
||||
if (parentElement) {
|
||||
s *= parentElement->getScale();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
//!Gets the element's current scale
|
||||
//!Considers scale, scaleDyn, and the parent element's getScale() value
|
||||
virtual float getScaleX() {
|
||||
float s = scaleX * scaleDyn;
|
||||
|
||||
if (parentElement) {
|
||||
s *= parentElement->getScaleX();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
//!Gets the element's current scale
|
||||
//!Considers scale, scaleDyn, and the parent element's getScale() value
|
||||
virtual float getScaleY() {
|
||||
float s = scaleY * scaleDyn;
|
||||
|
||||
if (parentElement) {
|
||||
s *= parentElement->getScaleY();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
//!Gets the element's current scale
|
||||
//!Considers scale, scaleDyn, and the parent element's getScale() value
|
||||
virtual float getScaleZ() {
|
||||
float s = scaleZ;
|
||||
|
||||
if (parentElement) {
|
||||
s *= parentElement->getScaleZ();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
//!Checks whether rumble was requested by the element
|
||||
//!\return true is rumble was requested, false otherwise
|
||||
virtual bool isRumbleActive() {
|
||||
return rumble;
|
||||
}
|
||||
|
||||
//!Sets whether or not the element is requesting a rumble event
|
||||
//!\param r true if requesting rumble, false if not
|
||||
virtual void setRumble(bool r) {
|
||||
rumble = r;
|
||||
}
|
||||
|
||||
//!Set an effect for the element
|
||||
//!\param e Effect to enable
|
||||
//!\param a Amount of the effect (usage varies on effect)
|
||||
//!\param t Target amount of the effect (usage varies on effect)
|
||||
virtual void setEffect(int32_t e, int32_t a, int32_t t = 0);
|
||||
|
||||
//!Sets an effect to be enabled on wiimote cursor over
|
||||
//!\param e Effect to enable
|
||||
//!\param a Amount of the effect (usage varies on effect)
|
||||
//!\param t Target amount of the effect (usage varies on effect)
|
||||
virtual void setEffectOnOver(int32_t e, int32_t a, int32_t t = 0);
|
||||
|
||||
//!Shortcut to SetEffectOnOver(EFFECT_SCALE, 4, 110)
|
||||
virtual void setEffectGrow() {
|
||||
setEffectOnOver(EFFECT_SCALE, 4, 110);
|
||||
}
|
||||
|
||||
//!Reset all applied effects
|
||||
virtual void resetEffects();
|
||||
|
||||
//!Gets the current element effects
|
||||
//!\return element effects
|
||||
virtual int32_t getEffect() const {
|
||||
return effects;
|
||||
}
|
||||
|
||||
//!\return true if element animation is on going
|
||||
virtual bool isAnimated() const {
|
||||
return (parentElement != 0) && (getEffect() > 0);
|
||||
}
|
||||
|
||||
//!Checks whether the specified coordinates are within the element's boundaries
|
||||
//!\param x X coordinate
|
||||
//!\param y Y coordinate
|
||||
//!\return true if contained within, false otherwise
|
||||
virtual bool isInside(float x, float y) {
|
||||
float rotatedX = x;
|
||||
float rotatedY = y;
|
||||
|
||||
if (getAngle() != 0.f) {
|
||||
// translate input point
|
||||
float tempX = x - getCenterX();
|
||||
float tempY = y - getCenterY();
|
||||
|
||||
// Conver to Rad
|
||||
auto angleInRad = (float) ((getAngle() * -1.0f) * M_PI / 180.0f);
|
||||
|
||||
// now apply rotation
|
||||
rotatedX = tempX * cos((angleInRad)) - tempY * sin(angleInRad);
|
||||
rotatedY = tempX * sin(angleInRad) + tempY * cos(angleInRad);
|
||||
|
||||
// translate back
|
||||
rotatedX = rotatedX + getCenterX();
|
||||
rotatedY = rotatedY + getCenterY();
|
||||
}
|
||||
|
||||
return (rotatedX > (this->getCenterX() - getScaleX() * getWidth() * 0.5f) && rotatedX < (this->getCenterX() + getScaleX() * getWidth() * 0.5f) && rotatedY > (this->getCenterY() - getScaleY() * getHeight() * 0.5f) && rotatedY < (this->getCenterY() + getScaleY() * getHeight() * 0.5f));
|
||||
}
|
||||
|
||||
//!Sets the element's position
|
||||
//!\param x X coordinate
|
||||
//!\param y Y coordinate
|
||||
virtual void setPosition(float x, float y) {
|
||||
xoffset = x;
|
||||
yoffset = y;
|
||||
}
|
||||
|
||||
//!Sets the element's position
|
||||
//!\param x X coordinate
|
||||
//!\param y Y coordinate
|
||||
//!\param z Z coordinate
|
||||
virtual void setPosition(float x, float y, float z) {
|
||||
xoffset = x;
|
||||
yoffset = y;
|
||||
zoffset = z;
|
||||
}
|
||||
|
||||
//!Gets whether or not the element is in STATE_SELECTED
|
||||
//!\return true if selected, false otherwise
|
||||
virtual int32_t getSelected() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//!Sets the element's alignment respective to its parent element
|
||||
//!Bitwise ALIGN_LEFT | ALIGN_RIGHT | ALIGN_CENTRE, ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE)
|
||||
//!\param align Alignment
|
||||
virtual void setAlignment(int32_t a) {
|
||||
alignment = a;
|
||||
}
|
||||
|
||||
//!Gets the element's alignment
|
||||
virtual int32_t getAlignment() const {
|
||||
return alignment;
|
||||
}
|
||||
|
||||
//!Angle of the object
|
||||
virtual void setAngle(float a) {
|
||||
angle = a;
|
||||
}
|
||||
|
||||
//!Angle of the object
|
||||
virtual float getAngle() const {
|
||||
float r_angle = angle;
|
||||
if (parentElement) { r_angle += parentElement->getAngle(); }
|
||||
r_angle += angleDyn;
|
||||
return r_angle;
|
||||
}
|
||||
|
||||
//!Called constantly to allow the element to respond to the current input data
|
||||
//!\param t Pointer to a GuiController, containing the current input data from PAD/WPAD/VPAD
|
||||
virtual void update([[maybe_unused]] GuiController *t) {}
|
||||
|
||||
//!Called constantly to redraw the element
|
||||
virtual void draw([[maybe_unused]] bool SRGBConversion) {}
|
||||
|
||||
//!Called constantly to process stuff in the element
|
||||
virtual void process() {}
|
||||
|
||||
//!Updates the element's effects (dynamic values)
|
||||
//!Called by Draw(), used for animation purposes
|
||||
virtual void updateEffects();
|
||||
|
||||
typedef struct _POINT {
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
} POINT;
|
||||
|
||||
enum {
|
||||
STATE_DEFAULT = 0,
|
||||
STATE_SELECTED = 0x01,
|
||||
STATE_CLICKED = 0x02,
|
||||
STATE_HELD = 0x04,
|
||||
STATE_OVER = 0x08,
|
||||
STATE_HIDDEN = 0x10,
|
||||
STATE_DISABLE_INPUT = 0x20,
|
||||
STATE_CLICKED_TOUCH = 0x40,
|
||||
STATE_DISABLED = 0x80
|
||||
};
|
||||
|
||||
//! Switch pointer from control to screen position
|
||||
POINT PtrToScreen(POINT p) {
|
||||
//! TODO for 3D
|
||||
//POINT r = { p.x + getLeft(), p.y + getTop() };
|
||||
return p;
|
||||
}
|
||||
|
||||
//! Switch pointer screen to control position
|
||||
POINT PtrToControl(POINT p) {
|
||||
//! TODO for 3D
|
||||
//POINT r = { p.x - getLeft(), p.y - getTop() };
|
||||
return p;
|
||||
}
|
||||
|
||||
//! Signals
|
||||
sigslot::signal2<GuiElement *, bool> visibleChanged;
|
||||
sigslot::signal3<GuiElement *, int32_t, int32_t> stateChanged;
|
||||
sigslot::signal1<GuiElement *> effectFinished;
|
||||
|
||||
protected:
|
||||
bool rumble; //!< Wiimote rumble (on/off) - set to on when this element requests a rumble event
|
||||
bool visible; //!< Visibility of the element. If false, Draw() is skipped
|
||||
bool selectable; //!< Whether or not this element selectable (can change to SELECTED state)
|
||||
bool clickable; //!< Whether or not this element is clickable (can change to CLICKED state)
|
||||
bool holdable; //!< Whether or not this element is holdable (can change to HELD state)
|
||||
bool drawOverOnlyWhenSelected; //!< Whether or not this element is holdable (can change to HELD state)
|
||||
float width; //!< Element width
|
||||
float height; //!< Element height
|
||||
float xoffset; //!< Element X offset
|
||||
float yoffset; //!< Element Y offset
|
||||
float zoffset; //!< Element Z offset
|
||||
float alpha; //!< Element alpha value (0-255)
|
||||
float angle; //!< Angle of the object (0-360)
|
||||
float scaleX; //!< Element scale (1 = 100%)
|
||||
float scaleY; //!< Element scale (1 = 100%)
|
||||
float scaleZ; //!< Element scale (1 = 100%)
|
||||
int32_t alignment; //!< Horizontal element alignment, respective to parent element
|
||||
int32_t state[5]; //!< Element state (DEFAULT, SELECTED, CLICKED, DISABLED)
|
||||
int32_t stateChan; //!< Which controller channel is responsible for the last change in state
|
||||
GuiElement *parentElement; //!< Parent element
|
||||
|
||||
//! TODO: Move me to some Animator class
|
||||
int32_t xoffsetDyn; //!< Element X offset, dynamic (added to xoffset value for animation effects)
|
||||
int32_t yoffsetDyn; //!< Element Y offset, dynamic (added to yoffset value for animation effects)
|
||||
float alphaDyn; //!< Element alpha, dynamic (multiplied by alpha value for blending/fading effects)
|
||||
float scaleDyn; //!< Element scale, dynamic (multiplied by alpha value for blending/fading effects)
|
||||
float angleDyn;
|
||||
int32_t effects; //!< Currently enabled effect(s). 0 when no effects are enabled
|
||||
int32_t effectAmount; //!< Effect amount. Used by different effects for different purposes
|
||||
int32_t effectTarget; //!< Effect target amount. Used by different effects for different purposes
|
||||
uint64_t effectTargetInMS; //!< Effect target amount in ms
|
||||
int32_t effectsOver; //!< Effects to enable when wiimote cursor is over this element. Copied to effects variable on over event
|
||||
int32_t effectAmountOver; //!< EffectAmount to set when wiimote cursor is over this element
|
||||
int32_t effectTargetOver; //!< EffectTarget to set when wiimote cursor is over this element
|
||||
int32_t effectShakeFrame;
|
||||
};
|
208
src/gui/GuiFrame.cpp
Normal file
208
src/gui/GuiFrame.cpp
Normal file
@ -0,0 +1,208 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#include "GuiFrame.h"
|
||||
|
||||
GuiFrame::GuiFrame(GuiFrame *p) {
|
||||
parent = p;
|
||||
width = 0;
|
||||
height = 0;
|
||||
dim = false;
|
||||
|
||||
if (parent) {
|
||||
parent->append(this);
|
||||
}
|
||||
}
|
||||
|
||||
GuiFrame::GuiFrame(float w, float h, GuiFrame *p) {
|
||||
parent = p;
|
||||
width = w;
|
||||
height = h;
|
||||
dim = false;
|
||||
|
||||
if (parent) {
|
||||
parent->append(this);
|
||||
}
|
||||
}
|
||||
|
||||
GuiFrame::~GuiFrame() {
|
||||
closing(this);
|
||||
|
||||
if (parent) {
|
||||
parent->remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiFrame::append(GuiElement *e) {
|
||||
if (e == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
remove(e);
|
||||
elements.push_back(e);
|
||||
e->setParent(this);
|
||||
}
|
||||
|
||||
void GuiFrame::insert(GuiElement *e, uint32_t index) {
|
||||
if (e == nullptr || (index >= elements.size())) {
|
||||
return;
|
||||
}
|
||||
|
||||
remove(e);
|
||||
elements.insert(elements.begin() + index, e);
|
||||
e->setParent(this);
|
||||
}
|
||||
|
||||
void GuiFrame::remove(GuiElement *e) {
|
||||
if (e == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < elements.size(); ++i) {
|
||||
if (e == elements[i]) {
|
||||
elements.erase(elements.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GuiFrame::removeAll() {
|
||||
elements.clear();
|
||||
}
|
||||
|
||||
void GuiFrame::close() {
|
||||
//Application::instance()->pushForDelete(this);
|
||||
}
|
||||
|
||||
void GuiFrame::dimBackground(bool d) {
|
||||
dim = d;
|
||||
}
|
||||
|
||||
GuiElement *GuiFrame::getGuiElementAt(uint32_t index) const {
|
||||
if (index >= elements.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return elements[index];
|
||||
}
|
||||
|
||||
uint32_t GuiFrame::getSize() {
|
||||
return elements.size();
|
||||
}
|
||||
|
||||
void GuiFrame::resetState() {
|
||||
GuiElement::resetState();
|
||||
|
||||
for (auto &element : elements) {
|
||||
element->resetState();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiFrame::setState(int32_t s, int32_t c) {
|
||||
GuiElement::setState(s, c);
|
||||
for (auto &element : elements) {
|
||||
element->setState(s, c);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiFrame::clearState(int32_t s, int32_t c) {
|
||||
GuiElement::clearState(s, c);
|
||||
|
||||
for (auto &element : elements) {
|
||||
element->clearState(s, c);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiFrame::setVisible(bool v) {
|
||||
visible = v;
|
||||
|
||||
for (auto &element : elements) {
|
||||
element->setVisible(v);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t GuiFrame::getSelected() {
|
||||
// find selected element
|
||||
int32_t found = -1;
|
||||
for (uint32_t i = 0; i < elements.size(); ++i) {
|
||||
if (elements[i]->isStateSet(STATE_SELECTED | STATE_OVER)) {
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
void GuiFrame::draw(bool SRGBConversion) {
|
||||
if (!this->isVisible() && parentElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (parentElement && dim) {
|
||||
//GXColor dimColor = (GXColor){0, 0, 0, 0x70};
|
||||
//Menu_DrawRectangle(0, 0, GetZPosition(), screenwidth,screenheight, &dimColor, false, true);
|
||||
}
|
||||
|
||||
//! render appended items next frame but allow stop of render if size is reached
|
||||
uint32_t size = elements.size();
|
||||
|
||||
for (uint32_t i = 0; i < size && i < elements.size(); ++i) {
|
||||
elements[i]->draw(SRGBConversion);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiFrame::updateEffects() {
|
||||
if (!this->isVisible() && parentElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
GuiElement::updateEffects();
|
||||
|
||||
//! render appended items next frame but allow stop of render if size is reached
|
||||
uint32_t size = elements.size();
|
||||
|
||||
for (uint32_t i = 0; i < size && i < elements.size(); ++i) {
|
||||
elements[i]->updateEffects();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiFrame::process() {
|
||||
if (!this->isVisible() && parentElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
GuiElement::process();
|
||||
|
||||
//! render appended items next frame but allow stop of render if size is reached
|
||||
uint32_t size = elements.size();
|
||||
|
||||
for (uint32_t i = 0; i < size && i < elements.size(); ++i) {
|
||||
elements[i]->process();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiFrame::update(GuiController *c) {
|
||||
if (isStateSet(STATE_DISABLED) && parentElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
//! update appended items next frame
|
||||
uint32_t size = elements.size();
|
||||
|
||||
for (uint32_t i = 0; i < size && i < elements.size(); ++i) {
|
||||
elements[i]->update(c);
|
||||
}
|
||||
}
|
131
src/gui/GuiFrame.h
Normal file
131
src/gui/GuiFrame.h
Normal file
@ -0,0 +1,131 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#ifndef GUI_FRAME_H_
|
||||
#define GUI_FRAME_H_
|
||||
|
||||
#include <gui/GuiElement.h>
|
||||
#include <gui/sigslot.h>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
//!Allows GuiElements to be grouped together into a "window"
|
||||
class GuiFrame : public GuiElement {
|
||||
public:
|
||||
//!Constructor
|
||||
GuiFrame(GuiFrame *parent = 0);
|
||||
|
||||
//!\overload
|
||||
//!\param w Width of window
|
||||
//!\param h Height of window
|
||||
GuiFrame(float w, float h, GuiFrame *parent = 0);
|
||||
|
||||
//!Destructor
|
||||
virtual ~GuiFrame();
|
||||
|
||||
//!Appends a GuiElement to the GuiFrame
|
||||
//!\param e The GuiElement to append. If it is already in the GuiFrame, it is removed first
|
||||
void append(GuiElement *e);
|
||||
|
||||
//!Inserts a GuiElement into the GuiFrame at the specified index
|
||||
//!\param e The GuiElement to insert. If it is already in the GuiFrame, it is removed first
|
||||
//!\param i Index in which to insert the element
|
||||
void insert(GuiElement *e, uint32_t i);
|
||||
|
||||
//!Removes the specified GuiElement from the GuiFrame
|
||||
//!\param e GuiElement to be removed
|
||||
void remove(GuiElement *e);
|
||||
|
||||
//!Removes all GuiElements
|
||||
void removeAll();
|
||||
|
||||
//!Bring element to front of the window
|
||||
void bringToFront(GuiElement *e) {
|
||||
remove(e);
|
||||
append(e);
|
||||
}
|
||||
|
||||
//!Returns the GuiElement at the specified index
|
||||
//!\param index The index of the element
|
||||
//!\return A pointer to the element at the index, NULL on error (eg: out of bounds)
|
||||
GuiElement *getGuiElementAt(uint32_t index) const;
|
||||
|
||||
//!Returns the size of the list of elements
|
||||
//!\return The size of the current element list
|
||||
uint32_t getSize();
|
||||
|
||||
//!Sets the visibility of the window
|
||||
//!\param v visibility (true = visible)
|
||||
void setVisible(bool v);
|
||||
|
||||
//!Resets the window's state to STATE_DEFAULT
|
||||
void resetState();
|
||||
|
||||
//!Sets the window's state
|
||||
//!\param s State
|
||||
void setState(int32_t s, int32_t c = -1);
|
||||
|
||||
void clearState(int32_t s, int32_t c = -1);
|
||||
|
||||
//!Gets the index of the GuiElement inside the window that is currently selected
|
||||
//!\return index of selected GuiElement
|
||||
int32_t getSelected();
|
||||
|
||||
//!Dim the Window's background
|
||||
void dimBackground(bool d);
|
||||
|
||||
//!Draws all the elements in this GuiFrame
|
||||
void draw(bool SRGBConversion);
|
||||
|
||||
//!Draws all the elements in this GuiFrame
|
||||
bool empty() {
|
||||
return elements.empty();
|
||||
}
|
||||
|
||||
//!Updates the window and all elements contains within
|
||||
//!Allows the GuiFrame and all elements to respond to the input data specified
|
||||
//!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD
|
||||
void update(GuiController *t);
|
||||
|
||||
//!virtual Close Window - this will put the object on the delete queue in MainWindow
|
||||
virtual void close();
|
||||
|
||||
//!virtual show window function
|
||||
virtual void show() {}
|
||||
|
||||
//!virtual hide window function
|
||||
virtual void hide() {}
|
||||
|
||||
//!virtual enter main loop function (blocking)
|
||||
virtual void exec() {}
|
||||
|
||||
//!virtual updateEffects which is called by the main loop
|
||||
virtual void updateEffects();
|
||||
|
||||
//!virtual process which is called by the main loop
|
||||
virtual void process();
|
||||
|
||||
//! Signals
|
||||
//! On Closing
|
||||
sigslot::signal1<GuiFrame *> closing;
|
||||
|
||||
protected:
|
||||
bool dim; //! Enable/disable dim of a window only
|
||||
GuiFrame *parent; //!< Parent Window
|
||||
std::vector<GuiElement *> elements; //!< Contains all elements within the GuiFrame
|
||||
};
|
||||
|
||||
#endif
|
174
src/gui/GuiImage.cpp
Normal file
174
src/gui/GuiImage.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#include "GuiImage.h"
|
||||
#include "shaders/ColorShader.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
GuiImage::GuiImage(int32_t w, int32_t h, const GX2Color &c, int32_t type) {
|
||||
internalInit(w, h);
|
||||
imgType = type;
|
||||
colorCount = ColorShader::cuColorVtxsSize / ColorShader::cuColorAttrSize;
|
||||
|
||||
colorVtxs = (uint8_t *) MEMAllocFromMappedMemoryForGX2Ex(colorCount * ColorShader::cuColorAttrSize, GX2_VERTEX_BUFFER_ALIGNMENT);
|
||||
colorVtxsCorrected = (uint8_t *) MEMAllocFromMappedMemoryForGX2Ex(colorCount * ColorShader::cuColorAttrSize, GX2_VERTEX_BUFFER_ALIGNMENT);
|
||||
if (colorVtxs && colorVtxsCorrected) {
|
||||
for (uint32_t i = 0; i < colorCount; i++) {
|
||||
setImageColor(c, i);
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc colorVtxs");
|
||||
}
|
||||
}
|
||||
|
||||
GuiImage::GuiImage(int32_t w, int32_t h, const GX2Color *c, uint32_t color_count, int32_t type) {
|
||||
internalInit(w, h);
|
||||
imgType = type;
|
||||
colorCount = ColorShader::cuColorVtxsSize / ColorShader::cuColorAttrSize;
|
||||
if (colorCount < color_count) {
|
||||
colorCount = color_count;
|
||||
}
|
||||
|
||||
colorVtxs = (uint8_t *) MEMAllocFromMappedMemoryForGX2Ex(colorCount * ColorShader::cuColorAttrSize, GX2_VERTEX_BUFFER_ALIGNMENT);
|
||||
colorVtxsCorrected = (uint8_t *) MEMAllocFromMappedMemoryForGX2Ex(colorCount * ColorShader::cuColorAttrSize, GX2_VERTEX_BUFFER_ALIGNMENT);
|
||||
if (colorVtxs && colorVtxsCorrected) {
|
||||
for (uint32_t i = 0; i < colorCount; i++) {
|
||||
// take the last as reference if not enough colors defined
|
||||
int32_t idx = (i < color_count) ? i : (color_count - 1);
|
||||
setImageColor(c[idx], i);
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc colorVtxs");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor for the GuiImage class.
|
||||
*/
|
||||
GuiImage::~GuiImage() {
|
||||
if (colorVtxs) {
|
||||
MEMFreeToMappedMemory(colorVtxs);
|
||||
colorVtxs = nullptr;
|
||||
}
|
||||
if (colorVtxsCorrected) {
|
||||
MEMFreeToMappedMemory(colorVtxsCorrected);
|
||||
colorVtxsCorrected = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiImage::internalInit(int32_t w, int32_t h) {
|
||||
width = w;
|
||||
height = h;
|
||||
tileHorizontal = -1;
|
||||
tileVertical = -1;
|
||||
imgType = IMAGE_COLOR;
|
||||
colorVtxsDirty = false;
|
||||
colorVtxs = nullptr;
|
||||
colorCount = 0;
|
||||
posVtxs = nullptr;
|
||||
texCoords = nullptr;
|
||||
vtxCount = 4;
|
||||
primitive = GX2_PRIMITIVE_MODE_QUADS;
|
||||
|
||||
imageAngle = 0.0f;
|
||||
blurDirection = glm::vec3(0.0f);
|
||||
positionOffsets = glm::vec3(0.0f);
|
||||
scaleFactor = glm::vec3(1.0f);
|
||||
colorIntensity = glm::vec4(1.0f);
|
||||
}
|
||||
|
||||
void GuiImage::setImageColor(const GX2Color &c, int32_t idx) {
|
||||
if (!colorVtxs || !colorVtxsCorrected) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx >= 0 && idx < (int32_t) colorCount) {
|
||||
colorVtxs[(idx << 2) + 0] = c.r;
|
||||
colorVtxs[(idx << 2) + 1] = c.g;
|
||||
colorVtxs[(idx << 2) + 2] = c.b;
|
||||
colorVtxs[(idx << 2) + 3] = c.a;
|
||||
|
||||
colorVtxsCorrected[(idx << 2) + 0] = SRGBComponentToRGB(c.r);
|
||||
colorVtxsCorrected[(idx << 2) + 1] = SRGBComponentToRGB(c.g);
|
||||
colorVtxsCorrected[(idx << 2) + 2] = SRGBComponentToRGB(c.b);
|
||||
colorVtxsCorrected[(idx << 2) + 3] = c.a;
|
||||
colorVtxsDirty = true;
|
||||
} else if (colorVtxs) {
|
||||
for (uint32_t i = 0; i < (ColorShader::cuColorVtxsSize / sizeof(uint8_t)); i += 4) {
|
||||
colorVtxs[i + 0] = c.r;
|
||||
colorVtxs[i + 1] = c.g;
|
||||
colorVtxs[i + 2] = c.b;
|
||||
colorVtxs[i + 3] = c.a;
|
||||
colorVtxsCorrected[i + 0] = SRGBComponentToRGB(c.r);
|
||||
colorVtxsCorrected[i + 1] = SRGBComponentToRGB(c.g);
|
||||
colorVtxsCorrected[i + 2] = SRGBComponentToRGB(c.b);
|
||||
colorVtxsCorrected[i + 3] = c.a;
|
||||
}
|
||||
colorVtxsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiImage::setSize(float w, float h) {
|
||||
width = w;
|
||||
height = h;
|
||||
}
|
||||
|
||||
#define DegToRad(a) ((a) *0.01745329252f)
|
||||
|
||||
void GuiImage::draw(bool SRGBConversion) {
|
||||
if (!this->isVisible() || tileVertical == 0 || tileHorizontal == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
float widthScaleFactor = 1.0f / (float) 1280;
|
||||
float heightScaleFactor = 1.0f / (float) 720;
|
||||
float depthScaleFactor = 1.0f / (float) 720;
|
||||
|
||||
float currScaleX = getScaleX();
|
||||
float currScaleY = getScaleY();
|
||||
|
||||
positionOffsets[0] = getCenterX() * widthScaleFactor * 2.0f;
|
||||
positionOffsets[1] = getCenterY() * heightScaleFactor * 2.0f;
|
||||
positionOffsets[2] = getDepth() * depthScaleFactor * 2.0f;
|
||||
|
||||
scaleFactor[0] = currScaleX * getWidth() * widthScaleFactor;
|
||||
scaleFactor[1] = currScaleY * getHeight() * heightScaleFactor;
|
||||
scaleFactor[2] = getScaleZ();
|
||||
|
||||
//! add other colors intensities parameters
|
||||
colorIntensity[3] = getAlpha();
|
||||
|
||||
//! angle of the object
|
||||
imageAngle = DegToRad(getAngle());
|
||||
|
||||
if (colorVtxsDirty && colorVtxs) {
|
||||
//! flush color vertex only on main GX2 thread
|
||||
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, colorVtxs, colorCount * ColorShader::cuColorAttrSize);
|
||||
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, colorVtxsCorrected, colorCount * ColorShader::cuColorAttrSize);
|
||||
colorVtxsDirty = false;
|
||||
}
|
||||
|
||||
if (imgType == IMAGE_COLOR && colorVtxs && colorVtxsCorrected) {
|
||||
ColorShader::instance()->setShaders();
|
||||
ColorShader::instance()->setAttributeBuffer(SRGBConversion ? colorVtxsCorrected : colorVtxs, posVtxs, vtxCount);
|
||||
ColorShader::instance()->setAngle(imageAngle);
|
||||
ColorShader::instance()->setOffset(positionOffsets);
|
||||
ColorShader::instance()->setScale(scaleFactor);
|
||||
ColorShader::instance()->setColorIntensity(colorIntensity);
|
||||
ColorShader::instance()->draw(primitive, vtxCount);
|
||||
}
|
||||
}
|
95
src/gui/GuiImage.h
Normal file
95
src/gui/GuiImage.h
Normal file
@ -0,0 +1,95 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "shaders/Shader.h"
|
||||
#include "shaders/gx2_ext.h"
|
||||
#include <gui/GuiElement.h>
|
||||
|
||||
//!Display, manage, and manipulate images in the GUI
|
||||
class GuiImage : public GuiElement {
|
||||
public:
|
||||
enum ImageTypes {
|
||||
IMAGE_COLOR
|
||||
};
|
||||
|
||||
//!\overload
|
||||
//!Creates an image filled with the specified color
|
||||
//!\param w Image width
|
||||
//!\param h Image height
|
||||
//!\param c Array with 4 x image color (BL, BR, TL, TR)
|
||||
GuiImage(int32_t w, int32_t h, const GX2Color &c, int32_t imgType = IMAGE_COLOR);
|
||||
|
||||
GuiImage(int32_t w, int32_t h, const GX2Color *c, uint32_t colorCount = 1, int32_t imgType = IMAGE_COLOR);
|
||||
|
||||
//!Destructor
|
||||
~GuiImage() override;
|
||||
|
||||
//!Sets the number of times to draw the image horizontally
|
||||
//!\param t Number of times to draw the image
|
||||
void setTileHorizontal(int32_t t) {
|
||||
tileHorizontal = t;
|
||||
}
|
||||
|
||||
//!Sets the number of times to draw the image vertically
|
||||
//!\param t Number of times to draw the image
|
||||
void setTileVertical(int32_t t) {
|
||||
tileVertical = t;
|
||||
}
|
||||
|
||||
//!Constantly called to draw the image
|
||||
void draw(bool SRGBConversion) override;
|
||||
|
||||
//!Change ImageColor
|
||||
void setImageColor(const GX2Color &c, int32_t idx = -1);
|
||||
|
||||
//!Change ImageColor
|
||||
void setSize(float w, float h) override;
|
||||
|
||||
void setBlurDirection(uint8_t dir, float value) {
|
||||
if (dir < 2) {
|
||||
blurDirection[dir] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void setColorIntensity(const glm::vec4 &col) {
|
||||
colorIntensity = col;
|
||||
}
|
||||
|
||||
protected:
|
||||
void internalInit(int32_t w, int32_t h);
|
||||
|
||||
int32_t imgType; //!< Type of image data (IMAGE_TEXTURE, IMAGE_COLOR, IMAGE_DATA)
|
||||
int32_t tileHorizontal; //!< Number of times to draw (tile) the image horizontally
|
||||
int32_t tileVertical; //!< Number of times to draw (tile) the image vertically
|
||||
|
||||
//! Internally used variables for rendering
|
||||
uint8_t *colorVtxs;
|
||||
uint8_t *colorVtxsCorrected;
|
||||
uint32_t colorCount;
|
||||
bool colorVtxsDirty;
|
||||
glm::vec3 positionOffsets;
|
||||
glm::vec3 scaleFactor;
|
||||
glm::vec4 colorIntensity;
|
||||
float imageAngle;
|
||||
glm::vec3 blurDirection;
|
||||
|
||||
const float *posVtxs;
|
||||
const float *texCoords;
|
||||
uint32_t vtxCount;
|
||||
int32_t primitive;
|
||||
};
|
206
src/gui/GuiText.cpp
Normal file
206
src/gui/GuiText.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#include "GuiText.h"
|
||||
#include "SchriftGX2.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
SchriftGX2 *GuiText::presentFont = nullptr;
|
||||
int32_t GuiText::presetSize = 20;
|
||||
int32_t GuiText::presetAlignment = ALIGN_CENTERED;
|
||||
GX2ColorF32 GuiText::presetColor = (GX2ColorF32){1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
/**
|
||||
* Constructor for the GuiText class.
|
||||
*/
|
||||
|
||||
GuiText::GuiText() {
|
||||
text = nullptr;
|
||||
size = presetSize;
|
||||
currentSize = size;
|
||||
color = glm::vec4(presetColor.r, presetColor.g, presetColor.b, presetColor.a);
|
||||
colorCorrected = {SRGBComponentToRGB((uint8_t) (color.r * 255.0f)) / 255.0f,
|
||||
SRGBComponentToRGB((uint8_t) (color.g * 255.0f)) / 255.0f,
|
||||
SRGBComponentToRGB((uint8_t) (color.b * 255.0f)) / 255.0f,
|
||||
color.a};
|
||||
alpha = presetColor.a;
|
||||
alignment = presetAlignment;
|
||||
textWidth = 0;
|
||||
textHeight = 0;
|
||||
font = presentFont;
|
||||
defaultBlur = 4.0f;
|
||||
blurGlowIntensity = 0.0f;
|
||||
blurAlpha = 0.0f;
|
||||
blurGlowColor = glm::vec4(0.0f);
|
||||
width = 0;
|
||||
height = 0;
|
||||
}
|
||||
|
||||
GuiText::GuiText(const char *t, int s, const glm::vec4 &c) {
|
||||
text = nullptr;
|
||||
size = s;
|
||||
currentSize = size;
|
||||
color = c;
|
||||
alpha = c[3];
|
||||
alignment = ALIGN_CENTER | ALIGN_MIDDLE;
|
||||
font = presentFont;
|
||||
textWidth = 0;
|
||||
textHeight = 0;
|
||||
defaultBlur = 4.0f;
|
||||
blurGlowIntensity = 0.0f;
|
||||
blurAlpha = 0.0f;
|
||||
blurGlowColor = glm::vec4(0.0f);
|
||||
|
||||
if (t) {
|
||||
std::lock_guard<std::mutex> textLock(mTextLock);
|
||||
text = SchriftGX2::charToWideChar(t);
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
|
||||
textHeightDirty = true;
|
||||
textWidthDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor for the GuiText class.
|
||||
*/
|
||||
GuiText::~GuiText() {
|
||||
std::lock_guard<std::mutex> textLock(mTextLock);
|
||||
delete[] text;
|
||||
|
||||
text = nullptr;
|
||||
}
|
||||
|
||||
void GuiText::setText(const char *t) {
|
||||
std::lock_guard<std::mutex> textLock(mTextLock);
|
||||
delete[] text;
|
||||
|
||||
text = nullptr;
|
||||
|
||||
if (t) {
|
||||
text = SchriftGX2::charToWideChar(t);
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
textHeightDirty = true;
|
||||
textWidthDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiText::setPresets(int sz, const glm::vec4 &c, int w, int a) {
|
||||
presetSize = sz;
|
||||
presetColor = (GX2ColorF32){(float) c.r / 255.0f, (float) c.g / 255.0f, (float) c.b / 255.0f, (float) c.a / 255.0f};
|
||||
presetMaxWidth = w;
|
||||
presetAlignment = a;
|
||||
}
|
||||
|
||||
void GuiText::setPresetFont(SchriftGX2 *f) {
|
||||
presentFont = f;
|
||||
}
|
||||
|
||||
void GuiText::setFontSize(int s) {
|
||||
std::lock_guard<std::mutex> textLock(mTextLock);
|
||||
size = s;
|
||||
}
|
||||
|
||||
void GuiText::setColor(const glm::vec4 &c) {
|
||||
color = c;
|
||||
alpha = c[3];
|
||||
|
||||
colorCorrected = {SRGBComponentToRGB((uint8_t) (color.r * 255.0f)) / 255.0f,
|
||||
SRGBComponentToRGB((uint8_t) (color.g * 255.0f)) / 255.0f,
|
||||
SRGBComponentToRGB((uint8_t) (color.b * 255.0f)) / 255.0f,
|
||||
color.a};
|
||||
}
|
||||
|
||||
void GuiText::setBlurGlowColor(float blur, const glm::vec4 &c) {
|
||||
blurGlowColor = c;
|
||||
blurGlowIntensity = blur;
|
||||
blurAlpha = c[3];
|
||||
}
|
||||
|
||||
/**
|
||||
* Change font
|
||||
*/
|
||||
bool GuiText::setFont(SchriftGX2 *f) {
|
||||
std::lock_guard<std::mutex> textLock(mTextLock);
|
||||
if (!f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
font = f;
|
||||
textHeightDirty = true;
|
||||
textWidthDirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the text on screen
|
||||
*/
|
||||
void GuiText::draw(bool SRGBConversion) {
|
||||
if (!text || !font) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> textLock(mTextLock);
|
||||
|
||||
color[3] = getAlpha();
|
||||
blurGlowColor[3] = blurAlpha * getAlpha();
|
||||
|
||||
float x_pos = getCenterX();
|
||||
float y_pos = getCenterY();
|
||||
|
||||
if (alignment & ALIGN_TOP) {
|
||||
y_pos -= getTextHeight();
|
||||
} else if (alignment & ALIGN_MIDDLE) {
|
||||
y_pos -= getTextHeight() / 2.0f;
|
||||
}
|
||||
if (alignment & ALIGN_RIGHT) {
|
||||
x_pos -= getTextWidth();
|
||||
} else if (alignment & ALIGN_CENTER) {
|
||||
x_pos -= getTextWidth() / 2.0f;
|
||||
}
|
||||
|
||||
font->drawText(x_pos, y_pos, getDepth(), text, currentSize, SRGBConversion ? colorCorrected : color, alignment, getTextWidth(), defaultBlur, blurGlowIntensity, blurGlowColor);
|
||||
}
|
||||
|
||||
void GuiText::updateTextSize() {
|
||||
int newSize = size * getScale();
|
||||
if (newSize != currentSize) {
|
||||
currentSize = newSize;
|
||||
textWidthDirty = true;
|
||||
textHeightDirty = true;
|
||||
}
|
||||
|
||||
if (textWidthDirty && font) {
|
||||
textWidth = font->getWidth(text, currentSize);
|
||||
textWidthDirty = false;
|
||||
}
|
||||
if (textHeightDirty && font) {
|
||||
textHeight = font->getHeight(text, currentSize);
|
||||
textHeightDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiText::process() {
|
||||
GuiElement::process();
|
||||
}
|
104
src/gui/GuiText.h
Normal file
104
src/gui/GuiText.h
Normal file
@ -0,0 +1,104 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "GuiElement.h"
|
||||
#include <mutex>
|
||||
//!Forward declaration
|
||||
class SchriftGX2;
|
||||
|
||||
//!Display, manage, and manipulate text in the GUI
|
||||
class GuiText : public GuiElement {
|
||||
public:
|
||||
//!Constructor
|
||||
GuiText();
|
||||
//!\param t Text
|
||||
//!\param s Font size
|
||||
//!\param c Font color
|
||||
GuiText(const char *t, int32_t s, const glm::vec4 &c);
|
||||
//!Destructor
|
||||
~GuiText() override;
|
||||
//!Sets the text of the GuiText element
|
||||
//!\param t Text
|
||||
virtual void setText(const char *t);
|
||||
//!Sets up preset values to be used by GuiText(t)
|
||||
//!Useful when print32_ting multiple text elements, all with the same attributes set
|
||||
//!\param sz Font size
|
||||
//!\param c Font color
|
||||
//!\param w Maximum width of texture background (for text wrapping)
|
||||
//!\param wrap Wrapmode when w>0
|
||||
//!\param a Text alignment
|
||||
static void setPresets(int32_t sz, const glm::vec4 &c, int32_t w, int32_t a);
|
||||
static void setPresetFont(SchriftGX2 *font);
|
||||
//!Sets the font size
|
||||
//!\param s Font size
|
||||
void setFontSize(int32_t s);
|
||||
|
||||
//!Sets the font color
|
||||
//!\param c Font color
|
||||
void setColor(const glm::vec4 &c);
|
||||
|
||||
void setBlurGlowColor(float blurint32_tensity, const glm::vec4 &c);
|
||||
|
||||
void setTextBlur(float blur) { defaultBlur = blur; }
|
||||
//!Get the original text as char
|
||||
[[nodiscard]] virtual const wchar_t *getText() const { return text; }
|
||||
|
||||
//!Get fontsize
|
||||
[[nodiscard]] int32_t getFontSize() const { return size; };
|
||||
|
||||
//!Change the font
|
||||
bool setFont(SchriftGX2 *font);
|
||||
|
||||
//!Constantly called to draw the text
|
||||
void draw(bool SRGBConversion) override;
|
||||
void process() override;
|
||||
|
||||
[[nodiscard]] int32_t getTextWidth() const {
|
||||
return textWidth;
|
||||
}
|
||||
[[nodiscard]] int32_t getTextHeight() const {
|
||||
return textHeight;
|
||||
}
|
||||
|
||||
|
||||
void updateTextSize();
|
||||
|
||||
protected:
|
||||
static SchriftGX2 *presentFont;
|
||||
static int32_t presetSize;
|
||||
static int32_t presetMaxWidth;
|
||||
static int32_t presetAlignment;
|
||||
static GX2ColorF32 presetColor;
|
||||
|
||||
wchar_t *text;
|
||||
int32_t size; //!< Font size
|
||||
SchriftGX2 *font;
|
||||
int32_t textWidth;
|
||||
bool textWidthDirty = true;
|
||||
int32_t textHeight{};
|
||||
bool textHeightDirty = true;
|
||||
int32_t currentSize;
|
||||
glm::vec4 color{};
|
||||
glm::vec4 colorCorrected{};
|
||||
float defaultBlur;
|
||||
float blurGlowIntensity;
|
||||
float blurAlpha;
|
||||
glm::vec4 blurGlowColor{};
|
||||
|
||||
std::mutex mTextLock;
|
||||
};
|
98
src/gui/Notification.cpp
Normal file
98
src/gui/Notification.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
#include "Notification.h"
|
||||
|
||||
Notification::Notification(const std::string &overlayText,
|
||||
NotificationStatus status,
|
||||
float delayBeforeFadeoutInSeconds,
|
||||
float shakeDuration,
|
||||
GX2Color textColor,
|
||||
GX2Color backgroundColor,
|
||||
void (*finishFunc)(NotificationModuleHandle, void *),
|
||||
void *context,
|
||||
void (*removedFromOverlayCallback)(Notification *)) : GuiFrame(0, 0), mBackground(0, 0, backgroundColor) {
|
||||
mFinishFunction = finishFunc;
|
||||
mFinishFunctionContext = context;
|
||||
mRemovedFromOverlayCallback = removedFromOverlayCallback;
|
||||
mDelayBeforeFadeoutInSeconds = delayBeforeFadeoutInSeconds;
|
||||
mShakeDurationInSeconds = shakeDuration;
|
||||
mBackground.setImageColor(backgroundColor);
|
||||
|
||||
mNotificationText.setColor({textColor.r / 255.0f, textColor.g / 255.0f, textColor.b / 255.0f, textColor.a / 255.0f});
|
||||
mNotificationText.setPosition(0, 0);
|
||||
mNotificationText.setFontSize(20);
|
||||
mNotificationText.setAlignment(ALIGN_CENTERED);
|
||||
|
||||
updateStatus(status);
|
||||
|
||||
if (!overlayText.empty()) {
|
||||
updateText(overlayText.c_str());
|
||||
}
|
||||
|
||||
mWaitForReset = true;
|
||||
|
||||
append(&mBackground);
|
||||
append(&mNotificationText);
|
||||
}
|
||||
|
||||
Notification::~Notification() {
|
||||
finishFunction();
|
||||
remove(&mNotificationText);
|
||||
remove(&mBackground);
|
||||
}
|
||||
|
||||
void Notification::process() {
|
||||
GuiFrame::process();
|
||||
|
||||
if (mWaitForReset) {
|
||||
mTimer.reset();
|
||||
mWaitForReset = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mInternalStatus == NOTIFICATION_STATUS_WAIT) {
|
||||
if (mTimer.elapsed() >= mDelayBeforeFadeoutInSeconds) {
|
||||
mInternalStatus = NOTIFICATION_STATUS_REQUESTED_FADE_OUT_AND_EXIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Notification::finishFunction() {
|
||||
if (!mFinishFunctionCalled && mFinishFunction) {
|
||||
mFinishFunction(this->getHandle(), mFinishFunctionContext);
|
||||
mFinishFunctionCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Notification::draw(bool SRGBConversion) {
|
||||
if (!mPositionSet) {
|
||||
return;
|
||||
}
|
||||
if (mTextDirty) {
|
||||
mNotificationText.updateTextSize();
|
||||
mTextDirty = false;
|
||||
}
|
||||
width = (float) mNotificationText.getTextWidth() + 25;
|
||||
height = (float) mNotificationText.getTextHeight() + 25;
|
||||
|
||||
mBackground.setSize(width, height);
|
||||
if (width > 25 || height > 25) {
|
||||
GuiFrame::draw(SRGBConversion);
|
||||
}
|
||||
}
|
||||
|
||||
void Notification::updateStatus(NotificationStatus newStatus) {
|
||||
switch (newStatus) {
|
||||
case NOTIFICATION_STATUS_INFO:
|
||||
mInternalStatus = NOTIFICATION_STATUS_WAIT;
|
||||
break;
|
||||
case NOTIFICATION_STATUS_ERROR:
|
||||
mInternalStatus = NOTIFICATION_STATUS_REQUESTED_SHAKE;
|
||||
break;
|
||||
case NOTIFICATION_STATUS_IN_PROGRESS:
|
||||
mInternalStatus = NOTIFICATION_STATUS_NOTHING;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
mWaitForReset = true;
|
||||
this->mStatus = newStatus;
|
||||
}
|
111
src/gui/Notification.h
Normal file
111
src/gui/Notification.h
Normal file
@ -0,0 +1,111 @@
|
||||
#pragma once
|
||||
#include "GuiFrame.h"
|
||||
#include "GuiImage.h"
|
||||
#include "GuiText.h"
|
||||
#include "Timer.h"
|
||||
#include "utils/logger.h"
|
||||
#include <notifications/notification_defines.h>
|
||||
|
||||
typedef enum {
|
||||
NOTIFICATION_STATUS_INFO,
|
||||
NOTIFICATION_STATUS_ERROR,
|
||||
NOTIFICATION_STATUS_IN_PROGRESS,
|
||||
} NotificationStatus;
|
||||
|
||||
typedef enum {
|
||||
NOTIFICATION_STATUS_NOTHING,
|
||||
NOTIFICATION_STATUS_WAIT,
|
||||
NOTIFICATION_STATUS_REQUESTED_SHAKE,
|
||||
NOTIFICATION_STATUS_EFFECT,
|
||||
NOTIFICATION_STATUS_REQUESTED_FADE_OUT_AND_EXIT,
|
||||
NOTIFICATION_STATUS_REQUESTED_EXIT,
|
||||
} NotificationInternalStatus;
|
||||
|
||||
class OverlayFrame;
|
||||
|
||||
class Notification : public GuiFrame {
|
||||
|
||||
public:
|
||||
friend class OverlayFrame;
|
||||
explicit Notification(const std::string &overlayText,
|
||||
NotificationStatus status = NOTIFICATION_STATUS_INFO,
|
||||
float delayBeforeFadeoutInSeconds = 2.0f,
|
||||
float shakeDuration = 0.5f,
|
||||
GX2Color textColor = {255, 255, 255, 255},
|
||||
GX2Color backgroundColor = {100, 100, 100, 255},
|
||||
void (*finishFunc)(NotificationModuleHandle, void *) = nullptr,
|
||||
void *context = nullptr,
|
||||
void (*removedFromOverlayCallback)(Notification *) = nullptr);
|
||||
|
||||
~Notification() override;
|
||||
|
||||
void process() override;
|
||||
void draw(bool SRGBConversion) override;
|
||||
|
||||
void finishFunction();
|
||||
|
||||
void updateText(const char *text) {
|
||||
mNotificationText.setText(text);
|
||||
mTextDirty = true;
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
|
||||
void updateBackgroundColor(GX2Color color) {
|
||||
mBackground.setImageColor(color);
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
|
||||
void updateTextColor(GX2Color textColor) {
|
||||
mNotificationText.setColor({textColor.r / 255.0f, textColor.g / 255.0f, textColor.b / 255.0f, textColor.a / 255.0f});
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
|
||||
void updateStatus(NotificationStatus newStatus);
|
||||
|
||||
NotificationStatus getStatus() {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
uint32_t getHandle() {
|
||||
return (uint32_t) this;
|
||||
}
|
||||
|
||||
void updateWaitDuration(float duration) {
|
||||
this->mDelayBeforeFadeoutInSeconds = duration;
|
||||
}
|
||||
|
||||
void updateShakeDuration(float duration) {
|
||||
this->mShakeDurationInSeconds = duration;
|
||||
}
|
||||
|
||||
void callDeleteCallback() {
|
||||
if (mRemovedFromOverlayCallback != nullptr) {
|
||||
mRemovedFromOverlayCallback(this);
|
||||
mRemovedFromOverlayCallback = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void setPosition(float x, float y) override {
|
||||
GuiElement::setPosition(x, y);
|
||||
mPositionSet = true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void(NotificationModuleHandle, void *)> mFinishFunction;
|
||||
std::function<void(Notification *)> mRemovedFromOverlayCallback;
|
||||
|
||||
void *mFinishFunctionContext;
|
||||
GuiImage mBackground;
|
||||
GuiText mNotificationText;
|
||||
Timer mTimer;
|
||||
float mDelayBeforeFadeoutInSeconds;
|
||||
float mShakeDurationInSeconds;
|
||||
bool mFinishFunctionCalled = false;
|
||||
bool mWaitForReset = false;
|
||||
|
||||
bool mTextDirty = false;
|
||||
bool mPositionSet = false;
|
||||
|
||||
NotificationStatus mStatus = NOTIFICATION_STATUS_INFO;
|
||||
NotificationInternalStatus mInternalStatus = NOTIFICATION_STATUS_NOTHING;
|
||||
};
|
72
src/gui/OverlayFrame.cpp
Normal file
72
src/gui/OverlayFrame.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
#include "OverlayFrame.h"
|
||||
|
||||
void OverlayFrame::addNotification(std::shared_ptr<Notification> status) {
|
||||
status->setParent(this);
|
||||
append(status.get());
|
||||
status->setAlignment(ALIGN_TOP_LEFT);
|
||||
status->setEffect(EFFECT_FADE, 55, 255);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(gNotificationListMutex);
|
||||
list.push_front(std::move(status));
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayFrame::OnFadeOutFinished(GuiElement *element) {
|
||||
auto *item = dynamic_cast<Notification *>(element);
|
||||
if (item) {
|
||||
item->mInternalStatus = NOTIFICATION_STATUS_REQUESTED_EXIT;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to fade out item: dynamic cast failed");
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayFrame::OnShakeFinished(GuiElement *element) {
|
||||
auto *item = dynamic_cast<Notification *>(element);
|
||||
if (item) {
|
||||
item->mInternalStatus = NOTIFICATION_STATUS_WAIT;
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayFrame::clearElements() {
|
||||
std::lock_guard<std::mutex> lock(gNotificationListMutex);
|
||||
for (auto &element : list) {
|
||||
remove(element.get());
|
||||
}
|
||||
list.clear();
|
||||
}
|
||||
|
||||
void OverlayFrame::process() {
|
||||
GuiFrame::process();
|
||||
|
||||
std::lock_guard<std::mutex> lock(gNotificationListMutex);
|
||||
|
||||
float offset = -25.0f;
|
||||
for (auto &item : list) {
|
||||
item->process();
|
||||
item->setPosition(25, offset);
|
||||
offset -= (item->getHeight() + 10.0f);
|
||||
if (item->mInternalStatus == NOTIFICATION_STATUS_REQUESTED_FADE_OUT_AND_EXIT) {
|
||||
item->resetEffects();
|
||||
item->setEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT | EFFECT_SLIDE_FROM, 30);
|
||||
item->effectFinished.connect(this, &OverlayFrame::OnFadeOutFinished);
|
||||
item->finishFunction();
|
||||
item->mInternalStatus = NOTIFICATION_STATUS_EFFECT;
|
||||
} else if (item->mInternalStatus == NOTIFICATION_STATUS_REQUESTED_SHAKE) {
|
||||
item->resetEffects();
|
||||
// shake for fixed duration, even if we drop frames
|
||||
item->setEffect(EFFECT_SHAKE, 0, (int32_t) (item->mShakeDurationInSeconds * 1000));
|
||||
item->effectFinished.connect(this, &OverlayFrame::OnShakeFinished);
|
||||
item->mInternalStatus = NOTIFICATION_STATUS_EFFECT;
|
||||
}
|
||||
}
|
||||
auto oit = list.before_begin(), it = std::next(oit);
|
||||
while (it != list.end()) {
|
||||
if ((*it)->mInternalStatus == NOTIFICATION_STATUS_REQUESTED_EXIT) {
|
||||
(*it)->callDeleteCallback();
|
||||
remove((*it).get());
|
||||
list.erase_after(oit);
|
||||
break;
|
||||
}
|
||||
oit = it++;
|
||||
}
|
||||
}
|
28
src/gui/OverlayFrame.h
Normal file
28
src/gui/OverlayFrame.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "GuiFrame.h"
|
||||
#include "Notification.h"
|
||||
#include "sigslot.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/utils.h"
|
||||
#include <forward_list>
|
||||
|
||||
class OverlayFrame : public GuiFrame, public sigslot::has_slots<> {
|
||||
|
||||
public:
|
||||
OverlayFrame(int w, int h) : GuiFrame(w, h) {
|
||||
}
|
||||
~OverlayFrame() override = default;
|
||||
|
||||
void addNotification(std::shared_ptr<Notification> status);
|
||||
|
||||
void OnFadeOutFinished(GuiElement *element);
|
||||
|
||||
void OnShakeFinished(GuiElement *element);
|
||||
|
||||
void process() override;
|
||||
|
||||
void clearElements();
|
||||
|
||||
private:
|
||||
std::forward_list<std::shared_ptr<Notification>> list;
|
||||
};
|
621
src/gui/SchriftGX2.cpp
Normal file
621
src/gui/SchriftGX2.cpp
Normal file
@ -0,0 +1,621 @@
|
||||
/*
|
||||
* SchriftGX2 is a wrapper class for libFreeType which renders a compiled
|
||||
* FreeType parsable font so a GX texture for Wii homebrew development.
|
||||
* Copyright (C) 2008 Armin Tamzarian
|
||||
* Modified by Dimok, 2015 for WiiU GX2
|
||||
*
|
||||
* This file is part of SchriftGX2.
|
||||
*
|
||||
* SchriftGX2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* SchriftGX2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SchriftGX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SchriftGX2.h"
|
||||
#include "schrift.h"
|
||||
#include "shaders/Texture2DShader.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* Default constructor for the SchriftGX2 class.
|
||||
*/
|
||||
SchriftGX2::SchriftGX2(const uint8_t *fontBuffer, uint32_t bufferSize) {
|
||||
GX2InitSampler(&ftSampler, GX2_TEX_CLAMP_MODE_CLAMP_BORDER, GX2_TEX_XY_FILTER_MODE_LINEAR);
|
||||
ftPointSize = 0;
|
||||
|
||||
pFont.xScale = 20;
|
||||
pFont.yScale = 20,
|
||||
pFont.flags = SFT_DOWNWARD_Y;
|
||||
pFont.font = sft_loadmem(fontBuffer, bufferSize);
|
||||
if (!pFont.font) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load font!!");
|
||||
} else {
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
|
||||
uint32_t heapSize = 1024 * 1024;
|
||||
glyphHeap = (uint8_t *) MEMAllocFromMappedMemoryForGX2Ex(heapSize, 0x100);
|
||||
if (!glyphHeap) {
|
||||
heapSize = 512 * 1024;
|
||||
glyphHeap = (uint8_t *) MEMAllocFromMappedMemoryForGX2Ex(heapSize, 0x100);
|
||||
}
|
||||
if (glyphHeap) {
|
||||
glyphHeapHandle = MEMCreateExpHeapEx((void *) (glyphHeap), heapSize, 1);
|
||||
if (!glyphHeapHandle) {
|
||||
OSFatal("NotificationModule: Failed to create heap for glyphData");
|
||||
}
|
||||
} else {
|
||||
OSFatal("NotificationModule: Failed to alloc heap for glyphData");
|
||||
}
|
||||
|
||||
ftKerningEnabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default destructor for the SchriftGX2 class.
|
||||
*/
|
||||
SchriftGX2::~SchriftGX2() {
|
||||
unloadFont();
|
||||
sft_freefont(pFont.font);
|
||||
pFont.font = nullptr;
|
||||
|
||||
MEMFreeToMappedMemory(glyphHeap);
|
||||
glyphHeap = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a short char string to a wide char string.
|
||||
*
|
||||
* This routine converts a supplied short character string into a wide character string.
|
||||
* Note that it is the user's responsibility to clear the returned buffer once it is no longer needed.
|
||||
*
|
||||
* @param strChar Character string to be converted.
|
||||
* @return Wide character representation of supplied character string.
|
||||
*/
|
||||
|
||||
wchar_t *SchriftGX2::charToWideChar(const char *strChar) {
|
||||
if (!strChar) return nullptr;
|
||||
|
||||
auto *strWChar = new (std::nothrow) wchar_t[strlen(strChar) + 1];
|
||||
if (!strWChar) return nullptr;
|
||||
|
||||
int32_t bt = mbstowcs(strWChar, strChar, strlen(strChar));
|
||||
if (bt > 0) {
|
||||
strWChar[bt] = 0;
|
||||
return strWChar;
|
||||
}
|
||||
|
||||
wchar_t *tempDest = strWChar;
|
||||
while ((*tempDest++ = *strChar++))
|
||||
;
|
||||
|
||||
return strWChar;
|
||||
}
|
||||
|
||||
char *SchriftGX2::wideCharToUTF8(const wchar_t *strChar) {
|
||||
if (!strChar) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t len = 0;
|
||||
wchar_t wc;
|
||||
|
||||
for (size_t i = 0; strChar[i]; ++i) {
|
||||
wc = strChar[i];
|
||||
if (wc < 0x80)
|
||||
++len;
|
||||
else if (wc < 0x800)
|
||||
len += 2;
|
||||
else if (wc < 0x10000)
|
||||
len += 3;
|
||||
else
|
||||
len += 4;
|
||||
}
|
||||
|
||||
char *pOut = new (std::nothrow) char[len];
|
||||
if (!pOut)
|
||||
return nullptr;
|
||||
|
||||
size_t n = 0;
|
||||
|
||||
for (size_t i = 0; strChar[i]; ++i) {
|
||||
wc = strChar[i];
|
||||
if (wc < 0x80)
|
||||
pOut[n++] = (char) wc;
|
||||
else if (wc < 0x800) {
|
||||
pOut[n++] = (char) ((wc >> 6) | 0xC0);
|
||||
pOut[n++] = (char) ((wc & 0x3F) | 0x80);
|
||||
} else if (wc < 0x10000) {
|
||||
pOut[n++] = (char) ((wc >> 12) | 0xE0);
|
||||
pOut[n++] = (char) (((wc >> 6) & 0x3F) | 0x80);
|
||||
pOut[n++] = (char) ((wc & 0x3F) | 0x80);
|
||||
} else {
|
||||
pOut[n++] = (char) (((wc >> 18) & 0x07) | 0xF0);
|
||||
pOut[n++] = (char) (((wc >> 12) & 0x3F) | 0x80);
|
||||
pOut[n++] = (char) (((wc >> 6) & 0x3F) | 0x80);
|
||||
pOut[n++] = (char) ((wc & 0x3F) | 0x80);
|
||||
}
|
||||
}
|
||||
return pOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all loaded font glyph data.
|
||||
*
|
||||
* This routine clears all members of the font map structure and frees all allocated memory back to the system.
|
||||
*/
|
||||
void SchriftGX2::unloadFont() {
|
||||
std::lock_guard<std::mutex> lock(fontDataMutex);
|
||||
for (auto &dataForSize : fontData) {
|
||||
for (auto &cur : dataForSize.second.ftgxCharMap) {
|
||||
if (cur.second.texture) {
|
||||
if (cur.second.texture->surface.image) {
|
||||
MEMFreeToExpHeap(glyphHeapHandle, cur.second.texture->surface.image);
|
||||
}
|
||||
delete cur.second.texture;
|
||||
cur.second.texture = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fontData.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches the given font glyph in the instance font texture buffer.
|
||||
*
|
||||
* This routine renders and stores the requested glyph's bitmap and relevant information into its own quickly addressible
|
||||
* structure within an instance-specific map.
|
||||
*
|
||||
* @param charCode The requested glyph's character code.
|
||||
* @return A pointer to the allocated font structure.
|
||||
*/
|
||||
ftgxCharData *SchriftGX2::cacheGlyphData(wchar_t charCode, int16_t pixelSize) {
|
||||
std::lock_guard<std::mutex> lock(fontDataMutex);
|
||||
auto itr = fontData.find(pixelSize);
|
||||
if (itr != fontData.end()) {
|
||||
auto itr2 = itr->second.ftgxCharMap.find(charCode);
|
||||
if (itr2 != itr->second.ftgxCharMap.end()) {
|
||||
return &itr2->second;
|
||||
}
|
||||
}
|
||||
//!Cache ascender and decender as well
|
||||
ftGX2Data *ftData = &fontData[pixelSize];
|
||||
|
||||
uint16_t textureWidth = 0, textureHeight = 0;
|
||||
if (ftPointSize != pixelSize) {
|
||||
ftPointSize = pixelSize;
|
||||
pFont.xScale = ftPointSize;
|
||||
pFont.yScale = ftPointSize;
|
||||
SFT_LMetrics metrics;
|
||||
sft_lmetrics(&pFont, &metrics);
|
||||
|
||||
ftData->ftgxAlign.ascender = (int16_t) metrics.ascender;
|
||||
ftData->ftgxAlign.descender = (int16_t) metrics.descender;
|
||||
ftData->ftgxAlign.max = 0;
|
||||
ftData->ftgxAlign.min = 0;
|
||||
}
|
||||
|
||||
SFT_Glyph gid; // unsigned long gid;
|
||||
if (sft_lookup(&pFont, charCode, &gid) >= 0) {
|
||||
SFT_GMetrics mtx;
|
||||
if (sft_gmetrics(&pFont, gid, &mtx) < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("bad glyph metrics");
|
||||
}
|
||||
textureWidth = (mtx.minWidth + 3) & ~3;
|
||||
textureHeight = mtx.minHeight;
|
||||
|
||||
SFT_Image img = {
|
||||
.width = textureWidth,
|
||||
.height = textureHeight,
|
||||
};
|
||||
|
||||
if (textureWidth == 0) {
|
||||
textureWidth = 4;
|
||||
}
|
||||
if (textureHeight == 0) {
|
||||
textureHeight = 4;
|
||||
}
|
||||
|
||||
img.pixels = malloc(img.width * img.height);
|
||||
if (!img.pixels) {
|
||||
return nullptr;
|
||||
}
|
||||
if (sft_render(&pFont, gid, img) < 0) {
|
||||
free(img.pixels);
|
||||
DEBUG_FUNCTION_LINE_ERR("sft_render failed.");
|
||||
} else {
|
||||
ftgxCharData charData;
|
||||
charData.renderOffsetX = (int16_t) mtx.leftSideBearing;
|
||||
charData.renderOffsetY = (int16_t) -mtx.yOffset;
|
||||
charData.glyphAdvanceX = (uint16_t) mtx.advanceWidth;
|
||||
charData.glyphAdvanceY = (uint16_t) 0;
|
||||
charData.glyphIndex = (uint32_t) gid;
|
||||
charData.renderOffsetMax = (int16_t) (short) -mtx.yOffset;
|
||||
charData.renderOffsetMin = (int16_t) (short) (img.height - (-mtx.yOffset));
|
||||
|
||||
//! Initialize texture
|
||||
charData.texture = new (std::nothrow) GX2Texture;
|
||||
if (!charData.texture) {
|
||||
free(img.pixels);
|
||||
return nullptr;
|
||||
}
|
||||
GX2InitTexture(charData.texture, textureWidth, textureHeight, 1, 0, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_SURFACE_DIM_TEXTURE_2D, GX2_TILE_MODE_LINEAR_ALIGNED);
|
||||
if (!loadGlyphData(&img, &charData, ftData)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load glyph %d", charCode);
|
||||
delete charData.texture;
|
||||
charData.texture = nullptr;
|
||||
free(img.pixels);
|
||||
return nullptr;
|
||||
} else {
|
||||
free(img.pixels);
|
||||
ftData->ftgxCharMap[charCode] = charData;
|
||||
}
|
||||
|
||||
return &ftData->ftgxCharMap[charCode];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the rendered bitmap into the relevant structure's data buffer.
|
||||
*
|
||||
* This routine does a simple byte-wise copy of the glyph's rendered 8-bit grayscale bitmap into the structure's buffer.
|
||||
* Each byte is converted from the bitmap's intensity value into the a uint32_t RGBA value.
|
||||
*
|
||||
* @param bmp A pointer to the most recently rendered glyph's bitmap.
|
||||
* @param charData A pointer to an allocated ftgxCharData structure whose data represent that of the last rendered glyph.
|
||||
*/
|
||||
|
||||
bool SchriftGX2::loadGlyphData(SFT_Image *bmp, ftgxCharData *charData, ftGX2Data *ftData) {
|
||||
if (charData == nullptr || charData->texture->surface.imageSize == 0 || charData->texture->surface.alignment == 0 || ftData == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Input data was NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
charData->texture->surface.image = (uint8_t *) MEMAllocFromExpHeapEx(glyphHeapHandle, charData->texture->surface.imageSize, charData->texture->surface.alignment);
|
||||
if (!charData->texture->surface.image) {
|
||||
DEBUG_FUNCTION_LINE_INFO("Cache is full, let's clear it");
|
||||
for (auto &cur : ftData->ftgxCharMap) {
|
||||
if (cur.second.texture) {
|
||||
if (cur.second.texture->surface.image) {
|
||||
MEMFreeToExpHeap(glyphHeapHandle, cur.second.texture->surface.image);
|
||||
}
|
||||
delete cur.second.texture;
|
||||
}
|
||||
}
|
||||
ftData->ftgxCharMap.clear();
|
||||
charData->texture->surface.image = (uint8_t *) MEMAllocFromExpHeapEx(glyphHeapHandle, charData->texture->surface.imageSize, charData->texture->surface.alignment);
|
||||
if (!charData->texture->surface.image) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
memset(charData->texture->surface.image, 0x00, charData->texture->surface.imageSize);
|
||||
|
||||
auto *src = (uint8_t *) bmp->pixels;
|
||||
auto *dst = (uint32_t *) charData->texture->surface.image;
|
||||
uint32_t x, y;
|
||||
|
||||
for (y = 0; y < bmp->height; y++) {
|
||||
for (x = 0; x < bmp->width; x++) {
|
||||
uint8_t val = src[y * bmp->width + x];
|
||||
dst[y * charData->texture->surface.pitch + x] = val << 24 | val << 16 | val << 8 | val;
|
||||
}
|
||||
}
|
||||
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_TEXTURE, charData->texture->surface.image, charData->texture->surface.imageSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the x offset of the rendered string.
|
||||
*
|
||||
* This routine calculates the x offset of the rendered string based off of a supplied positional format parameter.
|
||||
*
|
||||
* @param width Current pixel width of the string.
|
||||
* @param format Positional format of the string.
|
||||
*/
|
||||
int16_t SchriftGX2::getStyleOffsetWidth(uint16_t width, uint16_t format) {
|
||||
if (format & FTGX_JUSTIFY_LEFT)
|
||||
return 0;
|
||||
else if (format & FTGX_JUSTIFY_CENTER)
|
||||
return -(width >> 1);
|
||||
else if (format & FTGX_JUSTIFY_RIGHT)
|
||||
return -width;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the y offset of the rendered string.
|
||||
*
|
||||
* This routine calculates the y offset of the rendered string based off of a supplied positional format parameter.
|
||||
*
|
||||
* @param offset Current pixel offset data of the string.
|
||||
* @param format Positional format of the string.
|
||||
*/
|
||||
int16_t SchriftGX2::getStyleOffsetHeight(int16_t format, uint16_t pixelSize) {
|
||||
std::lock_guard<std::mutex> lock(fontDataMutex);
|
||||
std::map<int16_t, ftGX2Data>::iterator itr = fontData.find(pixelSize);
|
||||
if (itr == fontData.end()) return 0;
|
||||
|
||||
switch (format & FTGX_ALIGN_MASK) {
|
||||
case FTGX_ALIGN_TOP:
|
||||
return itr->second.ftgxAlign.descender;
|
||||
|
||||
case FTGX_ALIGN_MIDDLE:
|
||||
default:
|
||||
return (itr->second.ftgxAlign.ascender + itr->second.ftgxAlign.descender + 1) >> 1;
|
||||
|
||||
case FTGX_ALIGN_BOTTOM:
|
||||
return itr->second.ftgxAlign.ascender;
|
||||
|
||||
case FTGX_ALIGN_BASELINE:
|
||||
return 0;
|
||||
|
||||
case FTGX_ALIGN_GLYPH_TOP:
|
||||
return itr->second.ftgxAlign.max;
|
||||
|
||||
case FTGX_ALIGN_GLYPH_MIDDLE:
|
||||
return (itr->second.ftgxAlign.max + itr->second.ftgxAlign.min + 1) >> 1;
|
||||
|
||||
case FTGX_ALIGN_GLYPH_BOTTOM:
|
||||
return itr->second.ftgxAlign.min;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the supplied text string and prints the results at the specified coordinates.
|
||||
*
|
||||
* This routine processes each character of the supplied text string, loads the relevant preprocessed bitmap buffer,
|
||||
* a texture from said buffer, and loads the resultant texture into the EFB.
|
||||
*
|
||||
* @param x Screen X coordinate at which to output the text.
|
||||
* @param y Screen Y coordinate at which to output the text. Note that this value corresponds to the text string origin and not the top or bottom of the glyphs.
|
||||
* @param text NULL terminated string to output.
|
||||
* @param color Optional color to apply to the text characters. If not specified default value is ftgxWhite: (GXColor){0xff, 0xff, 0xff, 0xff}
|
||||
* @param textStyle Flags which specify any styling which should be applied to the rendered string.
|
||||
* @return The number of characters printed.
|
||||
*/
|
||||
|
||||
uint16_t SchriftGX2::drawText(int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, const glm::vec4 &color, uint16_t textStyle, uint16_t textWidth, const float &textBlur, const float &colorBlurIntensity, const glm::vec4 &blurColor) {
|
||||
if (!text) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(fontDataMutex);
|
||||
|
||||
// uint16_t fullTextWidth = (textWidth > 0) ? textWidth : getWidth(text, pixelSize);
|
||||
uint16_t x_pos = x, printed = 0;
|
||||
uint16_t x_offset = 0, y_offset = 0;
|
||||
|
||||
if (textStyle & FTGX_JUSTIFY_MASK) {
|
||||
//x_offset = getStyleOffsetWidth(fullTextWidth, textStyle);
|
||||
}
|
||||
if (textStyle & FTGX_ALIGN_MASK) {
|
||||
//y_offset = getStyleOffsetHeight(textStyle, pixelSize);
|
||||
}
|
||||
|
||||
int32_t i = 0;
|
||||
while (text[i]) {
|
||||
ftgxCharData *glyphData = cacheGlyphData(text[i], pixelSize);
|
||||
|
||||
if (glyphData != nullptr) {
|
||||
if (ftKerningEnabled && i > 0) {
|
||||
SFT_Kerning kerning;
|
||||
sft_kerning(&pFont, fontData[pixelSize].ftgxCharMap[text[i - 1]].glyphIndex, glyphData->glyphIndex, &kerning);
|
||||
x_pos += (kerning.xShift);
|
||||
}
|
||||
copyTextureToFramebuffer(glyphData->texture, x_pos + glyphData->renderOffsetX + x_offset, y + glyphData->renderOffsetY - y_offset, z, color, textBlur, colorBlurIntensity, blurColor);
|
||||
|
||||
x_pos += glyphData->glyphAdvanceX;
|
||||
++printed;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
return printed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes the supplied string and return the width of the string in pixels.
|
||||
*
|
||||
* This routine processes each character of the supplied text string and calculates the width of the entire string.
|
||||
* Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function.
|
||||
*
|
||||
* @param text NULL terminated string to calculate.
|
||||
* @return The width of the text string in pixels.
|
||||
*/
|
||||
uint16_t SchriftGX2::getWidth(const wchar_t *text, int16_t pixelSize) {
|
||||
if (!text) {
|
||||
return 0;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(fontDataMutex);
|
||||
|
||||
uint16_t strWidth = 0;
|
||||
int32_t i = 0;
|
||||
|
||||
while (text[i]) {
|
||||
ftgxCharData *glyphData = cacheGlyphData(text[i], pixelSize);
|
||||
if (glyphData != nullptr) {
|
||||
if (ftKerningEnabled && (i > 0)) {
|
||||
SFT_Kerning kerning;
|
||||
sft_kerning(&pFont, fontData[pixelSize].ftgxCharMap[text[i - 1]].glyphIndex, glyphData->glyphIndex, &kerning);
|
||||
strWidth += kerning.xShift;
|
||||
}
|
||||
|
||||
strWidth += glyphData->glyphAdvanceX;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return strWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Single char width
|
||||
*/
|
||||
uint16_t SchriftGX2::getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar) {
|
||||
std::lock_guard<std::mutex> lock(fontDataMutex);
|
||||
uint16_t strWidth = 0;
|
||||
ftgxCharData *glyphData = cacheGlyphData(wChar, pixelSize);
|
||||
|
||||
if (glyphData != nullptr) {
|
||||
if (ftKerningEnabled && prevChar != 0x0000) {
|
||||
SFT_Kerning kerning;
|
||||
sft_kerning(&pFont, fontData[pixelSize].ftgxCharMap[prevChar].glyphIndex, glyphData->glyphIndex, &kerning);
|
||||
strWidth += kerning.xShift;
|
||||
}
|
||||
strWidth += glyphData->glyphAdvanceX;
|
||||
}
|
||||
|
||||
return strWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the supplied string and return the height of the string in pixels.
|
||||
*
|
||||
* This routine processes each character of the supplied text string and calculates the height of the entire string.
|
||||
* Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function.
|
||||
*
|
||||
* @param text NULL terminated string to calculate.
|
||||
* @return The height of the text string in pixels.
|
||||
*/
|
||||
uint16_t SchriftGX2::getHeight(const wchar_t *text, int16_t pixelSize) {
|
||||
std::lock_guard<std::mutex> lock(fontDataMutex);
|
||||
getOffset(text, pixelSize);
|
||||
return fontData[pixelSize].ftgxAlign.max - fontData[pixelSize].ftgxAlign.min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum offset above and minimum offset below the font origin line.
|
||||
*
|
||||
* This function calculates the maximum pixel height above the font origin line and the minimum
|
||||
* pixel height below the font origin line and returns the values in an addressible structure.
|
||||
*
|
||||
* @param text NULL terminated string to calculate.
|
||||
* @param offset returns the max and min values above and below the font origin line
|
||||
*
|
||||
*/
|
||||
void SchriftGX2::getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widthLimit) {
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(fontDataMutex);
|
||||
int16_t strMax = 0, strMin = 9999;
|
||||
uint16_t currWidth = 0;
|
||||
|
||||
int32_t i = 0;
|
||||
|
||||
while (text[i]) {
|
||||
if (widthLimit > 0 && currWidth >= widthLimit) break;
|
||||
|
||||
ftgxCharData *glyphData = cacheGlyphData(text[i], pixelSize);
|
||||
|
||||
if (glyphData != nullptr) {
|
||||
strMax = glyphData->renderOffsetMax > strMax ? glyphData->renderOffsetMax : strMax;
|
||||
strMin = glyphData->renderOffsetMin < strMin ? glyphData->renderOffsetMin : strMin;
|
||||
currWidth += glyphData->glyphAdvanceX;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (ftPointSize != pixelSize) {
|
||||
ftPointSize = pixelSize;
|
||||
pFont.xScale = ftPointSize;
|
||||
pFont.yScale = ftPointSize;
|
||||
}
|
||||
SFT_LMetrics metrics;
|
||||
sft_lmetrics(&pFont, &metrics);
|
||||
|
||||
fontData[pixelSize].ftgxAlign.ascender = metrics.ascender;
|
||||
fontData[pixelSize].ftgxAlign.descender = metrics.descender;
|
||||
fontData[pixelSize].ftgxAlign.max = strMax;
|
||||
fontData[pixelSize].ftgxAlign.min = strMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the supplied texture quad to the EFB.
|
||||
*
|
||||
* This routine uses the in-built GX quad builder functions to define the texture bounds and location on the EFB target.
|
||||
*
|
||||
* @param texObj A pointer to the glyph's initialized texture object.
|
||||
* @param texWidth The pixel width of the texture object.
|
||||
* @param texHeight The pixel height of the texture object.
|
||||
* @param screenX The screen X coordinate at which to output the rendered texture.
|
||||
* @param screenY The screen Y coordinate at which to output the rendered texture.
|
||||
* @param color Color to apply to the texture.
|
||||
*/
|
||||
void SchriftGX2::copyTextureToFramebuffer(GX2Texture *texture, int16_t x, int16_t y, int16_t z, const glm::vec4 &color, const float &defaultBlur, const float &blurIntensity, const glm::vec4 &blurColor) {
|
||||
static const float imageAngle = 0.0f;
|
||||
static const float blurScale = (2.0f);
|
||||
|
||||
float widthScaleFactor = 1.0f / (float) 1280;
|
||||
float heightScaleFactor = 1.0f / (float) 720;
|
||||
|
||||
float offsetLeft = 2.0f * ((float) x + 0.5f * (float) texture->surface.width) * widthScaleFactor;
|
||||
float offsetTop = 2.0f * ((float) y - 0.5f * (float) texture->surface.height) * heightScaleFactor;
|
||||
|
||||
float widthScale = blurScale * (float) texture->surface.width * widthScaleFactor;
|
||||
float heightScale = blurScale * (float) texture->surface.height * heightScaleFactor;
|
||||
|
||||
glm::vec3 positionOffsets(offsetLeft, offsetTop, (float) z);
|
||||
|
||||
//! blur doubles due to blur we have to scale the texture
|
||||
glm::vec3 scaleFactor(widthScale, heightScale, 1.0f);
|
||||
|
||||
glm::vec3 blurDirection;
|
||||
blurDirection[2] = 1.0f;
|
||||
|
||||
Texture2DShader::instance()->setShaders();
|
||||
Texture2DShader::instance()->setAttributeBuffer();
|
||||
Texture2DShader::instance()->setAngle(imageAngle);
|
||||
Texture2DShader::instance()->setOffset(positionOffsets);
|
||||
Texture2DShader::instance()->setScale(scaleFactor);
|
||||
Texture2DShader::instance()->setTextureAndSampler(texture, &ftSampler);
|
||||
|
||||
if (blurIntensity > 0.0f) {
|
||||
//! glow blur color
|
||||
Texture2DShader::instance()->setColorIntensity(blurColor);
|
||||
|
||||
//! glow blur horizontal
|
||||
blurDirection[0] = blurIntensity;
|
||||
blurDirection[1] = 0.0f;
|
||||
Texture2DShader::instance()->setBlurring(blurDirection);
|
||||
Texture2DShader::instance()->draw();
|
||||
|
||||
//! glow blur vertical
|
||||
blurDirection[0] = 0.0f;
|
||||
blurDirection[1] = blurIntensity;
|
||||
Texture2DShader::instance()->setBlurring(blurDirection);
|
||||
Texture2DShader::instance()->draw();
|
||||
}
|
||||
|
||||
//! set text color
|
||||
Texture2DShader::instance()->setColorIntensity(color);
|
||||
|
||||
//! blur horizontal
|
||||
blurDirection[0] = defaultBlur;
|
||||
blurDirection[1] = 0.0f;
|
||||
Texture2DShader::instance()->setBlurring(blurDirection);
|
||||
Texture2DShader::instance()->draw();
|
||||
|
||||
//! blur vertical
|
||||
blurDirection[0] = 0.0f;
|
||||
blurDirection[1] = defaultBlur;
|
||||
Texture2DShader::instance()->setBlurring(blurDirection);
|
||||
Texture2DShader::instance()->draw();
|
||||
}
|
156
src/gui/SchriftGX2.h
Normal file
156
src/gui/SchriftGX2.h
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* SchriftGX2 is a wrapper class for libFreeType which renders a compiled
|
||||
* FreeType parsable font into a GX texture for Wii homebrew development.
|
||||
* Copyright (C) 2008 Armin Tamzarian
|
||||
* Modified by Dimok, 2015 for WiiU GX2
|
||||
*
|
||||
* This file is part of SchriftGX2.
|
||||
*
|
||||
* SchriftGX2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* SchriftGX2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with SchriftGX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "schrift.h"
|
||||
#include "shaders/gx2_ext.h"
|
||||
#include <cstring>
|
||||
#include <cwchar>
|
||||
#include <gx2/sampler.h>
|
||||
#include <gx2/texture.h>
|
||||
#include <malloc.h>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#pragma GCC diagnostic ignored "-Wvolatile"
|
||||
#include <coreinit/memexpheap.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
/*! \struct ftgxCharData_
|
||||
*
|
||||
* Font face character glyph relevant data structure.
|
||||
*/
|
||||
typedef struct ftgxCharData_ {
|
||||
int16_t renderOffsetX; /**< Texture X axis bearing offset. */
|
||||
uint16_t glyphAdvanceX; /**< Character glyph X coordinate advance in pixels. */
|
||||
uint16_t glyphAdvanceY; /**< Character glyph Y coordinate advance in pixels. */
|
||||
uint32_t glyphIndex; /**< Charachter glyph index in the font face. */
|
||||
|
||||
int16_t renderOffsetY; /**< Texture Y axis bearing offset. */
|
||||
int16_t renderOffsetMax; /**< Texture Y axis bearing maximum value. */
|
||||
int16_t renderOffsetMin; /**< Texture Y axis bearing minimum value. */
|
||||
|
||||
GX2Texture *texture;
|
||||
} ftgxCharData;
|
||||
|
||||
/*! \struct ftgxDataOffset_
|
||||
*
|
||||
* Offset structure which hold both a maximum and minimum value.
|
||||
*/
|
||||
typedef struct ftgxDataOffset_ {
|
||||
int16_t ascender; /**< Maximum data offset. */
|
||||
int16_t descender; /**< Minimum data offset. */
|
||||
int16_t max; /**< Maximum data offset. */
|
||||
int16_t min; /**< Minimum data offset. */
|
||||
} ftgxDataOffset;
|
||||
|
||||
typedef struct ftgxCharData_ ftgxCharData;
|
||||
typedef struct ftgxDataOffset_ ftgxDataOffset;
|
||||
#define _TEXT(t) L##t /**< Unicode helper macro. */
|
||||
|
||||
#define FTGX_NULL 0x0000
|
||||
#define FTGX_JUSTIFY_LEFT 0x0001
|
||||
#define FTGX_JUSTIFY_CENTER 0x0002
|
||||
#define FTGX_JUSTIFY_RIGHT 0x0004
|
||||
#define FTGX_JUSTIFY_MASK 0x000f
|
||||
|
||||
#define FTGX_ALIGN_TOP 0x0010
|
||||
#define FTGX_ALIGN_MIDDLE 0x0020
|
||||
#define FTGX_ALIGN_BOTTOM 0x0040
|
||||
#define FTGX_ALIGN_BASELINE 0x0080
|
||||
#define FTGX_ALIGN_GLYPH_TOP 0x0100
|
||||
#define FTGX_ALIGN_GLYPH_MIDDLE 0x0200
|
||||
#define FTGX_ALIGN_GLYPH_BOTTOM 0x0400
|
||||
#define FTGX_ALIGN_MASK 0x0ff0
|
||||
|
||||
#define FTGX_STYLE_UNDERLINE 0x1000
|
||||
#define FTGX_STYLE_STRIKE 0x2000
|
||||
#define FTGX_STYLE_MASK 0xf000
|
||||
|
||||
/**< Constant color value used only to sanitize Doxygen documentation. */
|
||||
static const GX2ColorF32 ftgxWhite = (GX2ColorF32){
|
||||
1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
|
||||
/*! \class SchriftGX2
|
||||
* \brief Wrapper class for the libFreeType library with GX rendering.
|
||||
* \author Armin Tamzarian
|
||||
* \version 0.2.4
|
||||
*
|
||||
* SchriftGX2 acts as a wrapper class for the libFreeType library. It supports precaching of transformed glyph data into
|
||||
* a specified texture format. Rendering of the data to the EFB is accomplished through the application of high performance
|
||||
* GX texture functions resulting in high throughput of string rendering.
|
||||
*/
|
||||
class SchriftGX2 {
|
||||
private:
|
||||
int16_t ftPointSize; /**< Current set size of the rendered font. */
|
||||
bool ftKerningEnabled; /**< Flag indicating the availability of font kerning data. */
|
||||
uint8_t vertexIndex; /**< Vertex format descriptor index. */
|
||||
GX2Sampler ftSampler;
|
||||
|
||||
SFT pFont = {};
|
||||
|
||||
uint8_t *glyphHeap = nullptr;
|
||||
MEMHeapHandle glyphHeapHandle = nullptr;
|
||||
|
||||
typedef struct _ftGX2Data {
|
||||
ftgxDataOffset ftgxAlign;
|
||||
std::map<wchar_t, ftgxCharData> ftgxCharMap;
|
||||
} ftGX2Data;
|
||||
|
||||
std::map<int16_t, ftGX2Data> fontData; /**< Map which holds the glyph data structures for the corresponding characters in one size. */
|
||||
|
||||
int16_t getStyleOffsetWidth(uint16_t width, uint16_t format);
|
||||
|
||||
int16_t getStyleOffsetHeight(int16_t format, uint16_t pixelSize);
|
||||
|
||||
ftgxCharData *cacheGlyphData(wchar_t charCode, int16_t pixelSize);
|
||||
|
||||
bool loadGlyphData(SFT_Image *bmp, ftgxCharData *charData, ftGX2Data *ftData);
|
||||
|
||||
void copyTextureToFramebuffer(GX2Texture *tex, int16_t screenX, int16_t screenY, int16_t screenZ, const glm::vec4 &color, const float &textBlur, const float &colorBlurIntensity, const glm::vec4 &blurColor);
|
||||
|
||||
std::mutex fontDataMutex;
|
||||
|
||||
public:
|
||||
SchriftGX2(const uint8_t *fontBuffer, uint32_t bufferSize);
|
||||
|
||||
~SchriftGX2();
|
||||
|
||||
void unloadFont();
|
||||
|
||||
uint16_t drawText(int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, const glm::vec4 &color,
|
||||
uint16_t textStyling, uint16_t textWidth, const float &textBlur, const float &colorBlurIntensity, const glm::vec4 &blurColor);
|
||||
|
||||
uint16_t getWidth(const wchar_t *text, int16_t pixelSize);
|
||||
|
||||
uint16_t getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar = 0x0000);
|
||||
|
||||
uint16_t getHeight(const wchar_t *text, int16_t pixelSize);
|
||||
void getOffset(const wchar_t *text, int16_t pixelSize, uint16_t widthLimit = 0);
|
||||
|
||||
static wchar_t *charToWideChar(const char *p);
|
||||
|
||||
static char *wideCharToUTF8(const wchar_t *strChar);
|
||||
};
|
18
src/gui/Timer.h
Normal file
18
src/gui/Timer.h
Normal file
@ -0,0 +1,18 @@
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
class Timer {
|
||||
public:
|
||||
Timer() { clock_gettime(CLOCK_REALTIME, &beg_); }
|
||||
|
||||
double elapsed() {
|
||||
clock_gettime(CLOCK_REALTIME, &end_);
|
||||
return end_.tv_sec - beg_.tv_sec +
|
||||
(end_.tv_nsec - beg_.tv_nsec) / 1000000000.;
|
||||
}
|
||||
|
||||
void reset() { clock_gettime(CLOCK_REALTIME, &beg_); }
|
||||
|
||||
private:
|
||||
timespec beg_, end_;
|
||||
};
|
1462
src/gui/schrift.c
Normal file
1462
src/gui/schrift.c
Normal file
File diff suppressed because it is too large
Load Diff
88
src/gui/schrift.h
Normal file
88
src/gui/schrift.h
Normal file
@ -0,0 +1,88 @@
|
||||
/* This file is part of libschrift.
|
||||
*
|
||||
* © 2019-2022 Thomas Oltmann and contributors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#ifndef SCHRIFT_H
|
||||
#define SCHRIFT_H 1
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <stdint.h> /* uint_fast32_t, uint_least32_t */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SFT_DOWNWARD_Y 0x01
|
||||
|
||||
typedef struct SFT SFT;
|
||||
typedef struct SFT_Font SFT_Font;
|
||||
typedef uint_least32_t SFT_UChar; /* Guaranteed to be compatible with char32_t. */
|
||||
typedef uint_fast32_t SFT_Glyph;
|
||||
typedef struct SFT_LMetrics SFT_LMetrics;
|
||||
typedef struct SFT_GMetrics SFT_GMetrics;
|
||||
typedef struct SFT_Kerning SFT_Kerning;
|
||||
typedef struct SFT_Image SFT_Image;
|
||||
|
||||
struct SFT {
|
||||
SFT_Font *font;
|
||||
double xScale;
|
||||
double yScale;
|
||||
double xOffset;
|
||||
double yOffset;
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct SFT_LMetrics {
|
||||
double ascender;
|
||||
double descender;
|
||||
double lineGap;
|
||||
};
|
||||
|
||||
struct SFT_GMetrics {
|
||||
double advanceWidth;
|
||||
double leftSideBearing;
|
||||
int yOffset;
|
||||
int minWidth;
|
||||
int minHeight;
|
||||
};
|
||||
|
||||
struct SFT_Kerning {
|
||||
double xShift;
|
||||
double yShift;
|
||||
};
|
||||
|
||||
struct SFT_Image {
|
||||
void *pixels;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
const char *sft_version(void);
|
||||
|
||||
SFT_Font *sft_loadmem(const void *mem, size_t size);
|
||||
void sft_freefont(SFT_Font *font);
|
||||
|
||||
int sft_lmetrics(const SFT *sft, SFT_LMetrics *metrics);
|
||||
int sft_lookup(const SFT *sft, SFT_UChar codepoint, SFT_Glyph *glyph);
|
||||
int sft_gmetrics(const SFT *sft, SFT_Glyph glyph, SFT_GMetrics *metrics);
|
||||
int sft_kerning(const SFT *sft, SFT_Glyph leftGlyph, SFT_Glyph rightGlyph,
|
||||
SFT_Kerning *kerning);
|
||||
int sft_render(const SFT *sft, SFT_Glyph glyph, SFT_Image image);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
2452
src/gui/sigslot.h
Normal file
2452
src/gui/sigslot.h
Normal file
File diff suppressed because it is too large
Load Diff
78
src/main.cpp
Normal file
78
src/main.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
#include "export.h"
|
||||
#include "function_patches.h"
|
||||
#include "retain_vars.hpp"
|
||||
#include "shaders/ColorShader.h"
|
||||
#include "shaders/Texture2DShader.h"
|
||||
#include "utils/logger.h"
|
||||
#include "version.h"
|
||||
#include <coreinit/memory.h>
|
||||
#include <function_patcher/function_patching.h>
|
||||
#include <wums.h>
|
||||
|
||||
WUMS_MODULE_EXPORT_NAME("homebrew_notifications");
|
||||
|
||||
#define VERSION "v0.1.0"
|
||||
|
||||
WUMS_DEPENDS_ON(homebrew_memorymapping);
|
||||
WUMS_DEPENDS_ON(homebrew_functionpatcher);
|
||||
|
||||
WUMS_INITIALIZE() {
|
||||
initLogging();
|
||||
|
||||
if (FunctionPatcher_InitLibrary() != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||
OSFatal("homebrew_notifications: FunctionPatcher_InitLibrary failed");
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("Patch NotificationModule functions");
|
||||
for (uint32_t i = 0; i < function_replacements_size; i++) {
|
||||
if (FunctionPatcher_AddFunctionPatch(&function_replacements[i], nullptr, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||
OSFatal("NotificationModule: Failed to patch NotificationModule function");
|
||||
}
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("Patch NotificationModule functions finished");
|
||||
|
||||
gOverlayInitDone = false;
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Init context state");
|
||||
// cannot be in unknown regions for GX2 like 0xBCAE1000
|
||||
gContextState = (GX2ContextState *) MEMAllocFromMappedMemoryForGX2Ex(
|
||||
sizeof(GX2ContextState),
|
||||
GX2_CONTEXT_STATE_ALIGNMENT);
|
||||
if (gContextState == nullptr) {
|
||||
OSFatal("Failed to allocate gContextState");
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Allocated %d bytes for gCont extState", sizeof(GX2ContextState));
|
||||
}
|
||||
|
||||
void *font = nullptr;
|
||||
uint32_t size = 0;
|
||||
OSGetSharedData(OS_SHAREDDATATYPE_FONT_STANDARD, 0, &font, &size);
|
||||
if (font && size) {
|
||||
gFontSystem = new (std::nothrow) SchriftGX2((uint8_t *) font, (int32_t) size);
|
||||
if (gFontSystem) {
|
||||
GuiText::setPresetFont(gFontSystem);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to init font system");
|
||||
}
|
||||
}
|
||||
OSMemoryBarrier();
|
||||
deinitLogging();
|
||||
}
|
||||
|
||||
WUMS_APPLICATION_STARTS() {
|
||||
initLogging();
|
||||
OSReport("Running NotificationModule " VERSION VERSION_EXTRA "\n");
|
||||
gDrawReady = false;
|
||||
}
|
||||
|
||||
WUMS_APPLICATION_ENDS() {
|
||||
if (gOverlayFrame) {
|
||||
gOverlayFrame->clearElements();
|
||||
}
|
||||
ExportCleanUp();
|
||||
if (gFontSystem) {
|
||||
gFontSystem->unloadFont();
|
||||
}
|
||||
ColorShader::destroyInstance();
|
||||
Texture2DShader::destroyInstance();
|
||||
deinitLogging();
|
||||
}
|
10
src/retain_vars.cpp
Normal file
10
src/retain_vars.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "retain_vars.hpp"
|
||||
|
||||
GX2SurfaceFormat gTVSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8;
|
||||
GX2SurfaceFormat gDRCSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8;
|
||||
GX2ContextState *gContextState = nullptr;
|
||||
GX2ContextState *gOriginalContextState = nullptr;
|
||||
OverlayFrame *gOverlayFrame = nullptr;
|
||||
SchriftGX2 *gFontSystem = nullptr;
|
||||
bool gOverlayInitDone = false;
|
||||
bool gDrawReady = false;
|
13
src/retain_vars.hpp
Normal file
13
src/retain_vars.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "gui/OverlayFrame.h"
|
||||
#include "gui/SchriftGX2.h"
|
||||
#include <gx2/context.h>
|
||||
|
||||
extern GX2SurfaceFormat gTVSurfaceFormat;
|
||||
extern GX2SurfaceFormat gDRCSurfaceFormat;
|
||||
extern GX2ContextState *gContextState;
|
||||
extern GX2ContextState *gOriginalContextState;
|
||||
extern OverlayFrame *gOverlayFrame;
|
||||
extern SchriftGX2 *gFontSystem;
|
||||
extern bool gOverlayInitDone;
|
||||
extern bool gDrawReady;
|
169
src/shaders/ColorShader.cpp
Normal file
169
src/shaders/ColorShader.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#include "ColorShader.h"
|
||||
|
||||
static const uint32_t cpVertexShaderProgram[] = {
|
||||
0x00000000, 0x00008009, 0x20000000, 0x000078a0,
|
||||
0x3c200000, 0x88060094, 0x00c00000, 0x88062014,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00a11f00, 0xfc00620f, 0x02490001, 0x80000040,
|
||||
0xfd041f80, 0x900c0060, 0x83f9223e, 0x0000803f,
|
||||
0xfe282001, 0x10000040, 0xfe001f80, 0x00080060,
|
||||
0xfeac9f80, 0xfd00624f, 0xdb0f49c0, 0xdb0fc940,
|
||||
0xfea81f80, 0x9000e02f, 0x83f9223e, 0x00000000,
|
||||
0xfe041f80, 0x00370000, 0xffa01f00, 0x80000000,
|
||||
0xff101f00, 0x800c0020, 0x7f041f80, 0x80370000,
|
||||
0x0000103f, 0x00000000, 0x02c51f00, 0x80000000,
|
||||
0xfea41f00, 0x80000020, 0xffa09f00, 0x80000040,
|
||||
0xff001f80, 0x800c0060, 0x398ee33f, 0x0000103f,
|
||||
0x02c41f00, 0x9000e00f, 0x02c59f01, 0x80000020,
|
||||
0xfea81f00, 0x80000040, 0x02c19f80, 0x9000e06f,
|
||||
0x398ee33f, 0x00000000, 0x02c11f01, 0x80000000,
|
||||
0x02c49f80, 0x80000060, 0x02e08f01, 0xfe0c620f,
|
||||
0x02c01f80, 0x7f00622f, 0xfe242000, 0x10000000,
|
||||
0xfe20a080, 0x10000020, 0xf2178647, 0x49c0e9fb,
|
||||
0xfbbdb2ab, 0x768ac733};
|
||||
|
||||
static const uint32_t cpVertexShaderRegs[] = {
|
||||
0x00000103, 0x00000000, 0x00000000, 0x00000001,
|
||||
0xffffff00, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0x00000000, 0xfffffffc,
|
||||
0x00000002, 0x00000001, 0x00000000, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x00000000, 0x0000000e, 0x00000010};
|
||||
|
||||
static const uint32_t cpPixelShaderProgram[] = {
|
||||
0x20000000, 0x00000ca0, 0x00000000, 0x88062094,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00002000, 0x90000000, 0x0004a000, 0x90000020,
|
||||
0x00082001, 0x90000040, 0x000ca081, 0x90000060,
|
||||
0xbb7dd898, 0x9746c59c, 0xc69b00e7, 0x03c36218};
|
||||
static const uint32_t cpPixelShaderRegs[] = {
|
||||
0x00000001, 0x00000002, 0x14000001, 0x00000000,
|
||||
0x00000001, 0x00000100, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x0000000f, 0x00000001, 0x00000010,
|
||||
0x00000000};
|
||||
|
||||
ColorShader *ColorShader::shaderInstance = nullptr;
|
||||
|
||||
ColorShader::ColorShader()
|
||||
: vertexShader(cuAttributeCount) {
|
||||
//! create pixel shader
|
||||
pixelShader.setProgram(cpPixelShaderProgram, sizeof(cpPixelShaderProgram), cpPixelShaderRegs, sizeof(cpPixelShaderRegs));
|
||||
|
||||
colorIntensityLocation = 0;
|
||||
pixelShader.addUniformVar((GX2UniformVar){
|
||||
"unf_color_intensity", GX2_SHADER_VAR_TYPE_FLOAT4, 1, colorIntensityLocation, -1});
|
||||
|
||||
//! create vertex shader
|
||||
vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs));
|
||||
|
||||
angleLocation = 0;
|
||||
offsetLocation = 4;
|
||||
scaleLocation = 8;
|
||||
vertexShader.addUniformVar((GX2UniformVar){
|
||||
"unf_angle", GX2_SHADER_VAR_TYPE_FLOAT, 1, angleLocation, -1});
|
||||
vertexShader.addUniformVar((GX2UniformVar){
|
||||
"unf_offset", GX2_SHADER_VAR_TYPE_FLOAT3, 1, offsetLocation, -1});
|
||||
vertexShader.addUniformVar((GX2UniformVar){
|
||||
"unf_scale", GX2_SHADER_VAR_TYPE_FLOAT3, 1, scaleLocation, -1});
|
||||
|
||||
colorLocation = 1;
|
||||
positionLocation = 0;
|
||||
vertexShader.addAttribVar((GX2AttribVar){
|
||||
"attr_color", GX2_SHADER_VAR_TYPE_FLOAT4, 0, colorLocation});
|
||||
vertexShader.addAttribVar((GX2AttribVar){
|
||||
"attr_position", GX2_SHADER_VAR_TYPE_FLOAT3, 0, positionLocation});
|
||||
|
||||
//! setup attribute streams
|
||||
GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32_32);
|
||||
GX2InitAttribStream(vertexShader.getAttributeBuffer(1), colorLocation, 1, 0, GX2_ATTRIB_FORMAT_UNORM_8_8_8_8);
|
||||
|
||||
//! create fetch shader
|
||||
fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount());
|
||||
|
||||
//! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000
|
||||
positionVtxs = (float *) MEMAllocFromMappedMemoryForGX2Ex(cuPositionVtxsSize, GX2_VERTEX_BUFFER_ALIGNMENT);
|
||||
if (positionVtxs) {
|
||||
//! position vertex structure
|
||||
int32_t i = 0;
|
||||
positionVtxs[i++] = -1.0f;
|
||||
positionVtxs[i++] = -1.0f;
|
||||
positionVtxs[i++] = 0.0f;
|
||||
positionVtxs[i++] = 1.0f;
|
||||
positionVtxs[i++] = -1.0f;
|
||||
positionVtxs[i++] = 0.0f;
|
||||
positionVtxs[i++] = 1.0f;
|
||||
positionVtxs[i++] = 1.0f;
|
||||
positionVtxs[i++] = 0.0f;
|
||||
positionVtxs[i++] = -1.0f;
|
||||
positionVtxs[i++] = 1.0f;
|
||||
positionVtxs[i++] = 0.0f;
|
||||
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, positionVtxs, cuPositionVtxsSize);
|
||||
}
|
||||
}
|
||||
|
||||
ColorShader::~ColorShader() {
|
||||
if (positionVtxs) {
|
||||
MEMFreeToMappedMemory(positionVtxs);
|
||||
positionVtxs = nullptr;
|
||||
}
|
||||
|
||||
delete fetchShader;
|
||||
fetchShader = nullptr;
|
||||
}
|
90
src/shaders/ColorShader.h
Normal file
90
src/shaders/ColorShader.h
Normal file
@ -0,0 +1,90 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "FetchShader.h"
|
||||
#include "PixelShader.h"
|
||||
#include "VertexShader.h"
|
||||
|
||||
class ColorShader : public Shader {
|
||||
private:
|
||||
ColorShader();
|
||||
virtual ~ColorShader();
|
||||
|
||||
static const uint32_t cuAttributeCount = 2;
|
||||
static const uint32_t cuPositionVtxsSize = 4 * cuVertexAttrSize;
|
||||
|
||||
static ColorShader *shaderInstance;
|
||||
|
||||
FetchShader *fetchShader;
|
||||
VertexShader vertexShader;
|
||||
PixelShader pixelShader;
|
||||
|
||||
float *positionVtxs;
|
||||
|
||||
uint32_t angleLocation;
|
||||
uint32_t offsetLocation;
|
||||
uint32_t scaleLocation;
|
||||
uint32_t colorLocation;
|
||||
uint32_t colorIntensityLocation;
|
||||
uint32_t positionLocation;
|
||||
|
||||
public:
|
||||
static const uint32_t cuColorVtxsSize = 4 * cuColorAttrSize;
|
||||
|
||||
static ColorShader *instance() {
|
||||
if (!shaderInstance) {
|
||||
shaderInstance = new ColorShader();
|
||||
}
|
||||
return shaderInstance;
|
||||
}
|
||||
static void destroyInstance() {
|
||||
if (shaderInstance) {
|
||||
delete shaderInstance;
|
||||
shaderInstance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void setShaders() const {
|
||||
fetchShader->setShader();
|
||||
vertexShader.setShader();
|
||||
pixelShader.setShader();
|
||||
}
|
||||
|
||||
void setAttributeBuffer(const uint8_t *colorAttr, const float *posVtxs_in = nullptr, const uint32_t &vtxCount = 0) const {
|
||||
if (posVtxs_in && vtxCount) {
|
||||
VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in);
|
||||
VertexShader::setAttributeBuffer(1, vtxCount * cuColorAttrSize, cuColorAttrSize, colorAttr);
|
||||
} else {
|
||||
VertexShader::setAttributeBuffer(0, cuPositionVtxsSize, cuVertexAttrSize, positionVtxs);
|
||||
VertexShader::setAttributeBuffer(1, cuColorVtxsSize, cuColorAttrSize, colorAttr);
|
||||
}
|
||||
}
|
||||
|
||||
void setAngle(const float &val) const {
|
||||
VertexShader::setUniformReg(angleLocation, 4, &val);
|
||||
}
|
||||
void setOffset(const glm::vec3 &vec) const {
|
||||
VertexShader::setUniformReg(offsetLocation, 4, &vec[0]);
|
||||
}
|
||||
void setScale(const glm::vec3 &vec) const {
|
||||
VertexShader::setUniformReg(scaleLocation, 4, &vec[0]);
|
||||
}
|
||||
void setColorIntensity(const glm::vec4 &vec) const {
|
||||
PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]);
|
||||
}
|
||||
};
|
55
src/shaders/FetchShader.h
Normal file
55
src/shaders/FetchShader.h
Normal file
@ -0,0 +1,55 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "Shader.h"
|
||||
#include <malloc.h>
|
||||
#include <memory/mappedmemory.h>
|
||||
|
||||
class FetchShader : public Shader {
|
||||
public:
|
||||
FetchShader(GX2AttribStream *attributes, uint32_t attrCount, GX2FetchShaderType type = GX2_FETCH_SHADER_TESSELLATION_NONE, GX2TessellationMode tess = GX2_TESSELLATION_MODE_DISCRETE)
|
||||
: fetchShader(nullptr), fetchShaderProgramm(nullptr) {
|
||||
uint32_t shaderSize = GX2CalcFetchShaderSizeEx(attrCount, type, tess);
|
||||
fetchShaderProgramm = (uint8_t *) MEMAllocFromMappedMemoryForGX2Ex(shaderSize, GX2_SHADER_PROGRAM_ALIGNMENT);
|
||||
if (fetchShaderProgramm) {
|
||||
fetchShader = (GX2FetchShader *) memalign(0x40, sizeof(GX2FetchShader));
|
||||
GX2InitFetchShaderEx(fetchShader, fetchShaderProgramm, attrCount, attributes, type, tess);
|
||||
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, fetchShaderProgramm, shaderSize);
|
||||
}
|
||||
}
|
||||
~FetchShader() override {
|
||||
if (fetchShaderProgramm) {
|
||||
MEMFreeToMappedMemory(fetchShaderProgramm);
|
||||
}
|
||||
if (fetchShader) {
|
||||
free(fetchShader);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] GX2FetchShader *getFetchShader() const {
|
||||
return fetchShader;
|
||||
}
|
||||
|
||||
void setShader() const {
|
||||
GX2SetFetchShader(fetchShader);
|
||||
}
|
||||
|
||||
protected:
|
||||
GX2FetchShader *fetchShader;
|
||||
uint8_t *fetchShaderProgramm;
|
||||
};
|
137
src/shaders/PixelShader.h
Normal file
137
src/shaders/PixelShader.h
Normal file
@ -0,0 +1,137 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "Shader.h"
|
||||
#include <malloc.h>
|
||||
|
||||
class PixelShader : public Shader {
|
||||
public:
|
||||
PixelShader()
|
||||
: pixelShader((GX2PixelShader *) memalign(0x40, sizeof(GX2PixelShader))) {
|
||||
if (pixelShader) {
|
||||
memset(pixelShader, 0, sizeof(GX2PixelShader));
|
||||
pixelShader->mode = GX2_SHADER_MODE_UNIFORM_REGISTER;
|
||||
}
|
||||
}
|
||||
~PixelShader() override {
|
||||
if (pixelShader) {
|
||||
if (pixelShader->program) {
|
||||
MEMFreeToMappedMemory(pixelShader->program);
|
||||
}
|
||||
for (uint32_t i = 0; i < pixelShader->uniformBlockCount; i++) {
|
||||
free((void *) pixelShader->uniformBlocks[i].name);
|
||||
}
|
||||
if (pixelShader->uniformBlocks) {
|
||||
free((void *) pixelShader->uniformBlocks);
|
||||
}
|
||||
for (uint32_t i = 0; i < pixelShader->uniformVarCount; i++) {
|
||||
free((void *) pixelShader->uniformVars[i].name);
|
||||
}
|
||||
if (pixelShader->uniformVars) {
|
||||
free((void *) pixelShader->uniformVars);
|
||||
}
|
||||
if (pixelShader->initialValues) {
|
||||
free((void *) pixelShader->initialValues);
|
||||
}
|
||||
for (uint32_t i = 0; i < pixelShader->samplerVarCount; i++) {
|
||||
free((void *) pixelShader->samplerVars[i].name);
|
||||
}
|
||||
if (pixelShader->samplerVars) {
|
||||
free((void *) pixelShader->samplerVars);
|
||||
}
|
||||
if (pixelShader->loopVars) {
|
||||
free((void *) pixelShader->loopVars);
|
||||
}
|
||||
free(pixelShader);
|
||||
}
|
||||
}
|
||||
|
||||
void setProgram(const uint32_t *program, const uint32_t &programSize, const uint32_t *regs, const uint32_t ®sSize) {
|
||||
if (!pixelShader)
|
||||
return;
|
||||
|
||||
//! this must be moved into an area where the graphic engine has access to and must be aligned to 0x100
|
||||
pixelShader->size = programSize;
|
||||
pixelShader->program = (uint8_t *) MEMAllocFromMappedMemoryForGX2Ex(pixelShader->size, GX2_SHADER_PROGRAM_ALIGNMENT);
|
||||
if (pixelShader->program) {
|
||||
memcpy(pixelShader->program, program, pixelShader->size);
|
||||
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, pixelShader->program, pixelShader->size);
|
||||
}
|
||||
|
||||
memcpy(&pixelShader->regs, regs, regsSize);
|
||||
}
|
||||
|
||||
void addUniformVar(const GX2UniformVar &var) {
|
||||
if (!pixelShader) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t idx = pixelShader->uniformVarCount;
|
||||
|
||||
auto *newVar = (GX2UniformVar *) memalign(0x40, (pixelShader->uniformVarCount + 1) * sizeof(GX2UniformVar));
|
||||
if (newVar) {
|
||||
if (pixelShader->uniformVars) {
|
||||
memcpy(newVar, pixelShader->uniformVars, pixelShader->uniformVarCount * sizeof(GX2UniformVar));
|
||||
free(pixelShader->uniformVars);
|
||||
}
|
||||
pixelShader->uniformVars = newVar;
|
||||
|
||||
memcpy(pixelShader->uniformVars + idx, &var, sizeof(GX2UniformVar));
|
||||
pixelShader->uniformVars[idx].name = (char *) memalign(0x40, strlen(var.name) + 1);
|
||||
strcpy((char *) pixelShader->uniformVars[idx].name, var.name);
|
||||
|
||||
pixelShader->uniformVarCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void addSamplerVar(const GX2SamplerVar &var) {
|
||||
if (!pixelShader)
|
||||
return;
|
||||
|
||||
uint32_t idx = pixelShader->samplerVarCount;
|
||||
|
||||
auto *newVar = (GX2SamplerVar *) memalign(0x40, (pixelShader->samplerVarCount + 1) * sizeof(GX2SamplerVar));
|
||||
if (newVar) {
|
||||
if (pixelShader->samplerVars) {
|
||||
memcpy(newVar, pixelShader->samplerVars, pixelShader->samplerVarCount * sizeof(GX2SamplerVar));
|
||||
free(pixelShader->samplerVars);
|
||||
}
|
||||
pixelShader->samplerVars = newVar;
|
||||
|
||||
memcpy(pixelShader->samplerVars + idx, &var, sizeof(GX2SamplerVar));
|
||||
pixelShader->samplerVars[idx].name = (char *) memalign(0x40, strlen(var.name) + 1);
|
||||
strcpy((char *) pixelShader->samplerVars[idx].name, var.name);
|
||||
|
||||
pixelShader->samplerVarCount++;
|
||||
}
|
||||
}
|
||||
[[nodiscard]] GX2PixelShader *getPixelShader() const {
|
||||
return pixelShader;
|
||||
}
|
||||
|
||||
void setShader() const {
|
||||
GX2SetPixelShader(pixelShader);
|
||||
}
|
||||
|
||||
static inline void setUniformReg(uint32_t location, uint32_t size, const void *reg) {
|
||||
GX2SetPixelUniformReg(location, size, (uint32_t *) reg);
|
||||
}
|
||||
|
||||
protected:
|
||||
GX2PixelShader *pixelShader;
|
||||
};
|
70
src/shaders/Shader.h
Normal file
70
src/shaders/Shader.h
Normal file
@ -0,0 +1,70 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "gx2_ext.h"
|
||||
#pragma GCC diagnostic ignored "-Wvolatile"
|
||||
#include <glm/glm.hpp>
|
||||
#include <gx2/draw.h>
|
||||
#include <gx2/enum.h>
|
||||
#include <gx2/mem.h>
|
||||
#include <gx2/registers.h>
|
||||
#include <gx2/shaders.h>
|
||||
#include <gx2/texture.h>
|
||||
#include <memory/mappedmemory.h>
|
||||
|
||||
class Shader {
|
||||
protected:
|
||||
Shader() = default;
|
||||
virtual ~Shader() = default;
|
||||
|
||||
public:
|
||||
static const uint16_t cuVertexAttrSize = sizeof(float) * 3;
|
||||
static const uint16_t cuTexCoordAttrSize = sizeof(float) * 2;
|
||||
static const uint16_t cuColorAttrSize = sizeof(uint8_t) * 4;
|
||||
|
||||
static void setLineWidth(const float &width) {
|
||||
GX2SetLineWidth(width);
|
||||
}
|
||||
|
||||
static void draw(int32_t primitive = GX2_PRIMITIVE_MODE_QUADS, uint32_t vtxCount = 4) {
|
||||
switch (primitive) {
|
||||
default:
|
||||
case GX2_PRIMITIVE_MODE_QUADS: {
|
||||
GX2DrawEx(GX2_PRIMITIVE_MODE_QUADS, vtxCount, 0, 1);
|
||||
break;
|
||||
}
|
||||
case GX2_PRIMITIVE_MODE_TRIANGLES: {
|
||||
GX2DrawEx(GX2_PRIMITIVE_MODE_TRIANGLES, vtxCount, 0, 1);
|
||||
break;
|
||||
}
|
||||
case GX2_PRIMITIVE_MODE_TRIANGLE_FAN: {
|
||||
GX2DrawEx(GX2_PRIMITIVE_MODE_TRIANGLE_FAN, vtxCount, 0, 1);
|
||||
break;
|
||||
}
|
||||
case GX2_PRIMITIVE_MODE_LINES: {
|
||||
GX2DrawEx(GX2_PRIMITIVE_MODE_LINES, vtxCount, 0, 1);
|
||||
break;
|
||||
}
|
||||
case GX2_PRIMITIVE_MODE_LINE_STRIP: {
|
||||
GX2DrawEx(GX2_PRIMITIVE_MODE_LINE_STRIP, vtxCount, 0, 1);
|
||||
break;
|
||||
}
|
||||
//! TODO: add other primitives later
|
||||
};
|
||||
}
|
||||
};
|
279
src/shaders/Texture2DShader.cpp
Normal file
279
src/shaders/Texture2DShader.cpp
Normal file
@ -0,0 +1,279 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#include "Texture2DShader.h"
|
||||
|
||||
static const uint32_t cpVertexShaderProgram[] = {
|
||||
0x00000000, 0x00008009, 0x20000000, 0x000080a0,
|
||||
0x3c200100, 0x88060094, 0x00400000, 0x88042014,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x02290001, 0x80000000, 0x02041f00, 0x900c0020,
|
||||
0x00a11f00, 0xfc00624f, 0xfd041f00, 0x900c4060,
|
||||
0x02001f80, 0x900c0000, 0x83f9223e, 0x0000803f,
|
||||
0xfe081f00, 0x00080020, 0xfe202081, 0x10004040,
|
||||
0xfea49f80, 0xfd00620f, 0xdb0f49c0, 0xdb0fc940,
|
||||
0xfea01f80, 0x9000e06f, 0x83f9223e, 0x00000000,
|
||||
0xfe0c1f80, 0x00370000, 0xffa01f00, 0x80000040,
|
||||
0xff101f00, 0x800c0060, 0x7f0c1f80, 0x80370040,
|
||||
0x0000103f, 0x00000000, 0xffa01f00, 0x80000000,
|
||||
0xff001f00, 0x800c0020, 0x02c51f01, 0x80000040,
|
||||
0xfeac9f80, 0x80000060, 0x0000103f, 0x398ee33f,
|
||||
0xfea01f00, 0x80000000, 0x02c19f01, 0x9000e02f,
|
||||
0x01c41f01, 0x9000e04f, 0x02c59f80, 0x80000060,
|
||||
0x398ee33f, 0x00000000, 0x01c49f01, 0x80000020,
|
||||
0x02c11f80, 0x80000040, 0x01e08f00, 0xfe04624f,
|
||||
0x01c01f81, 0x7f08626f, 0xfe2c2000, 0x10004000,
|
||||
0xfe28a080, 0x10004020, 0xeb825790, 0xb6f711be,
|
||||
0x7c0e2df2, 0x81173cfa};
|
||||
|
||||
static const uint32_t cpVertexShaderRegs[] = {
|
||||
0x00000103, 0x00000000, 0x00000000, 0x00000001,
|
||||
0xffffff00, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0x00000000, 0xfffffffc,
|
||||
0x00000002, 0x00000000, 0x00000001, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
0x000000ff, 0x00000000, 0x0000000e, 0x00000010};
|
||||
|
||||
static const uint32_t cPixelShaderProgram[] = {
|
||||
0x20000000, 0x00000ca4, 0x0b000000, 0x00000085,
|
||||
0x24000000, 0x000050a0, 0xb0000000, 0x000cc080,
|
||||
0x39000000, 0x00005ca0, 0xb8000000, 0x000cc080,
|
||||
0x51000000, 0x000078a0, 0xc0000000, 0x000cc080,
|
||||
0x70000000, 0x000064a0, 0xc8000000, 0x0008c080,
|
||||
0x8a000000, 0x00005ca0, 0x0e000000, 0x01008086,
|
||||
0xce000000, 0x0000c080, 0xa2000000, 0x00000ca8,
|
||||
0x00800000, 0x88062094, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00051f00, 0x80060000, 0x00011f80, 0x80060040,
|
||||
0xfec81f80, 0xfb802320, 0x01041f80, 0x8c220000,
|
||||
0x00a41f00, 0xfc10620f, 0x010d1f00, 0x900c0021,
|
||||
0x00091f00, 0x80060040, 0x00a01f80, 0xfc10626f,
|
||||
0x00000040, 0x00000000, 0xfe080000, 0xfe8cc300,
|
||||
0xfe088080, 0xfe80c320, 0x00a11f00, 0xfe000200,
|
||||
0x00a51f00, 0xfe040220, 0x00a19f00, 0xfe000240,
|
||||
0x00a59f00, 0xfe040260, 0x00a11f81, 0xfe002600,
|
||||
0x4260e5bc, 0xa69bc4bc, 0x0ad7a3bc, 0x00000000,
|
||||
0x00a11f00, 0x06004200, 0x00a59f00, 0x06042220,
|
||||
0x00a51f00, 0x06044240, 0x00a11f01, 0x06008260,
|
||||
0x00a51f81, 0x06048620, 0x6f1283bc, 0x0ad7a3bc,
|
||||
0xa69b44bc, 0x00000000, 0x00a41f00, 0x80000000,
|
||||
0x00a01f00, 0x80000020, 0x00ac1f00, 0x80000040,
|
||||
0x00a81f00, 0x80000060, 0x00a19f80, 0x06000600,
|
||||
0xcac3123c, 0x6f1203bc, 0x03a41f00, 0xfe00620f,
|
||||
0x03a01f00, 0xfe04622f, 0x03ac1f00, 0xfe08624f,
|
||||
0x03a81f00, 0xfe0c626f, 0x00a59f80, 0x06040620,
|
||||
0xcc28913b, 0x6f1203bc, 0x01a41f00, 0xfe00620f,
|
||||
0x01a01f00, 0xfe04622f, 0x01ac1f00, 0xfe08624f,
|
||||
0x01a81f00, 0xfe0c626f, 0x00a19f80, 0x06002600,
|
||||
0xe8eab03c, 0x6f1283bb, 0x02ac1f00, 0xfe084200,
|
||||
0x02a81f00, 0xfe0c4220, 0x02a41f00, 0xfe004240,
|
||||
0x02a01f00, 0xfe044260, 0x00a59f80, 0x06042620,
|
||||
0x92bb353d, 0x6f1283bb, 0x04a81f00, 0x0204620f,
|
||||
0x04ac1f00, 0x0200662f, 0x04a41f00, 0x0208624f,
|
||||
0x04a01f00, 0x020c626f, 0x00a19f80, 0x06004600,
|
||||
0xc4139f3d, 0x6f12833b, 0x00a41f00, 0xfe08620f,
|
||||
0x00a01f00, 0xfe0c622f, 0x00ac1f00, 0xfe04624f,
|
||||
0x00a81f00, 0xfe00626f, 0x00a59f80, 0x06044620,
|
||||
0xb950ed3d, 0x6f12833b, 0x01a41f00, 0xfe00620f,
|
||||
0x01a01f00, 0xfe04622f, 0x01ac1f00, 0xfe08624f,
|
||||
0x01a81f00, 0xfe0c626f, 0x00a19f80, 0x06002600,
|
||||
0xecd7163e, 0x6f12033c, 0x03a41f00, 0xfe000200,
|
||||
0x03a01f00, 0xfe040220, 0x03ac1f00, 0xfe082240,
|
||||
0x03a81f00, 0xfe0c2260, 0x00a59f80, 0x06042620,
|
||||
0x2168233e, 0x6f12033c, 0x00a11f00, 0x06006200,
|
||||
0x00a51f00, 0x06046220, 0x00a19f00, 0x06006240,
|
||||
0x00a59f00, 0x06046260, 0x00a11f81, 0x0600e600,
|
||||
0xa69b443c, 0x6f12833c, 0x0ad7a33c, 0x00000000,
|
||||
0x02ac1f00, 0x0108620f, 0x02a81f00, 0x010c622f,
|
||||
0x02a41f00, 0x0000624f, 0x02a01f00, 0x0004666f,
|
||||
0x00a59f80, 0x0604e620, 0xecd7163e, 0x0ad7a33c,
|
||||
0x04a81f00, 0xfe04620f, 0x04ac1f00, 0xfe00622f,
|
||||
0x04a41f00, 0xfe08624f, 0x04a01f00, 0xfe0c626f,
|
||||
0x00a19f80, 0x06008600, 0xb950ed3d, 0xa69bc43c,
|
||||
0x05a41f00, 0xfe08620f, 0x05a01f00, 0xfe0c622f,
|
||||
0x05ac1f00, 0xfe04624f, 0x05a81f00, 0xfe00626f,
|
||||
0x00a59f80, 0x06048620, 0xc4139f3d, 0xa69bc43c,
|
||||
0x03a41f00, 0xfe00a200, 0x03a01f00, 0xfe04a220,
|
||||
0x03ac1f00, 0xfe086240, 0x03a81f00, 0xfe0c6260,
|
||||
0x00a19f80, 0x06006600, 0x92bb353d, 0x4260e53c,
|
||||
0x00a51f80, 0x06046220, 0x4260e53c, 0x00000000,
|
||||
0x07ac1f00, 0x0308620f, 0x07a81f00, 0x030c622f,
|
||||
0x07a41f00, 0x0500624f, 0x07a01f80, 0x0504626f,
|
||||
0xe8eab03c, 0x00000000, 0x04a81f00, 0xfe04620f,
|
||||
0x04ac1f00, 0xfe00622f, 0x04a41f00, 0xfe08624f,
|
||||
0x04a01f80, 0xfe0c626f, 0xcac3123c, 0x00000000,
|
||||
0x06a41f00, 0xfe08620f, 0x06a01f00, 0xfe0c622f,
|
||||
0x06ac1f00, 0xfe04624f, 0x06a81f80, 0xfe00626f,
|
||||
0xcc28913b, 0x00000000, 0xfe20a000, 0x9000e00f,
|
||||
0xfe242000, 0x9000e02f, 0xfe28a001, 0x9000e04f,
|
||||
0xfe2c2081, 0x9000e06f, 0xfe28a081, 0x80060020,
|
||||
0xfee48f00, 0x7f842300, 0xfee40f00, 0x7f802320,
|
||||
0xfee48f01, 0x7f8c2340, 0xfee40f81, 0x08842b60,
|
||||
0x00202000, 0x90002000, 0x0024a000, 0x90002020,
|
||||
0x00282001, 0x90002040, 0x002ca081, 0x90002060,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x10000000, 0x03100df0, 0x00008010, 0xecdfea0d,
|
||||
0x10000000, 0x00100df0, 0x0000a051, 0xecdfea0d,
|
||||
0x10000100, 0x01100df0, 0x00008010, 0xecdfea0d,
|
||||
0x10000200, 0x02100df0, 0x00000011, 0xecdfea0d,
|
||||
0x10000400, 0x04100df0, 0x0000b070, 0xecdfea0d,
|
||||
0x10000000, 0x00100df0, 0x00008010, 0xecdfea0d,
|
||||
0x10000100, 0x01100df0, 0x00008010, 0xecdfea0d,
|
||||
0x10000600, 0x03100df0, 0x00008010, 0xecdfea0d,
|
||||
0x10000200, 0x02100df0, 0x00008010, 0xecdfea0d,
|
||||
0x10000100, 0x04100df0, 0x00008010, 0xecdfea0d,
|
||||
0x10000300, 0x05100df0, 0x00008010, 0xecdfea0d,
|
||||
0x10000300, 0x03100df0, 0x0000a051, 0xecdfea0d,
|
||||
0x10000700, 0x07100df0, 0x00008010, 0xecdfea0d,
|
||||
0x10000400, 0x04100df0, 0x00008010, 0xecdfea0d,
|
||||
0x10000300, 0x06100df0, 0x00008010, 0xecdfea0d,
|
||||
0x10000000, 0x00100df0, 0x00008010, 0xecdfea0d,
|
||||
0xc8581837, 0x22740275, 0x281eddcc, 0xfa8b9b65};
|
||||
static const uint32_t cPixelShaderRegs[] = {
|
||||
0x00000109, 0x00000002, 0x14000001, 0x00000000,
|
||||
0x00000001, 0x00000100, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x0000000f, 0x00000001, 0x00000010,
|
||||
0x00000000};
|
||||
|
||||
Texture2DShader *Texture2DShader::shaderInstance = nullptr;
|
||||
|
||||
Texture2DShader::Texture2DShader()
|
||||
: vertexShader(cuAttributeCount) {
|
||||
//! create pixel shader
|
||||
pixelShader.setProgram(cPixelShaderProgram, sizeof(cPixelShaderProgram), cPixelShaderRegs, sizeof(cPixelShaderRegs));
|
||||
|
||||
blurLocation = 0;
|
||||
colorIntensityLocation = 4;
|
||||
pixelShader.addUniformVar((GX2UniformVar){
|
||||
"unf_blur_texture_direction", GX2_SHADER_VAR_TYPE_FLOAT3, 1, blurLocation, -1});
|
||||
pixelShader.addUniformVar((GX2UniformVar){
|
||||
"unf_color_intensity", GX2_SHADER_VAR_TYPE_FLOAT4, 1, colorIntensityLocation, -1});
|
||||
|
||||
samplerLocation = 0;
|
||||
pixelShader.addSamplerVar((GX2SamplerVar){
|
||||
"sampl_texture", GX2_SAMPLER_VAR_TYPE_SAMPLER_2D, samplerLocation});
|
||||
|
||||
//! create vertex shader
|
||||
vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs));
|
||||
|
||||
angleLocation = 0;
|
||||
offsetLocation = 4;
|
||||
scaleLocation = 8;
|
||||
vertexShader.addUniformVar((GX2UniformVar){
|
||||
"unf_angle", GX2_SHADER_VAR_TYPE_FLOAT, 1, angleLocation, -1});
|
||||
vertexShader.addUniformVar((GX2UniformVar){
|
||||
"unf_offset", GX2_SHADER_VAR_TYPE_FLOAT3, 1, offsetLocation, -1});
|
||||
vertexShader.addUniformVar((GX2UniformVar){
|
||||
"unf_scale", GX2_SHADER_VAR_TYPE_FLOAT3, 1, scaleLocation, -1});
|
||||
|
||||
positionLocation = 0;
|
||||
texCoordLocation = 1;
|
||||
vertexShader.addAttribVar((GX2AttribVar){
|
||||
"attr_position", GX2_SHADER_VAR_TYPE_FLOAT3, 0, positionLocation});
|
||||
vertexShader.addAttribVar((GX2AttribVar){
|
||||
"attr_texture_coord", GX2_SHADER_VAR_TYPE_FLOAT2, 0, texCoordLocation});
|
||||
|
||||
//! setup attribute streams
|
||||
GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32_32);
|
||||
GX2InitAttribStream(vertexShader.getAttributeBuffer(1), texCoordLocation, 1, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32);
|
||||
|
||||
//! create fetch shader
|
||||
fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount());
|
||||
|
||||
//! model vertex and texture coords have to be align and cannot be in unknown regions for GX2 like 0xBCAE1000
|
||||
posVtxs = (float *) MEMAllocFromMappedMemoryForGX2Ex(ciPositionVtxsSize, GX2_VERTEX_BUFFER_ALIGNMENT);
|
||||
texCoords = (float *) MEMAllocFromMappedMemoryForGX2Ex(ciTexCoordsVtxsSize, GX2_VERTEX_BUFFER_ALIGNMENT);
|
||||
|
||||
//! defaults for normal square
|
||||
//! position vertex structure and texture coordinate vertex structure
|
||||
int32_t i = 0;
|
||||
posVtxs[i++] = -1.0f;
|
||||
posVtxs[i++] = -1.0f;
|
||||
posVtxs[i++] = 0.0f;
|
||||
posVtxs[i++] = 1.0f;
|
||||
posVtxs[i++] = -1.0f;
|
||||
posVtxs[i++] = 0.0f;
|
||||
posVtxs[i++] = 1.0f;
|
||||
posVtxs[i++] = 1.0f;
|
||||
posVtxs[i++] = 0.0f;
|
||||
posVtxs[i++] = -1.0f;
|
||||
posVtxs[i++] = 1.0f;
|
||||
posVtxs[i++] = 0.0f;
|
||||
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, posVtxs, ciPositionVtxsSize);
|
||||
|
||||
i = 0;
|
||||
texCoords[i++] = 0.0f;
|
||||
texCoords[i++] = 1.0f;
|
||||
texCoords[i++] = 1.0f;
|
||||
texCoords[i++] = 1.0f;
|
||||
texCoords[i++] = 1.0f;
|
||||
texCoords[i++] = 0.0f;
|
||||
texCoords[i++] = 0.0f;
|
||||
texCoords[i++] = 0.0f;
|
||||
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, texCoords, ciTexCoordsVtxsSize);
|
||||
}
|
||||
|
||||
Texture2DShader::~Texture2DShader() {
|
||||
if (posVtxs) {
|
||||
MEMFreeToMappedMemory(posVtxs);
|
||||
posVtxs = nullptr;
|
||||
}
|
||||
if (texCoords) {
|
||||
MEMFreeToMappedMemory(texCoords);
|
||||
texCoords = nullptr;
|
||||
}
|
||||
|
||||
delete fetchShader;
|
||||
fetchShader = nullptr;
|
||||
}
|
104
src/shaders/Texture2DShader.h
Normal file
104
src/shaders/Texture2DShader.h
Normal file
@ -0,0 +1,104 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#ifndef __TEXTURE_2D_SHADER_H_
|
||||
#define __TEXTURE_2D_SHADER_H_
|
||||
|
||||
#include "FetchShader.h"
|
||||
#include "PixelShader.h"
|
||||
#include "VertexShader.h"
|
||||
|
||||
|
||||
class Texture2DShader : public Shader {
|
||||
private:
|
||||
Texture2DShader();
|
||||
virtual ~Texture2DShader();
|
||||
|
||||
static const uint32_t cuAttributeCount = 2;
|
||||
static const uint32_t ciPositionVtxsSize = 4 * cuVertexAttrSize;
|
||||
static const uint32_t ciTexCoordsVtxsSize = 4 * cuTexCoordAttrSize;
|
||||
|
||||
static Texture2DShader *shaderInstance;
|
||||
|
||||
FetchShader *fetchShader;
|
||||
VertexShader vertexShader;
|
||||
PixelShader pixelShader;
|
||||
|
||||
float *posVtxs;
|
||||
float *texCoords;
|
||||
|
||||
uint32_t angleLocation;
|
||||
uint32_t offsetLocation;
|
||||
uint32_t scaleLocation;
|
||||
uint32_t colorIntensityLocation;
|
||||
uint32_t blurLocation;
|
||||
uint32_t samplerLocation;
|
||||
uint32_t positionLocation;
|
||||
uint32_t texCoordLocation;
|
||||
|
||||
public:
|
||||
static Texture2DShader *instance() {
|
||||
if (!shaderInstance) {
|
||||
shaderInstance = new Texture2DShader();
|
||||
}
|
||||
return shaderInstance;
|
||||
}
|
||||
static void destroyInstance() {
|
||||
if (shaderInstance) {
|
||||
delete shaderInstance;
|
||||
shaderInstance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void setShaders() const {
|
||||
fetchShader->setShader();
|
||||
vertexShader.setShader();
|
||||
pixelShader.setShader();
|
||||
}
|
||||
|
||||
void setAttributeBuffer(const float *texCoords_in = nullptr, const float *posVtxs_in = nullptr, const uint32_t &vtxCount = 0) const {
|
||||
if (posVtxs_in && texCoords_in && vtxCount) {
|
||||
VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in);
|
||||
VertexShader::setAttributeBuffer(1, vtxCount * cuTexCoordAttrSize, cuTexCoordAttrSize, texCoords_in);
|
||||
} else {
|
||||
VertexShader::setAttributeBuffer(0, ciPositionVtxsSize, cuVertexAttrSize, posVtxs);
|
||||
VertexShader::setAttributeBuffer(1, ciTexCoordsVtxsSize, cuTexCoordAttrSize, texCoords);
|
||||
}
|
||||
}
|
||||
|
||||
void setAngle(const float &val) {
|
||||
VertexShader::setUniformReg(angleLocation, 4, &val);
|
||||
}
|
||||
void setOffset(const glm::vec3 &vec) {
|
||||
VertexShader::setUniformReg(offsetLocation, 4, &vec[0]);
|
||||
}
|
||||
void setScale(const glm::vec3 &vec) {
|
||||
VertexShader::setUniformReg(scaleLocation, 4, &vec[0]);
|
||||
}
|
||||
void setColorIntensity(const glm::vec4 &vec) {
|
||||
PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]);
|
||||
}
|
||||
void setBlurring(const glm::vec3 &vec) {
|
||||
PixelShader::setUniformReg(blurLocation, 4, &vec[0]);
|
||||
}
|
||||
|
||||
void setTextureAndSampler(const GX2Texture *texture, const GX2Sampler *sampler) const {
|
||||
GX2SetPixelTexture((GX2Texture *) texture, samplerLocation);
|
||||
GX2SetPixelSampler((GX2Sampler *) sampler, samplerLocation);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __TEXTURE_2D_SHADER_H_
|
164
src/shaders/VertexShader.h
Normal file
164
src/shaders/VertexShader.h
Normal file
@ -0,0 +1,164 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2015 Dimok
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "Shader.h"
|
||||
#include <cstring>
|
||||
#include <gx2/enum.h>
|
||||
|
||||
class VertexShader : public Shader {
|
||||
public:
|
||||
explicit VertexShader(uint32_t numAttr)
|
||||
: attributesCount(numAttr), attributes((GX2AttribStream *) memalign(0x40, sizeof(GX2AttribStream) * attributesCount)), vertexShader((GX2VertexShader *) memalign(0x40, sizeof(GX2VertexShader))) {
|
||||
if (vertexShader) {
|
||||
memset(vertexShader, 0, sizeof(GX2VertexShader));
|
||||
vertexShader->mode = GX2_SHADER_MODE_UNIFORM_REGISTER;
|
||||
}
|
||||
}
|
||||
|
||||
~VertexShader() override {
|
||||
free(attributes);
|
||||
|
||||
if (vertexShader) {
|
||||
if (vertexShader->program) {
|
||||
MEMFreeToMappedMemory(vertexShader->program);
|
||||
}
|
||||
for (uint32_t i = 0; i < vertexShader->uniformBlockCount; i++) {
|
||||
free((void *) vertexShader->uniformBlocks[i].name);
|
||||
}
|
||||
if (vertexShader->uniformBlocks) {
|
||||
free((void *) vertexShader->uniformBlocks);
|
||||
}
|
||||
for (uint32_t i = 0; i < vertexShader->uniformVarCount; i++) {
|
||||
free((void *) vertexShader->uniformVars[i].name);
|
||||
}
|
||||
if (vertexShader->uniformVars) {
|
||||
free((void *) vertexShader->uniformVars);
|
||||
}
|
||||
if (vertexShader->initialValues) {
|
||||
free((void *) vertexShader->initialValues);
|
||||
}
|
||||
for (uint32_t i = 0; i < vertexShader->samplerVarCount; i++) {
|
||||
free((void *) vertexShader->samplerVars[i].name);
|
||||
}
|
||||
if (vertexShader->samplerVars) {
|
||||
free((void *) vertexShader->samplerVars);
|
||||
}
|
||||
for (uint32_t i = 0; i < vertexShader->attribVarCount; i++) {
|
||||
free((void *) vertexShader->attribVars[i].name);
|
||||
}
|
||||
if (vertexShader->attribVars) {
|
||||
free((void *) vertexShader->attribVars);
|
||||
}
|
||||
if (vertexShader->loopVars) {
|
||||
free((void *) vertexShader->loopVars);
|
||||
}
|
||||
|
||||
free(vertexShader);
|
||||
}
|
||||
}
|
||||
|
||||
void setProgram(const uint32_t *program, const uint32_t &programSize, const uint32_t *regs, const uint32_t ®sSize) {
|
||||
if (!vertexShader)
|
||||
return;
|
||||
|
||||
//! this must be moved into an area where the graphic engine has access to and must be aligned to 0x100
|
||||
vertexShader->size = programSize;
|
||||
vertexShader->program = (uint8_t *) MEMAllocFromMappedMemoryForGX2Ex(vertexShader->size, GX2_SHADER_PROGRAM_ALIGNMENT);
|
||||
if (vertexShader->program) {
|
||||
memcpy(vertexShader->program, program, vertexShader->size);
|
||||
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, vertexShader->program, vertexShader->size);
|
||||
}
|
||||
|
||||
memcpy(&vertexShader->regs, regs, regsSize);
|
||||
}
|
||||
|
||||
void addUniformVar(const GX2UniformVar &var) {
|
||||
if (!vertexShader)
|
||||
return;
|
||||
|
||||
uint32_t idx = vertexShader->uniformVarCount;
|
||||
|
||||
auto *newVar = (GX2UniformVar *) memalign(0x40, (vertexShader->uniformVarCount + 1) * sizeof(GX2UniformVar));
|
||||
if (newVar) {
|
||||
if (vertexShader->uniformVarCount > 0) {
|
||||
memcpy(newVar, vertexShader->uniformVars, vertexShader->uniformVarCount * sizeof(GX2UniformVar));
|
||||
free(vertexShader->uniformVars);
|
||||
}
|
||||
vertexShader->uniformVars = newVar;
|
||||
|
||||
memcpy(vertexShader->uniformVars + idx, &var, sizeof(GX2UniformVar));
|
||||
vertexShader->uniformVars[idx].name = (char *) memalign(0x40, strlen(var.name) + 1);
|
||||
strcpy((char *) vertexShader->uniformVars[idx].name, var.name);
|
||||
|
||||
vertexShader->uniformVarCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void addAttribVar(const GX2AttribVar &var) {
|
||||
if (!vertexShader)
|
||||
return;
|
||||
|
||||
uint32_t idx = vertexShader->attribVarCount;
|
||||
|
||||
auto *newVar = (GX2AttribVar *) memalign(0x40, (vertexShader->attribVarCount + 1) * sizeof(GX2AttribVar));
|
||||
if (newVar) {
|
||||
if (vertexShader->attribVarCount > 0) {
|
||||
memcpy(newVar, vertexShader->attribVars, vertexShader->attribVarCount * sizeof(GX2AttribVar));
|
||||
free(vertexShader->attribVars);
|
||||
}
|
||||
vertexShader->attribVars = newVar;
|
||||
|
||||
memcpy(vertexShader->attribVars + idx, &var, sizeof(GX2AttribVar));
|
||||
vertexShader->attribVars[idx].name = (char *) memalign(0x40, strlen(var.name) + 1);
|
||||
strcpy((char *) vertexShader->attribVars[idx].name, var.name);
|
||||
|
||||
vertexShader->attribVarCount++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void setAttributeBuffer(uint32_t bufferIdx, uint32_t bufferSize, uint32_t stride, const void *buffer) {
|
||||
GX2SetAttribBuffer(bufferIdx, bufferSize, stride, (void *) buffer);
|
||||
}
|
||||
|
||||
[[nodiscard]] GX2VertexShader *getVertexShader() const {
|
||||
return vertexShader;
|
||||
}
|
||||
|
||||
void setShader() const {
|
||||
GX2SetVertexShader(vertexShader);
|
||||
}
|
||||
|
||||
[[nodiscard]] GX2AttribStream *getAttributeBuffer(uint32_t idx = 0) const {
|
||||
if (idx >= attributesCount) {
|
||||
return nullptr;
|
||||
}
|
||||
return &attributes[idx];
|
||||
}
|
||||
[[nodiscard]] uint32_t getAttributesCount() const {
|
||||
return attributesCount;
|
||||
}
|
||||
|
||||
static void setUniformReg(uint32_t location, uint32_t size, const void *reg) {
|
||||
GX2SetVertexUniformReg(location, size, (uint32_t *) reg);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t attributesCount;
|
||||
GX2AttribStream *attributes;
|
||||
GX2VertexShader *vertexShader;
|
||||
};
|
162
src/shaders/gx2_ext.h
Normal file
162
src/shaders/gx2_ext.h
Normal file
@ -0,0 +1,162 @@
|
||||
#pragma once
|
||||
|
||||
#include <gx2/utils.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <coreinit/cache.h>
|
||||
#include <gx2/draw.h>
|
||||
#include <gx2/enum.h>
|
||||
#include <gx2/mem.h>
|
||||
#include <gx2/registers.h>
|
||||
#include <gx2/sampler.h>
|
||||
#include <gx2/shaders.h>
|
||||
#include <gx2/surface.h>
|
||||
#include <gx2/texture.h>
|
||||
|
||||
#define GX2_AA_BUFFER_CLEAR_VALUE 0xCC
|
||||
|
||||
#define GX2_COMP_SEL_NONE 0x04040405
|
||||
#define GX2_COMP_SEL_X001 0x00040405
|
||||
#define GX2_COMP_SEL_XY01 0x00010405
|
||||
#define GX2_COMP_SEL_XYZ1 0x00010205
|
||||
#define GX2_COMP_SEL_XYZW 0x00010203
|
||||
#define GX2_COMP_SEL_XXXX 0x00000000
|
||||
#define GX2_COMP_SEL_YYYY 0x01010101
|
||||
#define GX2_COMP_SEL_ZZZZ 0x02020202
|
||||
#define GX2_COMP_SEL_WWWW 0x03030303
|
||||
#define GX2_COMP_SEL_WZYX 0x03020100
|
||||
#define GX2_COMP_SEL_WXYZ 0x03000102
|
||||
|
||||
typedef struct _GX2Color {
|
||||
uint8_t r, g, b, a;
|
||||
} GX2Color;
|
||||
|
||||
typedef struct _GX2ColorF32 {
|
||||
float r, g, b, a;
|
||||
} GX2ColorF32;
|
||||
|
||||
static const uint32_t attribute_dest_comp_selector[20] = {
|
||||
GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_X001, GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_X001,
|
||||
GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW,
|
||||
GX2_COMP_SEL_XY01, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZ1,
|
||||
GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW};
|
||||
|
||||
static const uint32_t texture_comp_selector[54] = {
|
||||
GX2_COMP_SEL_NONE, GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_X001,
|
||||
GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW,
|
||||
GX2_COMP_SEL_WZYX, GX2_COMP_SEL_X001, GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XY01, GX2_COMP_SEL_NONE,
|
||||
GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_NONE,
|
||||
GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_WZYX, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XY01,
|
||||
GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW,
|
||||
GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_X001,
|
||||
GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZ1,
|
||||
GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01};
|
||||
|
||||
static inline void GX2InitDepthBuffer(GX2DepthBuffer *depthBuffer, GX2SurfaceDim dim, uint32_t width, uint32_t height, uint32_t depth, GX2SurfaceFormat format, GX2AAMode aa) {
|
||||
depthBuffer->surface.dim = dim;
|
||||
depthBuffer->surface.width = width;
|
||||
depthBuffer->surface.height = height;
|
||||
depthBuffer->surface.depth = depth;
|
||||
depthBuffer->surface.mipLevels = 1;
|
||||
depthBuffer->surface.format = format;
|
||||
depthBuffer->surface.aa = aa;
|
||||
depthBuffer->surface.use = (GX2SurfaceUse) (((format == GX2_SURFACE_FORMAT_UNORM_R24_X8) || (format == GX2_SURFACE_FORMAT_FLOAT_D24_S8)) ? GX2_SURFACE_USE_DEPTH_BUFFER : (GX2_SURFACE_USE_DEPTH_BUFFER | GX2_SURFACE_USE_TEXTURE));
|
||||
depthBuffer->surface.tileMode = GX2_TILE_MODE_DEFAULT;
|
||||
depthBuffer->surface.swizzle = 0;
|
||||
depthBuffer->viewMip = 0;
|
||||
depthBuffer->viewFirstSlice = 0;
|
||||
depthBuffer->viewNumSlices = depth;
|
||||
depthBuffer->depthClear = 1.0f;
|
||||
depthBuffer->stencilClear = 0;
|
||||
depthBuffer->hiZPtr = nullptr;
|
||||
depthBuffer->hiZSize = 0;
|
||||
GX2CalcSurfaceSizeAndAlignment(&depthBuffer->surface);
|
||||
GX2InitDepthBufferRegs(depthBuffer);
|
||||
}
|
||||
|
||||
static inline void GX2InitColorBuffer(GX2ColorBuffer *colorBuffer, GX2SurfaceDim dim, uint32_t width, uint32_t height, uint32_t depth, GX2SurfaceFormat format, GX2AAMode aa, GX2TileMode tilemode, uint32_t swizzle,
|
||||
void *aaBuffer, uint32_t aaSize) {
|
||||
colorBuffer->surface.dim = dim;
|
||||
colorBuffer->surface.width = width;
|
||||
colorBuffer->surface.height = height;
|
||||
colorBuffer->surface.depth = depth;
|
||||
colorBuffer->surface.mipLevels = 1;
|
||||
colorBuffer->surface.format = format;
|
||||
colorBuffer->surface.aa = aa;
|
||||
colorBuffer->surface.use = GX2_SURFACE_USE_TEXTURE_COLOR_BUFFER_TV;
|
||||
colorBuffer->surface.imageSize = 0;
|
||||
colorBuffer->surface.image = nullptr;
|
||||
colorBuffer->surface.mipmapSize = 0;
|
||||
colorBuffer->surface.mipmaps = nullptr;
|
||||
colorBuffer->surface.tileMode = tilemode;
|
||||
colorBuffer->surface.swizzle = swizzle;
|
||||
colorBuffer->surface.alignment = 0;
|
||||
colorBuffer->surface.pitch = 0;
|
||||
uint32_t i;
|
||||
for (i = 0; i < 13; i++)
|
||||
colorBuffer->surface.mipLevelOffset[i] = 0;
|
||||
colorBuffer->viewMip = 0;
|
||||
colorBuffer->viewFirstSlice = 0;
|
||||
colorBuffer->viewNumSlices = depth;
|
||||
colorBuffer->aaBuffer = aaBuffer;
|
||||
colorBuffer->aaSize = aaSize;
|
||||
for (i = 0; i < 5; i++)
|
||||
colorBuffer->regs[i] = 0;
|
||||
|
||||
GX2CalcSurfaceSizeAndAlignment(&colorBuffer->surface);
|
||||
GX2InitColorBufferRegs(colorBuffer);
|
||||
}
|
||||
|
||||
static inline void GX2InitAttribStream(GX2AttribStream *attr, uint32_t location, uint32_t buffer, uint32_t offset, GX2AttribFormat format) {
|
||||
attr->location = location;
|
||||
attr->buffer = buffer;
|
||||
attr->offset = offset;
|
||||
attr->format = format;
|
||||
attr->type = GX2_ATTRIB_INDEX_PER_VERTEX;
|
||||
attr->aluDivisor = 0;
|
||||
attr->mask = attribute_dest_comp_selector[format & 0xff];
|
||||
attr->endianSwap = GX2_ENDIAN_SWAP_DEFAULT;
|
||||
}
|
||||
|
||||
static inline void GX2InitTexture(GX2Texture *tex, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipLevels, GX2SurfaceFormat format, GX2SurfaceDim dim, GX2TileMode tile) {
|
||||
tex->surface.dim = dim;
|
||||
tex->surface.width = width;
|
||||
tex->surface.height = height;
|
||||
tex->surface.depth = depth;
|
||||
tex->surface.mipLevels = mipLevels;
|
||||
tex->surface.format = format;
|
||||
tex->surface.aa = GX2_AA_MODE1X;
|
||||
tex->surface.use = GX2_SURFACE_USE_TEXTURE;
|
||||
tex->surface.imageSize = 0;
|
||||
tex->surface.image = nullptr;
|
||||
tex->surface.mipmapSize = 0;
|
||||
tex->surface.mipmaps = nullptr;
|
||||
tex->surface.tileMode = tile;
|
||||
tex->surface.swizzle = 0;
|
||||
tex->surface.alignment = 0;
|
||||
tex->surface.pitch = 0;
|
||||
uint32_t i;
|
||||
for (i = 0; i < 13; i++) {
|
||||
tex->surface.mipLevelOffset[i] = 0;
|
||||
}
|
||||
tex->viewFirstMip = 0;
|
||||
tex->viewNumMips = mipLevels;
|
||||
tex->viewFirstSlice = 0;
|
||||
tex->viewNumSlices = depth;
|
||||
tex->compMap = texture_comp_selector[format & 0x3f];
|
||||
for (i = 0; i < 5; i++) {
|
||||
tex->regs[i] = 0;
|
||||
}
|
||||
|
||||
tex->compMap = GX2_COMP_MAP(GX2_SQ_SEL_R, GX2_SQ_SEL_G, GX2_SQ_SEL_B, GX2_SQ_SEL_A);
|
||||
|
||||
DCFlushRange(&tex, sizeof(GX2Texture));
|
||||
GX2CalcSurfaceSizeAndAlignment(&tex->surface);
|
||||
GX2InitTextureRegs(tex);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
36
src/utils/logger.c
Normal file
36
src/utils/logger.c
Normal 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
|
||||
}
|
70
src/utils/logger.h
Normal file
70
src/utils/logger.h
Normal file
@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include <coreinit/debug.h>
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LOG_APP_TYPE "M"
|
||||
#define LOG_APP_NAME "notification_module"
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
|
||||
#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_INFO(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##INFO ## ", "", 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_INFO(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##INFO ## ", "\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
|
78
src/utils/utils.cpp
Normal file
78
src/utils/utils.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
#include "utils.h"
|
||||
#include "utils/logger.h"
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
|
||||
#define PRINTF_BUFFER_LENGTH 2048
|
||||
|
||||
// https://gist.github.com/ccbrown/9722406
|
||||
void dumpHex(const void *data, size_t size) {
|
||||
char ascii[17];
|
||||
size_t i, j;
|
||||
ascii[16] = '\0';
|
||||
DEBUG_FUNCTION_LINE("0x%08X (0x0000): ", data);
|
||||
for (i = 0; i < size; ++i) {
|
||||
WHBLogWritef("%02X ", ((unsigned char *) data)[i]);
|
||||
if (((unsigned char *) data)[i] >= ' ' && ((unsigned char *) data)[i] <= '~') {
|
||||
ascii[i % 16] = ((unsigned char *) data)[i];
|
||||
} else {
|
||||
ascii[i % 16] = '.';
|
||||
}
|
||||
if ((i + 1) % 8 == 0 || i + 1 == size) {
|
||||
WHBLogWritef(" ");
|
||||
if ((i + 1) % 16 == 0) {
|
||||
WHBLogPrintf("| %s ", ascii);
|
||||
if (i + 1 < size) {
|
||||
DEBUG_FUNCTION_LINE("0x%08X (0x%04X); ", ((uint32_t) data) + i + 1, i + 1);
|
||||
}
|
||||
} else if (i + 1 == size) {
|
||||
ascii[(i + 1) % 16] = '\0';
|
||||
if ((i + 1) % 16 <= 8) {
|
||||
WHBLogWritef(" ");
|
||||
}
|
||||
for (j = (i + 1) % 16; j < 16; ++j) {
|
||||
WHBLogWritef(" ");
|
||||
}
|
||||
WHBLogPrintf("| %s ", ascii);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t RGBComponentToSRGBTable[] = {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};
|
||||
|
||||
uint8_t SRGBComponentToRGBTable[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07,
|
||||
0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C,
|
||||
0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13,
|
||||
0x14, 0x14, 0x15, 0x16, 0x16, 0x17, 0x17, 0x18, 0x18, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1C, 0x1D,
|
||||
0x1D, 0x1E, 0x1F, 0x1F, 0x20, 0x21, 0x21, 0x22, 0x23, 0x24, 0x24, 0x25, 0x26, 0x26, 0x27, 0x28,
|
||||
0x29, 0x2A, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
|
||||
0x37, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x46,
|
||||
0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x57, 0x58,
|
||||
0x59, 0x5A, 0x5C, 0x5D, 0x5E, 0x5F, 0x61, 0x62, 0x63, 0x65, 0x66, 0x67, 0x69, 0x6A, 0x6B, 0x6D,
|
||||
0x6E, 0x70, 0x71, 0x72, 0x74, 0x75, 0x77, 0x78, 0x7A, 0x7B, 0x7D, 0x7E, 0x80, 0x81, 0x83, 0x84,
|
||||
0x86, 0x87, 0x89, 0x8B, 0x8C, 0x8E, 0x90, 0x91, 0x93, 0x94, 0x96, 0x98, 0x99, 0x9B, 0x9D, 0x9F,
|
||||
0xA0, 0xA2, 0xA4, 0xA6, 0xA7, 0xA9, 0xAB, 0xAD, 0xAF, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC,
|
||||
0xBE, 0xC0, 0xC1, 0xC3, 0xC5, 0xC7, 0xC9, 0xCB, 0xCD, 0xCF, 0xD1, 0xD3, 0xD5, 0xD7, 0xDA, 0xDC,
|
||||
0xDE, 0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEB, 0xED, 0xEF, 0xF1, 0xF3, 0xF5, 0xF8, 0xFA, 0xFC, 0xFF};
|
||||
|
||||
std::mutex gNotificationListMutex;
|
||||
std::forward_list<std::shared_ptr<Notification>> gNotificationList;
|
49
src/utils/utils.h
Normal file
49
src/utils/utils.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "gui/Notification.h"
|
||||
#include <forward_list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
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)...));
|
||||
}
|
||||
|
||||
template<typename T, class Allocator, class Predicate>
|
||||
bool remove_locked_first_if(std::mutex &mutex, std::forward_list<T, Allocator> &list, Predicate pred) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
auto oit = list.before_begin(), it = std::next(oit);
|
||||
while (it != list.end()) {
|
||||
if (pred(*it)) {
|
||||
list.erase_after(oit);
|
||||
return true;
|
||||
}
|
||||
oit = it++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// those work only in powers of 2
|
||||
#define ROUNDDOWN(val, align) ((val) & ~(align - 1))
|
||||
#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align - 1)), align)
|
||||
|
||||
extern uint8_t SRGBComponentToRGBTable[];
|
||||
extern uint8_t RGBComponentToSRGBTable[];
|
||||
|
||||
inline uint8_t SRGBComponentToRGB(uint8_t ci) {
|
||||
return SRGBComponentToRGBTable[ci];
|
||||
}
|
||||
|
||||
inline uint8_t RGBComponentToSRGB(uint8_t ci) {
|
||||
return RGBComponentToSRGBTable[ci];
|
||||
}
|
||||
|
||||
extern std::mutex gNotificationListMutex;
|
||||
extern std::forward_list<std::shared_ptr<Notification>> gNotificationList;
|
2
src/version.h
Normal file
2
src/version.h
Normal file
@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
#define VERSION_EXTRA ""
|
Loading…
x
Reference in New Issue
Block a user