Compare commits

..
23 Commits
Author SHA1 Message Date
tobid7 dac78d9c82 yet another memory debugger fix 2026-01-11 16:12:47 +01:00
tobid7 a16bce419d Add safe Memory Freeing
(cause in some cases random crashes could happen)
2026-01-10 12:58:04 +01:00
tobid7 bed24ff28a Add Memory debugger 2026-01-04 18:02:45 +01:00
tobid7 1acecd03ee Merge branch 'main' of github.com:tobid7/amethyst 2026-01-01 21:37:05 +01:00
tobid7 99b330b136 # Compile time hexcolor support ported from palladium 2026-01-01 21:36:15 +01:00
tobid7 5e5907ed30 Rename to DrawFromAtlas 2025-12-31 10:30:20 +01:00
tobid7 b4b1144c60 Implemet CutTex Rendering 2025-12-30 22:28:03 +01:00
tobid7 6e502d73d8 Add Clearcolor support 2025-12-22 12:50:40 +01:00
tobid7 468a112274 Load Fonts in A8 format, Fix Freeze with BMF 2025-12-22 11:41:54 +01:00
tobid7 4cf3685832 Fix the shader loader
- fixed cmake file as well?
- remove useless files from example
- reenable runtime shader compiler

for some reason the raw data of a shader must stay in ram while the shader is loaded. It can be unloaded when the shader gets unloaded
2025-12-17 08:53:59 +01:00
tobid7 38a2b21ba0 Add BMF loading support
- Add ability to make textures not unloadable
2025-12-14 22:59:16 +01:00
tobid7 38a1cad76a Fix some issues 2025-12-08 22:20:33 +01:00
tobid7 d85610a0bd Add GTrace
Make Fonts an Asset
Add FormatMillis and FormatNanos
2025-12-08 18:37:12 +01:00
tobid7 88e367a299 Implement Text Rendering
Added STB truetype
Switched AssetMgr to use Shared Ptr
2025-12-07 23:20:15 +01:00
tobid7 28d2e291b3 Add color class
Add Palladium Unique and Shared defs
Make stb_image an internal dependency
Start some work on font loader
2025-12-07 18:08:36 +01:00
tobid7 c18ef2161a Remove ctru / Add pre font work 2025-12-05 19:33:58 +01:00
tobid7 d136e6ac5e - Add Exit func 2025-12-01 22:39:39 +01:00
tobid7 777b23f4c8 Get it finally working (somehow)
- Add working example
- Add Namespace defs for Iron Ctr and C3D
- Add Exit func / Vertex / Index counter to Iron
- Add format bytes function to utils
- Make stb_image optional
- Compute texture uv's
- Clear Everything in Drawlist::Clear
- Use Amy::mat4 as matrix lib
- Fix the most stupid rendering bug (i -> m_idx)
2025-12-01 22:10:18 +01:00
tobid7 078af99ae5 Upload all my tests
- Add Count<> to AssetManager
- Initialize pCode in Shader
- Rename linearAllocator to LinearAllocator
- Add Construct and destroy to linear allocator
- Add Shader unloader (fixes atexit crash i guess)
-
2025-11-30 21:57:01 +01:00
tobid7 febf506a5e # Changes
- Add Debugstuff to main
- Add IsType and AutoLoad to AssetManager
- Add ID class for at compile time hashing
- Add A8 to image (but not supported yet)
- Fix error in Vertex constructor
- Add PathClear to PathFill func
- Add pCheckSize to check for overflows
- Make Tex in Texture a pointer ref
- Add default uv to texture
- Add own c++ exception
- Add FNV32 Hash func (compile and runtime)
- Fix Power2 check in texture loader
- Load Shader manualy in iron (cause it seems not working correctly with files)
2025-11-27 13:32:44 +01:00
tobid7 2a2a670e1a # Update
- Added GetTime funcs to utils
- Added Time() to App class to gather the apps run time in seconds
- Updated almost every part of the sourcecode to the D7 Style guide
2025-11-26 13:46:46 +01:00
tobid7 830524c9eb Add a max_size member func to linearAlloc 2025-11-26 11:18:48 +01:00
tobid7 9731579af9 use own mtx api cause i confirmed it as working 2025-11-26 11:08:36 +01:00
51 changed files with 7812 additions and 1008 deletions
+322
View File
@@ -0,0 +1,322 @@
---
Language: Cpp
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: true
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseArrows: false
AlignCaseColons: false
AlignConsecutiveTableGenBreakingDAGArgColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenCondOperatorColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenDefinitionColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseExpressionOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AllowShortNamespacesOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: BinPack
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakAfterReturnType: None
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakBinaryOperations: Never
BreakConstructorInitializers: BeforeColon
BreakFunctionDefinitionParameters: false
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
BreakTemplateDeclarations: Yes
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: true
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 3
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: true
IndentExportBlock: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLines:
AtEndOfFile: false
AtStartOfBlock: false
AtStartOfFile: true
KeepFormFeed: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
MainIncludeChar: Quote
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: NextLine
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakBeforeMemberAccess: 150
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
PPIndentWidth: -1
QualifierAlignment: Leave
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
- ParseTestProto
- ParsePartialTestProto
CanonicalDelimiter: pb
BasedOnStyle: google
ReferenceAlignment: Pointer
ReflowComments: Always
RemoveBracesLLVM: false
RemoveEmptyLinesInUnwrappedLines: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
ExceptDoubleParentheses: false
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Auto
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TableGenBreakInsideDAGArg: DontBreak
TabWidth: 8
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
WrapNamespaceBodyWithEmptyLines: Leave
...
+23 -6
View File
@@ -5,31 +5,48 @@ project(amethyst)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED true) set(CMAKE_CXX_STANDARD_REQUIRED true)
option(AMY_BUILD_3DS "Build for 3ds" ON)
option(AMY_GOD_DEV "Turn this on if you think you are god" OFF) option(AMY_GOD_DEV "Turn this on if you think you are god" OFF)
# THis option should be disabled if you use STB_IMAGE in you main project
option(AMY_BUILD_STB_IMAGE ON)
option(AMY_BUILD_STB_TRUETYPE ON)
add_subdirectory(vendor/libpicasso) add_subdirectory(vendor/libpicasso)
add_library(${PROJECT_NAME} STATIC add_library(${PROJECT_NAME} STATIC
source/app.cpp source/app.cpp
source/assets.cpp
source/amethyst.cpp source/amethyst.cpp
source/color.cpp
source/godtrace.cpp
source/image.cpp source/image.cpp
source/renderer.cpp source/renderer.cpp
source/texture.cpp source/texture.cpp
source/utils.cpp source/utils.cpp
source/c3d.cpp source/c3d.cpp
source/ctru.cpp
source/iron/iron.cpp source/iron/iron.cpp
source/iron/drawlist.cpp source/iron/drawlist.cpp
source/iron/font.cpp
source/maths/mat.cpp source/maths/mat.cpp
) )
target_include_directories(${PROJECT_NAME} PUBLIC include) target_include_directories(${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
${DEVKITPRO}/portlibs/3ds/include
)
target_include_directories(${PROJECT_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/source/internal
)
target_link_libraries(${PROJECT_NAME} PUBLIC pica::pica) target_link_libraries(${PROJECT_NAME} PUBLIC pica::pica)
if(${AMY_BUILD_3DS}) target_link_libraries(${PROJECT_NAME} PUBLIC m z ctru citro3d mpg123)
target_link_libraries(${PROJECT_NAME} PUBLIC m z ctru citro3d) if(${AMY_BUILD_STB_IMAGE})
target_compile_definitions(${PROJECT_NAME} PUBLIC AMY_3DS) target_compile_definitions(${PROJECT_NAME} PUBLIC AMY_STB_IMAGE)
endif() endif()
if(${AMY_BUILD_STB_TRUETYPE})
target_compile_definitions(${PROJECT_NAME} PUBLIC AMY_STB_TT)
endif()
target_compile_options(${PROJECT_NAME} PUBLIC -Wno-psabi)
add_subdirectory(example) add_subdirectory(example)
install(TARGETS ${PROJECT_NAME}) install(TARGETS ${PROJECT_NAME})
install(DIRECTORY include DESTINATION .)
+27 -1
View File
@@ -1,3 +1,29 @@
# amethyst # amethyst
2d Renderer Library made for ReCraft3DS based on palladium. 2d Renderer Library made for ReCraft3DS based on palladium.
## Usage
### Submodule:
Add amethyst as submodule to your repository
```bash
git submodule add https://github.com/tobid7/amethyst vendor/amethyst
```
Add it as submodule to your `CMakeLists.txt`
```cmake
add_subdirectory(vendor/amethyst)
target_link_libraries(${PROJECT_NAME} PUBLIC amethyst)
```
### Installed
Coming Soon...
## Credits
- [tobid7](https://github.com/tobid7) Lead Developer, Stealing a lot of code of [Palladium](https://github.com/tobid7/palladium)
- [nothings](https://github.com/nothings) stb_image and stb_truetype from [here](https://github.com/nothings/stb)
-18
View File
@@ -1,27 +1,9 @@
cmake_minimum_required(VERSION 3.22) cmake_minimum_required(VERSION 3.22)
find_program(PICASSO NAMES picasso REQUIRED)
# Function origanally Created in Re-Craft-3DS
function(__amy_make_shader arg1 arg2)
# These only exist cause i was stupid
set(__FILE ${arg1})
set(__NAME ${arg2})
# Need to build shaders during config stage :(
execute_process(
COMMAND ${PICASSO} -o "${CMAKE_CURRENT_SOURCE_DIR}/romfs/shaders/${__NAME}.shbin" "${__FILE}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
endfunction()
project(amethyst-example) project(amethyst-example)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED true) set(CMAKE_CXX_STANDARD_REQUIRED true)
__amy_make_shader(${CMAKE_CURRENT_SOURCE_DIR}/shaders/shader2d.v.pica shader2d)
__amy_make_shader(${CMAKE_CURRENT_SOURCE_DIR}/shaders/lithium.v.pica lithium)
add_executable(${PROJECT_NAME} source/main.cpp) add_executable(${PROJECT_NAME} source/main.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE amethyst) target_link_libraries(${PROJECT_NAME} PRIVATE amethyst)
target_compile_options(${PROJECT_NAME} PRIVATE -O2) target_compile_options(${PROJECT_NAME} PRIVATE -O2)
Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.
+93
View File
@@ -0,0 +1,93 @@
Copyright 2014 The Comic Neue Project Authors (https://github.com/crozynski/comicneue)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://openfontlicense.org
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

-34
View File
@@ -1,34 +0,0 @@
; LI7 Shader
; Constants
.constf myconst(0.0, 1.0, 0.00392156862745, 0.0)
.alias ones myconst.yyyy ; Vector full of ones
; Uniforms
.fvec projection[4]
; Outputs
.out out_position position
.out out_color color
.out out_uv texcoord0
; Inputs
.alias in_xy v0
.alias in_uvc v1
.alias in_col v2
.entry vmain
.proc vmain
mov r0.xy, in_xy.xy
mov r0.w, ones
dp4 out_position.x, projection[0], r0
dp4 out_position.y, projection[1], r0
dp4 out_position.z, projection[2], r0
dp4 out_position.w, projection[3], r0
mov out_uv, in_uvc.xy
mul r1, myconst.zzzz, in_col
mov out_color, r1
end
.end
-38
View File
@@ -1,38 +0,0 @@
; Example PICA200 vertex shader
; Uniforms
.fvec projection[4]
; Constants
.constf myconst(0.0, 1.0, -1.0, 0.1)
.constf myconst2(0.3, 0.0, 0.0, 0.0)
.alias zeros myconst.xxxx ; Vector full of zeros
.alias ones myconst.yyyy ; Vector full of ones
; Outputs
.out outpos position
.out outclr color
; Inputs (defined as aliases for convenience)
.alias inpos v0
.alias inclr v1
.bool test
.proc main
; Force the w component of inpos to be 1.0
mov r0.xyz, inpos
mov r0.w, ones
; outpos = projectionMatrix * inpos
dp4 outpos.x, projection[0], r0
dp4 outpos.y, projection[1], r0
dp4 outpos.z, projection[2], r0
dp4 outpos.w, projection[3], r0
; outclr = inclr
mov outclr, inclr
; We're finished
end
.end
+67 -48
View File
@@ -1,58 +1,77 @@
#include <amethyst.hpp> #include <amethyst.hpp>
#include <iostream>
#include "amethyst/iron.hpp" class Example : public Amy::App {
class example : public amy::app {
public: public:
example() { Example() {
amy::ctru::init(); Amy::GTrace::Scope s("Init");
consoleInit(GFX_BOTTOM, NULL); gfxInitDefault();
amy::c3d::init(); romfsInit();
m_top = amy::c3d::createScreen(GFX_TOP, GFX_LEFT); C3D::Init();
amy::iron::init(); Top = C3D::CreateScreen(GFX_TOP);
dl = new amy::iron::drawlist(); Mgr = new Amy::AssetMgr();
dl->drawSolid(); Iron::Init();
auto cmd = std::make_unique<amy::iron::command>(); Mgr->AutoLoad("icon", "romfs:/icon.png");
cmd->index = 0; auto fnt = Iron::Font::New();
cmd->layer = 0; fnt->LoadBMF("romfs:/ComicNeue.png");
cmd->tex = amy::iron::whiteTex(); Mgr->Add("font", fnt);
cmd->add(0).add(1).add(2); // Mgr->AutoLoad("font", "romfs:/ComicNeue.ttf");
cmd->add(amy::iron::vertex(200, 50, 0, 0, 0xff0000ff)); dl = Iron::Drawlist::New();
cmd->add(amy::iron::vertex(100, 190, 0, 0, 0xff00ff00)); dl->SetFont(Mgr->Get<Iron::Font>("font"));
cmd->add(amy::iron::vertex(300, 190, 0, 0, 0xffff0000));
cmdl.push_back(std::move(cmd));
// throw std::runtime_error(std::format(
// "solid tex: {:#08x}\nsize: {}\nptr: {:#08x}",
// (amy::ui)amy::iron::whiteTex(), amy::iron::whiteTex()->size(),
// (amy::ui)amy::iron::whiteTex()->ptr()));
};
~example() {
amy::c3d::deleteScreen(m_top);
amy::c3d::deinit();
};
void main() {
amy::c3d::startFrame();
m_top->startDraw();
m_top->clear();
// dl->drawRectFilled(0, 50, 0xff00ff00);
amy::iron::newFrame();
amy::iron::drawOn(m_top);
// amy::iron::draw(dl->data());
amy::iron::draw(cmdl);
// dl->clear();
amy::c3d::endFrame();
} }
private: ~Example() {
amy::c3d::screen* m_top = nullptr; dl.reset();
amy::iron::drawlist* dl = nullptr; delete Top;
std::vector<amy::iron::command::ref> cmdl; delete Mgr;
Iron::Exit();
C3D::Deinit();
romfsExit();
gfxExit();
}
void Main() {
hidScanInput();
if (hidKeysDown() & KEY_START) {
Exit();
}
std::string stats = std::format(
"Delta: {:.3} -> {:.3} FPS\nTime: {}\nLinearRam: {}\nVIT: "
"[{}/{}/{}]\nAssets: {}\nMain: {}",
this->Delta(), 1000.0 / this->Delta(),
Amy::Utils::FormatMillis(this->Time() * 1000.f),
Amy::Utils::FormatBytes(linearSpaceFree()), Amy::Iron::VerticesDrawn(),
Amy::Iron::IndicesDrawn(), Amy::Iron::IndicesDrawn() / 3,
Mgr->CountAll(),
Amy::Utils::FormatNanos(
Amy::GTrace::GetTraceRef("Main")->GetLastDiff()));
C3D::StartFrame();
Amy::GTrace::Beg("Main");
Top->Clear();
Top->Use();
dl->DrawTex(Mgr->Get<Amy::Texture>("icon"));
dl->DrawRectFilled(Amy::fvec2(50, 0), 48, Amy::Color(255, 255, 255, 160));
dl->DrawCircleFilled(Amy::fvec2(200, 120), 50, Amy::Color("#ffffff"), 40);
dl->DrawSolid();
dl->DrawRectFilled(0, 50, Amy::Color(0.f, 1.f, 0.f, 1.f));
dl->DrawText(Amy::fvec2(5, 50), stats, Amy::Color(255, 0, 255));
Iron::NewFrame();
Iron::DrawOn(Top);
Iron::Draw(dl->Data());
dl->Clear();
C3D::EndFrame();
Amy::GTrace::End("Main");
}
C3D::Screen* Top;
Amy::AssetMgr* Mgr;
Iron::Drawlist::Ref dl = nullptr;
}; };
int main() { int main() {
amy::registerCxxExceptionHandler(); Amy::RegisterCxxExceptionHandler();
example app; Example App;
app.run(); App.Run();
return 0; return 0;
} }
+28 -4
View File
@@ -3,11 +3,35 @@
#include <amethyst/app.hpp> #include <amethyst/app.hpp>
#include <amethyst/assets.hpp> #include <amethyst/assets.hpp>
#include <amethyst/c3d.hpp> #include <amethyst/c3d.hpp>
#include <amethyst/ctru.hpp> #include <amethyst/color.hpp>
#include <amethyst/godtrace.hpp>
#include <amethyst/image.hpp> #include <amethyst/image.hpp>
#include <amethyst/iron.hpp>
#include <amethyst/renderer.hpp> #include <amethyst/renderer.hpp>
#include <amethyst/texture.hpp> #include <amethyst/texture.hpp>
#include <amethyst/utils.hpp>
#include <atomic>
namespace amy { namespace Amy {
void registerCxxExceptionHandler(); void RegisterCxxExceptionHandler();
} void* Malloc(size_t size);
void Free(void* ptr);
namespace Memory {
struct MemMetrics {
std::atomic<ull> Allocated = 0; ///< Total Allocated Memory
std::atomic<ull> Current = 0; ///< Current Allocated Memory
std::atomic<ull> Deleted = 0; ///< Total Deleted Memory
std::atomic<ull> Allocations = 0; ///< Current Allocations count
/// @brief Gets the Currently Allocated Memory
ull CurrentlyAllocated() { return Current; }
};
ull GetTotalAllocated();
ull GetTotalFreed();
ull GetCurrent();
ull GetAllocationCount();
} // namespace Memory
} // namespace Amy
using Iron = Amy::Iron;
using C3D = Amy::C3D;
using GTrace = Amy::GTrace;
+20 -10
View File
@@ -2,19 +2,29 @@
#include <amethyst/asset.hpp> #include <amethyst/asset.hpp>
#include <amethyst/types.hpp> #include <amethyst/types.hpp>
#include <amethyst/utils.hpp>
namespace amy { namespace Amy {
class app { class App {
public: public:
app() {} App() {
~app() {} pDelta = 0.0;
pTime = 0.0;
pLast = 0LL;
pExit = false;
}
~App() {}
virtual void main() {} virtual void Main() {}
void run(); void Run();
double delta() const { return m_delta; } double Delta() const { return pDelta; }
double Time() const { return pTime; }
void Exit() { pExit = true; }
private: private:
ull m_last; bool pExit;
double m_delta; ull pLast;
double pDelta;
double pTime;
}; };
} // namespace amy } // namespace Amy
+8 -5
View File
@@ -1,9 +1,12 @@
#pragma once #pragma once
namespace amy { #include <amethyst/types.hpp>
class asset {
namespace Amy {
class Asset {
public: public:
asset() = default; Asset() = default;
virtual ~asset() = default; virtual ~Asset() = default;
AMY_SHARED(Asset);
}; };
} // namespace amy } // namespace Amy
+51 -16
View File
@@ -1,34 +1,69 @@
#pragma once #pragma once
#include <amethyst/id.hpp>
#include <amethyst/texture.hpp> #include <amethyst/texture.hpp>
#include <amethyst/types.hpp> #include <amethyst/types.hpp>
#include <memory>
namespace amy { namespace Amy {
class assets { class AssetMgr {
public: public:
assets() = default; AssetMgr() = default;
~assets() = default; ~AssetMgr() = default;
void add(cstr& id, asset* v) { m_assets[id] = v; } void AutoLoad(const ID& name, ksr path);
void remove(cstr& id) {
if (m_assets.count(id)) { void Add(const ID& id, Asset::Ref v) {
m_assets.erase(id); if (pAssets.count(id)) {
throw std::runtime_error("[amy]: assets: " + id.GetName() +
" already exists!");
}
pAssets[id] = v;
}
void Remove(const ID& id) {
if (pAssets.count(id)) {
pAssets.erase(id);
} }
} }
template <typename T> template <typename T>
T* get(cstr& id) { std::shared_ptr<T> Get(const ID& id) {
auto r = m_assets.find(id); auto r = pAssets.find(id);
if (r == m_assets.end()) { if (r == pAssets.end()) {
throw std::runtime_error("[amy] assets: unable to find " + id); throw std::runtime_error("[amy] assets: unable to find " + id.GetName());
} }
if (auto v = dynamic_cast<T*>(r->second)) { if (auto v = std::dynamic_pointer_cast<T>(r->second)) {
return v; return v;
} else { } else {
throw std::runtime_error(id + " is not of type " + typeid(T).name()); throw std::runtime_error(id.GetName() + " is not of type " +
typeid(T).name());
} }
} }
template <typename T>
bool IsType(const ID& id) {
auto r = pAssets.find(id);
if (r == pAssets.end()) {
throw std::runtime_error("[amy] assets: unable to find " + id.GetName());
}
return std::dynamic_pointer_cast<T>(r->second) != nullptr;
}
size_t CountAll() const { return pAssets.size(); }
template <typename T>
size_t Count() const {
size_t ret = 0;
for (auto& it : pAssets) {
if (std::dynamic_pointer_cast<T>(it.second)) {
ret++;
}
}
return ret;
}
private: private:
std::map<str, asset*> m_assets; std::map<ID, Asset::Ref> pAssets;
}; };
} // namespace amy } // namespace Amy
+69 -64
View File
@@ -9,115 +9,120 @@
#include <amethyst/types.hpp> #include <amethyst/types.hpp>
#include <string> #include <string>
namespace amy { namespace Amy {
class c3d { class C3D {
public: public:
c3d() = default; C3D() = default;
~c3d() = default; ~C3D() = default;
class screen { class Screen {
public: public:
screen(C3D_RenderTarget* t) { Screen(C3D_RenderTarget* t) {
m_target = t; pTarget = t;
// Width and height are swapped on 3ds due to screen layout // Width and height are swapped on 3ds due to screen layout
m_width = m_target->frameBuf.height; pWidth = pTarget->frameBuf.height;
m_height = m_target->frameBuf.width; pHeight = pTarget->frameBuf.width;
} }
~screen() { C3D_RenderTargetDelete(m_target); } ~Screen() { C3D_RenderTargetDelete(pTarget); }
int width() const { return m_width; } int Width() const { return pWidth; }
int height() const { return m_height; } int Height() const { return pHeight; }
ivec2 size() const { return ivec2(m_width, m_height); } ivec2 Size() const { return ivec2(pWidth, pHeight); }
void clear() { C3D_RenderTargetClear(m_target, C3D_CLEAR_ALL, 0, 0); } void Clear(ui clr = 0x0, ui depth_clr = 0x0) {
void startDraw() { C3D_FrameDrawOn(m_target); } C3D_RenderTargetClear(pTarget, C3D_CLEAR_ALL, clr, depth_clr);
}
void Use() { C3D_FrameDrawOn(pTarget); }
C3D_RenderTarget* Ptr() { return pTarget; }
private: private:
C3D_RenderTarget* m_target = nullptr; C3D_RenderTarget* pTarget = nullptr;
int m_width = 0; int pWidth = 0;
int m_height = 0; int pHeight = 0;
}; };
class shader : public asset { class Shader : public Asset {
public: public:
shader(const std::string& path); Shader(ksr path);
shader() {} Shader() {}
~shader(); ~Shader();
AMY_SHARED(Shader);
void load(const std::string& path); void Load(ksr path);
void load(const std::vector<uc>& data); void Load(kvr<uc> data);
void compile(const std::string& code); void Compile(ksr code);
void use(); void Use();
void input(int reg, GPU_FORMATS f, int num); void Input(int reg, GPU_FORMATS f, int num);
void input(GPU_FORMATS f, int num) { input(m_reg++, f, num); } void Input(GPU_FORMATS f, int num) { Input(pReg++, f, num); }
void setMat4(int loc, C3D_Mtx* m); void SetMat4(int loc, C3D_Mtx* m);
void setMat4(int loc, const mat4& m); void SetMat4(int loc, const mat4& m);
int loc(const std::string& name); int loc(ksr name);
private: // private:
C3D_AttrInfo m_info; C3D_AttrInfo pInfo;
shaderProgram_s m_program; shaderProgram_s pProgram;
DVLB_s* m_code; DVLB_s* pCode = nullptr;
int m_reg = 0; int pReg = 0;
std::vector<uc> pRawData;
}; };
class frag { class Frag {
public: public:
frag() = default; Frag() = default;
~frag() = default; ~Frag() = default;
static void edit(int id = 0); static void Edit(int id = 0);
static void src(C3D_TexEnvMode mode, GPU_TEVSRC s1 = GPU_PRIMARY_COLOR, static void Src(C3D_TexEnvMode mode, GPU_TEVSRC s1 = GPU_PRIMARY_COLOR,
GPU_TEVSRC s2 = GPU_PRIMARY_COLOR, GPU_TEVSRC s2 = GPU_PRIMARY_COLOR,
GPU_TEVSRC s3 = GPU_PRIMARY_COLOR); GPU_TEVSRC s3 = GPU_PRIMARY_COLOR);
static void func(C3D_TexEnvMode mode, GPU_COMBINEFUNC func); static void Func(C3D_TexEnvMode mode, GPU_COMBINEFUNC func);
private: private:
static C3D_TexEnv* m_env; static C3D_TexEnv* pEnv;
}; };
static void init(); static void Init();
static void deinit(); static void Deinit();
static void startFrame(bool sync = true); static void StartFrame(bool sync = true);
static void endFrame(); static void EndFrame();
static screen* createScreen(gfxScreen_t screen, gfx3dSide_t side = GFX_LEFT); static Screen* CreateScreen(gfxScreen_t screen, gfx3dSide_t side = GFX_LEFT);
static void deleteScreen(screen* screen); static void DeleteScreen(Screen* screen);
static void drawArrays(int start, int count, static void DrawArrays(int start, int count,
GPU_Primitive_t prim = GPU_TRIANGLES); GPU_Primitive_t prim = GPU_TRIANGLES);
static void drawElements(int count, const void* idx_ptr, static void DrawElements(int count, const void* idx_ptr,
int type = C3D_UNSIGNED_SHORT, int type = C3D_UNSIGNED_SHORT,
GPU_Primitive_t prim = GPU_TRIANGLES); GPU_Primitive_t prim = GPU_TRIANGLES);
static void depthTest(bool on, GPU_TESTFUNC func = GPU_GREATER, static void DepthTest(bool on, GPU_TESTFUNC func = GPU_GREATER,
GPU_WRITEMASK mask = GPU_WRITE_ALL); GPU_WRITEMASK mask = GPU_WRITE_ALL);
static void disableScissor(); static void DisableScissor();
static void enableScissor(const ivec4 rect); static void EnableScissor(const ivec4 rect);
/** /**
* Buf cfg die permutation at runtime berechnet * Buf cfg die permutation at runtime berechnet
*/ */
static void bufCfg(void* ptr, int stride, int shader_attribs); static void BufCfg(void* ptr, int stride, int shader_attribs);
/** /**
* Klassische config bei der man selber die permutation eintragen muss * Klassische config bei der man selber die permutation eintragen muss
*/ */
static void bufCfg(void* ptr, int stride, int shader_attribs, static void BufCfg(void* ptr, int stride, int shader_attribs,
u64 permutation); u64 permutation);
/** /**
* Hacky funktion um die permutation automatisch at compile time zu berechnen, * Hacky funktion um die permutation automatisch at compile time zu berechnen,
* falls diese immer gleich bleibt. * falls diese immer gleich bleibt.
* In der <> steht die anzahl der shader input werte * In der <> steht die anzahl der shader input werte
* usage: c3d::bufCfg<3>(data, sizeof(vertex)); * usage: C3D::bufCfg<3>(data, sizeof(vertex));
*/ */
template <int attribs> template <int attribs>
constexpr static void bufCfg(void* ptr, int stride) { constexpr static void BufCfg(void* ptr, int stride) {
auto buf = C3D_GetBufInfo(); auto buf = C3D_GetBufInfo();
BufInfo_Init(buf); BufInfo_Init(buf);
constexpr int pm = permutation(attribs); constexpr int pm = pPermutation(attribs);
BufInfo_Add(buf, ptr, stride, attribs, pm); BufInfo_Add(buf, ptr, stride, attribs, pm);
} }
static int drawcalls() { return m_drawcalls; } static int Drawcalls() { return pDrawcalls; }
private: private:
static int m_drawcalls; static int pDrawcalls;
static int m__dc__; static int p__dc__; // draw-calls internal
/** /**
* Funktion die anhand von **ac** genau den permu station wert für BufInfo * Funktion die anhand von **ac** genau den permu station wert für BufInfo
@@ -127,7 +132,7 @@ class c3d {
* ac = 4 -> 0x3210 * ac = 4 -> 0x3210
* ``` * ```
*/ */
constexpr static u64 permutation(int ac) { constexpr static u64 pPermutation(int ac) {
u64 ret = 0; u64 ret = 0;
if (ac < 1 || ac > 15) { if (ac < 1 || ac > 15) {
throw std::runtime_error("[amy] " + std::to_string(ac) + throw std::runtime_error("[amy] " + std::to_string(ac) +
@@ -139,4 +144,4 @@ class c3d {
return ret; return ret;
} }
}; };
} // namespace amy } // namespace Amy
+124
View File
@@ -0,0 +1,124 @@
#pragma once
#include <amethyst/types.hpp>
#include <amethyst/utils.hpp>
// We all know where the code is from ... RenderD7 -> Palladium/Amy
namespace Amy {
class Color {
public:
/**
* Default Constructor (all variables are set to 0)
*/
constexpr Color() : r(0), g(0), b(0), a(0) {}
constexpr ~Color() {}
/**
* Constructor for 32Bit Color Input
* @param color 32Bit Color value
*/
constexpr Color(ui clr) {
a = (clr >> 24) & 0xff;
b = (clr >> 16) & 0xff;
g = (clr >> 8) & 0xff;
r = clr & 0xff;
}
/**
* Constructor for 8Bit Input
* @param r Red Value
* @param g Green Value
* @param b Blue Value
* @param a Optional Alpha Value (Defaults to 255)
*/
constexpr Color(int r, int g, int b, int a = 255) : r(r), g(g), b(b), a(a) {}
/**
* Constructor for float Input
* @param r Red Value
* @param g Green Value
* @param b Blue Value
* @param a Optional Alpha Value (Defaults to 1.0f)
* @note There is no Check if the number is between 0.0 and 1.0
*/
constexpr Color(float r, float g, float b, float a = 1.f)
: r(static_cast<uc>(255.f * r)),
g(static_cast<uc>(255.f * g)),
b(static_cast<uc>(255.f * b)),
a(static_cast<uc>(255.f * a)) {}
/**
* Constructor for Hex Input
* @param hex Hex String in `#ffffff` or `#ffffffff` format
*/
constexpr Color(const std::string& hex) { Hex(hex); }
/**
* Create Color Object by Hex String
* @param hex Hex String in `#ffffff` or `#ffffffff` format
* @return Color class itself
*/
constexpr Color& Hex(const std::string& hex) {
if (!(hex.length() == 7 || hex.length() == 9)) {
throw "[PD] Color: hex string is not rgb or rgba!";
}
r = Utils::HexChar2Int(hex[1]) * 16 + Utils::HexChar2Int(hex[2]);
g = Utils::HexChar2Int(hex[3]) * 16 + Utils::HexChar2Int(hex[4]);
b = Utils::HexChar2Int(hex[5]) * 16 + Utils::HexChar2Int(hex[6]);
if (hex.length() == 9) {
a = Utils::HexChar2Int(hex[7]) * 16 + Utils::HexChar2Int(hex[8]);
} else {
a = 255;
}
return *this;
}
/**
* Convert this Color Object to Hex string
* @param rgba [default false] sets if 8 or 6 digit color should be returned
* @return Color Hex String
*/
std::string Hex(bool rgba = false) const;
/**
* Fade from Current to another Color
* @param color Color to fade to
* @param p Amount (supports -1.0 to 1.0 for use of sine)
* @return Class Reference
*/
constexpr Color& Fade(const Color& color, float p) {
a = static_cast<uc>((color.a - a) * ((p + 1.f) / 2));
b = static_cast<uc>((color.b - b) * ((p + 1.f) / 2));
g = static_cast<uc>((color.g - g) * ((p + 1.f) / 2));
r = static_cast<uc>((color.r - r) * ((p + 1.f) / 2));
return *this;
}
/**
* Get 32Bit Color Value
* @return 32Bit Color Value (ABGR iirc)
*/
constexpr ui Get() const { return (a << 24) | (b << 16) | (g << 8) | r; }
/**
* Get The Luminance of the Color
* @return luminance (from 0.0 to 1.0)
*/
constexpr float Luminance() const {
// For Reference https://en.wikipedia.org/wiki/HSL_and_HSV#Lightness
return (0.3 * (r / 255.f) + 0.59 * (g / 255.f) + 0.11 * (b / 255.f));
}
/**
* Check if the Color is Light or Dark
* @return true if light
*/
constexpr bool IsLight() const { return (Luminance() >= 0.5); }
/**
* Operator to cast Color to 32Bit Value
* @return 32Bit Color Value
*/
constexpr operator ui() const { return Get(); }
/** Public Access Data section */
uc r;
uc g;
uc b;
uc a;
};
} // namespace Amy
-17
View File
@@ -1,17 +0,0 @@
#pragma once
#include <amethyst/types.hpp>
namespace amy {
namespace ctru {
enum services {
romfs = 1 << 0,
cfgu = 1 << 1,
gfx = 1 << 2,
gfx_def = 1 << 3,
def = romfs | gfx_def
};
void init(unsigned int srv = def);
ull getTime();
} // namespace ctru
} // namespace amy
+205 -6
View File
@@ -1,13 +1,212 @@
#pragma once #pragma once
#include <string> #include <amethyst/types.hpp>
#include <amethyst/id.hpp>
namespace amy { namespace Amy {
class gtrace { class GTrace {
public: public:
gtrace() = default; GTrace() = default;
~gtrace() = default; ~GTrace() = default;
class Stats {
public:
/**
* Constructor taking a lengh for the List
* @param l Lengh of the data list
*/
Stats(int l) : len(l), val(l, 0) {}
~Stats() = default;
AMY_SHARED(Stats);
/**
* Add a New Value to the list
* @param v value to add
*/
void Add(ull v) {
val[idx] = v;
idx = next(idx);
num_val = std::min(num_val + 1, len);
}
/**
* Get Avarage Num
* @return Average
*/
ull GetAverage() {
if (!num_val) return 0.f;
ull res = 0;
for (int i = 0; i < num_val; i++) {
res += val[smart_idx(i)];
}
return res / num_val;
}
/**
* Get Minimum Num
* @return Minimum value
*/
ull GetMin() {
if (!num_val) return 0.f;
ull res = std::numeric_limits<ull>::max();
for (int i = 0; i < num_val; i++) {
res = std::min(val[smart_idx(i)], res);
}
return res;
}
/**
* Get Maximum Value
* @return Max Value
*/
ull GetMax() {
if (!num_val) return 0.f;
ull res = 0;
for (int i = 0; i < num_val; i++) {
res = std::max(val[smart_idx(i)], res);
}
return res;
}
/**
* Clear the List
*/
void Clear() {
val.assign(len, 0);
idx = 0;
num_val = 0;
}
/**
* Get Data Buffer
* @return data bufer (not edidable)
*/
const std::vector<ull>& GetData() { return val; }
/**
* Access an element in the list [not edidable]
* @return value to access
*/
const ull& operator[](int i) { return val[smart_idx(i)]; }
/**
* Get List Lengh
* @return Lengh
*/
const size_t GetLen() { return len; }
/**
* Get Number of Values
* @return number of values
*/
const size_t GetNumValues() { return num_val; }
private:
/**
* Get the Next Position to write to
* @param c current position
* @return next position
*/
size_t next(size_t c) const { return (c + 1) % len; }
/**
* Smart Indexing in for loops to make sure to
* not index a value that was not set yet
* @param v pos in for loop
* @return indexing pos
*/
size_t smart_idx(size_t v) const { return (idx + len - num_val + v) % len; }
/** Lengh of the list */
int len = 0;
/** Value Storage */
std::vector<ull> val;
int idx = 0;
int num_val = 0;
};
class Trace {
public:
Trace() { protocol = Stats::New(60); }
~Trace() = default;
AMY_SHARED(Trace);
void SetID(ksr v) { Name = v; }
kstr GetID() { return Name; }
void SetStart(ull v) { Start = v; }
ull GetStart() { return Start; }
void SetEnd(ull v) {
End = v;
Diff = End - Start;
protocol->Add(GetLastDiff());
}
ull GetEnd() { return End; }
ull GetLastDiff() { return Diff; }
Stats::Ref GetProtocol() { return protocol; }
private:
str Name;
ull Start = 0;
ull End = 0;
ull Diff = 0;
Stats::Ref protocol;
};
/**
* Begin a Trace
* @param id Name of the Trace
*/
static void Beg(ksr id);
/**
* End a Trace
* @param id Name of the Trace
*/
static void End(ksr id);
/**
* Collect Start end end of the trace by tracking
* when the Scope object goes out of scope
*
* Example:
* ```cpp
* void SomeFunction() {
* // Create a Scoped Trace called "SomeFunc"
* PD::TT::Scope st("SomeFunc");
* // Do your functions stuff
* // End at the end it goes out of
* // scope which collects the end time
* }
* ```
*/
class Scope {
public:
/**
* Constructor requiring a Name for the Trace
* @param id Name of the Trace
*/
Scope(ksr id) {
this->ID = id;
GTrace::Beg(id);
}
/**
* Deconstructor getting the end time when going out of scope
*/
~Scope() { GTrace::End(ID); }
private:
/** Trace Name/ID */
str ID;
};
using TraceMap = std::unordered_map<std::string, Trace::Ref>;
static TraceMap& GetTraceMap() { return GetTraceMap(); }
static Trace::Ref& GetTraceRef(ksr id) {
if (!pTraces.count(id)) {
pTraces[id] = Trace::New();
pTraces[id]->SetID(id);
}
return pTraces[id];
}
static bool TraceExist(ksr id) { return pTraces.count(id); }
private: private:
static TraceMap pTraces;
}; };
} // namespace amy } // namespace Amy
+42
View File
@@ -0,0 +1,42 @@
#pragma once
#include <amethyst/types.hpp>
#include <amethyst/utils.hpp>
namespace Amy {
class ID {
public:
constexpr ID(const ui& id) { pID = id; }
constexpr ID(std::string name) {
pID = Utils::FNV32(name);
#ifdef AMY_KEEP_STR_ID
pName = name;
#endif
}
constexpr ID(const char* name) {
pID = Utils::FNV32(name);
#ifdef AMY_KEEP_STR_ID
pName = name;
#endif
}
~ID() {}
ui GetID() { return pID; }
std::string GetName() const {
#ifdef AMY_KEEP_STR_ID
return pName;
#else
return std::format("hash({:#08x})", pID);
#endif
}
operator ui() const { return pID; }
operator std::string() const { return GetName(); }
private:
ui pID;
#ifdef AMY_KEEP_STR_ID
str pName;
#endif
};
} // namespace Amy
+32 -31
View File
@@ -2,54 +2,55 @@
#include <amethyst/types.hpp> #include <amethyst/types.hpp>
namespace amy { namespace Amy {
class image { class Image {
public: public:
enum format { enum Format {
RGBA, // bpp == 4 RGBA, // bpp == 4
RGB, // bpp == 3 RGB, // bpp == 3
RGB565, // bpp == 2 (not supported in laoding) RGB565, // bpp == 2 (not supported in laoding)
BGR, // bpp == 3 BGR, // bpp == 3
ABGR, // bpp == 4 ABGR, // bpp == 4
BGRA, // bpp == 4 BGRA, // bpp == 4
A8, // bpp == 1 (not supported in laoding)
}; };
image() = default; Image() = default;
image(cstr& path) { this->load(path); } Image(ksr path) { this->Load(path); }
image(const std::vector<uc>& buf) { this->load(buf); } Image(kvr<uc> buf) { this->Load(buf); }
image(const std::vector<uc>& buf, int w, int h, const format& fmt) { Image(kvr<uc> buf, int w, int h, const Format& fmt) {
this->copy(buf, w, h, fmt); this->Copy(buf, w, h, fmt);
} }
~image() = default; ~Image() = default;
void load(cstr& path); void Load(ksr path);
void load(const std::vector<uc>& buf); void Load(kvr<uc> buf);
void copy(const std::vector<uc>& buf, int w, int h, const format& fmt); void Copy(kvr<uc> buf, int w, int h, const Format& fmt);
std::vector<uc>& getBuffer() { return m_buffer; } vec<uc>& GetBuffer() { return pBuffer; }
std::vector<uc> getBuffer() const { return m_buffer; } vec<uc> GetBuffer() const { return pBuffer; }
int width() const { return m_w; } int Width() const { return pW; }
int height() const { return m_h; } int Height() const { return pH; }
int bpp() const { return getBppOfFmt(m_fmt); } int Bpp() const { return GetBppOfFmt(pFmt); }
format fmt() const { return m_fmt; } Format Fmt() const { return pFmt; }
void convert(const format& dst) { convert(*this, dst); } void Convert(const Format& dst) { Convert(*this, dst); }
void retile(std::function<ui(int x, int y, int w)> src, void Retile(std::function<ui(int x, int y, int w)> src,
std::function<ui(int x, int y, int w)> dst) { std::function<ui(int x, int y, int w)> dst) {
retile(*this, src, dst); Retile(*this, src, dst);
} }
uc& operator[](int idx) { return m_buffer[idx]; } uc& operator[](int idx) { return pBuffer[idx]; }
uc operator[](int idx) const { return m_buffer[idx]; } uc operator[](int idx) const { return pBuffer[idx]; }
static void convert(image& img, const format& dst); static void Convert(Image& img, const Format& dst);
static void retile(image& img, std::function<ui(int x, int y, int w)> src, static void Retile(Image& img, std::function<ui(int x, int y, int w)> src,
std::function<ui(int x, int y, int w)> dst); std::function<ui(int x, int y, int w)> dst);
static int getBppOfFmt(const format& fmt); static int GetBppOfFmt(const Format& fmt);
private: private:
std::vector<uc> m_buffer; vec<uc> pBuffer;
int m_w = 0; int pW = 0;
int m_h = 0; int pH = 0;
format m_fmt = RGBA; Format pFmt = RGBA;
}; };
} // namespace amy } // namespace Amy
+171 -97
View File
@@ -8,157 +8,231 @@
#include <amethyst/texture.hpp> #include <amethyst/texture.hpp>
#include <amethyst/types.hpp> #include <amethyst/types.hpp>
namespace amy { using AmyTextFlags = Amy::ui;
class iron { enum AmyTextFlags_ {
AmyTextFlags_None = 0, ///< Do nothing
AmyTextFlags_AlignRight = 1 << 0, ///< Align Right of position
AmyTextFlags_AlignMid = 1 << 1, ///< Align in the middle of pos and box
AmyTextFlags_Shaddow = 1 << 2, ///< Draws the text twice to create shaddow
AmyTextFlags_Wrap = 1 << 3, ///< Wrap Text: May be runs better with TMS
AmyTextFlags_Short = 1 << 4, ///< Short Text: May be runs better with TMS
AmyTextFlags_Scroll = 1 << 5, ///< Not implemented [scoll text if to long]
};
namespace Amy {
class Iron {
public: public:
struct vertex { struct Vertex {
vertex(float x, float y, float u, float v, ui clr) { Vertex(float x, float y, float u, float v, ui clr) {
pos.x = x; pos.x = x;
pos.y = y; pos.y = y;
uv.x = x; uv.x = u;
uv.y = y; uv.y = v;
color = clr; color = clr;
} }
vertex(const fvec2& pos, const fvec2& uv, ui clr) { Vertex(const fvec2& pos, const fvec2& uv, ui clr) {
this->pos = pos; this->pos = pos;
this->uv = uv; this->uv = uv;
this->color = clr; this->color = clr;
} }
vertex() {} Vertex() {}
amy::fvec2 pos; fvec2 pos;
amy::fvec2 uv; fvec2 uv;
ui color = 0; ui color = 0;
}; };
class command { class Command {
public: public:
command() = default; Command() = default;
using ref = up<command>; ~Command() = default;
command& add(const u16& idx) { AMY_UNIQUE(Command)
indexBuf.push_back(vertexBuf.size() + idx);
Command& Add(const u16& idx) {
IndexBuf.push_back(VertexBuf.size() + idx);
return *this; return *this;
} }
command& add(const vertex& vtx) { Command& Add(const Vertex& vtx) {
vertexBuf.push_back(std::move(vtx)); VertexBuf.push_back(std::move(vtx));
return *this; return *this;
} }
std::vector<vertex> vertexBuf; std::vector<Vertex> VertexBuf;
std::vector<u16> indexBuf; std::vector<u16> IndexBuf;
ivec4 scissorRect; ivec4 ScissorRect;
bool scissorOn = false; bool ScissorOn = false;
int layer; int Layer = 0;
int index; int Index = 0;
texture* tex; Texture::Ref Tex = nullptr;
}; };
class drawlist {
class Font : public Asset {
public: public:
drawlist() { drawSolid(); } struct Codepoint {
~drawlist() { m_data.clear(); } ui Cp = 0;
fvec4 Uv;
Texture::Ref Tex = nullptr;
fvec2 Size;
float Offset = 0; // Unused??
bool Valid = true;
};
Font() = default;
~Font() = default;
AMY_SHARED(Font)
void LoadTTF(ksr path, int pxh = 32);
void LoadTTF(kvr<uc> data, int pxh = 32);
/**
* Bitmap Font BTW
*/
void LoadBMF(ksr path);
Codepoint& GetCodepoint(ui c);
fvec2 GetTextBounds(ksr text, float scale);
void CmdTextEx(vec<Command::Ref>& cmds, const fvec2& pos, ui color,
float scale, ksr text, AmyTextFlags flags = 0,
const fvec2& box = 0);
void pMakeAtlas(bool final, vec<uc>& pixels, int size, Texture::Ref tex);
int PxHeight;
int PxFactor = 24;
vec<Texture::Ref> Textures;
std::map<u32, Codepoint> pCodeMap;
};
class Drawlist {
public:
Drawlist() { DrawSolid(); }
~Drawlist() { pData.clear(); }
AMY_SHARED(Drawlist)
// required due to memory management // required due to memory management
drawlist(const drawlist&) = delete; Drawlist(const Drawlist&) = delete;
drawlist& operator=(const drawlist&) = delete; Drawlist& operator=(const Drawlist&) = delete;
drawlist(drawlist&&) noexcept = default; Drawlist(Drawlist&&) noexcept = default;
drawlist& operator=(drawlist&&) noexcept = default; Drawlist& operator=(Drawlist&&) noexcept = default;
std::vector<command::ref>& data() { return m_data; } std::vector<Command::Ref>& Data() { return pData; }
void merge(drawlist* list); void Merge(Drawlist* list);
command::ref newCommand(); Command::Ref NewCommand();
void push(command ::ref cmd); void Push(Command ::Ref cmd);
void clear(); void Clear();
void drawSolid();
void drawTex(texture* tex) { m_tex = tex; }
void DrawSolid();
void DrawTex(Texture::Ref tex) { pTex = tex; }
void DrawFromAtlas(fvec2 pos, fvec2 size, fvec4 cut_rect,
ui color = 0xffffffff);
void DrawFromAtlas(fvec2 pos, fvec2 size, fvec4 cut_rect, Texture::Ref tex,
ui color = 0xffffffff) {
DrawTex(tex);
DrawFromAtlas(pos, size, cut_rect, color);
DrawSolid();
}
void SetFont(Font::Ref fnt) { pCurrentFont = fnt; }
void SetFontScale(float v) { pFontScale = v; }
float GetFontScale() { return pFontScale; }
void DefaultFontScale() { pFontScale = 0.7; }
/** Draw Api */ /** Draw Api */
void drawRect(const fvec2& pos, const fvec2& size, ui color, void DrawRect(const fvec2& pos, const fvec2& size, ui color,
int thickness = 1); int thickness = 1);
void drawRectFilled(const fvec2& pos, const fvec2& size, ui color); void DrawRectFilled(const fvec2& pos, const fvec2& size, ui color);
void drawTriangle(const fvec2& a, const fvec2& b, const fvec2& c, ui color, void DrawTriangle(const fvec2& a, const fvec2& b, const fvec2& c, ui color,
int thickness = 1); int thickness = 1);
void drawTriangleFilled(const fvec2& a, const fvec2& b, const fvec2& c, void DrawTriangleFilled(const fvec2& a, const fvec2& b, const fvec2& c,
ui color); ui color);
void drawCircle(const fvec2& center, float radius, ui color, int segments, void DrawCircle(const fvec2& center, float radius, ui color, int segments,
int thickness = 1); int thickness = 1);
void drawCircleFilled(const fvec2& center, float radius, ui color, void DrawCircleFilled(const fvec2& center, float radius, ui color,
int segments); int segments);
void drawText(const fvec2& pos, const std::string& text, ui color); void DrawText(const fvec2& pos, const std::string& text, ui color);
void drawTextEx(const fvec2& pos, const std::string& text, ui color, void DrawTextEx(const fvec2& pos, const std::string& text, ui color,
ui flags, const fvec2& box = 0); ui flags, const fvec2& box = 0);
void drawLine(const fvec2& a, const fvec2& b, ui color, int thickness = 1); void DrawLine(const fvec2& a, const fvec2& b, ui color, int thickness = 1);
void drawPolyLine(const std::vector<fvec2>& points, ui color, ui flags = 0, void DrawPolyLine(const std::vector<fvec2>& points, ui color, ui flags = 0,
int thickness = 1); int thickness = 1);
void drawConvexPolyFilled(const std::vector<fvec2>& points, ui color); void DrawConvexPolyFilled(const std::vector<fvec2>& points, ui color);
/** Path api */ /** Path api */
void pathAdd(const fvec2& pos) { m_path.push_back(std::move(pos)); } void PathAdd(const fvec2& pos) { pPath.push_back(std::move(pos)); }
void pathClear() { m_path.clear(); } void PathClear() { pPath.clear(); }
void pathReserve(size_t count) { m_path.reserve(m_path.size() + count); } void PathReserve(size_t count) { pPath.reserve(pPath.size() + count); }
void pathStroke(ui color, int thickness = 1, ui flags = 0) { void PathStroke(ui color, int thickness = 1, ui flags = 0) {
drawPolyLine(m_path, color, flags, thickness); DrawPolyLine(pPath, color, flags, thickness);
pathClear(); PathClear();
} }
void pathFill(ui color) { drawConvexPolyFilled(m_path, color); } void PathFill(ui color) {
void pathArcToN(const fvec2& c, float radius, float a_min, float a_max, DrawConvexPolyFilled(pPath, color);
PathClear();
}
void PathArcToN(const fvec2& c, float radius, float a_min, float a_max,
int segments); int segments);
void pathFastArcToN(const fvec2& c, float radius, float a_min, float a_max, void PathFastArcToN(const fvec2& c, float radius, float a_min, float a_max,
int segments); int segments);
void pathRect(const fvec2& a, const fvec2& b, float rounding = 0.f); void PathRect(const fvec2& a, const fvec2& b, float rounding = 0.f);
void pathRectEx(const fvec2& a, const fvec2& b, float rounfing, ui flags); void PathRectEx(const fvec2& a, const fvec2& b, float rounfing, ui flags);
void pushClipRect(const fvec4& clip) { clipRects.push(clip); } void PushClipRect(const fvec4& clip) { ClipRects.push(clip); }
void popClipRect() { void PopClipRect() {
if (!clipRects.empty()) clipRects.pop(); if (!ClipRects.empty()) ClipRects.pop();
} }
operator std::vector<command::ref>&() { return m_data; } operator std::vector<Command::Ref>&() { return pData; }
private: private:
void clipCmd(command* ptr); void clipCmd(Command* ptr);
std::vector<command::ref> m_data; std::vector<Command::Ref> pData;
std::vector<fvec2> m_path; std::vector<fvec2> pPath;
texture* m_tex = nullptr; Texture::Ref pTex = nullptr;
std::stack<fvec4> clipRects; std::stack<fvec4> ClipRects;
int m_layer = 0; Font::Ref pCurrentFont;
int pLayer = 0;
float pFontScale = 0.7;
}; };
iron() = default; Iron() = default;
~iron() = default; ~Iron() = default;
static void init(); static void Init();
static void newFrame(); static void Exit();
static void drawOn(c3d::screen* screen); static void NewFrame();
static void draw(const std::vector<command::ref>& data); static void DrawOn(C3D::Screen* screen);
static texture* whiteTex() { return m_solid; } static void Draw(const std::vector<Command::Ref>& data);
static Texture::Ref WhiteTex() { return m_solid; }
/** Static renderer utility funcs */ /** Static renderer utility funcs */
static void rotateCorner(fvec2& pos, float s, float c); static void RotateCorner(fvec2& pos, float s, float c);
static rect primRect(const fvec2& pos, const fvec2& size, float angle = 0.f); static Rect PrimRect(const fvec2& pos, const fvec2& size, float angle = 0.f);
static rect primLine(const fvec2& a, const fvec2& b, int thickness = 1); static Rect PrimLine(const fvec2& a, const fvec2& b, int thickness = 1);
static void cmdQuad(command* cmd, const rect& q, const rect& uv, ui color); static void CmdQuad(Command* cmd, const Rect& q, const Rect& uv, ui color);
static void cmdTriangle(command* cmd, const fvec2& a, const fvec2& b, static void CmdTriangle(Command* cmd, const fvec2& a, const fvec2& b,
const fvec2& c, ui clr); const fvec2& c, ui clr);
static void cmdConvexPolyFilled(command* cmd, static void CmdConvexPolyFilled(Command* cmd,
const std::vector<fvec2>& points, ui clr, const std::vector<fvec2>& points, ui clr,
texture* tex); Texture::Ref tex);
static bool inBox(const fvec2& pos, const fvec2& size, const fvec4& area); static bool InBox(const fvec2& pos, const fvec2& size, const fvec4& area);
static bool inBox(const fvec2& pos, const fvec4& area); static bool InBox(const fvec2& pos, const fvec4& area);
static bool inBox(const fvec2& a, const fvec2& b, const fvec2& c, static bool InBox(const fvec2& a, const fvec2& b, const fvec2& c,
const fvec4& area); const fvec4& area);
private: static ui VerticesDrawn() { return VertexCount; }
static void setupShader(); static ui IndicesDrawn() { return IndexCount; }
static void fragConfig();
static void initSolidTex();
static std::vector<vertex, linearAllocator<vertex>> m_vbuf; private:
static std::vector<u16, linearAllocator<u16>> m_ibuf; static void pSetupShader();
static void pFragConfig(GPU_TEXCOLOR clr);
static void pInitSolidTex();
static bool pCheckSize(size_t idx, size_t vtx);
static std::vector<Vertex, LinearAllocator<Vertex>> m_vbuf;
static std::vector<u16, LinearAllocator<u16>> m_ibuf;
static int uLocProj; static int uLocProj;
static c3d::shader* m_shader; static C3D::Shader* m_shader;
static mat4 m_mtx; static mat4 m_mtx;
static int m_idx, m_vtx; static int m_idx, m_vtx;
static texture* m_solid; static Texture::Ref m_solid;
static ui VertexCount;
static ui IndexCount;
}; };
} // namespace amy } // namespace Amy
+23 -9
View File
@@ -9,28 +9,42 @@
// based on this guide: // based on this guide:
// https://johnfarrier.com/custom-allocators-in-c-high-performance-memory-management/ // https://johnfarrier.com/custom-allocators-in-c-high-performance-memory-management/
namespace amy { namespace Amy {
template <typename T> template <typename T>
class linearAllocator { class LinearAllocator {
public: public:
using value_type = T; using value_type = T;
linearAllocator() = default; LinearAllocator() noexcept = default;
template <typename U> template <typename U>
constexpr linearAllocator(const linearAllocator<U>&) noexcept {} constexpr LinearAllocator(const LinearAllocator<U>&) noexcept {}
T* allocate(std::size_t n) { T* allocate(std::size_t n) {
if (n > std::allocator_traits<linearAllocator>::max_size(*this)) { if (n > max_size()) {
throw std::bad_alloc(); throw std::runtime_error("[Amy] LinearAllocator: Bad alloc!");
} }
return static_cast<T*>(linearAlloc(n * sizeof(T))); return static_cast<T*>(linearAlloc(n * sizeof(T)));
} }
void deallocate(T* p, std::size_t) noexcept { linearFree(p); } void deallocate(T* p, std::size_t) noexcept { linearFree(p); }
friend bool operator==(const linearAllocator, const linearAllocator) { template <class U, class... Args>
void construct(U* p, Args&&... args) {
::new ((void*)p) U(std::forward<Args>(args)...);
}
template <class U>
void destroy(U* p) {
p->~U();
}
friend bool operator==(const LinearAllocator, const LinearAllocator) {
return true; return true;
} }
friend bool operator!=(const linearAllocator, const linearAllocator) { friend bool operator!=(const LinearAllocator, const LinearAllocator) {
return false; return false;
} }
// Use linearSpace free as max_size to not allocate out of bounds
// or to b eable to see a crash report screen.
size_t max_size() const noexcept { return linearSpaceFree(); }
}; };
} // namespace amy } // namespace Amy
+4 -4
View File
@@ -29,11 +29,11 @@ SOFTWARE.
#include <cmath> #include <cmath>
#include <numbers> #include <numbers>
namespace amy { namespace Amy {
namespace numbers { namespace Numbers {
constexpr float Tau = std::numbers::pi * 2.f; constexpr float Tau = std::numbers::pi * 2.f;
} }
constexpr float Radians(float v) { return v * (numbers::Tau / 360.0f); } constexpr float Radians(float v) { return v * (Numbers::Tau / 360.0f); }
/** /**
* Minimal Mtx4 Lib that precomputes * Minimal Mtx4 Lib that precomputes
* basic stuff stuff at compiletime * basic stuff stuff at compiletime
@@ -141,4 +141,4 @@ struct mat4 {
static mat4 perspective(float fov, float aspect, float n, float f); static mat4 perspective(float fov, float aspect, float n, float f);
static mat4 lookAt(const fvec3& pos, const fvec3& center, const fvec3& up); static mat4 lookAt(const fvec3& pos, const fvec3& center, const fvec3& up);
}; };
} // namespace amy } // namespace Amy
+6 -6
View File
@@ -36,25 +36,25 @@ SOFTWARE.
*/ */
template <typename T, typename CharT> template <typename T, typename CharT>
struct std::formatter<amy::vec2<T>, CharT> : std::formatter<T, CharT> { struct std::formatter<Amy::vec2<T>, CharT> : std::formatter<T, CharT> {
template <typename FormatContext> template <typename FormatContext>
auto format(const amy::vec2<T> &v, FormatContext &ctx) const { auto format(const Amy::vec2<T>& v, FormatContext& ctx) const {
return std::format_to(ctx.out(), "{}, {}", v.x, v.y); return std::format_to(ctx.out(), "{}, {}", v.x, v.y);
} }
}; };
template <typename T, typename CharT> template <typename T, typename CharT>
struct std::formatter<amy::vec3<T>, CharT> : std::formatter<T, CharT> { struct std::formatter<Amy::vec3<T>, CharT> : std::formatter<T, CharT> {
template <typename FormatContext> template <typename FormatContext>
auto format(const amy::vec3<T> &v, FormatContext &ctx) const { auto format(const Amy::vec3<T>& v, FormatContext& ctx) const {
return std::format_to(ctx.out(), "{}, {}, {}", v.x, v.y, v.z); return std::format_to(ctx.out(), "{}, {}, {}", v.x, v.y, v.z);
} }
}; };
template <typename T, typename CharT> template <typename T, typename CharT>
struct std::formatter<amy::vec4<T>, CharT> : std::formatter<T, CharT> { struct std::formatter<Amy::vec4<T>, CharT> : std::formatter<T, CharT> {
template <typename FormatContext> template <typename FormatContext>
auto format(const amy::vec4<T> &v, FormatContext &ctx) const { auto format(const Amy::vec4<T>& v, FormatContext& ctx) const {
return std::format_to(ctx.out(), "{}, {}, {}, {}", v.x, v.y, v.z, v.w); return std::format_to(ctx.out(), "{}, {}, {}, {}", v.x, v.y, v.z, v.w);
} }
}; };
+49 -26
View File
@@ -27,21 +27,24 @@ SOFTWARE.
#include <cmath> #include <cmath>
namespace amy { namespace Amy {
template <typename T> class vec2 { template <typename T>
public: class vec2 {
public:
T x; T x;
T y; T y;
// Constructors // Constructors
constexpr vec2() : x(0), y(0) {} constexpr vec2() : x(0), y(0) {}
template <typename T1> constexpr vec2(T1 v) { template <typename T1>
constexpr vec2(T1 v) {
x = (T)v; x = (T)v;
y = (T)v; y = (T)v;
} }
template <typename T1> constexpr vec2(const vec2<T1> &v) { template <typename T1>
constexpr vec2(const vec2<T1>& v) {
x = (T)v.x; x = (T)v.x;
y = (T)v.y; y = (T)v.y;
} }
@@ -50,93 +53,111 @@ public:
// Operations // Operations
template <typename T1> vec2<T> &operator+=(T1 v) { template <typename T1>
vec2<T>& operator+=(T1 v) {
x += (T)v; x += (T)v;
y += (T)v; y += (T)v;
return *this; return *this;
} }
template <typename T1> vec2<T> &operator+=(const vec2<T1> &v) { template <typename T1>
vec2<T>& operator+=(const vec2<T1>& v) {
x += (T)v.x; x += (T)v.x;
y += (T)v.y; y += (T)v.y;
return *this; return *this;
} }
template <typename T1> vec2<T> operator+(T1 v) const { template <typename T1>
vec2<T> operator+(T1 v) const {
return vec2<T>(x + (T)v, y + (T)v); return vec2<T>(x + (T)v, y + (T)v);
} }
template <typename T1> vec2<T> operator+(const vec2<T1> &v) const { template <typename T1>
vec2<T> operator+(const vec2<T1>& v) const {
return vec2<T>(x + (T)v.x, y + (T)v.y); return vec2<T>(x + (T)v.x, y + (T)v.y);
} }
template <typename T1> vec2<T> &operator-=(T1 v) { template <typename T1>
vec2<T>& operator-=(T1 v) {
x -= (T)v; x -= (T)v;
y -= (T)v; y -= (T)v;
return *this; return *this;
} }
template <typename T1> vec2<T> &operator-=(const vec2<T1> &v) { template <typename T1>
vec2<T>& operator-=(const vec2<T1>& v) {
x -= (T)v.x; x -= (T)v.x;
y -= (T)v.y; y -= (T)v.y;
return *this; return *this;
} }
template <typename T1> vec2<T> operator-(T1 v) const { template <typename T1>
vec2<T> operator-(T1 v) const {
return vec2<T>(x - (T)v, y - (T)v); return vec2<T>(x - (T)v, y - (T)v);
} }
template <typename T1> vec2<T> operator-(const vec2<T1> &v) const { template <typename T1>
vec2<T> operator-(const vec2<T1>& v) const {
return vec2<T>(x - (T)v.x, y - (T)v.y); return vec2<T>(x - (T)v.x, y - (T)v.y);
} }
template <typename T1> vec2<T> &operator*=(T1 v) { template <typename T1>
vec2<T>& operator*=(T1 v) {
x *= (T)v; x *= (T)v;
y *= (T)v; y *= (T)v;
return *this; return *this;
} }
template <typename T1> vec2<T> &operator*=(const vec2<T1> &v) { template <typename T1>
vec2<T>& operator*=(const vec2<T1>& v) {
x *= (T)v.x; x *= (T)v.x;
y *= (T)v.y; y *= (T)v.y;
return *this; return *this;
} }
template <typename T1> vec2<T> operator*(T1 v) const { template <typename T1>
vec2<T> operator*(T1 v) const {
return vec2<T>(x * (T)v, y * (T)v); return vec2<T>(x * (T)v, y * (T)v);
} }
template <typename T1> vec2<T> operator*(const vec2<T1> &v) const { template <typename T1>
vec2<T> operator*(const vec2<T1>& v) const {
return vec2<T>(x * (T)v.x, y * (T)v.y); return vec2<T>(x * (T)v.x, y * (T)v.y);
} }
template <typename T1> vec2<T> &operator/=(T1 v) { template <typename T1>
vec2<T>& operator/=(T1 v) {
x /= (T)v; x /= (T)v;
y /= (T)v; y /= (T)v;
return *this; return *this;
} }
template <typename T1> vec2<T> &operator/=(const vec2<T1> &v) { template <typename T1>
vec2<T>& operator/=(const vec2<T1>& v) {
x /= (T)v.x; x /= (T)v.x;
y /= (T)v.y; y /= (T)v.y;
return *this; return *this;
} }
template <typename T1> vec2<T> operator/(T1 v) const { template <typename T1>
vec2<T> operator/(T1 v) const {
return vec2<T>(x / (T)v, y / (T)v); return vec2<T>(x / (T)v, y / (T)v);
} }
template <typename T1> vec2<T> operator/(const vec2<T1> &v) const { template <typename T1>
vec2<T> operator/(const vec2<T1>& v) const {
return vec2<T>(x / (T)v.x, y / (T)v.y); return vec2<T>(x / (T)v.x, y / (T)v.y);
} }
// Generic Operations // Generic Operations
vec2 operator-() const { return vec2(-x, -y); } vec2 operator-() const { return vec2(-x, -y); }
template <typename T1> bool operator==(const vec2<T1> &v) const { template <typename T1>
bool operator==(const vec2<T1>& v) const {
return x == (T)v.x && y == (T)v.y; return x == (T)v.x && y == (T)v.y;
} }
template <typename T1> bool operator!=(const vec2<T1> &v) const { template <typename T1>
bool operator!=(const vec2<T1>& v) const {
return !(*this == v); return !(*this == v);
} }
@@ -145,7 +166,8 @@ public:
double Len() const { return std::sqrt(SqLen()); } double Len() const { return std::sqrt(SqLen()); }
double SqLen() const { return x * x + y * y; } double SqLen() const { return x * x + y * y; }
template <typename T1> double Distance(const vec2<T1> &v) const { template <typename T1>
double Distance(const vec2<T1>& v) const {
return (*this - v).Len(); return (*this - v).Len();
} }
@@ -157,7 +179,8 @@ public:
return *this / (T)l; return *this / (T)l;
} }
template <typename T1> T Dot(const vec2<T1> &v) const { template <typename T1>
T Dot(const vec2<T1>& v) const {
return x * (T)v.x + y * (T)v.y; return x * (T)v.x + y * (T)v.y;
} }
@@ -171,4 +194,4 @@ public:
using fvec2 = vec2<float>; using fvec2 = vec2<float>;
using ivec2 = vec2<int>; using ivec2 = vec2<int>;
using dvec2 = vec2<double>; using dvec2 = vec2<double>;
} // namespace amy } // namespace Amy
+53 -28
View File
@@ -29,9 +29,10 @@ SOFTWARE.
// Extended includes (rename if you use other filenames/paths) // Extended includes (rename if you use other filenames/paths)
#include <amethyst/maths/vec2.hpp> #include <amethyst/maths/vec2.hpp>
namespace amy { namespace Amy {
template <typename T> class vec3 { template <typename T>
public: class vec3 {
public:
T x; T x;
T y; T y;
T z; T z;
@@ -39,13 +40,15 @@ public:
// Constructors // Constructors
constexpr vec3() : x(0), y(0), z(0) {} constexpr vec3() : x(0), y(0), z(0) {}
template <typename T1> constexpr vec3(T1 v) { template <typename T1>
constexpr vec3(T1 v) {
x = (T)v; x = (T)v;
y = (T)v; y = (T)v;
z = (T)v; z = (T)v;
} }
template <typename T1> constexpr vec3(const vec3<T1> &v) { template <typename T1>
constexpr vec3(const vec3<T1>& v) {
x = (T)v.x; x = (T)v.x;
y = (T)v.y; y = (T)v.y;
z = (T)v.z; z = (T)v.z;
@@ -54,7 +57,8 @@ public:
constexpr explicit vec3(T x, T y, T z) : x(x), y(y), z(z) {} constexpr explicit vec3(T x, T y, T z) : x(x), y(y), z(z) {}
// Extended Constructors // Extended Constructors
template <typename T1> constexpr explicit vec3(const vec2<T1> &xy, T1 z) { template <typename T1>
constexpr explicit vec3(const vec2<T1>& xy, T1 z) {
{ {
x = (T)xy.x; x = (T)xy.x;
y = (T)xy.y; y = (T)xy.y;
@@ -64,101 +68,119 @@ public:
// Operations // Operations
template <typename T1> vec3<T> &operator+=(T1 v) { template <typename T1>
vec3<T>& operator+=(T1 v) {
x += (T)v; x += (T)v;
y += (T)v; y += (T)v;
z += (T)v; z += (T)v;
return *this; return *this;
} }
template <typename T1> vec3<T> &operator+=(const vec3<T1> &v) { template <typename T1>
vec3<T>& operator+=(const vec3<T1>& v) {
x += (T)v.x; x += (T)v.x;
y += (T)v.y; y += (T)v.y;
z += (T)v.z; z += (T)v.z;
return *this; return *this;
} }
template <typename T1> vec3<T> operator+(T1 v) const { template <typename T1>
vec3<T> operator+(T1 v) const {
return vec3<T>(x + (T)v, y + (T)v, z + (T)v); return vec3<T>(x + (T)v, y + (T)v, z + (T)v);
} }
template <typename T1> vec3<T> operator+(const vec3<T1> &v) const { template <typename T1>
vec3<T> operator+(const vec3<T1>& v) const {
return vec3<T>(x + (T)v.x, y + (T)v.y, z + (T)v.z); return vec3<T>(x + (T)v.x, y + (T)v.y, z + (T)v.z);
} }
template <typename T1> vec3<T> &operator-=(T1 v) { template <typename T1>
vec3<T>& operator-=(T1 v) {
x -= (T)v; x -= (T)v;
y -= (T)v; y -= (T)v;
z -= (T)v; z -= (T)v;
return *this; return *this;
} }
template <typename T1> vec3<T> &operator-=(const vec3<T1> &v) { template <typename T1>
vec3<T>& operator-=(const vec3<T1>& v) {
x -= (T)v.x; x -= (T)v.x;
y -= (T)v.y; y -= (T)v.y;
z -= (T)v.z; z -= (T)v.z;
return *this; return *this;
} }
template <typename T1> vec3<T> operator-(T1 v) const { template <typename T1>
vec3<T> operator-(T1 v) const {
return vec3<T>(x - (T)v, y - (T)v, z - (T)v); return vec3<T>(x - (T)v, y - (T)v, z - (T)v);
} }
template <typename T1> vec3<T> operator-(const vec3<T1> &v) const { template <typename T1>
vec3<T> operator-(const vec3<T1>& v) const {
return vec3<T>(x - (T)v.x, y - (T)v.y, z - (T)v.z); return vec3<T>(x - (T)v.x, y - (T)v.y, z - (T)v.z);
} }
template <typename T1> vec3<T> &operator*=(T1 v) { template <typename T1>
vec3<T>& operator*=(T1 v) {
x *= (T)v; x *= (T)v;
y *= (T)v; y *= (T)v;
z *= (T)v; z *= (T)v;
return *this; return *this;
} }
template <typename T1> vec3<T> &operator*=(const vec3<T1> &v) { template <typename T1>
vec3<T>& operator*=(const vec3<T1>& v) {
x *= (T)v.x; x *= (T)v.x;
y *= (T)v.y; y *= (T)v.y;
z *= (T)v.z; z *= (T)v.z;
return *this; return *this;
} }
template <typename T1> vec3<T> operator*(T1 v) const { template <typename T1>
vec3<T> operator*(T1 v) const {
return vec3<T>(x * (T)v, y * (T)v, z * (T)v); return vec3<T>(x * (T)v, y * (T)v, z * (T)v);
} }
template <typename T1> vec3<T> operator*(const vec3<T1> &v) const { template <typename T1>
vec3<T> operator*(const vec3<T1>& v) const {
return vec3<T>(x * (T)v.x, y * (T)v.y, z * (T)v.z); return vec3<T>(x * (T)v.x, y * (T)v.y, z * (T)v.z);
} }
template <typename T1> vec3<T> &operator/=(T1 v) { template <typename T1>
vec3<T>& operator/=(T1 v) {
x /= (T)v; x /= (T)v;
y /= (T)v; y /= (T)v;
z /= (T)v; z /= (T)v;
return *this; return *this;
} }
template <typename T1> vec3<T> &operator/=(const vec3<T1> &v) { template <typename T1>
vec3<T>& operator/=(const vec3<T1>& v) {
x /= (T)v.x; x /= (T)v.x;
y /= (T)v.y; y /= (T)v.y;
z /= (T)v.z; z /= (T)v.z;
return *this; return *this;
} }
template <typename T1> vec3<T> operator/(T1 v) const { template <typename T1>
vec3<T> operator/(T1 v) const {
return vec3<T>(x / (T)v, y / (T)v, z / (T)v); return vec3<T>(x / (T)v, y / (T)v, z / (T)v);
} }
template <typename T1> vec3<T> operator/(const vec3<T1> &v) const { template <typename T1>
vec3<T> operator/(const vec3<T1>& v) const {
return vec3<T>(x / (T)v.x, y / (T)v.y, z / (T)v.z); return vec3<T>(x / (T)v.x, y / (T)v.y, z / (T)v.z);
} }
// Generic Operations // Generic Operations
vec3 operator-() const { return vec3(-x, -y, -z); } vec3 operator-() const { return vec3(-x, -y, -z); }
template <typename T1> bool operator==(const vec3<T1> &v) const { template <typename T1>
bool operator==(const vec3<T1>& v) const {
return x == (T)v.x && y == (T)v.y && z == (T)v.z; return x == (T)v.x && y == (T)v.y && z == (T)v.z;
} }
template <typename T1> bool operator!=(const vec3<T1> &v) const { template <typename T1>
bool operator!=(const vec3<T1>& v) const {
return !(*this == v); return !(*this == v);
} }
@@ -167,7 +189,8 @@ public:
double Len() const { return std::sqrt(SqLen()); } double Len() const { return std::sqrt(SqLen()); }
double SqLen() const { return x * x + y * y + z * z; } double SqLen() const { return x * x + y * y + z * z; }
template <typename T1> double Distance(const vec3<T1> &v) const { template <typename T1>
double Distance(const vec3<T1>& v) const {
return (*this - v).Len(); return (*this - v).Len();
} }
@@ -179,11 +202,13 @@ public:
return *this / (T)l; return *this / (T)l;
} }
template <typename T1> T Dot(const vec3<T1> &v) const { template <typename T1>
T Dot(const vec3<T1>& v) const {
return x * (T)v.x + y * (T)v.y + z * (T)v.z; return x * (T)v.x + y * (T)v.y + z * (T)v.z;
} }
template <typename T1> vec3<T> Cross(const vec3<T1> &v) const { template <typename T1>
vec3<T> Cross(const vec3<T1>& v) const {
return vec3<T>(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); return vec3<T>(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
} }
@@ -207,4 +232,4 @@ public:
using fvec3 = vec3<float>; using fvec3 = vec3<float>;
using ivec3 = vec3<int>; using ivec3 = vec3<int>;
using dvec3 = vec3<double>; using dvec3 = vec3<double>;
} // namespace amy } // namespace Amy
+52 -28
View File
@@ -30,9 +30,10 @@ SOFTWARE.
#include <amethyst/maths/vec2.hpp> #include <amethyst/maths/vec2.hpp>
#include <amethyst/maths/vec3.hpp> #include <amethyst/maths/vec3.hpp>
namespace amy { namespace Amy {
template <typename T> class vec4 { template <typename T>
public: class vec4 {
public:
T x; T x;
T y; T y;
T z; T z;
@@ -41,14 +42,16 @@ public:
// Constructors // Constructors
constexpr vec4() : x(0), y(0), z(0), w(0) {} constexpr vec4() : x(0), y(0), z(0), w(0) {}
template <typename T1> constexpr vec4(T1 v) { template <typename T1>
constexpr vec4(T1 v) {
x = (T)v; x = (T)v;
y = (T)v; y = (T)v;
z = (T)v; z = (T)v;
w = (T)v; w = (T)v;
} }
template <typename T1> constexpr vec4(const vec4<T1> &v) { template <typename T1>
constexpr vec4(const vec4<T1>& v) {
x = (T)v.x; x = (T)v.x;
y = (T)v.y; y = (T)v.y;
z = (T)v.z; z = (T)v.z;
@@ -59,7 +62,7 @@ public:
// Extended Constructors // Extended Constructors
template <typename T1> template <typename T1>
constexpr explicit vec4(const vec2<T1> &xy, const vec2<T1> &zw) { constexpr explicit vec4(const vec2<T1>& xy, const vec2<T1>& zw) {
{ {
x = (T)xy.x; x = (T)xy.x;
y = (T)xy.y; y = (T)xy.y;
@@ -68,7 +71,8 @@ public:
} }
} }
template <typename T1> constexpr explicit vec4(const vec3<T1> &xyz, T1 w) { template <typename T1>
constexpr explicit vec4(const vec3<T1>& xyz, T1 w) {
{ {
x = (T)xyz.x; x = (T)xyz.x;
y = (T)xyz.y; y = (T)xyz.y;
@@ -79,7 +83,8 @@ public:
// Operations // Operations
template <typename T1> vec4<T> &operator+=(T1 v) { template <typename T1>
vec4<T>& operator+=(T1 v) {
x += (T)v; x += (T)v;
y += (T)v; y += (T)v;
z += (T)v; z += (T)v;
@@ -87,7 +92,8 @@ public:
return *this; return *this;
} }
template <typename T1> vec4<T> &operator+=(const vec4<T1> &v) { template <typename T1>
vec4<T>& operator+=(const vec4<T1>& v) {
x += (T)v.x; x += (T)v.x;
y += (T)v.y; y += (T)v.y;
z += (T)v.z; z += (T)v.z;
@@ -95,15 +101,18 @@ public:
return *this; return *this;
} }
template <typename T1> vec4<T> operator+(T1 v) const { template <typename T1>
vec4<T> operator+(T1 v) const {
return vec4<T>(x + (T)v, y + (T)v, z + (T)v, w + (T)v); return vec4<T>(x + (T)v, y + (T)v, z + (T)v, w + (T)v);
} }
template <typename T1> vec4<T> operator+(const vec4<T1> &v) const { template <typename T1>
vec4<T> operator+(const vec4<T1>& v) const {
return vec4<T>(x + (T)v.x, y + (T)v.y, z + (T)v.z, w + (T)v.w); return vec4<T>(x + (T)v.x, y + (T)v.y, z + (T)v.z, w + (T)v.w);
} }
template <typename T1> vec4<T> &operator-=(T1 v) { template <typename T1>
vec4<T>& operator-=(T1 v) {
x -= (T)v; x -= (T)v;
y -= (T)v; y -= (T)v;
z -= (T)v; z -= (T)v;
@@ -111,7 +120,8 @@ public:
return *this; return *this;
} }
template <typename T1> vec4<T> &operator-=(const vec4<T1> &v) { template <typename T1>
vec4<T>& operator-=(const vec4<T1>& v) {
x -= (T)v.x; x -= (T)v.x;
y -= (T)v.y; y -= (T)v.y;
z -= (T)v.z; z -= (T)v.z;
@@ -119,15 +129,18 @@ public:
return *this; return *this;
} }
template <typename T1> vec4<T> operator-(T1 v) const { template <typename T1>
vec4<T> operator-(T1 v) const {
return vec4<T>(x - (T)v, y - (T)v, z - (T)v, w - (T)v); return vec4<T>(x - (T)v, y - (T)v, z - (T)v, w - (T)v);
} }
template <typename T1> vec4<T> operator-(const vec4<T1> &v) const { template <typename T1>
vec4<T> operator-(const vec4<T1>& v) const {
return vec4<T>(x - (T)v.x, y - (T)v.y, z - (T)v.z, w - (T)v.w); return vec4<T>(x - (T)v.x, y - (T)v.y, z - (T)v.z, w - (T)v.w);
} }
template <typename T1> vec4<T> &operator*=(T1 v) { template <typename T1>
vec4<T>& operator*=(T1 v) {
x *= (T)v; x *= (T)v;
y *= (T)v; y *= (T)v;
z *= (T)v; z *= (T)v;
@@ -135,7 +148,8 @@ public:
return *this; return *this;
} }
template <typename T1> vec4<T> &operator*=(const vec4<T1> &v) { template <typename T1>
vec4<T>& operator*=(const vec4<T1>& v) {
x *= (T)v.x; x *= (T)v.x;
y *= (T)v.y; y *= (T)v.y;
z *= (T)v.z; z *= (T)v.z;
@@ -143,15 +157,18 @@ public:
return *this; return *this;
} }
template <typename T1> vec4<T> operator*(T1 v) const { template <typename T1>
vec4<T> operator*(T1 v) const {
return vec4<T>(x * (T)v, y * (T)v, z * (T)v, w * (T)v); return vec4<T>(x * (T)v, y * (T)v, z * (T)v, w * (T)v);
} }
template <typename T1> vec4<T> operator*(const vec4<T1> &v) const { template <typename T1>
vec4<T> operator*(const vec4<T1>& v) const {
return vec4<T>(x * (T)v.x, y * (T)v.y, z * (T)v.z, w * (T)v.w); return vec4<T>(x * (T)v.x, y * (T)v.y, z * (T)v.z, w * (T)v.w);
} }
template <typename T1> vec4<T> &operator/=(T1 v) { template <typename T1>
vec4<T>& operator/=(T1 v) {
x /= (T)v; x /= (T)v;
y /= (T)v; y /= (T)v;
z /= (T)v; z /= (T)v;
@@ -159,7 +176,8 @@ public:
return *this; return *this;
} }
template <typename T1> vec4<T> &operator/=(const vec4<T1> &v) { template <typename T1>
vec4<T>& operator/=(const vec4<T1>& v) {
x /= (T)v.x; x /= (T)v.x;
y /= (T)v.y; y /= (T)v.y;
z /= (T)v.z; z /= (T)v.z;
@@ -167,21 +185,25 @@ public:
return *this; return *this;
} }
template <typename T1> vec4<T> operator/(T1 v) const { template <typename T1>
vec4<T> operator/(T1 v) const {
return vec4<T>(x / (T)v, y / (T)v, z / (T)v, w / (T)v); return vec4<T>(x / (T)v, y / (T)v, z / (T)v, w / (T)v);
} }
template <typename T1> vec4<T> operator/(const vec4<T1> &v) const { template <typename T1>
vec4<T> operator/(const vec4<T1>& v) const {
return vec4<T>(x / (T)v.x, y / (T)v.y, z / (T)v.z, w / (T)v.w); return vec4<T>(x / (T)v.x, y / (T)v.y, z / (T)v.z, w / (T)v.w);
} }
// Generic Operations // Generic Operations
vec4 operator-() const { return vec4(-x, -y, -z, -w); } vec4 operator-() const { return vec4(-x, -y, -z, -w); }
template <typename T1> bool operator==(const vec4<T1> &v) const { template <typename T1>
bool operator==(const vec4<T1>& v) const {
return x == (T)v.x && y == (T)v.y && z == (T)v.z && w == (T)v.w; return x == (T)v.x && y == (T)v.y && z == (T)v.z && w == (T)v.w;
} }
template <typename T1> bool operator!=(const vec4<T1> &v) const { template <typename T1>
bool operator!=(const vec4<T1>& v) const {
return !(*this == v); return !(*this == v);
} }
@@ -190,7 +212,8 @@ public:
double Len() const { return std::sqrt(SqLen()); } double Len() const { return std::sqrt(SqLen()); }
double SqLen() const { return x * x + y * y + z * z + w * w; } double SqLen() const { return x * x + y * y + z * z + w * w; }
template <typename T1> double Distance(const vec4<T1> &v) const { template <typename T1>
double Distance(const vec4<T1>& v) const {
return (*this - v).Len(); return (*this - v).Len();
} }
@@ -202,7 +225,8 @@ public:
return *this / (T)l; return *this / (T)l;
} }
template <typename T1> T Dot(const vec4<T1> &v) const { template <typename T1>
T Dot(const vec4<T1>& v) const {
return x * (T)v.x + y * (T)v.y + z * (T)v.z + w * (T)v.w; return x * (T)v.x + y * (T)v.y + z * (T)v.z + w * (T)v.w;
} }
@@ -241,4 +265,4 @@ public:
using fvec4 = vec4<float>; using fvec4 = vec4<float>;
using ivec4 = vec4<int>; using ivec4 = vec4<int>;
using dvec4 = vec4<double>; using dvec4 = vec4<double>;
} // namespace amy } // namespace Amy
+37 -37
View File
@@ -2,60 +2,60 @@
#include <amethyst/types.hpp> #include <amethyst/types.hpp>
namespace amy { namespace Amy {
class rect { class Rect {
public: public:
rect() : m_top(0), m_bot(0) {} Rect() : pTop(0), pBot(0) {}
~rect() = default; ~Rect() = default;
rect(const fvec4& t, const fvec4& b) : m_top(t), m_bot(b) {} Rect(const fvec4& t, const fvec4& b) : pTop(t), pBot(b) {}
rect(const fvec2& tl, const fvec2& tr, const fvec2& bl, const fvec2& br) Rect(const fvec2& tl, const fvec2& tr, const fvec2& bl, const fvec2& br)
: m_top(tl, tr), m_bot(bl, br) {} : pTop(tl, tr), pBot(bl, br) {}
rect(const fvec4& duv) Rect(const fvec4& duv)
: m_top(duv.x, duv.y, duv.z, duv.y), m_bot(duv.x, duv.w, duv.z, duv.w) {} : pTop(duv.x, duv.y, duv.z, duv.y), pBot(duv.x, duv.w, duv.z, duv.w) {}
fvec2 topLeft() const { return fvec2(m_top.x, m_top.y); } fvec2 TopLeft() const { return fvec2(pTop.x, pTop.y); }
fvec2 topRight() const { return fvec2(m_top.z, m_top.w); } fvec2 TopRight() const { return fvec2(pTop.z, pTop.w); }
fvec2 botLeft() const { return fvec2(m_bot.x, m_bot.y); } fvec2 BotLeft() const { return fvec2(pBot.x, pBot.y); }
fvec2 botRight() const { return fvec2(m_bot.z, m_bot.w); } fvec2 BotRight() const { return fvec2(pBot.z, pBot.w); }
fvec4 top() const { return m_top; } fvec4 Top() const { return pTop; }
fvec4& top() { return m_top; } fvec4& Top() { return pTop; }
fvec4 bot() const { return m_bot; } fvec4 Bot() const { return pBot; }
fvec4& bot() { return m_bot; } fvec4& Bot() { return pBot; }
rect& topLeft(const fvec2& v) { Rect& TopLeft(const fvec2& v) {
m_top.x = v.x; pTop.x = v.x;
m_top.y = v.y; pTop.y = v.y;
return *this; return *this;
} }
rect& topRight(const fvec2& v) { Rect& TopRight(const fvec2& v) {
m_top.z = v.x; pTop.z = v.x;
m_top.w = v.y; pTop.w = v.y;
return *this; return *this;
} }
rect& botLeft(const fvec2& v) { Rect& BotLeft(const fvec2& v) {
m_bot.x = v.x; pBot.x = v.x;
m_bot.y = v.y; pBot.y = v.y;
return *this; return *this;
} }
rect& botRight(const fvec2& v) { Rect& BotRight(const fvec2& v) {
m_bot.z = v.x; pBot.z = v.x;
m_bot.w = v.y; pBot.w = v.y;
return *this; return *this;
} }
void swapVec2XY() { void SwapVec2XY() {
m_top.SwapXY(); pTop.SwapXY();
m_top.SwapZW(); pTop.SwapZW();
m_bot.SwapXY(); pBot.SwapXY();
m_bot.SwapZW(); pBot.SwapZW();
} }
private: private:
fvec4 m_top; fvec4 pTop;
fvec4 m_bot; fvec4 pBot;
}; };
} // namespace amy } // namespace Amy
+2 -2
View File
@@ -1,9 +1,9 @@
#pragma once #pragma once
namespace amy { namespace Amy {
class Renderer { class Renderer {
public: public:
Renderer(); Renderer();
~Renderer(); ~Renderer();
}; };
} // namespace amys } // namespace Amy
+37 -23
View File
@@ -7,33 +7,47 @@
#include <amethyst/rect.hpp> #include <amethyst/rect.hpp>
#include <amethyst/types.hpp> #include <amethyst/types.hpp>
namespace amy { namespace Amy {
class texture : public asset { class Texture : public Asset {
public: public:
texture() = default; Texture() = default;
texture(cstr& path); Texture(ksr path);
~texture(); Texture(C3D_Tex* tex, const ivec2& size, const Rect& uv) {
void load(cstr& path); Load(tex, size, uv);
void load(const std::vector<uc>& pixels, int w, int h, int bpp = 4, }
image::format fmt = image::RGBA); ~Texture();
void unload(); AMY_SHARED(Texture);
int w() const { return m_size.x; } void Load(ksr path);
int& w() { return m_size.x; } void Load(kvr<uc> pixels, int w, int h, int bpp = 4,
int h() const { return m_size.y; } Image::Format fmt = Image::RGBA);
int& h() { return m_size.y; } void Load(C3D_Tex* tex, const ivec2& size, const Rect& uv) {
ivec2 size() const { return m_size; } Unload();
ivec2& size() { return m_size; } pTex = tex;
rect& uv() { return m_uv; } pSize = size;
pUv = uv;
// Dont set as loaded as only the root tex can be loaded
}
void Unload();
void Unloadable(bool v) { pLoaded = v; }
bool Unloadable() { return pLoaded; }
C3D_Tex* ptr() { return m_loaded ? &m_tex : nullptr; } int W() const { return pSize.x; }
int& W() { return pSize.x; }
int H() const { return pSize.y; }
int& H() { return pSize.y; }
ivec2 Size() const { return pSize; }
ivec2& Size() { return pSize; }
Rect& Uv() { return pUv; }
void bind(int reg = 0); C3D_Tex* Ptr() { return pTex; }
void Bind(int reg = 0);
private: private:
C3D_Tex m_tex; C3D_Tex* pTex = nullptr;
ivec2 m_size; ivec2 pSize;
rect m_uv; Rect pUv = fvec4(0, 1, 1, 0);
bool m_loaded = false; bool pLoaded = false;
}; };
} // namespace amy } // namespace Amy
+32 -4
View File
@@ -2,7 +2,9 @@
#include <algorithm> #include <algorithm>
#include <amethyst/maths/vec.hpp> #include <amethyst/maths/vec.hpp>
#include <chrono>
#include <cinttypes> #include <cinttypes>
#include <format>
#include <functional> #include <functional>
#include <map> #include <map>
#include <memory> #include <memory>
@@ -12,18 +14,44 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace amy { #define AMY_SHARED(x) \
using Ref = std::shared_ptr<x>; \
template <typename... Args> \
static Ref New(Args&&... args) { \
return std::make_shared<x>(std::forward<Args>(args)...); \
}
#define AMY_UNIQUE(x) \
using Ref = std::unique_ptr<x>; \
template <typename... Args> \
static Ref New(Args&&... args) { \
return std::make_unique<x>(std::forward<Args>(args)...); \
}
namespace Amy {
using uc = unsigned char; using uc = unsigned char;
using us = unsigned short; using us = unsigned short;
using ui = unsigned int; using ui = unsigned int;
using ull = unsigned long long; using ull = unsigned long long;
// string
using str = std::string; using str = std::string;
using cstr = const std::string; // const string
using kstr = const std::string;
// const string reference
using ksr = const std::string&; using ksr = const std::string&;
// vector
template <typename T> template <typename T>
using vec = std::vector<T>; using vec = std::vector<T>;
// const vector reference
template <typename T> template <typename T>
using cvec = const std::vector<T>; using kvr = const std::vector<T>&;
// const vector
template <typename T>
using kvec = const std::vector<T>;
// unique pointer
template <typename T> template <typename T>
using up = std::unique_ptr<T>; using up = std::unique_ptr<T>;
} // namespace amy // shared pointer
template <typename T>
using sp = std::shared_ptr<T>;
} // namespace Amy
+61 -14
View File
@@ -2,17 +2,64 @@
#include <amethyst/types.hpp> #include <amethyst/types.hpp>
namespace amy { namespace Amy {
namespace utils { class Error : public std::runtime_error {
ui fastHash(cstr& s); public:
vec<uc> loadFile2Mem(cstr& path); Error(ksr str) : std::runtime_error("[amy] " + str) {}
ui hashMemory(cvec<uc>& data); };
ui nextPow2(ui v); namespace Utils {
bool isSingleBitNum(ui v); constexpr int HexChar2Int(char c) {
namespace image { /** Imagine man hat ne lookup table dafür verwendet :/ */
void reverseBuf(vec<uc>& buf, int w, int h, int c); if (c >= '0' && c <= '9') return c - '0';
void removeAlphaChannel(vec<uc>& buf, int w, int h); if (c >= 'a' && c <= 'f') return 10 + (c - 'a');
void addAlphaChannel(vec<uc>& buf, int w, int h); if (c >= 'A' && c <= 'F') return 10 + (c - 'A');
} // namespace image return -1; // Error
} // namespace utils }
} // namespace amy vec<uc> LoadFile2Mem(ksr path);
str FormatBytes(ull bytes);
ui HashMemory(kvr<uc> data);
ui NextPow2(ui v);
bool IsSingleBitNum(ui v);
ull GetTimeNano();
ull GetTimeMicro();
ull GetTimeMilli();
void String2U16(us* res, ksr src, size_t max);
std::string U16toU8(us* in, size_t max);
/**
* Generate a Formatted String by an Nanoseconds Input
* @param nanos Nanoseconds Input
* @return Result String
*/
kstr FormatNanos(ull nanos);
/**
* Generate a Formatted String by an Milliseconds Input
* @param millis Milliseconds Input
* @return Result String
*/
kstr FormatMillis(ull millis);
/**
* Create a formatted String by an input bytes value
* @param bytes value in bytes
* @result Formatted String for example `2.5MB`
*/
/**
* FNV Hash functiom (32 Bit)
* https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
* Able to run at compile time btw
*/
constexpr ui FNV32(std::string_view str) {
ui ret = 0x811C9DC5;
for (char it : str) {
ret ^= static_cast<ui>(it);
ret *= 16777619;
}
return ret;
}
namespace Image {
void ReverseBuf(vec<uc>& buf, int w, int h, int c);
void RemoveAlphaChannel(vec<uc>& buf, int w, int h);
void AddAlphaChannel(vec<uc>& buf, int w, int h);
} // namespace Image
} // namespace Utils
} // namespace Amy
+124 -4
View File
@@ -1,6 +1,10 @@
#include <amethyst.hpp> #include <amethyst.hpp>
#include <exception> #include <exception>
#include <iostream> #include <iostream>
#include <map>
#include <vector>
#define TRACK_NEW_DELETE
#ifdef AMY_3DS #ifdef AMY_3DS
#include <3ds.h> #include <3ds.h>
@@ -11,7 +15,7 @@ void NpiD7CxxExceptionHandler() {
std::cout << "[C++ Error Handler]" << std::endl; std::cout << "[C++ Error Handler]" << std::endl;
try { try {
std::rethrow_exception(std::current_exception()); std::rethrow_exception(std::current_exception());
} catch (const std::exception& e) { } catch (const std::exception &e) {
std::cout << "\n\n" << e.what() << std::endl; std::cout << "\n\n" << e.what() << std::endl;
} }
aptSetHomeAllowed(false); aptSetHomeAllowed(false);
@@ -26,10 +30,126 @@ void NpiD7CxxExceptionHandler() {
} }
#endif #endif
namespace amy { static Amy::Memory::MemMetrics metrics;
void registerCxxExceptionHandler() {
#ifdef TRACK_NEW_DELETE
constexpr uint32_t MemDBGMagic = 0x774733d7;
struct MemDBGHeader {
MemDBGHeader(size_t s) {
Magic = MemDBGMagic;
Size = s;
}
uint32_t Magic = MemDBGMagic;
size_t Size = 0;
};
void *MemDBGAllocate(size_t size) {
void *ptr = malloc(size + sizeof(MemDBGHeader));
if (!ptr) return reinterpret_cast<void *>(ptr);
MemDBGHeader *hdr = reinterpret_cast<MemDBGHeader *>(ptr);
hdr->Magic = MemDBGMagic;
hdr->Size = size;
metrics.Allocated.fetch_add(hdr->Size, std::memory_order_relaxed);
metrics.Current.fetch_add(hdr->Size, std::memory_order_relaxed);
metrics.Allocations.fetch_add(1, std::memory_order_relaxed);
return reinterpret_cast<void *>(hdr + 1);
}
void MemDBGFree(void *ptr) {
if (!ptr) return;
MemDBGHeader *hdr = reinterpret_cast<MemDBGHeader *>(ptr) - 1;
if (hdr->Magic == MemDBGMagic) {
hdr->Magic = 0;
size_t szs = hdr->Size;
metrics.Deleted.fetch_add(szs, std::memory_order_relaxed);
metrics.Current.fetch_sub(szs, std::memory_order_relaxed);
metrics.Allocations.fetch_sub(1, std::memory_order_relaxed);
free(reinterpret_cast<void *>(hdr));
} else {
std::abort();
}
}
void *operator new(size_t size) { return MemDBGAllocate(size); }
void *operator new[](size_t size) { return MemDBGAllocate(size); }
void operator delete(void *ptr) noexcept { MemDBGFree(ptr); }
void operator delete(void *ptr, size_t) noexcept { MemDBGFree(ptr); }
void operator delete[](void *ptr) noexcept { MemDBGFree(ptr); }
void operator delete[](void *ptr, size_t) noexcept { MemDBGFree(ptr); }
void *operator new(size_t size, const std::nothrow_t &) noexcept {
return MemDBGAllocate(size);
}
void *operator new[](size_t size, const std::nothrow_t &) noexcept {
return MemDBGAllocate(size);
}
void operator delete(void *ptr, const std::nothrow_t &) noexcept {
MemDBGFree(ptr);
}
void operator delete[](void *ptr, const std::nothrow_t &) noexcept {
MemDBGFree(ptr);
}
void *operator new(size_t size, std::align_val_t) {
return MemDBGAllocate(size);
}
void *operator new[](size_t size, std::align_val_t) {
return MemDBGAllocate(size);
}
void operator delete(void *ptr, std::align_val_t) noexcept { MemDBGFree(ptr); }
void operator delete[](void *ptr, std::align_val_t) noexcept {
MemDBGFree(ptr);
}
void *operator new(size_t size, std::align_val_t,
const std::nothrow_t &) noexcept {
return MemDBGAllocate(size);
}
void *operator new[](size_t size, std::align_val_t,
const std::nothrow_t &) noexcept {
return MemDBGAllocate(size);
}
void operator delete(void *ptr, size_t, std::align_val_t) noexcept {
MemDBGFree(ptr);
}
void operator delete[](void *ptr, size_t, std::align_val_t) noexcept {
MemDBGFree(ptr);
}
void operator delete(void *ptr, size_t, std::align_val_t,
const std::nothrow_t &) noexcept {
MemDBGFree(ptr);
}
void operator delete[](void *ptr, size_t, std::align_val_t,
const std::nothrow_t &) noexcept {
MemDBGFree(ptr);
}
#endif
namespace Amy {
void RegisterCxxExceptionHandler() {
#ifdef AMY_3DS #ifdef AMY_3DS
std::set_terminate(NpiD7CxxExceptionHandler); std::set_terminate(NpiD7CxxExceptionHandler);
#endif #endif
} }
} // namespace amy void *Malloc(size_t size) {
#ifdef TRACK_NEW_DELETE
return MemDBGAllocate(size);
#else
return malloc(size);
#endif
}
void Free(void *ptr) {
#ifdef TRACK_NEW_DELETE
MemDBGFree(ptr);
#else
free(ptr);
#endif
}
ull Memory::GetTotalAllocated() { return metrics.Allocated; }
ull Memory::GetTotalFreed() { return metrics.Deleted; }
ull Memory::GetCurrent() { return metrics.CurrentlyAllocated(); }
ull Memory::GetAllocationCount() { return metrics.Allocations; }
} // namespace Amy
+13 -9
View File
@@ -1,15 +1,19 @@
#include <3ds.h> #include <3ds.h>
#include <amethyst/app.hpp> #include <amethyst/app.hpp>
#include <amethyst/ctru.hpp> #include <amethyst/utils.hpp>
namespace amy { namespace Amy {
void app::run() { void App::Run() {
while (aptMainLoop()) { pLast = Utils::GetTimeNano();
ull c = ctru::getTime(); while (aptMainLoop() && !pExit) {
m_delta = static_cast<double>(c) - static_cast<float>(m_last); ull c = Utils::GetTimeNano();
m_last = c; pDelta = static_cast<double>(static_cast<double>(c) -
main(); static_cast<double>(pLast)) *
0.000001;
pTime += pDelta * 0.001;
pLast = c;
Main();
} }
} }
} // namespace amy } // namespace Amy
+26
View File
@@ -0,0 +1,26 @@
#include <amethyst/assets.hpp>
#include <amethyst/c3d.hpp>
#include <amethyst/iron.hpp>
#include <amethyst/texture.hpp>
namespace Amy {
void AssetMgr::AutoLoad(const ID& id, ksr path) {
if (path.ends_with(".png") || path.ends_with(".jpg") ||
path.ends_with(".bmp")) {
auto tex = Texture::New();
tex->Load(path);
Add(id, tex);
} else if (path.ends_with(".shbin")) {
auto shader = C3D::Shader::New();
shader->Load(path);
Add(id, shader);
} else if (path.ends_with(".ttf")) {
auto font = Iron::Font::New();
font->LoadTTF(path);
Add(id, font);
} else {
throw std::runtime_error("[amy]: assets: " + id.GetName() + " (" + path +
") is unsupported for AssetMgr::AutoLoad!");
}
}
} // namespace Amy
+65 -58
View File
@@ -4,131 +4,138 @@
#include <amethyst/utils.hpp> #include <amethyst/utils.hpp>
#include <pica.hpp> #include <pica.hpp>
namespace amy { namespace Amy {
const auto DISPLAY_TRANSFER_FLAGS = const auto DISPLAY_TRANSFER_FLAGS =
GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) |
GX_TRANSFER_RAW_COPY(0) | GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_RAW_COPY(0) | GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) |
GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) |
GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO); GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO);
C3D_TexEnv* c3d::frag::m_env = nullptr; C3D_TexEnv* C3D::Frag::pEnv = nullptr;
int c3d::m_drawcalls = 0; int C3D::pDrawcalls = 0;
int c3d::m__dc__ = 0; int C3D::p__dc__ = 0;
void c3d::init() { C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); } void C3D::Init() { C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); }
void c3d::deinit() { C3D_Fini(); } void C3D::Deinit() { C3D_Fini(); }
void c3d::startFrame(bool sync) { void C3D::StartFrame(bool sync) {
C3D_FrameBegin(sync ? C3D_FRAME_SYNCDRAW : C3D_FRAME_NONBLOCK); C3D_FrameBegin(sync ? C3D_FRAME_SYNCDRAW : C3D_FRAME_NONBLOCK);
m__dc__ = 0; p__dc__ = 0;
} }
void c3d::endFrame() { void C3D::EndFrame() {
C3D_FrameEnd(0); C3D_FrameEnd(0);
m_drawcalls = m__dc__; pDrawcalls = p__dc__;
} }
c3d::screen* c3d::createScreen(gfxScreen_t screen, gfx3dSide_t side) { C3D::Screen* C3D::CreateScreen(gfxScreen_t screen, gfx3dSide_t side) {
auto t = C3D_RenderTargetCreate(240, screen == GFX_TOP ? 400 : 320, auto t = C3D_RenderTargetCreate(240, screen == GFX_TOP ? 400 : 320,
GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
C3D_RenderTargetSetOutput(t, screen, side, DISPLAY_TRANSFER_FLAGS); C3D_RenderTargetSetOutput(t, screen, side, DISPLAY_TRANSFER_FLAGS);
return new c3d::screen(t); return new C3D::Screen(t);
} }
void c3d::deleteScreen(c3d::screen* screen) { delete screen; } void C3D::DeleteScreen(C3D::Screen* screen) { delete screen; }
c3d::shader::shader(const std::string& path) { load(path); } C3D::Shader::Shader(const std::string& path) { Load(path); }
c3d::shader::~shader() {} C3D::Shader::~Shader() {
if (pCode) {
shaderProgramFree(&pProgram);
DVLB_Free(pCode);
pCode = nullptr;
}
}
void c3d::shader::load(const std::string& path) { void C3D::Shader::Load(const std::string& path) {
auto code = utils::loadFile2Mem(path); auto code = Utils::LoadFile2Mem(path);
if (!code.size()) { if (!code.size()) {
throw std::runtime_error( throw std::runtime_error(
std::format("[amy] unsable to load shader ({})", path)); std::format("[amy] unable to load shader ({})", path));
} }
load(code); Load(code);
} }
void c3d::shader::load(const std::vector<uc>& data) { void C3D::Shader::Load(const std::vector<uc>& data) {
m_code = DVLB_ParseFile((u32*)&data[0], data.size()); if (!data.size()) {
shaderProgramInit(&m_program); throw std::runtime_error("[amy] unable to load shader from data!");
shaderProgramSetVsh(&m_program, &m_code->DVLE[0]); }
C3D_BindProgram(&m_program); pRawData = data;
AttrInfo_Init(&m_info); pCode = DVLB_ParseFile((u32*)&pRawData[0], pRawData.size());
shaderProgramInit(&pProgram);
shaderProgramSetVsh(&pProgram, &pCode->DVLE[0]);
AttrInfo_Init(&pInfo);
} }
void c3d::shader::compile(const std::string& code) { void C3D::Shader::Compile(const std::string& code) {
auto ret = Pica::AssembleCode(code.c_str()); Load(Pica::AssembleCode(code.c_str()));
load(ret);
} }
void c3d::shader::use() { void C3D::Shader::Use() {
C3D_BindProgram(&m_program);
// for some reason i need both ???
// code works perfectly without C3D_BindProgram // code works perfectly without C3D_BindProgram
// but nor withour shaderProgramUse ... // but nor without shaderProgramUse ...
shaderProgramUse(&m_program); shaderProgramUse(&pProgram);
C3D_SetAttrInfo(&m_info); C3D_BindProgram(&pProgram);
C3D_SetAttrInfo(&pInfo);
} }
void c3d::shader::setMat4(int loc, C3D_Mtx* m) { void C3D::Shader::SetMat4(int loc, C3D_Mtx* m) {
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, loc, m); C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, loc, m);
} }
void c3d::shader::setMat4(int loc, const mat4& m) { void C3D::Shader::SetMat4(int loc, const mat4& m) {
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, loc, (const C3D_Mtx*)&m); C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, loc, (const C3D_Mtx*)&m);
} }
int c3d::shader::loc(const std::string& name) { int C3D::Shader::loc(const std::string& name) {
return shaderInstanceGetUniformLocation(m_program.vertexShader, name.c_str()); return shaderInstanceGetUniformLocation(pProgram.vertexShader, name.c_str());
} }
void c3d::shader::input(int reg, GPU_FORMATS f, int num) { void C3D::Shader::Input(int reg, GPU_FORMATS f, int num) {
AttrInfo_AddLoader(&m_info, reg, f, num); AttrInfo_AddLoader(&pInfo, reg, f, num);
} }
void c3d::frag::src(C3D_TexEnvMode mode, GPU_TEVSRC s1, GPU_TEVSRC s2, void C3D::Frag::Src(C3D_TexEnvMode mode, GPU_TEVSRC s1, GPU_TEVSRC s2,
GPU_TEVSRC s3) { GPU_TEVSRC s3) {
C3D_TexEnvSrc(m_env, mode, s1, s2, s3); C3D_TexEnvSrc(pEnv, mode, s1, s2, s3);
} }
void c3d::frag::func(C3D_TexEnvMode mode, GPU_COMBINEFUNC func) { void C3D::Frag::Func(C3D_TexEnvMode mode, GPU_COMBINEFUNC func) {
C3D_TexEnvFunc(m_env, mode, func); C3D_TexEnvFunc(pEnv, mode, func);
} }
void c3d::frag::edit(int id) { void C3D::Frag::Edit(int id) {
m_env = C3D_GetTexEnv(id); pEnv = C3D_GetTexEnv(id);
C3D_TexEnvInit(m_env); C3D_TexEnvInit(pEnv);
} }
void c3d::drawArrays(int start, int count, GPU_Primitive_t prim) { void C3D::DrawArrays(int start, int count, GPU_Primitive_t prim) {
C3D_DrawArrays(prim, start, count); C3D_DrawArrays(prim, start, count);
m__dc__++; p__dc__++;
} }
void c3d::drawElements(int count, const void* idx_ptr, int type, void C3D::DrawElements(int count, const void* idx_ptr, int type,
GPU_Primitive_t prim) { GPU_Primitive_t prim) {
C3D_DrawElements(prim, count, type, idx_ptr); C3D_DrawElements(prim, count, type, idx_ptr);
m__dc__++; p__dc__++;
} }
void c3d::depthTest(bool on, GPU_TESTFUNC func, GPU_WRITEMASK mask) { void C3D::DepthTest(bool on, GPU_TESTFUNC func, GPU_WRITEMASK mask) {
C3D_DepthTest(on, func, mask); C3D_DepthTest(on, func, mask);
} }
void c3d::disableScissor() { C3D_SetScissor(GPU_SCISSOR_DISABLE, 0, 0, 0, 0); } void C3D::DisableScissor() { C3D_SetScissor(GPU_SCISSOR_DISABLE, 0, 0, 0, 0); }
void c3d::enableScissor(const ivec4 rect) { void C3D::EnableScissor(const ivec4 rect) {
C3D_SetScissor(GPU_SCISSOR_NORMAL, rect.x, rect.y, rect.z, rect.w); C3D_SetScissor(GPU_SCISSOR_NORMAL, rect.x, rect.y, rect.z, rect.w);
} }
void c3d::bufCfg(void* ptr, int stride, int shader_attribs, u64 permutation) { void C3D::BufCfg(void* ptr, int stride, int shader_attribs, u64 permutation) {
auto buf = C3D_GetBufInfo(); auto buf = C3D_GetBufInfo();
BufInfo_Init(buf); BufInfo_Init(buf);
BufInfo_Add(buf, ptr, stride, shader_attribs, permutation); BufInfo_Add(buf, ptr, stride, shader_attribs, permutation);
} }
void c3d::bufCfg(void* ptr, int stride, int shader_attribs) { void C3D::BufCfg(void* ptr, int stride, int shader_attribs) {
bufCfg(ptr, stride, shader_attribs, permutation(shader_attribs)); BufCfg(ptr, stride, shader_attribs, pPermutation(shader_attribs));
} }
} // namespace amy } // namespace Amy
+16
View File
@@ -0,0 +1,16 @@
#include <amethyst/color.hpp>
namespace Amy {
std::string Color::Hex(bool rgba) const {
/** Need to int cast (so it is used as num and not char...) */
std::stringstream s;
s << "#";
s << std::hex << std::setw(2) << std::setfill('0') << (int)r;
s << std::hex << std::setw(2) << std::setfill('0') << (int)g;
s << std::hex << std::setw(2) << std::setfill('0') << (int)b;
if (rgba) {
s << std::hex << std::setw(2) << std::setfill('0') << (int)a;
}
return s.str();
}
} // namespace Amy
-17
View File
@@ -1,17 +0,0 @@
#include <3ds.h>
#include <amethyst/ctru.hpp>
namespace amy {
namespace ctru {
void init(unsigned int srvs) {
if (srvs & romfs) {
romfsInit();
}
if (srvs & gfx_def) {
gfxInitDefault();
}
}
ull getTime() { return osGetTime(); }
} // namespace ctru
} // namespace amy
+14
View File
@@ -0,0 +1,14 @@
#include <amethyst/godtrace.hpp>
#include <amethyst/utils.hpp>
Amy::GTrace::TraceMap Amy::GTrace::pTraces;
void Amy::GTrace::Beg(ksr id) {
auto trace = GetTraceRef(id);
trace->SetStart(Amy::Utils::GetTimeNano());
}
void Amy::GTrace::End(ksr id) {
auto trace = GetTraceRef(id);
trace->SetEnd(Amy::Utils::GetTimeNano());
}
+84 -67
View File
@@ -2,67 +2,70 @@
#include <amethyst/utils.hpp> #include <amethyst/utils.hpp>
#include <stdexcept> #include <stdexcept>
// #define STB_IMAGE_IMPLEMENTATION // Only include stb Code if we need it
// Otherwise we just build the header
#ifdef AMY_STB_IMAGE
#define STB_IMAGE_IMPLEMENTATION
#endif
#include <stb_image.h> #include <stb_image.h>
namespace amy { namespace Amy {
void image::load(cstr& path) { void Image::Load(ksr path) {
int c = 0; int c = 0;
uc* buf = stbi_load(path.c_str(), &m_w, &m_h, &c, 4); uc* buf = stbi_load(path.c_str(), &pW, &pH, &c, 4);
if (c == 3) { if (c == 3) {
// Releoading the Image with tree channels requestet // Releoading the Image with tree channels requestet
// Still need to find a better way for this :( // Still need to find a better way for this :(
stbi_image_free(buf); stbi_image_free(buf);
buf = stbi_load(path.c_str(), &m_w, &m_h, &c, 3); buf = stbi_load(path.c_str(), &pW, &pH, &c, 3);
m_buffer.assign(buf, buf + (m_w * m_h * 3)); pBuffer.assign(buf, buf + (pW * pH * 3));
m_fmt = RGB; pFmt = RGB;
stbi_image_free(buf); stbi_image_free(buf);
} else if (c == 4) { } else if (c == 4) {
m_buffer.assign(buf, buf + (m_w * m_h * 4)); pBuffer.assign(buf, buf + (pW * pH * 4));
m_fmt = RGBA; pFmt = RGBA;
stbi_image_free(buf); stbi_image_free(buf);
} else { } else {
throw std::runtime_error(path + " is using an unsupported image format!"); throw std::runtime_error(path + " is using an unsupported image format!");
} }
} }
void image::load(const std::vector<uc>& data) { void Image::Load(const std::vector<uc>& data) {
int c = 0; int c = 0;
uc* buf = stbi_load_from_memory(data.data(), data.size(), &m_w, &m_h, &c, 4); uc* buf = stbi_load_from_memory(data.data(), data.size(), &pW, &pH, &c, 4);
if (c == 3) { if (c == 3) {
// Releoading the Image with tree channels requestet // Releoading the Image with tree channels requestet
// Still need to find a better way for this :( // Still need to find a better way for this :(
stbi_image_free(buf); stbi_image_free(buf);
buf = stbi_load_from_memory(data.data(), data.size(), &m_w, &m_h, &c, 3); buf = stbi_load_from_memory(data.data(), data.size(), &pW, &pH, &c, 3);
m_buffer.assign(buf, buf + (m_w * m_h * 3)); pBuffer.assign(buf, buf + (pW * pH * 3));
m_fmt = RGB; pFmt = RGB;
stbi_image_free(buf); stbi_image_free(buf);
} else if (m_fmt == 4) { } else if (pFmt == 4) {
m_buffer.assign(buf, buf + (m_w * m_h * 4)); pBuffer.assign(buf, buf + (pW * pH * 4));
m_fmt = RGBA; pFmt = RGBA;
stbi_image_free(buf); stbi_image_free(buf);
} else { } else {
throw std::runtime_error("image mem using an unsupported image format!"); throw std::runtime_error("image mem using an unsupported image format!");
} }
} }
void image::copy(const std::vector<uc>& pixels, int w, int h, void Image::Copy(kvr<uc> pixels, int w, int h, const Format& fmt) {
const format& fmt) { int f = GetBppOfFmt(fmt);
int f = getBppOfFmt(fmt);
if (pixels.size() != static_cast<size_t>(w * h * f)) { if (pixels.size() != static_cast<size_t>(w * h * f)) {
throw std::runtime_error("Connot copy image due to size error!"); throw std::runtime_error("Connot copy image due to size error!");
} }
m_fmt = fmt; pFmt = fmt;
m_w = w; pW = w;
m_h = h; pH = h;
m_buffer.clear(); pBuffer.clear();
m_buffer.resize(w * h * f); pBuffer.resize(w * h * f);
for (size_t i = 0; i < m_buffer.size(); i++) { for (size_t i = 0; i < pBuffer.size(); i++) {
m_buffer[i] = pixels[i]; pBuffer[i] = pixels[i];
} }
} }
int image::getBppOfFmt(const image::format& fmt) { int Image::GetBppOfFmt(const Image::Format& fmt) {
switch (fmt) { switch (fmt) {
case RGBA: case RGBA:
case ABGR: case ABGR:
@@ -76,6 +79,9 @@ int image::getBppOfFmt(const image::format& fmt) {
case RGB565: case RGB565:
return 2; return 2;
break; break;
case A8:
return 1;
break;
default: default:
return 0; // Unknown return 0; // Unknown
@@ -83,28 +89,39 @@ int image::getBppOfFmt(const image::format& fmt) {
} }
} }
void image::convert(image& img, const format& dst) { void Image::Convert(Image& img, const Format& dst) {
if (img.m_fmt == dst) { if (img.pFmt == dst) {
return; return;
} else if (img.m_fmt == RGB && dst == BGR) { } else if (img.pFmt == RGBA && dst == A8) {
utils::image::reverseBuf(img.m_buffer, img.m_w, img.m_h, 3); std::vector<uc> cpy = img.pBuffer;
img.m_fmt = BGR; img.pBuffer.resize(img.pW * img.pH);
} else if (img.m_fmt == RGB && dst == RGBA) { for (int y = 0; y < img.pH; y++) {
utils::image::addAlphaChannel(img.m_buffer, img.m_w, img.m_h); for (int x = 0; x < img.pW; x++) {
img.m_fmt = RGBA; int src = (y * img.pW + x) * 4;
} else if (img.m_fmt == RGBA && dst == RGB) { int dst = (y * img.pW + x);
utils::image::removeAlphaChannel(img.m_buffer, img.m_w, img.m_h); img.pBuffer[dst] = cpy[src + 3];
img.m_fmt = RGB; }
} else if (img.m_fmt == RGBA && dst == ABGR) { }
utils::image::reverseBuf(img.m_buffer, img.m_w, img.m_h, 4); img.pFmt = A8;
img.m_fmt = ABGR; } else if (img.pFmt == RGB && dst == BGR) {
} else if (img.m_fmt == RGB && dst == ABGR) { Utils::Image::ReverseBuf(img.pBuffer, img.pW, img.pH, 3);
convert(img, RGBA); img.pFmt = BGR;
convert(img, ABGR); } else if (img.pFmt == RGB && dst == RGBA) {
} else if (img.m_fmt == RGBA && dst == RGB565) { Utils::Image::AddAlphaChannel(img.pBuffer, img.pW, img.pH);
convert(img, RGB); img.pFmt = RGBA;
convert(img, RGB565); } else if (img.pFmt == RGBA && dst == RGB) {
} else if (img.m_fmt == RGB && dst == RGB565) { Utils::Image::RemoveAlphaChannel(img.pBuffer, img.pW, img.pH);
img.pFmt = RGB;
} else if (img.pFmt == RGBA && dst == ABGR) {
Utils::Image::ReverseBuf(img.pBuffer, img.pW, img.pH, 4);
img.pFmt = ABGR;
} else if (img.pFmt == RGB && dst == ABGR) {
Convert(img, RGBA);
Convert(img, ABGR);
} else if (img.pFmt == RGBA && dst == RGB565) {
Convert(img, RGB);
Convert(img, RGB565);
} else if (img.pFmt == RGB && dst == RGB565) {
// Inlined make pixel 565 func // Inlined make pixel 565 func
auto f = [](uc r, uc g, uc b) -> unsigned short { auto f = [](uc r, uc g, uc b) -> unsigned short {
unsigned short _r = (r >> 3); unsigned short _r = (r >> 3);
@@ -112,35 +129,35 @@ void image::convert(image& img, const format& dst) {
unsigned short _b = (b >> 3); unsigned short _b = (b >> 3);
return (_r << 11) | (_g << 5) | _b; return (_r << 11) | (_g << 5) | _b;
}; };
std::vector<uc> cpy = img.m_buffer; std::vector<uc> cpy = img.pBuffer;
img.m_buffer.resize(img.m_w * img.m_h * 2); img.pBuffer.resize(img.pW * img.pH * 2);
for (int y = 0; y < img.m_w; y++) { for (int y = 0; y < img.pW; y++) {
for (int x = 0; x < img.m_h; x++) { for (int x = 0; x < img.pH; x++) {
int src = (y * img.m_w + x) * 3; int src = (y * img.pW + x) * 3;
int dst = (y * img.m_w + x) * 2; int dst = (y * img.pW + x) * 2;
unsigned short new_px = f(cpy[src + 0], cpy[src + 1], cpy[src + 2]); unsigned short new_px = f(cpy[src + 0], cpy[src + 1], cpy[src + 2]);
img.m_buffer[dst + 0] = new_px >> 8; img.pBuffer[dst + 0] = new_px >> 8;
img.m_buffer[dst + 1] = new_px & 0xff; img.pBuffer[dst + 1] = new_px & 0xff;
} }
} }
img.m_fmt = RGB565; img.pFmt = RGB565;
} }
} }
void image::retile(image& img, std::function<ui(int x, int y, int w)> src, void Image::Retile(Image& img, std::function<ui(int x, int y, int w)> src,
std::function<ui(int x, int y, int w)> dst) { std::function<ui(int x, int y, int w)> dst) {
std::vector<uc> cpy = img.m_buffer; std::vector<uc> cpy = img.pBuffer;
/** could use fmt here but for 565 that woulnt work as it is not supported by /** could use fmt here but for 565 that woulnt work as it is not supported by
* file loading where fmt is used */ * file loading where fmt is used */
int bpp = img.bpp(); int bpp = img.Bpp();
for (int y = 0; y < img.m_h; y++) { for (int y = 0; y < img.pH; y++) {
for (int x = 0; x < img.m_w; x++) { for (int x = 0; x < img.pW; x++) {
int src_idx = src(x, y, img.m_w); int src_idx = src(x, y, img.pW);
int dst_idx = dst(x, y, img.m_w); int dst_idx = dst(x, y, img.pW);
for (int i = 0; i < bpp; i++) { for (int i = 0; i < bpp; i++) {
img.m_buffer[dst_idx + i] = cpy[src_idx + i]; img.pBuffer[dst_idx + i] = cpy[src_idx + i];
} }
} }
} }
} }
} // namespace amy } // namespace Amy
View File
File diff suppressed because it is too large Load Diff
+125 -108
View File
@@ -1,7 +1,7 @@
#include <amethyst/iron.hpp> #include <amethyst/iron.hpp>
/** Setup for everything (oder so) */ /** Setup for everything (oder so) */
enum LiPathRectFlags_ : amy::ui { enum LiPathRectFlags_ : Amy::ui {
LiPathRectFlags_None = 0, LiPathRectFlags_None = 0,
LiPathRectFlags_KeepTopLeft = (1 << 0), LiPathRectFlags_KeepTopLeft = (1 << 0),
LiPathRectFlags_KeepTopRight = (1 << 1), LiPathRectFlags_KeepTopRight = (1 << 1),
@@ -13,69 +13,75 @@ enum LiPathRectFlags_ : amy::ui {
LiPathRectFlags_KeepRight = (1 << 1) | (1 << 2), LiPathRectFlags_KeepRight = (1 << 1) | (1 << 2),
}; };
namespace amy { namespace Amy {
constexpr auto __pi = std::numbers::pi; constexpr auto __pi = std::numbers::pi;
void iron::drawlist::merge(iron::drawlist* list) { void Iron::Drawlist::Merge(Iron::Drawlist* list) {
for (size_t i = 0; i < list->m_data.size(); i++) { for (size_t i = 0; i < list->pData.size(); i++) {
m_data.push_back(std::move(list->m_data[i])); pData.push_back(std::move(list->pData[i]));
} }
list->clear(); list->Clear();
} }
void iron::drawlist::clear() { m_data.clear(); } void Iron::Drawlist::Clear() {
pData.clear();
iron::command::ref iron::drawlist::newCommand() { pPath.clear();
auto ret = std::make_unique<command>(); DrawSolid();
ret->layer = m_layer; while (!ClipRects.empty()) {
ret->index = m_data.size(); ClipRects.pop();
ret->tex = m_tex; }
return ret; pLayer = 0;
} }
void iron::drawlist::clipCmd(command* ptr) { Iron::Command::Ref Iron::Drawlist::NewCommand() {
if (!clipRects.empty()) { auto ret = Command::New();
ptr->scissorOn = true; ret->Layer = pLayer;
ptr->scissorRect = ivec4(clipRects.top()); ret->Index = pData.size();
ret->Tex = pTex;
return std::move(ret);
}
void Iron::Drawlist::clipCmd(Command* ptr) {
if (!ClipRects.empty()) {
ptr->ScissorOn = true;
ptr->ScissorRect = ivec4(ClipRects.top());
} }
} }
void iron::drawlist::push(command::ref cmd) { void Iron::Drawlist::Push(Command::Ref cmd) { pData.push_back(std::move(cmd)); }
m_data.push_back(std::move(cmd));
}
void iron::drawlist::drawSolid() { m_tex = iron::whiteTex(); } void Iron::Drawlist::DrawSolid() { pTex = Iron::WhiteTex(); }
void iron::drawlist::pathArcToN(const fvec2& c, float radius, float a_min, void Iron::Drawlist::PathArcToN(const fvec2& c, float radius, float a_min,
float a_max, int segments) { float a_max, int segments) {
// pathAdd(c) // pathAdd(c)
pathReserve(segments + 1); PathReserve(segments + 1);
for (int i = 0; i < segments; i++) { for (int i = 0; i < segments; i++) {
float a = a_min + ((float)i / (float)segments) * (a_max - a_min); float a = a_min + ((float)i / (float)segments) * (a_max - a_min);
pathAdd(fvec2(c.x + std::cos(a) * radius, c.y + std::sin(a) * radius)); PathAdd(fvec2(c.x + std::cos(a) * radius, c.y + std::sin(a) * radius));
} }
} }
void iron::drawlist::pathFastArcToN(const fvec2& c, float r, float amin, void Iron::Drawlist::PathFastArcToN(const fvec2& c, float r, float amin,
float amax, int s) { float amax, int s) {
/** /**
* Funcion with less division overhead * Funcion with less division overhead
* Usefull for stuff where a lot of calculations are required * Usefull for stuff where a lot of calculations are required
*/ */
float d = (amax - amin) / s; float d = (amax - amin) / s;
pathReserve(s + 1); PathReserve(s + 1);
for (int i = 0; i <= s; i++) { for (int i = 0; i <= s; i++) {
float a = amin + i * d; float a = amin + i * d;
pathAdd(fvec2(c.x + std::cos(a) * r, c.y + std::sin(a) * r)); PathAdd(fvec2(c.x + std::cos(a) * r, c.y + std::sin(a) * r));
} }
} }
void iron::drawlist::pathRect(const fvec2& a, const fvec2& b, float rounding) { void Iron::Drawlist::PathRect(const fvec2& a, const fvec2& b, float rounding) {
if (rounding == 0.f) { if (rounding == 0.f) {
pathAdd(a); PathAdd(a);
pathAdd(fvec2(b.x, a.y)); PathAdd(fvec2(b.x, a.y));
pathAdd(b); PathAdd(b);
pathAdd(fvec2(a.x, b.y)); PathAdd(fvec2(a.x, b.y));
} else { } else {
float r = std::min({rounding, (b.x - a.x) * 0.5f, (b.y - a.y) * 0.5f}); float r = std::min({rounding, (b.x - a.x) * 0.5f, (b.y - a.y) * 0.5f});
/** Calculate Optimal segment count automatically */ /** Calculate Optimal segment count automatically */
@@ -87,28 +93,28 @@ void iron::drawlist::pathRect(const fvec2& a, const fvec2& b, float rounding) {
* The Commands need to be setup clockwise * The Commands need to be setup clockwise
*/ */
/** Top Left */ /** Top Left */
pathAdd(fvec2(a.x + r, a.y)); PathAdd(fvec2(a.x + r, a.y));
pathFastArcToN(fvec2(b.x - r, a.y + r), r, -__pi / 2.0f, 0.0f, segments); PathFastArcToN(fvec2(b.x - r, a.y + r), r, -__pi / 2.0f, 0.0f, segments);
/** Top Right */ /** Top Right */
pathAdd(fvec2(b.x, b.y - r)); PathAdd(fvec2(b.x, b.y - r));
pathFastArcToN(fvec2(b.x - r, b.y - r), r, 0.0f, __pi / 2.0f, segments); PathFastArcToN(fvec2(b.x - r, b.y - r), r, 0.0f, __pi / 2.0f, segments);
/** Bottom Right */ /** Bottom Right */
pathAdd(fvec2(a.x + r, b.y)); PathAdd(fvec2(a.x + r, b.y));
pathFastArcToN(fvec2(a.x + r, b.y - r), r, __pi / 2.0f, __pi, segments); PathFastArcToN(fvec2(a.x + r, b.y - r), r, __pi / 2.0f, __pi, segments);
/** Bottom Left */ /** Bottom Left */
pathAdd(fvec2(a.x, a.y + r)); PathAdd(fvec2(a.x, a.y + r));
pathFastArcToN(fvec2(a.x + r, a.y + r), r, __pi, 3.0f * __pi / 2.0f, PathFastArcToN(fvec2(a.x + r, a.y + r), r, __pi, 3.0f * __pi / 2.0f,
segments); segments);
} }
} }
void iron::drawlist::pathRectEx(const fvec2& a, const fvec2& b, float rounding, void Iron::Drawlist::PathRectEx(const fvec2& a, const fvec2& b, float rounding,
ui flags) { ui flags) {
if (rounding == 0.f) { if (rounding == 0.f) {
pathAdd(a); PathAdd(a);
pathAdd(fvec2(b.x, a.y)); PathAdd(fvec2(b.x, a.y));
pathAdd(b); PathAdd(b);
pathAdd(fvec2(a.x, b.y)); PathAdd(fvec2(a.x, b.y));
} else { } else {
float r = std::min({rounding, (b.x - a.x) * 0.5f, (b.y - a.y) * 0.5f}); float r = std::min({rounding, (b.x - a.x) * 0.5f, (b.y - a.y) * 0.5f});
/** Calculate Optimal segment count automatically */ /** Calculate Optimal segment count automatically */
@@ -121,95 +127,106 @@ void iron::drawlist::pathRectEx(const fvec2& a, const fvec2& b, float rounding,
*/ */
/** Top Left */ /** Top Left */
if (flags & LiPathRectFlags_KeepTopLeft) { if (flags & LiPathRectFlags_KeepTopLeft) {
pathAdd(a); PathAdd(a);
} else { } else {
pathAdd(fvec2(a.x + r, a.y)); PathAdd(fvec2(a.x + r, a.y));
pathFastArcToN(fvec2(b.x - r, a.y + r), r, -__pi / 2.0f, 0.0f, segments); PathFastArcToN(fvec2(b.x - r, a.y + r), r, -__pi / 2.0f, 0.0f, segments);
} }
/** Top Right */ /** Top Right */
if (flags & LiPathRectFlags_KeepTopRight) { if (flags & LiPathRectFlags_KeepTopRight) {
pathAdd(fvec2(b.x, a.y)); PathAdd(fvec2(b.x, a.y));
} else { } else {
pathAdd(fvec2(b.x, b.y - r)); PathAdd(fvec2(b.x, b.y - r));
pathFastArcToN(fvec2(b.x - r, b.y - r), r, 0.0f, __pi / 2.0f, segments); PathFastArcToN(fvec2(b.x - r, b.y - r), r, 0.0f, __pi / 2.0f, segments);
} }
/** Bottom Right */ /** Bottom Right */
if (flags & LiPathRectFlags_KeepBotRight) { if (flags & LiPathRectFlags_KeepBotRight) {
pathAdd(b); PathAdd(b);
} else { } else {
pathAdd(fvec2(a.x + r, b.y)); PathAdd(fvec2(a.x + r, b.y));
pathFastArcToN(fvec2(a.x + r, b.y - r), r, __pi / 2.0f, __pi, segments); PathFastArcToN(fvec2(a.x + r, b.y - r), r, __pi / 2.0f, __pi, segments);
} }
/** Bottom Left */ /** Bottom Left */
if (flags & LiPathRectFlags_KeepBotLeft) { if (flags & LiPathRectFlags_KeepBotLeft) {
pathAdd(fvec2(a.x, b.y)); PathAdd(fvec2(a.x, b.y));
} else { } else {
pathAdd(fvec2(a.x, a.y + r)); PathAdd(fvec2(a.x, a.y + r));
pathFastArcToN(fvec2(a.x + r, a.y + r), r, __pi, 3.0f * __pi / 2.0f, PathFastArcToN(fvec2(a.x + r, a.y + r), r, __pi, 3.0f * __pi / 2.0f,
segments); segments);
} }
} }
} }
void iron::drawlist::drawRect(const fvec2& pos, const fvec2& size, ui color, void Iron::Drawlist::DrawRect(const fvec2& pos, const fvec2& size, ui color,
int thickness) { int thickness) {
pathRect(pos, pos + size); PathRect(pos, pos + size);
pathStroke(color, thickness, 1); PathStroke(color, thickness, 1);
} }
void iron::drawlist::drawRectFilled(const fvec2& pos, const fvec2& size, void Iron::Drawlist::DrawRectFilled(const fvec2& pos, const fvec2& size,
ui color) { ui color) {
pathRect(pos, pos + size); PathRect(pos, pos + size);
pathFill(color); PathFill(color);
} }
void iron::drawlist::drawTriangle(const fvec2& a, const fvec2& b, void Iron::Drawlist::DrawTriangle(const fvec2& a, const fvec2& b,
const fvec2& c, ui color, int thickness) { const fvec2& c, ui color, int thickness) {
pathAdd(a); PathAdd(a);
pathAdd(b); PathAdd(b);
pathAdd(c); PathAdd(c);
pathStroke(color, thickness, 1); PathStroke(color, thickness, 1);
} }
void iron::drawlist::drawTriangleFilled(const fvec2& a, const fvec2& b, void Iron::Drawlist::DrawTriangleFilled(const fvec2& a, const fvec2& b,
const fvec2& c, ui color) { const fvec2& c, ui color) {
pathAdd(a); PathAdd(a);
pathAdd(b); PathAdd(b);
pathAdd(c); PathAdd(c);
pathFill(color); PathFill(color);
} }
void iron::drawlist::drawCircle(const fvec2& center, float rad, ui color, void Iron::Drawlist::DrawCircle(const fvec2& center, float rad, ui color,
int segments, int thickness) { int segments, int thickness) {
if (segments <= 0) { if (segments <= 0) {
// Auto Segment // Auto Segment
} else { } else {
float am = (__pi * 2.0f) * ((float)segments) / (float)segments; float am = (__pi * 2.0f) * ((float)segments) / (float)segments;
pathArcToN(center, rad, 0.f, am, segments); PathArcToN(center, rad, 0.f, am, segments);
} }
drawSolid(); // Only Solid Color Supported DrawSolid(); // Only Solid Color Supported
pathStroke(color, thickness, 1); PathStroke(color, thickness, 1);
} }
void iron::drawlist::drawCircleFilled(const fvec2& center, float rad, ui color, void Iron::Drawlist::DrawCircleFilled(const fvec2& center, float rad, ui color,
int segments) { int segments) {
if (segments <= 0) { if (segments <= 0) {
// Auto Segment // Auto Segment
} else { } else {
float am = (__pi * 2.0f) * ((float)segments) / (float)segments; float am = (__pi * 2.0f) * ((float)segments) / (float)segments;
pathArcToN(center, rad, 0.f, am, segments); PathArcToN(center, rad, 0.f, am, segments);
} }
pathFill(color); PathFill(color);
} }
void iron::drawlist::drawPolyLine(const std::vector<fvec2>& points, ui clr, void Iron::Drawlist::DrawFromAtlas(fvec2 pos, fvec2 size, fvec4 cut_rect,
ui color) {
auto r = Iron::PrimRect(pos, size);
auto cmd = NewCommand();
auto uv = cut_rect / fvec4(pTex->Size(), pTex->Size());
uv.y = 1.f - uv.y;
uv.w = 1.f - uv.w;
Iron::CmdQuad(cmd.get(), r, uv, color);
Push(std::move(cmd));
}
void Iron::Drawlist::DrawPolyLine(const std::vector<fvec2>& points, ui clr,
ui flags, int thickness) { ui flags, int thickness) {
if (points.size() < 2) { if (points.size() < 2) {
return; return;
} }
drawSolid(); DrawSolid();
auto cmd = newCommand(); auto cmd = NewCommand();
bool close = (flags & (1 << 0)); bool close = (flags & (1 << 0));
int num_points = close ? (int)points.size() : (int)points.size() - 1; int num_points = close ? (int)points.size() : (int)points.size() - 1;
if (flags & (1 << 1)) { if (flags & (1 << 1)) {
@@ -218,54 +235,54 @@ void iron::drawlist::drawPolyLine(const std::vector<fvec2>& points, ui clr,
// Non antialiased lines look awful when rendering with thickness != 1 // Non antialiased lines look awful when rendering with thickness != 1
for (int i = 0; i < num_points; i++) { for (int i = 0; i < num_points; i++) {
int j = (i + 1) == (int)points.size() ? 0 : (i + 1); int j = (i + 1) == (int)points.size() ? 0 : (i + 1);
auto line = primLine(points[i], points[j], thickness); auto line = PrimLine(points[i], points[j], thickness);
cmdQuad(cmd.get(), line, fvec4(0.f, 1.f, 1.f, 0.f), clr); CmdQuad(cmd.get(), line, fvec4(0.f, 1.f, 1.f, 0.f), clr);
} }
} }
push(std::move(cmd)); Push(std::move(cmd));
} }
void iron::drawlist::drawConvexPolyFilled(const std::vector<fvec2>& points, void Iron::Drawlist::DrawConvexPolyFilled(const std::vector<fvec2>& points,
ui clr) { ui clr) {
if (points.size() < 3) { if (points.size() < 3) {
return; // Need at least three points return; // Need at least three points
} }
auto cmd = newCommand(); auto cmd = NewCommand();
cmdConvexPolyFilled(cmd.get(), points, clr, m_tex); CmdConvexPolyFilled(cmd.get(), points, clr, pTex);
push(std::move(cmd)); Push(std::move(cmd));
} }
void iron::drawlist::drawText(const fvec2& pos, const std::string& text, void Iron::Drawlist::DrawText(const fvec2& pos, const std::string& text,
ui color) { ui color) {
/*if (!pCurrentFont) { if (!pCurrentFont) {
return; return;
} }
std::vector<Command::Ref> cmds; std::vector<Command::Ref> cmds;
pCurrentFont->CmdTextEx(cmds, pos, color, pFontScale, text); pCurrentFont->CmdTextEx(cmds, pos, color, pFontScale, text);
for (size_t i = 0; i < cmds.size(); i++) { for (size_t i = 0; i < cmds.size(); i++) {
cmds[i]->Index = pDrawList.size(); cmds[i]->Index = pData.size();
cmds[i]->Layer = Layer; cmds[i]->Layer = pLayer;
AddCommand(std::move(cmds[i])); Push(std::move(cmds[i]));
}*/ }
} }
void iron::drawlist::drawTextEx(const fvec2& p, const std::string& text, void Iron::Drawlist::DrawTextEx(const fvec2& p, const std::string& text,
ui color, ui flags, const fvec2& box) { ui color, ui flags, const fvec2& box) {
/*if (!pCurrentFont) { if (!pCurrentFont) {
return; return;
} }
std::vector<Command::Ref> cmds; std::vector<Command::Ref> cmds;
pCurrentFont->CmdTextEx(cmds, p, color, pFontScale, text, flags, box); pCurrentFont->CmdTextEx(cmds, p, color, pFontScale, text, flags, box);
for (size_t i = 0; i < cmds.size(); i++) { for (size_t i = 0; i < cmds.size(); i++) {
cmds[i]->Index = pDrawList.size(); cmds[i]->Index = pData.size();
cmds[i]->Layer = Layer; cmds[i]->Layer = pLayer;
AddCommand(std::move(cmds[i])); Push(std::move(cmds[i]));
}*/ }
} }
void iron::drawlist::drawLine(const fvec2& a, const fvec2& b, ui color, int t) { void Iron::Drawlist::DrawLine(const fvec2& a, const fvec2& b, ui color, int t) {
pathAdd(a); PathAdd(a);
pathAdd(b); PathAdd(b);
pathStroke(color, t); PathStroke(color, t);
} }
} // namespace amy } // namespace Amy
+307
View File
@@ -0,0 +1,307 @@
#include <amethyst/iron.hpp>
#include <amethyst/utils.hpp>
#include <filesystem>
#include <fstream>
//#ifdef AMY_STB_TT
#define STB_TRUETYPE_IMPLEMENTATION
//#endif
#include <stb_truetype.h>
namespace Amy {
// Dont read this code please ... tnaks
void Iron::Font::LoadBMF(ksr path) {
Image img(path);
img.Convert(Image::A8);
if (img.Width() != img.Height() || img.Bpp() != 1 || img.Width() <= 0 ||
img.Height() <= 0) {
throw std::runtime_error(
"[Amy] Font: BMF is not in rgba or not 1x1 dimensioned!");
}
auto base = Amy::Texture::New();
base->Load(img.GetBuffer(), img.Width(), img.Height(), img.Bpp(), img.Fmt());
base->Unloadable(false);
PxHeight = img.Height() / 16;
for (int i = 0; i < img.Height(); i += PxHeight) {
for (int j = 0; j < img.Width(); j += PxHeight) {
int maxw = 0;
Amy::Texture::Ref tex = Amy::Texture::New();
for (int y = i; y < i + PxHeight; y++) {
for (int x = j; x < j + PxHeight; x++) {
if (img.GetBuffer()[y * img.Width() + x] != 0) {
maxw = std::max(maxw, x - j);
}
}
}
Codepoint cp;
cp.Valid = maxw != 0;
cp.Cp = (i / PxHeight) * 16 + (j / PxHeight);
cp.Offset = 0.f;
if (cp.Valid) {
tex->Load(base->Ptr(), base->Size(), base->Uv());
cp.Size = fvec2(maxw + 1, PxHeight);
cp.Tex = tex;
cp.Uv = fvec4(float(j) / float(img.Width()),
1.f - float(i) / float(img.Height()),
float(j + maxw + 1) / float(img.Width()),
1.f - float(i + PxHeight) / float(img.Height()));
Textures.push_back(tex);
}
pCodeMap[(i / PxHeight) * 16 + (j / PxHeight)] = cp;
}
}
}
void Iron::Font::LoadTTF(ksr path, int size) {
auto data = Amy::Utils::LoadFile2Mem(path);
LoadTTF(data, size);
}
void Iron::Font::LoadTTF(const vec<uc>& data, int size) {
/**
* Some additional Info:
* Removed the stbtt get bitmapbox as we dont need to place
* the glyps nicely in the tex. next step would be using the free
* space on the y axis to get mor glyphs inside
*/
PxHeight = size;
int texszs = Amy::Utils::NextPow2(PxHeight * 16);
if (texszs > 1024) {
texszs = 1024; // Max size
}
stbtt_fontinfo inf;
if (!stbtt_InitFont(&inf, data.data(), 0)) {
return;
}
float scale = stbtt_ScaleForPixelHeight(&inf, PxHeight);
int ascent, descent, lineGap;
stbtt_GetFontVMetrics(&inf, &ascent, &descent, &lineGap);
int baseline = static_cast<int>(ascent * scale);
// Cache to not render same codepoint tex twice
std::map<u32, int> buf_cache;
std::vector<u8> font_tex(texszs * texszs, 0);
auto tex = Texture::New();
fvec2 off;
bool empty = true;
for (u32 ii = 0x0000; ii <= 0xFFFF; ii++) {
int gi = stbtt_FindGlyphIndex(&inf, ii);
if (gi == 0) continue;
if (stbtt_IsGlyphEmpty(&inf, gi)) continue;
int w = 0, h = 0, xo = 0, yo = 0;
unsigned char* bitmap =
stbtt_GetCodepointBitmap(&inf, scale, scale, ii, &w, &h, &xo, &yo);
if (!bitmap || w <= 0 || h <= 0) {
if (bitmap) free(bitmap);
continue;
}
u32 hashed_map =
Utils::HashMemory(std::vector<u8>(bitmap, bitmap + (w * h)));
if (buf_cache.find(hashed_map) != buf_cache.end()) {
Codepoint c = GetCodepoint(buf_cache[hashed_map]);
c.Cp = ii;
pCodeMap[ii] = c;
free(bitmap);
continue;
} else {
buf_cache[hashed_map] = ii;
}
// Next row
if (off.x + w > texszs) {
off.y += PxHeight;
off.x = 0.0f;
}
// Bake cause we go out of the tex
if (off.y + PxHeight > texszs) {
pMakeAtlas(false, font_tex, texszs, tex);
tex = Texture::New();
off = 0;
std::fill(font_tex.begin(), font_tex.end(), 0);
empty = true;
}
// UVs & Codepoint
Codepoint c;
fvec4 uvs;
// cast the ints to floats and not the floats...
// dont know where my mind was when creating the code
uvs.x = off.x / static_cast<float>(texszs);
uvs.y = off.y / static_cast<float>(texszs);
uvs.z = (off.x + w) / static_cast<float>(texszs);
uvs.w = (off.y + h) / static_cast<float>(texszs);
// Flip (too lazy to place it into the seq at top)
uvs.y = 1.f - uvs.y;
uvs.w = 1.f - uvs.w;
c.Uv = uvs;
c.Tex = tex;
c.Size = fvec2(w, h);
c.Offset = baseline + yo;
c.Cp = ii;
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
int map_pos = ((static_cast<int>(off.y) + y) * texszs +
(static_cast<int>(off.x) + x));
font_tex[map_pos] = bitmap[x + y * w];
}
}
empty = false;
pCodeMap[ii] = c;
free(bitmap);
// offset by 1 (prevents visual glitches i had)
off.x += w + 1;
}
if (!empty) {
pMakeAtlas(true, font_tex, texszs, tex);
}
}
void Iron::Font::pMakeAtlas(bool final, vec<uc>& font_tex, int texszs,
Texture::Ref tex) {
tex->Load(font_tex, texszs, texszs, 1, Amy::Image::A8);
Textures.push_back(tex);
}
Iron::Font::Codepoint& Iron::Font::GetCodepoint(ui cp) {
// Check if codepoijt exist or return a static invalid one
auto res = pCodeMap.find(cp);
if (res == pCodeMap.end()) {
static Codepoint invalid;
invalid.Valid = false;
return invalid;
}
return res->second;
}
fvec2 Iron::Font::GetTextBounds(ksr text, float scale) {
// Use wstring for exemple for german äöü
auto wtext = std::filesystem::path(text).wstring();
// Create a temp position and offset as [0, 0]
fvec2 res;
float x = 0;
// Curent Font Scale
float cfs = (PxFactor * scale) / (float)PxHeight;
float lh = (float)PxHeight * cfs;
size_t index = 0;
for (auto& it : wtext) {
if (it == L'\0') {
break;
}
index++;
auto cp = GetCodepoint(it);
if (!cp.Valid && it != '\n' && it != '\t' && it != ' ') {
continue;
}
switch (it) {
case L'\n':
res.y += lh;
res.x = std::max(res.x, x);
x = 0.f;
break;
case L'\t':
x += 16 * cfs;
break;
case L' ':
x += 4 * cfs;
// Fall trough here to get the same result as in
// TextCommand if/else Section
default:
x += cp.Size.x * cfs;
if (index != wtext.size()) {
x += 2 * cfs;
}
break;
}
}
res.x = std::max(res.x, x);
res.y += lh;
return res;
}
void Iron::Font::CmdTextEx(vec<Command::Ref>& cmds, const fvec2& pos, ui color,
float scale, const std::string& text,
AmyTextFlags flags, const fvec2& box) {
fvec2 off;
float cfs = (PxFactor * scale) / (float)PxHeight;
float lh = (float)PxHeight * cfs;
fvec2 td;
fvec2 rpos = pos;
fvec2 rbox = box;
if (flags & (AmyTextFlags_AlignMid | AmyTextFlags_AlignRight)) {
td = GetTextBounds(text, scale);
}
if (flags & AmyTextFlags_AlignMid) {
rpos = rbox * 0.5 - td * 0.5 + pos;
}
if (flags & AmyTextFlags_AlignRight) {
rpos.x = rpos.x - td.x;
}
std::vector<std::string> lines;
std::istringstream iss(text);
std::string tmp;
while (std::getline(iss, tmp)) {
lines.push_back(tmp);
}
for (auto& it : lines) {
/*if (flags & AmyTextFlags_Short) {
fvec2 tmp_dim;
it = ShortText(it, box.x() - pos.x(), tmp_dim);
}*/
// Bitte nicht nachmachen... Also ernsthaft jz, bitte macht das nicht
auto wline = std::filesystem::path(it).wstring();
auto cmd = Command::New();
auto Tex = GetCodepoint(wline[0]).Tex;
cmd->Tex = Tex;
for (auto& jt : wline) {
auto cp = GetCodepoint(jt);
if ((!cp.Valid && jt != L' ' && jt != L'\n' && jt != L'\t') &&
jt != L'\r') {
continue;
}
if (Tex != cp.Tex) {
cmds.push_back(std::move(cmd));
cmd = Command::New();
Tex = cp.Tex;
cmd->Tex = Tex;
}
if (jt == L'\t') {
off.x += 16 * cfs;
} else {
if (jt != L' ') {
if (flags & AmyTextFlags_Shaddow) {
// Draw
Rect rec = Iron::PrimRect(
rpos + vec2(off.x + 1, off.y + (cp.Offset * cfs)) + 1,
cp.Size * cfs, 0.f);
Iron::CmdQuad(cmd.get(), rec, cp.Uv, 0xff111111);
}
// Draw
Rect rec = Iron::PrimRect(rpos + off + fvec2(0, (cp.Offset * cfs)),
cp.Size * cfs, 0.f);
Iron::CmdQuad(cmd.get(), rec, cp.Uv, color);
off.x += cp.Size.x * cfs + 2 * cfs;
} else {
off.x += 4 * cfs;
}
}
}
cmds.push_back(std::move(cmd));
off.y += lh;
off.x = 0;
}
}
} // namespace Amy
+118 -103
View File
@@ -1,20 +1,9 @@
#include <amethyst/iron.hpp> #include <amethyst/iron.hpp>
#include <amethyst/utils.hpp>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#define catch2() \ namespace Amy {
; \
({ \
std::cout << std::format("{}:{}", __FILE__, __LINE__) << std::endl; \
while (aptMainLoop()) { \
hidScanInput(); \
if (hidKeysDown() & KEY_A) { \
break; \
} \
} \
})
namespace amy {
const char* __ironshader__ = R"(; LI7 Shader const char* __ironshader__ = R"(; LI7 Shader
; Constants ; Constants
.constf myconst(0.0, 1.0, 0.00392156862745, 0.0) .constf myconst(0.0, 1.0, 0.00392156862745, 0.0)
@@ -50,128 +39,153 @@ const char* __ironshader__ = R"(; LI7 Shader
end end
.end)"; .end)";
// clang-format off std::vector<Iron::Vertex, LinearAllocator<Iron::Vertex>> Iron::m_vbuf;
unsigned char li_shader[] = { std::vector<u16, LinearAllocator<u16>> Iron::m_ibuf;
0x44, 0x56, 0x4c, 0x42, 0x1, 0x0, 0x0, 0x0, 0xa4, 0x0, 0x0, 0x0, 0x44, 0x56, 0x4c, 0x50, 0x0, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x98, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4e, 0x1, 0xf0, 0x7, 0x4e, 0x2, 0x8, 0x2, 0x8, 0x3, 0x18, 0x2, 0x8, 0x4, 0x28, 0x2, 0x8, 0x5, 0x38, 0x2, 0x8, 0x6, 0x10, 0x40, 0x4c, 0x7, 0xf1, 0x27, 0x22, 0x8, 0x10, 0x21, 0x4c, 0x0, 0x0, 0x0, 0x88, 0xac, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa1, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0xc3, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x64, 0xc3, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x62, 0xc3, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x61, 0xc3, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0xaf, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4f, 0xd5, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x44, 0x56, 0x4c, 0x45, 0x2, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x54, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x54, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x6c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x74, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x2, 0x0, 0x5f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x1, 0x1, 0x37, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0x2, 0x0, 0x1, 0x0, 0xf, 0x0, 0x0, 0x0, 0x3, 0x0, 0x2, 0x0, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x13, 0x0, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0, 0x0, int Iron::uLocProj = 0;
}; C3D::Shader* Iron::m_shader = nullptr;
// clang-format on mat4 Iron::m_mtx;
size_t li_shader_size = 0x124; int Iron::m_idx = 0, Iron::m_vtx = 0;
std::vector<iron::vertex, linearAllocator<iron::vertex>> iron::m_vbuf; Texture::Ref Iron::m_solid = nullptr;
std::vector<u16, linearAllocator<u16>> iron::m_ibuf; ui Iron::VertexCount = 0;
int iron::uLocProj = 0; ui Iron::IndexCount = 0;
c3d::shader* iron::m_shader = nullptr;
mat4 iron::m_mtx;
int iron::m_idx = 0, iron::m_vtx = 0;
texture* iron::m_solid = nullptr;
void iron::init() { void Iron::Init() {
setupShader(); pSetupShader();
m_vbuf.resize(4 * 4096); m_vbuf.resize(4 * 4096);
m_ibuf.resize(6 * 4096); m_ibuf.resize(6 * 4096);
initSolidTex(); pInitSolidTex();
} }
void iron::newFrame() { void Iron::Exit() {
m_solid.reset();
delete m_shader;
m_vbuf.clear();
m_ibuf.clear();
}
void Iron::NewFrame() {
VertexCount = m_vtx;
IndexCount = m_idx;
m_idx = 0; m_idx = 0;
m_vtx = 0; m_vtx = 0;
} }
C3D_Mtx m; void Iron::DrawOn(C3D::Screen* screen) {
m_shader->Use();
void iron::drawOn(c3d::screen* screen) { m_mtx = mat4::ortho(0.f, (float)screen->Width(), (float)screen->Height(), 0.f,
m_shader->use();
Mtx_Identity(&m);
Mtx_OrthoTilt(&m, 0.f, (float)screen->width(), (float)screen->height(), 0.f,
1.f, -1.f, false);
m_mtx = mat4::ortho(0.f, (float)screen->width(), (float)screen->height(), 0.f,
1.f, -1.f); 1.f, -1.f);
m_shader->setMat4(uLocProj, &m); m_shader->SetMat4(uLocProj, m_mtx);
} }
void iron::draw(const std::vector<iron::command::ref>& data) { void Iron::Draw(const std::vector<Iron::Command::Ref>& data) {
// disable depthtest cause we have no z buffer // disable depthtest cause we have no z buffer
c3d::depthTest(false); C3D::DepthTest(false);
fragConfig();
size_t i = 0; size_t i = 0;
while (i < data.size()) { while (i < data.size()) {
texture* tex = data[i]->tex; Texture::Ref tex = data[i]->Tex;
if (!tex) { if (!tex || !tex->Ptr()) {
i++; i++;
continue; continue;
} }
auto scissorOn = data[i]->scissorOn; pFragConfig(tex->Ptr()->fmt);
auto scissor = data[i]->scissorRect; auto scissorOn = data[i]->ScissorOn;
auto start = i; auto scissor = data[i]->ScissorRect;
auto start = m_idx;
// Loop until a statgechange and copy all data into vertex/index buf // Loop until a statgechange and copy all data into Vertex/index buf
while (i < data.size() && scissorOn == data[i]->scissorOn && while (i < data.size() && scissorOn == data[i]->ScissorOn &&
scissor == data[i]->scissorRect && tex == data[i]->tex) { scissor == data[i]->ScissorRect && tex == data[i]->Tex) {
auto c = data[i].get(); auto c = data[i].get();
for (int j = 0; j < c->indexBuf.size(); j++) { if (!pCheckSize(c->IndexBuf.size(), c->VertexBuf.size())) {
m_ibuf[m_idx++] = m_vtx + c->indexBuf[j]; throw Error("iron: too much draw data!!!" +
std::format("\nIdx: {}\nVtx: {}", c->IndexBuf.size(),
c->VertexBuf.size()));
} }
for (int j = 0; j < c->vertexBuf.size(); j++) {
m_vbuf[m_vtx++] = c->vertexBuf[j]; for (int j = 0; j < c->IndexBuf.size(); j++) {
m_ibuf[m_idx++] = m_vtx + c->IndexBuf[j];
}
for (int j = 0; j < c->VertexBuf.size(); j++) {
m_vbuf[m_vtx++] = std::move(c->VertexBuf[j]);
} }
i++; i++;
} }
///// SCISSOR LOGIC BEG ///// ///// SCISSOR LOGIC BEG /////
///// SCISSOR LOGIC END ///// ///// SCISSOR LOGIC END /////
tex->bind(); tex->Bind();
c3d::bufCfg<3>(m_vbuf.data(), sizeof(vertex)); C3D::BufCfg<3>(m_vbuf.data(), sizeof(Vertex));
c3d::drawElements(i - start, m_ibuf.data() + start); C3D::DrawElements(m_idx - start, m_ibuf.data() + start);
} }
c3d::depthTest(true); C3D::DepthTest(true);
} }
void iron::setupShader() { bool Iron::pCheckSize(size_t idx, size_t vtx) {
m_shader = new c3d::shader(); return idx < m_ibuf.size() && vtx < m_vbuf.size();
m_shader->load("romfs:/shaders/lithium.shbin"); }
// m_shader->compile(__ironshader__);
m_shader->input(GPU_FLOAT, 2); // pos void Iron::pSetupShader() {
m_shader->input(GPU_FLOAT, 2); // uv m_shader = new C3D::Shader();
m_shader->input(GPU_UNSIGNED_BYTE, 4); // color m_shader->Compile(__ironshader__);
m_shader->Input(GPU_FLOAT, 2); // pos
m_shader->Input(GPU_FLOAT, 2); // uv
m_shader->Input(GPU_UNSIGNED_BYTE, 4); // color
uLocProj = m_shader->loc("projection"); uLocProj = m_shader->loc("projection");
} }
void iron::fragConfig() { void Iron::pFragConfig(GPU_TEXCOLOR clr) {
c3d::frag::edit(); C3D::Frag::Edit();
c3d::frag::src(C3D_Both, GPU_TEXTURE0); switch (clr) {
c3d::frag::func(C3D_Both, GPU_MODULATE); case GPU_A4:
case GPU_A8:
case GPU_L4:
case GPU_L8:
C3D::Frag::Src(C3D_Alpha, GPU_TEXTURE0);
C3D::Frag::Func(C3D_RGB, GPU_REPLACE);
C3D::Frag::Func(C3D_Alpha, GPU_MODULATE);
break;
default:
C3D::Frag::Src(C3D_Both, GPU_TEXTURE0);
C3D::Frag::Func(C3D_Both, GPU_MODULATE);
break;
}
} }
void iron::initSolidTex() { void Iron::pInitSolidTex() {
// i know there is a lot of memory wasted :( // i know there is a lot of memory wasted :(
std::vector<uc> pixels(16 * 16 * 4, 0xff); std::vector<uc> pixels(16 * 16, 0xff);
m_solid = new texture(); m_solid = Texture::New();
m_solid->load(pixels, 16, 16); m_solid->Load(pixels, 16, 16, 1, Amy::Image::A8);
if (!m_solid->Ptr()) {
throw Error("white tex failed to load!");
}
} }
bool iron::inBox(const fvec2& pos, const fvec2& size, const fvec4& area) { bool Iron::InBox(const fvec2& pos, const fvec2& size, const fvec4& area) {
return (pos.x + size.x >= area.x && pos.y + size.y >= area.y && return (pos.x + size.x >= area.x && pos.y + size.y >= area.y &&
pos.x <= area.z && pos.y <= area.w); pos.x <= area.z && pos.y <= area.w);
} }
bool iron::inBox(const fvec2& pos, const fvec4& area) { bool Iron::InBox(const fvec2& pos, const fvec4& area) {
return (pos.x > area.x && pos.x < area.x + area.z && pos.y > area.y && return (pos.x > area.x && pos.x < area.x + area.z && pos.y > area.y &&
pos.y < area.y + area.w); pos.y < area.y + area.w);
} }
bool iron::inBox(const fvec2& a, const fvec2& b, const fvec2& c, bool Iron::InBox(const fvec2& a, const fvec2& b, const fvec2& c,
const fvec4& area) { const fvec4& area) {
return ((a.x < area.z && b.x < area.z && c.x < area.z) || return ((a.x < area.z && b.x < area.z && c.x < area.z) ||
(a.y < area.w && b.y < area.w && c.y < area.w) || (a.y < area.w && b.y < area.w && c.y < area.w) ||
(a.x > 0 && b.x > 0 && c.x > 0) || (a.y > 0 && b.y > 0 && c.y > 0)); (a.x > 0 && b.x > 0 && c.x > 0) || (a.y > 0 && b.y > 0 && c.y > 0));
} }
void iron::rotateCorner(fvec2& pos, float s, float c) { void Iron::RotateCorner(fvec2& pos, float s, float c) {
float x = pos.x * c - pos.y * s; float x = pos.x * c - pos.y * s;
float y = pos.y * c - pos.x * s; float y = pos.y * c - pos.x * s;
pos = fvec2(x, y); pos = fvec2(x, y);
} }
rect iron::primRect(const fvec2& pos, const fvec2& size, float angle) { Rect Iron::PrimRect(const fvec2& pos, const fvec2& size, float angle) {
fvec2 c = size * 0.5f; // Center fvec2 c = size * 0.5f; // Center
fvec2 corner[4] = { fvec2 corner[4] = {
fvec2(-c.x, -c.y), fvec2(-c.x, -c.y),
@@ -185,16 +199,16 @@ rect iron::primRect(const fvec2& pos, const fvec2& size, float angle) {
float s = std::sin(angle); float s = std::sin(angle);
float co = std::cos(angle); float co = std::cos(angle);
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
rotateCorner(corner[i], s, co); RotateCorner(corner[i], s, co);
} }
} }
// Return Result // Return Result
return rect(corner[0] + pos + c, corner[1] + pos + c, corner[2] + pos + c, return Rect(corner[0] + pos + c, corner[1] + pos + c, corner[2] + pos + c,
corner[3] + pos + c); corner[3] + pos + c);
} }
rect iron::primLine(const fvec2& a, const fvec2& b, int thickness) { Rect Iron::PrimLine(const fvec2& a, const fvec2& b, int thickness) {
// Using the vec maths api makes the code as short as it is // Using the vec maths api makes the code as short as it is
fvec2 dir = a - b; fvec2 dir = a - b;
float len = dir.Len(); float len = dir.Len();
@@ -202,35 +216,36 @@ rect iron::primLine(const fvec2& a, const fvec2& b, int thickness) {
fvec2 perpendicular(-unit_dir.y, unit_dir.x); fvec2 perpendicular(-unit_dir.y, unit_dir.x);
fvec2 off = perpendicular * ((float)thickness * 0.5f); fvec2 off = perpendicular * ((float)thickness * 0.5f);
return rect(a + off, b + off, a - off, b - off); return Rect(a + off, b + off, a - off, b - off);
} }
void iron::cmdQuad(command* cmd, const rect& q, const rect& uv, ui color) { void Iron::CmdQuad(Command* cmd, const Rect& q, const Rect& uv, ui color) {
cmd->add(0).add(1).add(2); cmd->Add(0).Add(1).Add(2);
cmd->add(0).add(2).add(3); cmd->Add(0).Add(2).Add(3);
cmd->add(vertex(q.botRight(), uv.botRight(), color)); cmd->Add(Vertex(q.BotRight(), uv.BotRight(), color));
cmd->add(vertex(q.topRight(), uv.topRight(), color)); cmd->Add(Vertex(q.TopRight(), uv.TopRight(), color));
cmd->add(vertex(q.topLeft(), uv.topLeft(), color)); cmd->Add(Vertex(q.TopLeft(), uv.TopLeft(), color));
cmd->add(vertex(q.botLeft(), uv.botLeft(), color)); cmd->Add(Vertex(q.BotLeft(), uv.BotLeft(), color));
} }
void iron::cmdTriangle(command* cmd, const fvec2& a, const fvec2& b, void Iron::CmdTriangle(Command* cmd, const fvec2& a, const fvec2& b,
const fvec2& c, ui color) { const fvec2& c, ui color) {
cmd->add(2).add(1).add(0); // reverse cause otherwise invisible cmd->Add(2).Add(1).Add(0); // reverse cause otherwise invisible
cmd->add(vertex(a, fvec2(0, 1), color)); cmd->Add(Vertex(a, fvec2(0, 1), color));
cmd->add(vertex(b, fvec2(1, 1), color)); cmd->Add(Vertex(b, fvec2(1, 1), color));
cmd->add(vertex(c, fvec2(1, 0), color)); cmd->Add(Vertex(c, fvec2(1, 0), color));
} }
void iron::cmdConvexPolyFilled(command* cmd, const std::vector<fvec2>& points, void Iron::CmdConvexPolyFilled(Command* cmd, const std::vector<fvec2>& points,
ui color, texture* tex) { ui color, Texture::Ref tex) {
if (points.size() < 3 || tex == nullptr) { if (points.size() < 3 || tex == nullptr) {
#ifdef AMY_GOD_DEV #ifdef AMY_GOD_DEV
return; return;
#else #else
throw std::runtime_error("[amy] iron: trying to render convex poly with " + throw std::runtime_error("[amy] iron: trying to render convex poly with " +
std::to_string(points.size()) + std::to_string(points.size()) +
" points and texture " + std::to_string((ui)tex)); " points and Texture " +
std::to_string((ui)tex.get()));
#endif #endif
} }
// Support for Custom Textures (UV calculation) // Support for Custom Textures (UV calculation)
@@ -245,13 +260,13 @@ void iron::cmdConvexPolyFilled(command* cmd, const std::vector<fvec2>& points,
} }
// Get Short defines for UV // Get Short defines for UV
// (Bottom Right is not required) // (Bottom Right is not required)
auto uv_tl = tex->uv().topLeft(); auto uv_tl = tex->Uv().TopLeft();
auto uv_tr = tex->uv().topRight(); auto uv_tr = tex->Uv().TopRight();
auto uv_bl = tex->uv().botLeft(); auto uv_bl = tex->Uv().BotLeft();
// Render // Render
for (int i = 2; i < (int)points.size(); i++) { for (int i = 2; i < (int)points.size(); i++) {
cmd->add(0).add(i).add(i - 1); cmd->Add(0).Add(i).Add(i - 1);
} }
for (int i = 0; i < (int)points.size(); i++) { for (int i = 0; i < (int)points.size(); i++) {
// Calculate U and V coords // Calculate U and V coords
@@ -259,7 +274,7 @@ void iron::cmdConvexPolyFilled(command* cmd, const std::vector<fvec2>& points,
uv_tl.x + ((points[i].x - minX) / (maxX - minX)) * (uv_tr.x - uv_tl.x); uv_tl.x + ((points[i].x - minX) / (maxX - minX)) * (uv_tr.x - uv_tl.x);
float v = float v =
uv_tl.y + ((points[i].y - minY) / (maxY - minY)) * (uv_bl.y - uv_tl.y); uv_tl.y + ((points[i].y - minY) / (maxY - minY)) * (uv_bl.y - uv_tl.y);
cmd->add(vertex(points[i], fvec2(u, v), color)); cmd->Add(Vertex(points[i], fvec2(u, v), color));
} }
} }
} // namespace amy } // namespace Amy
+2 -2
View File
@@ -24,7 +24,7 @@ SOFTWARE.
#include <amethyst/maths/mat.hpp> #include <amethyst/maths/mat.hpp>
namespace amy { namespace Amy {
mat4 mat4::rotateX(float a) { mat4 mat4::rotateX(float a) {
float c = std::cos(a); float c = std::cos(a);
float s = std::sin(a); float s = std::sin(a);
@@ -118,4 +118,4 @@ mat4 mat4::lookAt(const fvec3& pos, const fvec3& center, const fvec3& up) {
ret(2, 3) = f.Dot(pos); ret(2, 3) = f.Dot(pos);
return ret; return ret;
} }
} // namespace amy } // namespace Amy
+2 -2
View File
@@ -1,7 +1,7 @@
#include <amethyst/renderer.hpp> #include <amethyst/renderer.hpp>
namespace amy { namespace Amy {
Renderer::Renderer() {} Renderer::Renderer() {}
Renderer::~Renderer() {} Renderer::~Renderer() {}
} // namespace amy } // namespace Amy
+44 -41
View File
@@ -6,88 +6,91 @@
#include <amethyst/utils.hpp> #include <amethyst/utils.hpp>
#include <stdexcept> #include <stdexcept>
namespace amy { namespace Amy {
ui tile3dsTex(int x, int y, int w) { ui tile3dsTex(int x, int y, int w) {
return ((((y >> 3) * ((int)w >> 3) + (x >> 3)) << 6) + return ((((y >> 3) * ((int)w >> 3) + (x >> 3)) << 6) +
((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) |
((x & 4) << 2) | ((y & 4) << 3))); ((x & 4) << 2) | ((y & 4) << 3)));
} }
GPU_TEXCOLOR image2TexFmt(const image::format& fmt) { GPU_TEXCOLOR image2TexFmt(const Image::Format& fmt) {
switch (fmt) { switch (fmt) {
case image::RGB: case Image::RGB:
return GPU_RGB8; return GPU_RGB8;
break; break;
case image::RGBA: case Image::RGBA:
return GPU_RGBA8; return GPU_RGBA8;
break; break;
case image::RGB565: case Image::RGB565:
return GPU_RGB565; return GPU_RGB565;
break; break;
case Image::A8:
return GPU_A8;
break;
default: default:
// Dummy // Dummy
return GPU_A4;
throw std::runtime_error( throw std::runtime_error(
"[amy] texture: Unsupported texture format used!"); "[amy] texture: Unsupported texture Format used!");
break; break;
} }
} }
texture::texture(cstr& path) { load(path); } Texture::Texture(ksr path) { Load(path); }
texture::~texture() { unload(); } Texture::~Texture() { Unload(); }
void texture::unload() { void Texture::Unload() {
if (m_loaded) { if (pLoaded) {
C3D_TexDelete(&m_tex); C3D_TexDelete(pTex);
m_loaded = false; delete pTex;
pTex = nullptr;
pLoaded = false;
} }
} }
void texture::load(cstr& path) { void Texture::Load(ksr path) {
image img(path); Image img(path);
if (img.width() > 1024 || img.height() > 1024) { Load(img.GetBuffer(), img.Width(), img.Height(), img.Bpp(), img.Fmt());
throw std::runtime_error("Max Texture Size is 1024x1024!");
}
load(img.getBuffer(), img.width(), img.height(), img.bpp(), img.fmt());
} }
void texture::load(const std::vector<uc>& pixels, int w, int h, int bpp, void Texture::Load(kvr<uc> pixels, int w, int h, int bpp, Image::Format fmt) {
image::format fmt) {
if (w > 1024 || h > 1024) { if (w > 1024 || h > 1024) {
throw std::runtime_error("Max Texture Size is 1024x1024!"); throw std::runtime_error("[amy] texture: Max Texture Size is 1024x1024!");
} }
unload(); Unload();
m_size.x = w; pSize.x = w;
if (utils::isSingleBitNum(m_size.x)) { if (!Utils::IsSingleBitNum(pSize.x)) {
m_size.x = utils::nextPow2(m_size.x); pSize.x = Utils::NextPow2(pSize.x);
} }
m_size.y = h; pSize.y = h;
if (utils::isSingleBitNum(m_size.y)) { if (!Utils::IsSingleBitNum(pSize.y)) {
m_size.y = utils::nextPow2(m_size.y); pSize.y = Utils::NextPow2(pSize.y);
} }
pUv = Amy::fvec4(0, 1.f, (float)w / (float)pSize.x,
1.f - ((float)h / (float)pSize.y));
auto filter = GPU_NEAREST; auto filter = GPU_NEAREST;
auto format = image2TexFmt(fmt); auto Format = image2TexFmt(fmt);
C3D_TexInit(&m_tex, (u16)m_size.x, (u16)m_size.y, format); pTex = new C3D_Tex;
C3D_TexSetFilter(&m_tex, filter, filter); C3D_TexInit(pTex, (u16)pSize.x, (u16)pSize.y, Format);
C3D_TexSetFilter(pTex, filter, filter);
// Using std::fill_n instead cause i hate this error lines // Using std::fill_n instead cause i hate this error lines
// under the memset func in my editor // under the memset func in my editor
std::fill_n((unsigned char*)m_tex.data, m_tex.size, 0); std::fill_n((uc*)pTex->data, pTex->size, 0);
for (int x = 0; x < w; x++) { for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) { for (int y = 0; y < h; y++) {
int dst_pos = tile3dsTex(x, y, m_size.x) * bpp; int dst_pos = tile3dsTex(x, y, pSize.x) * bpp;
int src_pos = (y * w + x) * bpp; int src_pos = (y * w + x) * bpp;
/// Best idea i had /// Best idea i had
for (int i = 0; i < bpp; i++) { for (int i = 0; i < bpp; i++) {
((u8*)m_tex.data)[dst_pos + bpp - 1 - i] = pixels[src_pos + i]; ((u8*)pTex->data)[dst_pos + bpp - 1 - i] = pixels[src_pos + i];
} }
} }
} }
C3D_TexFlush(&m_tex); C3D_TexFlush(pTex);
m_tex.border = 0x00000000; pTex->border = 0x00000000;
C3D_TexSetWrap(&m_tex, GPU_REPEAT, GPU_REPEAT); C3D_TexSetWrap(pTex, GPU_REPEAT, GPU_REPEAT);
m_loaded = true; pLoaded = true;
} }
void texture::bind(int reg) { C3D_TexBind(reg, &m_tex); } void Texture::Bind(int reg) { C3D_TexBind(reg, pTex); }
} // namespace amy } // namespace Amy
+155 -21
View File
@@ -1,17 +1,9 @@
#include <amethyst/utils.hpp> #include <amethyst/utils.hpp>
#include <fstream> #include <fstream>
namespace amy { namespace Amy {
namespace utils { namespace Utils {
ui fastHash(cstr& s) { vec<uc> LoadFile2Mem(ksr path) {
ui hash = 5381;
for (auto& it : s) {
hash = (hash * 33) + static_cast<uc>(it);
}
return hash;
}
vec<uc> loadFile2Mem(cstr& path) {
std::ifstream iff(path, std::ios::binary); std::ifstream iff(path, std::ios::binary);
if (!iff) { if (!iff) {
return vec<uc>(); return vec<uc>();
@@ -25,7 +17,23 @@ vec<uc> loadFile2Mem(cstr& path) {
return res; return res;
} }
ui hashMemory(cvec<uc>& data) { str FormatBytes(ull bytes) {
static const vec<str> endings = {
"B", "KB", "MB", "GB", "TB", "Unk",
};
int i = 0;
double b = bytes;
while (b > 1024) {
i++;
b /= 1024;
}
if (i >= (int)endings.size()) {
i = (int)endings.size() - 1;
}
return std::format("{:.1f} {}", b, endings[i]);
}
ui HashMemory(kvr<uc> data) {
ui hash = 4477; ui hash = 4477;
for (auto& it : data) { for (auto& it : data) {
hash = (hash * 33) + it; hash = (hash * 33) + it;
@@ -33,7 +41,7 @@ ui hashMemory(cvec<uc>& data) {
return hash; return hash;
} }
ui nextPow2(ui v) { ui NextPow2(ui v) {
v--; v--;
v |= v >> 1; v |= v >> 1;
v |= v >> 2; v |= v >> 2;
@@ -44,10 +52,136 @@ ui nextPow2(ui v) {
return (v >= 64 ? v : 64); return (v >= 64 ? v : 64);
} }
bool isSingleBitNum(ui v) { return v && !(v & (v - 1)); } bool IsSingleBitNum(ui v) { return v && !(v & (v - 1)); }
namespace image { ull GetTimeNano() {
void reverseBuf(vec<uc>& buf, int w, int h, int c) { return std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count();
}
ull GetTimeMicro() {
return std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count();
}
ull GetTimeMilli() {
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count();
}
void String2U16(us* res, ksr src, size_t max) {
/// GOT FORCED TO REPLACE std::wstring_convert by some
/// manual work as it got removed in cxx20
/// TODO ///
/// ADD SOME ERROR API IN HERE
if (max == 0) return;
size_t len = 0;
size_t i = 0;
while (i < src.size() && len < max) {
uc c = src[i];
if (c < 0x80) {
// 1byte
res[len++] = c;
i++;
} else if ((c >> 5) == 0x6) {
// 2byte
if (i + 1 >= src.size())
throw std::invalid_argument("Invalid UTF-8 sequence");
res[len++] = ((c & 0x1F) << 6) | (src[i + 1] & 0x3F);
i += 2;
} else if ((c >> 4) == 0xE) {
// 3byte
if (i + 2 >= src.size())
throw std::invalid_argument("Invalid UTF-8 sequence");
res[len++] =
((c & 0x0F) << 12) | ((src[i + 1] & 0x3F) << 6) | (src[i + 2] & 0x3F);
i += 3;
} else if ((c >> 3) == 0x1E) {
// 4byte
if (i + 3 >= src.size())
throw std::invalid_argument("Invalid UTF-8 sequence");
ui codepoint = ((c & 0x07) << 18) | ((src[i + 1] & 0x3F) << 12) |
((src[i + 2] & 0x3F) << 6) | (src[i + 3] & 0x3F);
codepoint -= 0x10000;
res[len++] = 0xD800 | ((codepoint >> 10) & 0x3FF);
res[len++] = 0xDC00 | (codepoint & 0x3FF);
i += 4;
} else {
return;
}
}
}
std::string U16toU8(us* in, size_t max) {
/// GOT FORCED TO REPLACE std::wstring_convert by some
/// manual work as it got removed in cxx20
if (!in || max == 0) {
return "";
}
std::string result;
result.reserve(max * 3);
for (size_t i = 0; i < max; i++) {
uint16_t c = in[i];
if (c < 0x80) {
result.push_back(static_cast<char>(c));
} else if (c < 0x800) {
result.push_back(static_cast<char>(0xC0 | (c >> 6)));
result.push_back(static_cast<char>(0x80 | (c & 0x3F)));
} else if (c < 0x10000) {
result.push_back(static_cast<char>(0xE0 | (c >> 12)));
result.push_back(static_cast<char>(0x80 | ((c >> 6) & 0x3F)));
result.push_back(static_cast<char>(0x80 | (c & 0x3F)));
} else {
continue;
}
}
return result;
}
kstr FormatNanos(ull nanos) {
// Based on some code of my minecraft plugins
if (nanos < 1000) {
return std::format("{}ns", nanos);
} else if (nanos < 1000000) {
ull micros = nanos / 1000;
return std::format("{}us {}ns", micros, nanos % 1000);
} else if (nanos < 1000000000) {
ull millis = nanos / 1000000;
return std::format("{}ms {}us", millis, (nanos % 1000000) / 1000);
} else if (nanos < 60000000000ULL) {
ull seconds = nanos / 1000000000;
return std::format("{}s {}ms", seconds, (nanos % 1000000000) / 1000000);
} else {
ull minutes = nanos / 60000000000ULL;
ull seconds = (nanos % 60000000000ULL) / 1000000000;
return std::format("{}m {}s", minutes, seconds);
}
return "";
}
kstr FormatMillis(ull millis) {
// Original Code can be found in some of my mc plugins
if (millis < 1000) {
return std::format("{}ms", millis);
} else if (millis < 60000) {
ull seconds = millis / 1000;
return std::format("{}s {}ms", seconds, (millis % 1000));
} else {
ull minutes = millis / 60000;
ull seconds = (millis % 60000) / 1000;
return std::format("{}m {}s {}ms", minutes, seconds, (millis % 1000));
}
return "";
}
namespace Image {
void ReverseBuf(vec<uc>& buf, int w, int h, int c) {
vec<uc> cpy = buf; vec<uc> cpy = buf;
for (int x = 0; x < w; x++) { for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) { for (int y = 0; y < h; y++) {
@@ -59,7 +193,7 @@ void reverseBuf(vec<uc>& buf, int w, int h, int c) {
} }
} }
void removeAlphaChannel(vec<uc>& buf, int w, int h) { void RemoveAlphaChannel(vec<uc>& buf, int w, int h) {
vec<uc> cpy = buf; vec<uc> cpy = buf;
buf.resize(w * h * 3); buf.resize(w * h * 3);
for (int y = 0; y < h; y++) { for (int y = 0; y < h; y++) {
@@ -73,7 +207,7 @@ void removeAlphaChannel(vec<uc>& buf, int w, int h) {
} }
} }
void addAlphaChannel(vec<uc>& buf, int w, int h) { void AddAlphaChannel(vec<uc>& buf, int w, int h) {
vec<uc> cpy = buf; vec<uc> cpy = buf;
buf.resize(w * h * 4); buf.resize(w * h * 4);
for (int y = 0; y < h; y++) { for (int y = 0; y < h; y++) {
@@ -87,6 +221,6 @@ void addAlphaChannel(vec<uc>& buf, int w, int h) {
} }
} }
} }
} // namespace image } // namespace Image
} // namespace utils } // namespace Utils
} // namespace amy } // namespace Amy