diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e62e652..95066b6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,7 @@ repos: -- repo: https://github.com/pre-commit/mirrors-clang-format - rev: v16.0.5 - hooks: - - id: clang-format - files: \.(c|cc|cpp|h|hpp|cxx|hh|hpp|tpp)$ \ No newline at end of file + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: v16.0.5 + hooks: + - id: clang-format + files: \.(c|cc|cpp|h|hpp|cxx|hh|hpp|tpp)$ + exclude: ^example/ \ No newline at end of file diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css index 4300af9..4db54bf 100644 --- a/docs/_static/css/custom.css +++ b/docs/_static/css/custom.css @@ -90,13 +90,19 @@ --classref-secondary-color: #616770; --classref-setget-color: #56585b; - --search-input-background-color: #e6eef3; /* derived from --input-background-color */ - --search-match-color: #2c6b96; /* derived from --link-color */ - --search-match-background-color: #e3f2fd; /* derived from --link-color */ + --search-input-background-color: #e6eef3; + /* derived from --input-background-color */ + --search-match-color: #2c6b96; + /* derived from --link-color */ + --search-match-background-color: #e3f2fd; + /* derived from --link-color */ --search-active-color: #efefef; - --search-credits-background-color: #333f67; /* derived from --navbar-background-color */ - --search-credits-color: #b3b3b3; /* derived from --footer-color */ - --search-credits-link-color: #4392c5; /* derived from --link-color */ + --search-credits-background-color: #333f67; + /* derived from --navbar-background-color */ + --search-credits-color: #b3b3b3; + /* derived from --footer-color */ + --search-credits-link-color: #4392c5; + /* derived from --link-color */ --search-odd-color: rgb(133 160 253 / 24%); --search-even-color: rgb(202 209 239 / 30%); @@ -219,13 +225,19 @@ --classref-secondary-color: #929598; --classref-setget-color: #9e9fa0; - --search-input-background-color: #43464a; /* derived from --input-background-color */ - --search-match-color: #52b4ff; /* derived from --link-color */ - --search-match-background-color: #414c56; /* derived from --link-color */ + --search-input-background-color: #43464a; + /* derived from --input-background-color */ + --search-match-color: #52b4ff; + /* derived from --link-color */ + --search-match-background-color: #414c56; + /* derived from --link-color */ --search-active-color: #202326; - --search-credits-background-color: #202123; /* derived from --navbar-background-color */ - --search-credits-color: #6b6b6b; /* derived from --footer-color */ - --search-credits-link-color: #628fb1; /* derived from --link-color */ + --search-credits-background-color: #202123; + /* derived from --navbar-background-color */ + --search-credits-color: #6b6b6b; + /* derived from --footer-color */ + --search-credits-link-color: #628fb1; + /* derived from --link-color */ --search-odd-color: #202326; --search-even-color: #25282b; @@ -404,32 +416,42 @@ a.btn:hover { padding-right: 13px; } +.reference.external.image-reference { + background-image: none; + padding-right: 0; +} + +.tutorial-image-container { + display: flex; + gap: 1rem; +} + /* Style self-links to make them appear only on hover. */ -.classref-method > a[href*="-method-"].reference, -.classref-property > a[href*="-property-"].reference, -.classref-signal > a[href*="-signal-"].reference, -.classref-annotation > a[href*="-annotation-"].reference, -.classref-themeproperty > a[href*="-theme-"].reference, -.classref-method > a[href*="-method-"].reference, -.classref-constructor > a[href*="-constructor-"].reference, -.classref-operator > a[href*="-operator-"].reference, -.classref-constant > a[href*="-constant-"].reference, -.classref-enumeration > a[href^="#enum-"].reference { +.classref-method>a[href*="-method-"].reference, +.classref-property>a[href*="-property-"].reference, +.classref-signal>a[href*="-signal-"].reference, +.classref-annotation>a[href*="-annotation-"].reference, +.classref-themeproperty>a[href*="-theme-"].reference, +.classref-method>a[href*="-method-"].reference, +.classref-constructor>a[href*="-constructor-"].reference, +.classref-operator>a[href*="-operator-"].reference, +.classref-constant>a[href*="-constant-"].reference, +.classref-enumeration>a[href^="#enum-"].reference { visibility: hidden; padding-left: 20px; padding-right: 20px; } -.classref-method:hover > a[href*="-method-"].reference, -.classref-property:hover > a[href*="-property-"].reference, -.classref-signal:hover > a[href*="-signal-"].reference, -.classref-annotation:hover > a[href*="-annotation-"].reference, -.classref-themeproperty:hover > a[href*="-theme-"].reference, -.classref-method:hover > a[href*="-method-"].reference, -.classref-constructor:hover > a[href*="-constructor-"].reference, -.classref-operator:hover > a[href*="-operator-"].reference, -.classref-constant:hover > a[href*="-constant-"].reference, -.classref-enumeration:hover > a[href^="#enum-"].reference { +.classref-method:hover>a[href*="-method-"].reference, +.classref-property:hover>a[href*="-property-"].reference, +.classref-signal:hover>a[href*="-signal-"].reference, +.classref-annotation:hover>a[href*="-annotation-"].reference, +.classref-themeproperty:hover>a[href*="-theme-"].reference, +.classref-method:hover>a[href*="-method-"].reference, +.classref-constructor:hover>a[href*="-constructor-"].reference, +.classref-operator:hover>a[href*="-operator-"].reference, +.classref-constant:hover>a[href*="-constant-"].reference, +.classref-enumeration:hover>a[href^="#enum-"].reference { visibility: visible; padding-left: 20px; padding-right: 20px; @@ -512,14 +534,14 @@ hr, } /* Add more visual separation for the title of a search result island. */ -#search-results .search li > a:first-child { +#search-results .search li>a:first-child { font-weight: 600; font-size: 140%; } /* JavaScript documentation directives */ html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dt, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list) > dt { +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt { background-color: var(--admonition-note-background-color); border-color: var(--admonition-note-title-background-color); color: var(--admonition-note-color); @@ -541,10 +563,10 @@ html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not( width: 100%; } -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class > dt, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function > dt, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method > dt, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).attribute > dt { +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class>dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function>dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method>dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).attribute>dt { font-family: var(--monospace-font-family), serif; font-variant-ligatures: none; font-size: 90%; @@ -575,9 +597,9 @@ html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not( } html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-param, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt > em, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function dt > em, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method dt > em { +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt>em, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function dt>em, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method dt>em { color: var(--code-literal-color); font-style: normal; padding: 0 4px; @@ -587,7 +609,8 @@ html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not( font-style: normal; } -html.writer-html5 .rst-content dl:not(.docutils) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) > dt { +html.writer-html5 .rst-content dl:not(.docutils)>dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt { border-top-color: var(--highlight-background-emph-color); background: var(--highlight-background-color); } @@ -597,20 +620,21 @@ dl.simple dt { background: none !important; } -html.writer-html5 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) > dt { +html.writer-html5 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt { border-left-color: var(--highlight-background-emph-color); background: var(--highlight-background-color); } html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .sig-param, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt > .optional ~ em, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function dt > .optional ~ em, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method dt > .optional ~ em { +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt>.optional~em, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function dt>.optional~em, +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method dt>.optional~em { color: var(--highlight-number-color); font-style: italic; } -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt > em.property { +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).class dt>em.property { color: var(--highlight-keyword-color); } @@ -622,7 +646,7 @@ html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not( color: var(--link-color-visited); } -html.writer-html5 .rst-content dl.field-list > dd strong { +html.writer-html5 .rst-content dl.field-list>dd strong { font-family: var(--monospace-font-family), serif; font-variant-ligatures: none; } @@ -869,18 +893,18 @@ html.writer-html5 .rst-content table.docutils th { } /* Artificially increasing specificity to make it override theme.css. */ -html.writer-html5 .rst-content .wy-table-responsive > table td > p { +html.writer-html5 .rst-content .wy-table-responsive>table td>p { line-height: 1.425rem; } -html.writer-html5 .rst-content .wy-table-responsive > table th > p { +html.writer-html5 .rst-content .wy-table-responsive>table th>p { line-height: 1.425rem; font-size: .95rem; font-weight: 600; } -html.writer-html5 .rst-content .wy-table-responsive > table td > p tt.literal, -html.writer-html5 .rst-content .wy-table-responsive > table td > p code.literal { +html.writer-html5 .rst-content .wy-table-responsive>table td>p tt.literal, +html.writer-html5 .rst-content .wy-table-responsive>table td>p code.literal { font-size: .85rem; padding: 2px 5px; } @@ -948,111 +972,231 @@ code, background-color: var(--highlight-background-emph-color); } -.highlight .gh /* Generic.Heading */, -.highlight .gu /* Generic.Subheading */, -.highlight .go /* Generic.Output */, -.highlight .gt /* Generic.Traceback */ -{ +.highlight .gh +/* Generic.Heading */ +, +.highlight .gu +/* Generic.Subheading */ +, +.highlight .go +/* Generic.Output */ +, +.highlight .gt + +/* Generic.Traceback */ + { color: var(--highlight-default-color); } -.highlight .c /* Comment */, -.highlight .c1 /* Comment.Single */, -.highlight .cm /* Comment.Multiline */, -.highlight .cs /* Comment.Special */ -{ +.highlight .c +/* Comment */ +, +.highlight .c1 +/* Comment.Single */ +, +.highlight .cm +/* Comment.Multiline */ +, +.highlight .cs + +/* Comment.Special */ + { color: var(--highlight-comment-color); } -.highlight .bp /* Name.Builtin.Pseudo */, -.highlight .k /* Keyword */, -.highlight .kc /* Keyword.Constant */, -.highlight .kd /* Keyword.Declaration */, -.highlight .kn /* Keyword.Namespace */, -.highlight .kp /* Keyword.Pseudo */, -.highlight .kr /* Keyword.Reserved */, -.highlight .kt /* Keyword.Type */, -.highlight .ow /* Operator.Word */ -{ +.highlight .bp +/* Name.Builtin.Pseudo */ +, +.highlight .k +/* Keyword */ +, +.highlight .kc +/* Keyword.Constant */ +, +.highlight .kd +/* Keyword.Declaration */ +, +.highlight .kn +/* Keyword.Namespace */ +, +.highlight .kp +/* Keyword.Pseudo */ +, +.highlight .kr +/* Keyword.Reserved */ +, +.highlight .kt +/* Keyword.Type */ +, +.highlight .ow + +/* Operator.Word */ + { color: var(--highlight-keyword-color); } -.highlight .k-ControlFlow /* Keyword.ControlFlow */ -{ +.highlight .k-ControlFlow + +/* Keyword.ControlFlow */ + { color: var(--highlight-control-flow-keyword-color); } -.highlight .ch /* Comment.Hashbang */, -.highlight .cp /* Comment.Preproc */ -{ +.highlight .ch +/* Comment.Hashbang */ +, +.highlight .cp + +/* Comment.Preproc */ + { color: var(--highlight-keyword2-color); } -.highlight .m /* Literal.Number */, -.highlight .mf /* Literal.Number.Float */, -.highlight .mi /* Literal.Number.Integer */, -.highlight .il /* Literal.Number.Integer.Long */, -.highlight .mb /* Literal.Number.Bin */, -.highlight .mh /* Literal.Number.Hex */, -.highlight .mo /* Literal.Number.Oct */ -{ +.highlight .m +/* Literal.Number */ +, +.highlight .mf +/* Literal.Number.Float */ +, +.highlight .mi +/* Literal.Number.Integer */ +, +.highlight .il +/* Literal.Number.Integer.Long */ +, +.highlight .mb +/* Literal.Number.Bin */ +, +.highlight .mh +/* Literal.Number.Hex */ +, +.highlight .mo + +/* Literal.Number.Oct */ + { color: var(--highlight-number-color); } -.highlight .na /* Name.Attribute */, -.highlight .nd /* Name.Decorator */, -.highlight .ni /* Name.Entity */, -.highlight .nl /* Name.Label */ -{ +.highlight .na +/* Name.Attribute */ +, +.highlight .nd +/* Name.Decorator */ +, +.highlight .ni +/* Name.Entity */ +, +.highlight .nl + +/* Name.Label */ + { color: var(--highlight-decorator-color); } -.highlight .nb /* Name.Builtin */, -.highlight .ne /* Name.Exception */ -{ +.highlight .nb +/* Name.Builtin */ +, +.highlight .ne + +/* Name.Exception */ + { color: var(--highlight-type-color); } -.highlight .nc /* Name.Class */, -.highlight .nn /* Name.Namespace */, -.highlight .no /* Name.Constant */, -.highlight .nv /* Name.Variable */, -.highlight .vc /* Name.Variable.Class */, -.highlight .vg /* Name.Variable.Global */, -.highlight .vi /* Name.Variable.Instance */, -.highlight .vm /* Name.Variable.Magic */ -{ +.highlight .nc +/* Name.Class */ +, +.highlight .nn +/* Name.Namespace */ +, +.highlight .no +/* Name.Constant */ +, +.highlight .nv +/* Name.Variable */ +, +.highlight .vc +/* Name.Variable.Class */ +, +.highlight .vg +/* Name.Variable.Global */ +, +.highlight .vi +/* Name.Variable.Instance */ +, +.highlight .vm + +/* Name.Variable.Magic */ + { color: var(--highlight-type2-color); } -.highlight .nf /* Name.Function */, -.highlight .fm /* Name.Function.Magic */, -.highlight .nt /* Name.Tag */ -{ +.highlight .nf +/* Name.Function */ +, +.highlight .fm +/* Name.Function.Magic */ +, +.highlight .nt + +/* Name.Tag */ + { color: var(--highlight-function-color); } -.highlight .o /* Operator */, -.highlight .si /* Literal.String.Interpol */, -.highlight .sx /* Literal.String.Other */, -.highlight .sr /* Literal.String.Regex */, -.highlight .ss /* Literal.String.Symbol */ -{ +.highlight .o +/* Operator */ +, +.highlight .si +/* Literal.String.Interpol */ +, +.highlight .sx +/* Literal.String.Other */ +, +.highlight .sr +/* Literal.String.Regex */ +, +.highlight .ss + +/* Literal.String.Symbol */ + { color: var(--highlight-operator-color); } -.highlight .cpf /* Comment.PreprocFile */, -.highlight .s /* Literal.String */, -.highlight .s1 /* Literal.String.Single */, -.highlight .s2 /* Literal.String.Double */, -.highlight .sc /* Literal.String.Char */, -.highlight .se /* Literal.String.Escape */, -.highlight .sa /* Literal.String.Affix */, -.highlight .sb /* Literal.String.Backtick */, -.highlight .dl /* Literal.String.Delimiter */, -.highlight .sd /* Literal.String.Doc */, -.highlight .sh /* Literal.String.Heredoc */ -{ +.highlight .cpf +/* Comment.PreprocFile */ +, +.highlight .s +/* Literal.String */ +, +.highlight .s1 +/* Literal.String.Single */ +, +.highlight .s2 +/* Literal.String.Double */ +, +.highlight .sc +/* Literal.String.Char */ +, +.highlight .se +/* Literal.String.Escape */ +, +.highlight .sa +/* Literal.String.Affix */ +, +.highlight .sb +/* Literal.String.Backtick */ +, +.highlight .dl +/* Literal.String.Delimiter */ +, +.highlight .sd +/* Literal.String.Doc */ +, +.highlight .sh + +/* Literal.String.Heredoc */ + { color: var(--highlight-string-color); } @@ -1064,7 +1208,7 @@ code, margin-bottom: 12px; } -.rst-content .contribute > p { +.rst-content .contribute>p { margin-bottom: 0; } @@ -1155,9 +1299,10 @@ code, } /* Keyboard shortcuts tweaks */ -kbd, .kbd, -.rst-content :not(dl.option-list) > :not(dt):not(kbd):not(.kbd) > kbd, -.rst-content :not(dl.option-list) > :not(dt):not(kbd):not(.kbd) > .kbd { +kbd, +.kbd, +.rst-content :not(dl.option-list)> :not(dt):not(kbd):not(.kbd)>kbd, +.rst-content :not(dl.option-list)> :not(dt):not(kbd):not(.kbd)>.kbd { background-color: var(--kbd-background-color); border: 1px solid var(--kbd-outline-color); border-radius: 3px; @@ -1171,10 +1316,10 @@ kbd, .kbd, } /* Unset excessive styles for nested kbd tags. */ -kbd.compound > kbd, -kbd.compound > .kbd, -.kbd.compound > kbd, -.kbd.compound > .kbd { +kbd.compound>kbd, +kbd.compound>.kbd, +.kbd.compound>kbd, +.kbd.compound>.kbd { border: none; box-shadow: none; padding: 0; @@ -1193,16 +1338,16 @@ kbd.compound > .kbd, margin: 26px 0; } -.classref-descriptions-group > p.classref-property, -.classref-descriptions-group > p.classref-signal, -.classref-descriptions-group > p.classref-annotation, -.classref-descriptions-group > p.classref-themeproperty, -.classref-descriptions-group > p.classref-method, -.classref-descriptions-group > p.classref-constructor, -.classref-descriptions-group > p.classref-operator, -.classref-descriptions-group > p.classref-constant, -.classref-descriptions-group > p.classref-enumeration, -.classref-descriptions-group > p.classref-enumeration-constant { +.classref-descriptions-group>p.classref-property, +.classref-descriptions-group>p.classref-signal, +.classref-descriptions-group>p.classref-annotation, +.classref-descriptions-group>p.classref-themeproperty, +.classref-descriptions-group>p.classref-method, +.classref-descriptions-group>p.classref-constructor, +.classref-descriptions-group>p.classref-operator, +.classref-descriptions-group>p.classref-constant, +.classref-descriptions-group>p.classref-enumeration, +.classref-descriptions-group>p.classref-enumeration-constant { color: var(--classref-secondary-color); font-family: var(--monospace-font-family), serif; font-variant-ligatures: none; @@ -1215,68 +1360,68 @@ kbd.compound > .kbd, margin-bottom: 12px; } -p + .classref-constant { +p+.classref-constant { margin-top: 22px; } -.classref-descriptions-group > p.classref-enumeration-constant { +.classref-descriptions-group>p.classref-enumeration-constant { font-size: 100%; margin-top: 18px; margin-bottom: 14px; } -.classref-property > a, -.classref-signal > a, -.classref-annotation > a, -.classref-themeproperty > a, -.classref-method > a, -.classref-constructor > a, -.classref-operator > a, -.classref-constant > a, -.classref-enumeration > a { +.classref-property>a, +.classref-signal>a, +.classref-annotation>a, +.classref-themeproperty>a, +.classref-method>a, +.classref-constructor>a, +.classref-operator>a, +.classref-constant>a, +.classref-enumeration>a { opacity: 0.85; } -.classref-enumeration-constant > a { +.classref-enumeration-constant>a { opacity: 0.75; } -.classref-property > a:hover, -.classref-signal > a:hover, -.classref-annotation > a:hover, -.classref-themeproperty > a:hover, -.classref-method > a:hover, -.classref-constructor > a:hover, -.classref-operator > a:hover, -.classref-constant > a:hover, -.classref-enumeration > a:hover, -.classref-enumeration-constant > a:hover { +.classref-property>a:hover, +.classref-signal>a:hover, +.classref-annotation>a:hover, +.classref-themeproperty>a:hover, +.classref-method>a:hover, +.classref-constructor>a:hover, +.classref-operator>a:hover, +.classref-constant>a:hover, +.classref-enumeration>a:hover, +.classref-enumeration-constant>a:hover { opacity: 1; } -.classref-property > strong, -.classref-signal > strong, -.classref-annotation > strong, -.classref-themeproperty > strong, -.classref-method > strong, -.classref-constructor > strong, -.classref-operator > strong, -.classref-constant > strong, -.classref-enumeration > strong, -.classref-enumeration-constant > strong { +.classref-property>strong, +.classref-signal>strong, +.classref-annotation>strong, +.classref-themeproperty>strong, +.classref-method>strong, +.classref-constructor>strong, +.classref-operator>strong, +.classref-constant>strong, +.classref-enumeration>strong, +.classref-enumeration-constant>strong { color: var(--classref-primary-color); } -.classref-property > code.literal, -.classref-signal > code.literal, -.classref-annotation > code.literal, -.classref-themeproperty > code.literal, -.classref-method > code.literal, -.classref-constructor > code.literal, -.classref-operator > code.literal, -.classref-constant > code.literal, -.classref-enumeration > code.literal, -.classref-enumeration-constant > code.literal { +.classref-property>code.literal, +.classref-signal>code.literal, +.classref-annotation>code.literal, +.classref-themeproperty>code.literal, +.classref-method>code.literal, +.classref-constructor>code.literal, +.classref-operator>code.literal, +.classref-constant>code.literal, +.classref-enumeration>code.literal, +.classref-enumeration-constant>code.literal { background-color: transparent; border: none; padding: 0; @@ -1284,8 +1429,8 @@ p + .classref-constant { font-size: 90% } -.classref-constant > code.literal, -.classref-enumeration-constant > code.literal { +.classref-constant>code.literal, +.classref-enumeration-constant>code.literal { color: var(--classref-setget-color); font-weight: 400; } @@ -1297,7 +1442,7 @@ p + .classref-constant { margin-bottom: 22px; } -.classref-property-setget > li { +.classref-property-setget>li { line-height: 22px; } @@ -1308,19 +1453,19 @@ p + .classref-constant { line-height: 22px; } -.classref-property-setget p > a { +.classref-property-setget p>a { opacity: 0.75; } -.classref-property-setget p > a:hover { +.classref-property-setget p>a:hover { opacity: 1; } -.classref-property-setget p > strong { +.classref-property-setget p>strong { color: var(--classref-setget-color); } -.classref-property-setget p > code { +.classref-property-setget p>code { background-color: transparent; border: none; padding: 0; @@ -1335,17 +1480,17 @@ p + .classref-constant { margin-left: 48px; } -.classref-descriptions-group > h2, -.classref-descriptions-group > hr { +.classref-descriptions-group>h2, +.classref-descriptions-group>hr { margin-left: -24px; } -#enumerations.classref-descriptions-group > h2, -#enumerations.classref-descriptions-group > hr { +#enumerations.classref-descriptions-group>h2, +#enumerations.classref-descriptions-group>hr { margin-left: -48px; } -.classref-descriptions-group > p { +.classref-descriptions-group>p { margin-bottom: 12px; } @@ -1369,7 +1514,7 @@ p + .classref-constant { margin-bottom: 36px; } -.classref-reftable-group .wy-table-responsive > table { +.classref-reftable-group .wy-table-responsive>table { width: 100%; } @@ -1394,13 +1539,13 @@ p + .classref-constant { opacity: var(--logo-opacity); } -.wy-side-nav-search > a { +.wy-side-nav-search>a { padding: 0; margin-bottom: 0.404em; margin-top: 0.404em; } -.wy-side-nav-search > a img.logo { +.wy-side-nav-search>a img.logo { /* Fixed size to prevent reflows and support hiDPI displays */ /* A 5 pixel margin is added on each side. The logo itself displays at 200×200 at 100% scaling. */ width: 270px; @@ -1418,6 +1563,7 @@ p + .classref-constant { } @media only screen and (min-width: 769px) { + /* Simulate a drop shadow that only affects the bottom edge */ /* This is used to indicate the search bar is fixed */ .wy-side-nav-search.fixed-and-scrolled::after { @@ -1432,13 +1578,13 @@ p + .classref-constant { } } -.wy-side-nav-search > a:hover, -.wy-side-nav-search .wy-dropdown > a:hover { +.wy-side-nav-search>a:hover, +.wy-side-nav-search .wy-dropdown>a:hover { background-color: var(--navbar-background-color-hover); } -.wy-side-nav-search > a:active, -.wy-side-nav-search .wy-dropdown > a:active { +.wy-side-nav-search>a:active, +.wy-side-nav-search .wy-dropdown>a:active { background-color: var(--navbar-background-color-active); } @@ -1463,7 +1609,7 @@ p + .classref-constant { } /* Version branch label below the logo */ -.wy-side-nav-search > div.version { +.wy-side-nav-search>div.version { color: var(--navbar-dimmed-color); font-size: 14px; opacity: 0.9; @@ -1508,23 +1654,23 @@ p + .classref-constant { background-color: var(--navbar-current-background-color); } -.wy-menu-vertical li > a { +.wy-menu-vertical li>a { color: var(--navbar-level-1-color); font-size: 92%; line-height: 20px; padding: .4045em 1.618em; } -.wy-menu-vertical li > a:hover { +.wy-menu-vertical li>a:hover { background-color: var(--navbar-background-color-hover); color: var(--navbar-level-1-color); } -.wy-menu-vertical li > a:active { +.wy-menu-vertical li>a:active { background-color: var(--navbar-background-color-active); } -.wy-menu-vertical li > a button.toctree-expand { +.wy-menu-vertical li>a button.toctree-expand { color: var(--navbar-expand-base-color) !important; opacity: 0.9; margin-right: 8px; @@ -1532,26 +1678,27 @@ p + .classref-constant { /* Make the expand icon a bit easier to hit. */ position: relative; width: 12px; - min-width: 12px; /* Forces the size to stay this way in the flexbox model. */ + min-width: 12px; + /* Forces the size to stay this way in the flexbox model. */ height: 18px; } -.wy-menu-vertical li.current > a button.toctree-expand { +.wy-menu-vertical li.current>a button.toctree-expand { color: var(--navbar-current-color) !important; } -.wy-menu-vertical li > a:hover button.toctree-expand { +.wy-menu-vertical li>a:hover button.toctree-expand { color: var(--navbar-expand-hover-color) !important; opacity: 1; } -.wy-menu-vertical li > a:active button.toctree-expand { +.wy-menu-vertical li>a:active button.toctree-expand { color: var(--navbar-expand-active-color) !important; opacity: 1; } /* Make the expand icon a bit easier to hit. */ -.wy-menu-vertical li > a button.toctree-expand:before { +.wy-menu-vertical li>a button.toctree-expand:before { position: absolute; top: -2px; left: -6px; @@ -1560,8 +1707,8 @@ p + .classref-constant { padding: 6px; } -.wy-menu-vertical li.current > a, -.wy-menu-vertical li.toctree-l2.current > a { +.wy-menu-vertical li.current>a, +.wy-menu-vertical li.toctree-l2.current>a { background-color: var(--navbar-current-background-color-hover); border-bottom: 2px solid var(--navbar-current-background-color); color: var(--navbar-current-color); @@ -1572,68 +1719,68 @@ p + .classref-constant { display: flex; } -.wy-menu-vertical li.current > a:hover, -.wy-menu-vertical li.toctree-l2.current > a:hover { +.wy-menu-vertical li.current>a:hover, +.wy-menu-vertical li.toctree-l2.current>a:hover { background-color: var(--navbar-current-background-color-hover); } -.wy-menu-vertical li.current > a:active, -.wy-menu-vertical li.toctree-l2.current > a:active { +.wy-menu-vertical li.current>a:active, +.wy-menu-vertical li.toctree-l2.current>a:active { background-color: var(--navbar-current-background-color-active); } /* Slightly adjust first level items. */ -.wy-menu-vertical li.toctree-l1 > a, -.wy-menu-vertical li.toctree-l1.current > a { +.wy-menu-vertical li.toctree-l1>a, +.wy-menu-vertical li.toctree-l1.current>a { border: none; padding: .4045em 1.918em; } -.wy-menu-vertical li.toctree-l1.current > a { +.wy-menu-vertical li.toctree-l1.current>a { border-bottom: 2px solid var(--navbar-current-background-color); } /* Override styling for children of the current item. */ -.wy-menu-vertical li.current li > a, -.wy-menu-vertical li.toctree-l2.current li > a, -.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a, -.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a { +.wy-menu-vertical li.current li>a, +.wy-menu-vertical li.toctree-l2.current li>a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4>a { background-color: var(--navbar-current-background-color); border: none; border-bottom: 2px solid var(--navbar-current-background-color); color: var(--navbar-level-2-color); } -.wy-menu-vertical li.current li > a:hover, -.wy-menu-vertical li.toctree-l2.current li > a:hover, -.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover, -.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a:hover { +.wy-menu-vertical li.current li>a:hover, +.wy-menu-vertical li.toctree-l2.current li>a:hover, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a:hover, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4>a:hover { background-color: var(--navbar-current-background-color-hover); } -.wy-menu-vertical li.current li > a:active, -.wy-menu-vertical li.toctree-l2.current li > a:active, -.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:active, -.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a:active { +.wy-menu-vertical li.current li>a:active, +.wy-menu-vertical li.toctree-l2.current li>a:active, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a:active, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4>a:active { background-color: var(--navbar-current-background-color-active); } -.wy-menu-vertical li.toctree-l2.current li > a, -.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a, -.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a { +.wy-menu-vertical li.toctree-l2.current li>a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4>a { color: var(--navbar-level-3-color); } -.wy-menu-vertical li.toctree-l2.current li > a:hover, -.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover, -.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a:hover { +.wy-menu-vertical li.toctree-l2.current li>a:hover, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a:hover, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4>a:hover { color: var(--navbar-level-1-color); } -.wy-menu-vertical li.current li.current > a, -.wy-menu-vertical li.toctree-l2.current li.current > a, -.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current > a, -.wy-menu-vertical li.toctree-l2.current li.toctree-l4.current > a { +.wy-menu-vertical li.current li.current>a, +.wy-menu-vertical li.toctree-l2.current li.current>a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4.current>a { color: var(--navbar-current-color); font-weight: 600; } @@ -1687,7 +1834,7 @@ p + .classref-constant { color: var(--navbar-heading-color); } -.rst-versions .rst-other-versions dl + dl { +.rst-versions .rst-other-versions dl+dl { margin-top: 4px; } @@ -1837,11 +1984,11 @@ p + .classref-constant { transform-origin: 2px 16px; } -.wy-menu-vertical p.caption + ul { +.wy-menu-vertical p.caption+ul { display: none; } -.wy-menu-vertical p.caption + ul.active { +.wy-menu-vertical p.caption+ul.active { display: block; } @@ -1886,7 +2033,11 @@ p + .classref-constant { } /* Allow :abbr: tags' content to be displayed on mobile platforms by tapping the word */ -@media (hover: none), (hover: on-demand), (-moz-touch-enabled: 1), (pointer: coarse) { +@media (hover: none), +(hover: on-demand), +(-moz-touch-enabled: 1), +(pointer: coarse) { + /* Do not enable on desktop platforms to avoid doubling the tooltip */ abbr[title] { position: relative; @@ -1909,4 +2060,4 @@ p + .classref-constant { font-size: 14px; padding: 3px 5px; } -} +} \ No newline at end of file diff --git a/docs/getting_started/create_window.rst b/docs/getting_started/create_window.rst index 0b19486..e36d3c0 100644 --- a/docs/getting_started/create_window.rst +++ b/docs/getting_started/create_window.rst @@ -49,4 +49,4 @@ Let's break down the key components that make this program function: Think of it as flipping the pages of a book—ensuring smooth, sequential updates for the user. This template establishes a foundation for more advanced game logic and rendering. -In-depth tutorials on the next page cover the more intricate aspects of the Kraken Engine. +In-depth tutorials in the next section cover the more intricate aspects of the Kraken Engine. diff --git a/docs/index.rst b/docs/index.rst index 61ae93c..34ec623 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -44,7 +44,8 @@ We’re excited to see how you push the boundaries of creativity with the Kraken :maxdepth: 1 :caption: Manual - tutorials/index + manual/things_to_know + manual/tutorials .. toctree:: :hidden: @@ -69,6 +70,7 @@ We’re excited to see how you push the boundaries of creativity with the Kraken reference/constants reference/controller reference/draw + reference/input reference/key reference/math reference/mouse diff --git a/docs/manual/things_to_know.rst b/docs/manual/things_to_know.rst new file mode 100644 index 0000000..2250cd0 --- /dev/null +++ b/docs/manual/things_to_know.rst @@ -0,0 +1,57 @@ +Things To Know +============== + +This section contains information that you should be aware of when using Kraken Engine. + +Constant Prefixes +~~~~~~~~~~~~~~~~~ + +When working with keyboard, mouse, and controller input, you will notice that the constants for the keys and buttons have prefixes. +The prefixes are as follows: + +- ``K_`` for keyboard keycode constants +- ``S_`` for keyboard scancode constants +- ``M_`` for mouse button constants +- ``C_`` for controller button constants + +For example, to check if the ``A`` button on a controller is pressed, you would use the following code: + +.. code-block:: cpp + + if (kn::controller::isPressed(kn::C_A)) { + std::cout << "A button is pressed!" << std::endl; + } + +Keycode VS Scancode +~~~~~~~~~~~~~~~~~~~ + +Kraken Engine uses keycodes and scancodes to represent keyboard input. +Keycodes are the character that the key represents, while scancodes are the physical location of the key on the keyboard. +For example, the ``A`` key on a QWERTY keyboard has a keycode of ``K_a`` and a scancode of ``S_a``. + +If you are unsure which one to use, it is recommended to use keycodes in the event loop and scancodes for gameplay input. + +Here is a comparison of keycodes and scancodes for different scenarios: + +.. list-table:: + :widths: 25 50 50 + :header-rows: 1 + + * - Scenario + - Keycode (``K_``) + - Scancode (``S_``) + * - Menu navigation + - ✅ Layout-specific (intuitive keys) + - ❌ Might mismatch user expectations + * - Text input + - ✅ Matches user's layout + - ❌ Breaks for non-QWERTY layouts + * - Gameplay movement + - ❌ Layout-dependent inconsistency + - ✅ Consistent across layouts + * - Debug tools + - ❌ User layout might vary + - ✅ Always maps to physical key + + +.. note:: This page is a work in progress and will be updated as more information becomes available. \ No newline at end of file diff --git a/docs/manual/tutorials.rst b/docs/manual/tutorials.rst new file mode 100644 index 0000000..07e8b71 --- /dev/null +++ b/docs/manual/tutorials.rst @@ -0,0 +1,12 @@ +Tutorials +========= + +.. container:: tutorial-image-container + + .. image:: https://img.youtube.com/vi/WxGaBL7S3X8/maxresdefault.jpg + :alt: Get Started with Kraken Engine + :target: https://youtu.be/WxGaBL7S3X8 + + .. image:: https://img.youtube.com/vi/GSsHmFUB-yw/maxresdefault.jpg + :alt: Introduction to the Meson Build System + :target: https://youtu.be/GSsHmFUB-yw diff --git a/docs/reference/animation_controller.rst b/docs/reference/animation_controller.rst index 9d824a0..7b82289 100644 --- a/docs/reference/animation_controller.rst +++ b/docs/reference/animation_controller.rst @@ -1,6 +1,10 @@ AnimationController =================== +.. warning:: + + This class is still in development and is subject to change at any time. + Description ----------- diff --git a/docs/reference/controller.rst b/docs/reference/controller.rst index 418053f..bd10985 100644 --- a/docs/reference/controller.rst +++ b/docs/reference/controller.rst @@ -1,6 +1,10 @@ controller ========== +.. warning:: + + This namespace is still in development and is subject to change at any time. + Description ----------- @@ -14,7 +18,7 @@ Usage .. code-block:: cpp // Get the vector of the left joystick - kn::Vec2 leftJoystick = kn::controller::getLeftJoystick(); + kn::math::Vec2 leftJoystick = kn::controller::getLeftJoystick(); // Change the joysticks' dead zones kn::controller::setDeadZone(0.2f); @@ -24,6 +28,11 @@ Usage // Do something } + // Check if the A (bottom) button is pressed + if (kn::controller::isPressed(kn::C_A)) { + // Do something + } + Functions --------- @@ -35,6 +44,10 @@ Functions .. doxygenfunction:: kn::controller::getRightTrigger +.. doxygenfunction:: kn::controller::isPressed + .. doxygenfunction:: kn::controller::setDeadZone .. doxygenfunction:: kn::controller::getDeadZone + +.. note:: Functions for getting controller buttons that were just pressed or just released are planned for the future. \ No newline at end of file diff --git a/docs/reference/draw.rst b/docs/reference/draw.rst index 2018e40..0bc6d38 100644 --- a/docs/reference/draw.rst +++ b/docs/reference/draw.rst @@ -1,6 +1,31 @@ draw ==== +Description +----------- + +The **draw** namespace provides functions to draw basic shapes and lines on the screen. + +Usage +----- + +.. code-block:: cpp + + // Draw a rectangle at position (50, 50) with size (16, 16). + kn::draw::rect({50, 50, 16, 16}, kn::color::RED); + + // Draw a line from (50, 50) to (100, 100). + kn::draw::line({50, 50}, {100, 100}, kn::color::GREEN); + + // Draw a point at position (50, 50). + kn::draw::point({50, 50}, kn::color::BLUE); + + // Draw a circle at position (50, 50) with radius 16. + kn::draw::circle({50, 50}, 16, kn::color::YELLOW); + +Functions +--------- + .. doxygenfunction:: kn::draw::rect .. doxygenfunction:: kn::draw::line diff --git a/docs/reference/font.rst b/docs/reference/font.rst index b21ddf2..184f267 100644 --- a/docs/reference/font.rst +++ b/docs/reference/font.rst @@ -15,7 +15,7 @@ Usage kn::Font font("assets/font.ttf", 16); // Render a texture containing the text "Hello, World!" in white with no anti-aliasing. - const kn::Texture text = font.render("Hello, World!", false, {255, 255, 255}); + const kn::Texture text = font.render("Hello, World!", false, kn::color::WHITE); // Draw the text texture at position (50, 50). kn::window::blit(text, {50, 50}); diff --git a/docs/reference/input.rst b/docs/reference/input.rst new file mode 100644 index 0000000..397dcd9 --- /dev/null +++ b/docs/reference/input.rst @@ -0,0 +1,86 @@ +input +===== + +.. warning:: + + This namespace is still in development and is subject to change at any time. + +Description +----------- + +The **input** namespace lets you create binds for different kinds of input. + +Usage +----- + +.. code-block:: cpp + + /* Bind the 'left' action to: + - The 'a' key + - The left arrow key + - The left stick (negative direction) on a controller + */ + kn::input::bind( + "left", + { + kn::InputAction(kn::S_a), + kn::InputAction(kn::S_LEFT), + kn::InputAction(kn::C_AXIS_LEFTX, false), + } + ); + + /* Bind the 'right' action to: + - The 'd' key + - The right arrow key + - The left stick (positive direction) on a controller + */ + kn::input::bind( + "right", + { + kn::InputAction(kn::S_d), + kn::InputAction(kn::S_RIGHT), + kn::InputAction(kn::C_AXIS_LEFTX, true), + } + ); + + /* Bind the 'jump' action to: + - The space key + - The 'a' button on a controller + */ + kn::input::bind( + "jump", + { + kn::InputAction(kn::S_SPACE), + kn::InputAction(kn::C_A), + } + ); + + // Check if the 'jump' action is pressed + if (onGround) { + if (kn::input::isPressed("jump")) { + onGround = false; + // Handle jump action + } + } + + // Get the direction of the 'left' and 'right' actions + const double xDirection = kn::input::getDirection("left", "right").x; + +Members +------- + +.. doxygenstruct:: kn::InputAction + :members: + +Functions +--------- + +.. doxygenfunction:: kn::input::bind + +.. doxygenfunction:: kn::input::unbind + +.. doxygenfunction:: kn::input::getDirection + +.. doxygenfunction:: kn::input::isPressed + +.. note:: Functions for getting input actions that were just pressed or just released are planned for the future. \ No newline at end of file diff --git a/docs/reference/key.rst b/docs/reference/key.rst index cc09ff9..15bac84 100644 --- a/docs/reference/key.rst +++ b/docs/reference/key.rst @@ -5,24 +5,24 @@ Description ----------- The **key** namespace contains functions to handle input from the keyboard. -The two types of key codes are `scancodes` and `keycodes`. -Scancodes are the physical location of the key on the keyboard. -Keycodes are the character that the key represents. -For example, 'W' has a scancode of ``kn::S_w`` and a keycode of ``kn::K_w``. - -.. note:: A function similar to the removed ``kn::input::getVector`` will eventually be added to this namespace. +If you aren't familiar with the usage of keycodes and scancodes, please refer to the `Things To Know <../manual/things_to_know.html>`_ section. Usage ----- .. code-block:: cpp + // Get all currently pressed keys. + const auto* keys = kn::key::getPressed(); + // Check if the 'W' key is pressed. - if (kn::key::isPressed(kn::S_w)) { + if (keys[kn::S_w]) { // Handle 'W' key press. } Functions --------- -.. doxygenfunction:: kn::key::isPressed \ No newline at end of file +.. doxygenfunction:: kn::key::getPressed + +.. note:: Functions for getting keys that were just pressed or just released are planned for the future. \ No newline at end of file diff --git a/docs/reference/math.rst b/docs/reference/math.rst index 3747c71..1117f71 100644 --- a/docs/reference/math.rst +++ b/docs/reference/math.rst @@ -1,6 +1,16 @@ math ==== +Description +----------- + +This module provides a set of mathematical functions and classes for working with 2D vectors and angles. +In case you're not familiar with the concept of a vector, it's a mathematical object that has both a magnitude and a direction. +You may read more on the subject `here `_. + +Members +------- + .. doxygenstruct:: kn::math::PolarCoordinate :members: :undoc-members: @@ -8,9 +18,8 @@ math .. doxygenclass:: kn::math::Vec2 :members: -.. doxygenfunction:: kn::math::clampVec - -.. doxygenfunction:: kn::math::lerpVec +Functions +--------- .. doxygenfunction:: kn::math::scaleToLength @@ -18,6 +27,10 @@ math .. doxygenfunction:: kn::math::normalize +.. doxygenfunction:: kn::math::clampVec + +.. doxygenfunction:: kn::math::lerpVec + .. doxygenfunction:: kn::math::lerp .. doxygenfunction:: kn::math::remap @@ -30,6 +43,4 @@ math .. doxygenfunction:: kn::math::cross -.. doxygenfunction:: kn::math::angleBetween - -.. doxygenfunction:: kn::math::angleOfDifference \ No newline at end of file +.. doxygenfunction:: kn::math::angleBetween \ No newline at end of file diff --git a/docs/reference/mouse.rst b/docs/reference/mouse.rst index c51ce2d..ba30a9a 100644 --- a/docs/reference/mouse.rst +++ b/docs/reference/mouse.rst @@ -11,18 +11,21 @@ Usage .. code-block:: cpp - // Check if the left mouse button is pressed. - if (kn::mouse::isPressed(kn::BUTTON_LEFT)) { + // Check if the user left clicked. + const auto mousePressed = kn::mouse::getPressed(); + if (mousePressed == kn::MOUSE_LEFT) { // Handle left mouse button press. } // Get the mouse position and draw a circle at that position. kn::math::Vec2 mousePos = kn::mouse::getPos(); - kn::draw::circle(mousePos, 10, {255, 0, 0}); + kn::draw::circle(mousePos, 10, kn::color::RED); Functions --------- .. doxygenfunction:: kn::mouse::getPos -.. doxygenfunction:: kn::mouse::isPressed \ No newline at end of file +.. doxygenfunction:: kn::mouse::getPressed + +.. note:: Functions for getting mouse buttons that were just pressed or just released are planned for the future. \ No newline at end of file diff --git a/docs/reference/rect.rst b/docs/reference/rect.rst index 348557a..6aa3cb2 100644 --- a/docs/reference/rect.rst +++ b/docs/reference/rect.rst @@ -1,6 +1,10 @@ Rect ==== +.. warning:: + + This class may undergo changes in the near future. + Description ----------- diff --git a/docs/reference/texture.rst b/docs/reference/texture.rst index 95a8904..5a8e496 100644 --- a/docs/reference/texture.rst +++ b/docs/reference/texture.rst @@ -23,7 +23,7 @@ Usage imageTexture.angle = 30.0; // Create a 16x16 red texture. - kn::Texture colorTexture({16, 16}, {255, 0, 0}); + kn::Texture colorTexture({16, 16}, kn::color::RED); // Draw the textures. kn::window::blit(imageTexture, {50, 50}); diff --git a/docs/reference/window.rst b/docs/reference/window.rst index 9632772..29d7c79 100644 --- a/docs/reference/window.rst +++ b/docs/reference/window.rst @@ -1,6 +1,20 @@ window ====== +Description +----------- + +The window namespace provides functions to create and manage a window. +It provides methods to draw onto the screen, get input events, and manage the window's properties. + +You can find an example of window usage in the `Creating a Window <../getting_started/create_window.html>`_ guide. + +Variables +--------- + .. doxygenvariable:: kn::camera +Functions +--------- + .. doxygennamespace:: kn::window \ No newline at end of file diff --git a/docs/tutorials/index.rst b/docs/tutorials/index.rst deleted file mode 100644 index 3e916f8..0000000 --- a/docs/tutorials/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -Tutorials -========= - -.. image:: https://img.youtube.com/vi/WxGaBL7S3X8/maxresdefault.jpg - :alt: Get Started with Kraken Engine - :target: https://www.youtube.com/watch?v=WxGaBL7S3X8 - :align: center - :width: 600px diff --git a/example/main.cpp b/example/main.cpp index 1daf011..5f7f744 100644 --- a/example/main.cpp +++ b/example/main.cpp @@ -8,6 +8,32 @@ int main() kn::time::Clock clock; kn::camera = {-32, -26}; + constexpr kn::Color bgColor = {21, 18, 37, 255}; + + kn::input::bind( + "left", + { + kn::InputAction(kn::S_a), + kn::InputAction(kn::S_LEFT), + kn::InputAction(kn::C_AXIS_LEFTX, false), + } + ); + kn::input::bind( + "right", + { + kn::InputAction(kn::S_d), + kn::InputAction(kn::S_RIGHT), + kn::InputAction(kn::C_AXIS_LEFTX, true), + } + ); + kn::input::bind( + "jump", + { + kn::InputAction(kn::S_SPACE), + kn::InputAction(kn::C_A), + } + ); + const kn::TileMap tileMap("../example/assets/room.tmx"); Player player(tileMap); @@ -18,12 +44,10 @@ int main() const double dt = clock.tick() / 1000.0; while (kn::window::pollEvent(event)) - { if (event.type == kn::KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE) kn::window::close(); - } - kn::window::clear({21, 18, 37}); + kn::window::clear(bgColor); tileMap.drawMap(); player.update(dt); diff --git a/example/src/player.cpp b/example/src/player.cpp index c4e6686..c2e88f7 100644 --- a/example/src/player.cpp +++ b/example/src/player.cpp @@ -1,4 +1,5 @@ -#include "include/Player.hpp" +#include "Player.hpp" +#include #define AxisX 0 #define AxisY 1 @@ -16,23 +17,23 @@ void Player::update(const double dt) { if (onGround) { - if (kn::key::isPressed(kn::S_SPACE)) + if (kn::input::isPressed("jump")) { velocity.y = -200; onGround = false; } } else - velocity.y += 980.0 * dt; + velocity.y += 980.7 * dt; - const int xDir = kn::key::isPressed(kn::S_d) - kn::key::isPressed(kn::S_a); - if (xDir != 0) + const double xDir = kn::input::getDirection("left", "right").x; + if (xDir != 0.0) { animController.setAnim("walk"); - if (xDir > 0) + if (xDir > 0.0) facingRight = true; - else if (xDir < 0) + else if (xDir < 0.0) facingRight = false; } else @@ -47,7 +48,7 @@ void Player::update(const double dt) for (const auto& tile : interactables) if (rect.collideRect(tile.collider)) - kn::draw::rect(tile.rect, {255, 255, 0}, 1); + kn::draw::rect(tile.rect, kn::color::YELLOW, 1); const kn::Frame frame = animController.nextFrame(dt); diff --git a/include/AnimationController.hpp b/include/AnimationController.hpp index aa20b3c..871a963 100644 --- a/include/AnimationController.hpp +++ b/include/AnimationController.hpp @@ -47,7 +47,7 @@ class AnimationController final * @param frameSize The size of each frame in the sprite sheet. * @param fps The frame rate of the animation. * - * @return true if the setup was successful, false otherwise. + * @return ``true`` if the setup was successful, ``false`` otherwise. */ [[maybe_unused]] bool addAnim(const std::string& name, const std::string& filePath, const math::Vec2& frameSize, int fps); @@ -64,7 +64,7 @@ class AnimationController final * * @param name The name of an added animation. * - * @return true if the animation was successfully changed, false otherwise. + * @return ``true`` if the animation was successfully changed, ``false`` otherwise. */ [[maybe_unused]] bool setAnim(const std::string& name); @@ -88,7 +88,7 @@ class AnimationController final /** * @brief Check if the current animation playing is finished. * - * @return true if the animation is finished, false otherwise. + * @return ``true`` if the animation is finished, ``false`` otherwise. */ [[nodiscard]] bool isFinished(); @@ -97,7 +97,12 @@ class AnimationController final * * @return The name of the current animation. */ - [[nodiscard]] const std::string& getCurrentAnim() const { return m_currAnim; } + [[nodiscard]] const std::string& getCurrentAnim() const; + + /** + * @brief Rewind the currently playing animation to the beginning. + */ + void rewind(); /** * @brief Pause the animation. diff --git a/include/Constants.hpp b/include/Constants.hpp index b31f607..0f033f0 100644 --- a/include/Constants.hpp +++ b/include/Constants.hpp @@ -4,60 +4,88 @@ namespace kn { -typedef SDL_Scancode KEYS; +typedef SDL_Scancode Scancode; +typedef SDL_Keycode Keycode; +typedef SDL_GameControllerButton ControllerButton; +typedef SDL_GameControllerAxis ControllerAxis; typedef SDL_Event Event; typedef SDL_Color Color; -constexpr SDL_Scancode S_0 = SDL_SCANCODE_0; -constexpr SDL_Scancode S_1 = SDL_SCANCODE_1; -constexpr SDL_Scancode S_2 = SDL_SCANCODE_2; -constexpr SDL_Scancode S_3 = SDL_SCANCODE_3; -constexpr SDL_Scancode S_4 = SDL_SCANCODE_4; -constexpr SDL_Scancode S_5 = SDL_SCANCODE_5; -constexpr SDL_Scancode S_6 = SDL_SCANCODE_6; -constexpr SDL_Scancode S_7 = SDL_SCANCODE_7; -constexpr SDL_Scancode S_8 = SDL_SCANCODE_8; -constexpr SDL_Scancode S_9 = SDL_SCANCODE_9; -constexpr SDL_Scancode S_a = SDL_SCANCODE_A; -constexpr SDL_Scancode S_b = SDL_SCANCODE_B; -constexpr SDL_Scancode S_c = SDL_SCANCODE_C; -constexpr SDL_Scancode S_d = SDL_SCANCODE_D; -constexpr SDL_Scancode S_e = SDL_SCANCODE_E; -constexpr SDL_Scancode S_f = SDL_SCANCODE_F; -constexpr SDL_Scancode S_g = SDL_SCANCODE_G; -constexpr SDL_Scancode S_h = SDL_SCANCODE_H; -constexpr SDL_Scancode S_i = SDL_SCANCODE_I; -constexpr SDL_Scancode S_j = SDL_SCANCODE_J; -constexpr SDL_Scancode S_k = SDL_SCANCODE_K; -constexpr SDL_Scancode S_l = SDL_SCANCODE_L; -constexpr SDL_Scancode S_m = SDL_SCANCODE_M; -constexpr SDL_Scancode S_n = SDL_SCANCODE_N; -constexpr SDL_Scancode S_o = SDL_SCANCODE_O; -constexpr SDL_Scancode S_p = SDL_SCANCODE_P; -constexpr SDL_Scancode S_q = SDL_SCANCODE_Q; -constexpr SDL_Scancode S_r = SDL_SCANCODE_R; -constexpr SDL_Scancode S_s = SDL_SCANCODE_S; -constexpr SDL_Scancode S_t = SDL_SCANCODE_T; -constexpr SDL_Scancode S_u = SDL_SCANCODE_U; -constexpr SDL_Scancode S_v = SDL_SCANCODE_V; -constexpr SDL_Scancode S_w = SDL_SCANCODE_W; -constexpr SDL_Scancode S_x = SDL_SCANCODE_X; -constexpr SDL_Scancode S_y = SDL_SCANCODE_Y; -constexpr SDL_Scancode S_z = SDL_SCANCODE_Z; -constexpr SDL_Scancode S_DOWN = SDL_SCANCODE_DOWN; -constexpr SDL_Scancode S_LEFT = SDL_SCANCODE_LEFT; -constexpr SDL_Scancode S_RIGHT = SDL_SCANCODE_RIGHT; -constexpr SDL_Scancode S_UP = SDL_SCANCODE_UP; -constexpr SDL_Scancode S_LALT = SDL_SCANCODE_LALT; -constexpr SDL_Scancode S_LCTRL = SDL_SCANCODE_LCTRL; -constexpr SDL_Scancode S_LSHIFT = SDL_SCANCODE_LSHIFT; -constexpr SDL_Scancode S_RALT = SDL_SCANCODE_RALT; -constexpr SDL_Scancode S_RCTRL = SDL_SCANCODE_RCTRL; -constexpr SDL_Scancode S_RETURN = SDL_SCANCODE_RETURN; -constexpr SDL_Scancode S_RSHIFT = SDL_SCANCODE_RSHIFT; -constexpr SDL_Scancode S_SPACE = SDL_SCANCODE_SPACE; -constexpr SDL_Scancode S_TAB = SDL_SCANCODE_TAB; +// Predefined colors +namespace color +{ +constexpr Color BLACK = {0, 0, 0, 255}; +constexpr Color WHITE = {255, 255, 255, 255}; +constexpr Color RED = {255, 0, 0, 255}; +constexpr Color GREEN = {0, 255, 0, 255}; +constexpr Color BLUE = {0, 0, 255, 255}; +constexpr Color YELLOW = {255, 255, 0, 255}; +constexpr Color MAGENTA = {255, 0, 255, 255}; +constexpr Color CYAN = {0, 255, 255, 255}; +constexpr Color GRAY = {128, 128, 128, 255}; +constexpr Color DARK_GRAY = {64, 64, 64, 255}; +constexpr Color LIGHT_GRAY = {192, 192, 192, 255}; +constexpr Color ORANGE = {255, 165, 0, 255}; +constexpr Color BROWN = {139, 69, 19, 255}; +constexpr Color PINK = {255, 192, 203, 255}; +constexpr Color PURPLE = {128, 0, 128, 255}; +constexpr Color NAVY = {0, 0, 128, 255}; +constexpr Color TEAL = {0, 128, 128, 255}; +constexpr Color OLIVE = {128, 128, 0, 255}; +} // namespace color + +// Scancodes +constexpr Scancode S_0 = SDL_SCANCODE_0; +constexpr Scancode S_1 = SDL_SCANCODE_1; +constexpr Scancode S_2 = SDL_SCANCODE_2; +constexpr Scancode S_3 = SDL_SCANCODE_3; +constexpr Scancode S_4 = SDL_SCANCODE_4; +constexpr Scancode S_5 = SDL_SCANCODE_5; +constexpr Scancode S_6 = SDL_SCANCODE_6; +constexpr Scancode S_7 = SDL_SCANCODE_7; +constexpr Scancode S_8 = SDL_SCANCODE_8; +constexpr Scancode S_9 = SDL_SCANCODE_9; +constexpr Scancode S_a = SDL_SCANCODE_A; +constexpr Scancode S_b = SDL_SCANCODE_B; +constexpr Scancode S_c = SDL_SCANCODE_C; +constexpr Scancode S_d = SDL_SCANCODE_D; +constexpr Scancode S_e = SDL_SCANCODE_E; +constexpr Scancode S_f = SDL_SCANCODE_F; +constexpr Scancode S_g = SDL_SCANCODE_G; +constexpr Scancode S_h = SDL_SCANCODE_H; +constexpr Scancode S_i = SDL_SCANCODE_I; +constexpr Scancode S_j = SDL_SCANCODE_J; +constexpr Scancode S_k = SDL_SCANCODE_K; +constexpr Scancode S_l = SDL_SCANCODE_L; +constexpr Scancode S_m = SDL_SCANCODE_M; +constexpr Scancode S_n = SDL_SCANCODE_N; +constexpr Scancode S_o = SDL_SCANCODE_O; +constexpr Scancode S_p = SDL_SCANCODE_P; +constexpr Scancode S_q = SDL_SCANCODE_Q; +constexpr Scancode S_r = SDL_SCANCODE_R; +constexpr Scancode S_s = SDL_SCANCODE_S; +constexpr Scancode S_t = SDL_SCANCODE_T; +constexpr Scancode S_u = SDL_SCANCODE_U; +constexpr Scancode S_v = SDL_SCANCODE_V; +constexpr Scancode S_w = SDL_SCANCODE_W; +constexpr Scancode S_x = SDL_SCANCODE_X; +constexpr Scancode S_y = SDL_SCANCODE_Y; +constexpr Scancode S_z = SDL_SCANCODE_Z; +constexpr Scancode S_DOWN = SDL_SCANCODE_DOWN; +constexpr Scancode S_LEFT = SDL_SCANCODE_LEFT; +constexpr Scancode S_RIGHT = SDL_SCANCODE_RIGHT; +constexpr Scancode S_UP = SDL_SCANCODE_UP; +constexpr Scancode S_LALT = SDL_SCANCODE_LALT; +constexpr Scancode S_LCTRL = SDL_SCANCODE_LCTRL; +constexpr Scancode S_LSHIFT = SDL_SCANCODE_LSHIFT; +constexpr Scancode S_RALT = SDL_SCANCODE_RALT; +constexpr Scancode S_RCTRL = SDL_SCANCODE_RCTRL; +constexpr Scancode S_RETURN = SDL_SCANCODE_RETURN; +constexpr Scancode S_RSHIFT = SDL_SCANCODE_RSHIFT; +constexpr Scancode S_SPACE = SDL_SCANCODE_SPACE; +constexpr Scancode S_TAB = SDL_SCANCODE_TAB; +// Event types constexpr SDL_EventType QUIT = SDL_QUIT; constexpr SDL_EventType DISPLAYEVENT = SDL_DISPLAYEVENT; constexpr SDL_EventType WINDOWEVENT = SDL_WINDOWEVENT; @@ -93,6 +121,7 @@ constexpr SDL_EventType AUDIODEVICEADDED = SDL_AUDIODEVICEADDED; constexpr SDL_EventType AUDIODEVICEREMOVED = SDL_AUDIODEVICEREMOVED; constexpr SDL_EventType USEREVENT = SDL_USEREVENT; +// Keycodes constexpr SDL_KeyCode K_0 = SDLK_0; constexpr SDL_KeyCode K_1 = SDLK_1; constexpr SDL_KeyCode K_2 = SDLK_2; @@ -216,9 +245,36 @@ constexpr SDL_KeyCode K_QUOTEDBL = SDLK_QUOTEDBL; constexpr SDL_KeyCode K_RIGHTPAREN = SDLK_RIGHTPAREN; constexpr SDL_KeyCode K_UNDERSCORE = SDLK_UNDERSCORE; -constexpr int BUTTON_LEFT = SDL_BUTTON_LEFT; -constexpr int BUTTON_MIDDLE = SDL_BUTTON_MIDDLE; -constexpr int BUTTON_RIGHT = SDL_BUTTON_RIGHT; +// Mouse buttons +constexpr int M_LEFT = SDL_BUTTON_LEFT; +constexpr int M_MIDDLE = SDL_BUTTON_MIDDLE; +constexpr int M_RIGHT = SDL_BUTTON_RIGHT; +constexpr int M_SIDE1 = SDL_BUTTON_X1; +constexpr int M_SIDE2 = SDL_BUTTON_X2; + +// Controller buttonsW +constexpr ControllerButton C_A = SDL_CONTROLLER_BUTTON_A; +constexpr ControllerButton C_B = SDL_CONTROLLER_BUTTON_B; +constexpr ControllerButton C_X = SDL_CONTROLLER_BUTTON_X; +constexpr ControllerButton C_Y = SDL_CONTROLLER_BUTTON_Y; +constexpr ControllerButton C_BACK = SDL_CONTROLLER_BUTTON_BACK; +constexpr ControllerButton C_GUIDE = SDL_CONTROLLER_BUTTON_GUIDE; +constexpr ControllerButton C_START = SDL_CONTROLLER_BUTTON_START; +constexpr ControllerButton C_LEFTSTICK = SDL_CONTROLLER_BUTTON_LEFTSTICK; +constexpr ControllerButton C_RIGHTSTICK = SDL_CONTROLLER_BUTTON_RIGHTSTICK; +constexpr ControllerButton C_LEFTSHOULDER = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; +constexpr ControllerButton C_RIGHTSHOULDER = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; +constexpr ControllerButton C_DPAD_UP = SDL_CONTROLLER_BUTTON_DPAD_UP; +constexpr ControllerButton C_DPAD_DOWN = SDL_CONTROLLER_BUTTON_DPAD_DOWN; +constexpr ControllerButton C_DPAD_LEFT = SDL_CONTROLLER_BUTTON_DPAD_LEFT; +constexpr ControllerButton C_DPAD_RIGHT = SDL_CONTROLLER_BUTTON_DPAD_RIGHT; + +constexpr ControllerAxis C_AXIS_LEFTX = SDL_CONTROLLER_AXIS_LEFTX; +constexpr ControllerAxis C_AXIS_LEFTY = SDL_CONTROLLER_AXIS_LEFTY; +constexpr ControllerAxis C_AXIS_RIGHTX = SDL_CONTROLLER_AXIS_RIGHTX; +constexpr ControllerAxis C_AXIS_RIGHTY = SDL_CONTROLLER_AXIS_RIGHTY; +constexpr ControllerAxis C_TRIGGERLEFT = SDL_CONTROLLER_AXIS_TRIGGERLEFT; +constexpr ControllerAxis C_TRIGGERRIGHT = SDL_CONTROLLER_AXIS_TRIGGERRIGHT; constexpr unsigned int MILLISECONDS_PER_SECOND = 1000U; diff --git a/include/GameController.hpp b/include/GameController.hpp index 45f1799..7d149e1 100644 --- a/include/GameController.hpp +++ b/include/GameController.hpp @@ -1,4 +1,5 @@ #pragma once +#include "Constants.hpp" namespace kn { @@ -26,33 +27,43 @@ namespace controller /** * @brief Get how far the controller's left trigger is pressed. * - * @return The value of the left trigger from the range 0.0 to 1.0. If the controller is not - * connected, 0.0 is returned. + * @return The value of the left trigger from the range ``0.0`` to ``1.0``. If the controller is not + * connected, ``0.0`` is returned. */ [[nodiscard]] double getLeftTrigger(); /** * @brief Get how far the controller's right trigger is pressed. * - * @return The value of the right trigger from the range 0.0 to 1.0. If the controller is not - * connected, 0.0 is returned. + * @return The value of the right trigger from the range ``0.0`` to ``1.0``. If the controller is + * not connected, ``0.0`` is returned. */ [[nodiscard]] double getRightTrigger(); +/** + * @brief Check if a button on the controller is pressed. + * + * @param button The button to check. + * + * @return ``true`` if the button is pressed, ``false`` otherwise. If the controller is not + * connected, ``false`` is returned. + */ +[[nodiscard]] bool isPressed(ControllerButton button); + /** * @brief Change the dead zone for controller joystick input. * -* @param deadZone The dead zone for the controller from the range 0.0 to 1.0. +* @param deadZone The dead zone for the controller from the range ``0.0`` to ``1.0``. * -* @note Negative values will be clamped to 0.0 and values greater than 1.0 will be clamped -to 1.0. +* @note Negative values will be clamped to ``0.0`` and values greater than ``1.0`` will be clamped +to ``1.0``. */ void setDeadZone(float deadZone); /** * @brief Get the dead zone for controller joystick input. * - * @return The dead zone for the controller from the range 0.0 to 1.0. + * @return The dead zone for the controller from the range ``0.0`` to ``1.0``. */ [[nodiscard]] float getDeadZone(); diff --git a/include/Input.hpp b/include/Input.hpp new file mode 100644 index 0000000..8563eb9 --- /dev/null +++ b/include/Input.hpp @@ -0,0 +1,106 @@ +#pragma once + +#include +#include + +#include "Constants.hpp" + +namespace kn +{ + +enum class InputType +{ + KEYBOARD, + MOUSE, + CONTROLLER_AXIS, + CONTROLLER_BUTTON +}; + +/** + * @brief An input action. + * Can either be a keyboard key, a mouse button, a controller button or a controller joystick. + */ +struct InputAction +{ + InputType type; + union + { + Scancode key; + ControllerButton controllerButton; + uint32_t mouseButton; + struct + { + ControllerAxis axis; + bool isPositive; + } controllerAxis; + }; + + /** + * @param key The keyboard key. + */ + explicit InputAction(Scancode key); + + /** + * @param axis The controller axis. + * @param isPositive Whether the axis is positive or negative. + */ + InputAction(ControllerAxis axis, bool isPositive); + + /** + * @param controllerButton The controller button. + */ + explicit InputAction(ControllerButton controllerButton); + + /** + * @param mouseButton The mouse button. + */ + explicit InputAction(int mouseButton); +}; + +namespace math +{ +class Vec2; +} // namespace math + +namespace input +{ + +/** + * @brief Bind a name to a set of input actions. + * + * @param name The name to bind to the input actions. + * @param actions The input actions to bind to the name. + */ +void bind(const std::string& name, const std::vector& actions); + +/** + * @brief Unbind a name from the input actions. + * + * @param name The name to unbind from the input actions. + */ +void unbind(const std::string& name); + +/** + * @brief Get a normalized direction vector based on the input actions. + * + * @param left The name of the input action for moving left. + * @param right The name of the input action for moving right. + * @param up The name of the input action for moving up. + * @param down The name of the input action for moving down. + * + * @return A normalized direction vector. + */ +[[nodiscard]] math::Vec2 getDirection(const std::string& left = "", const std::string& right = "", + const std::string& up = "", const std::string& down = ""); + +/** + * @brief Check if an input action is pressed. + * + * @param name The name of the input action to check. + * + * @return ``true`` if the input action is pressed, ``false`` otherwise. + */ +[[nodiscard]] bool isPressed(const std::string& name); + +} // namespace input +} // namespace kn diff --git a/include/Key.hpp b/include/Key.hpp index 919525e..eb128b7 100644 --- a/include/Key.hpp +++ b/include/Key.hpp @@ -1,5 +1,7 @@ #pragma once +#include "Constants.hpp" + namespace kn { namespace math @@ -10,12 +12,11 @@ class Vec2; namespace key { /** - * @brief Check if the argument key is pressed. - * - * @param key The key to check. + * @brief Get the keys that are currently pressed. * - * @return If the argument key is pressed. + * @return The keys that are currently pressed. */ -bool isPressed(int key); +[[nodiscard]] const uint8_t* getPressed(); + } // namespace key } // namespace kn \ No newline at end of file diff --git a/include/KrakenEngine.hpp b/include/KrakenEngine.hpp index c52381f..6c940a0 100644 --- a/include/KrakenEngine.hpp +++ b/include/KrakenEngine.hpp @@ -7,6 +7,7 @@ #include "Draw.hpp" #include "Font.hpp" #include "GameController.hpp" +#include "Input.hpp" #include "Key.hpp" #include "Math.hpp" #include "Mouse.hpp" diff --git a/include/Math.hpp b/include/Math.hpp index e23b8b3..4d0dfa5 100644 --- a/include/Math.hpp +++ b/include/Math.hpp @@ -40,10 +40,17 @@ class Vec2 /** * @brief Get the length of the vector. - * @return The length of the vector if no overflow happens, otherwise -1.0. + * @return The length of the vector if no overflow happens, otherwise ``-1.0``. */ [[nodiscard]] double getLength() const; + /** + * @brief Get the angle of the vector in degrees. + * + * @return The angle of the vector in degrees. + */ + [[nodiscard]] double getAngle() const; + /** * @brief Rotates a vector in-place by a given angle in degrees. * @param angle The angle in degrees. @@ -100,7 +107,7 @@ class Vec2 /** * @brief Get the distance to another vector. * @param other The vector to calculate the distance to. - * @return The distance to another vector if no overflow happens, otherwise -1.0. + * @return The distance to another vector if no overflow happens, otherwise ``-1.0``. */ [[nodiscard]] double distanceTo(const Vec2& other) const; @@ -254,14 +261,6 @@ double cross(const Vec2& a, const Vec2& b); */ double angleBetween(const Vec2& a, const Vec2& b); -/** - * @brief Calculates the angle in radians between the heads of the vectors. - * @param a The lhs vector. - * @param b The rhs vector. - * @return The angle in radians between the heads of the vectors. - */ -double angleOfDifference(const Vec2& a, const Vec2& b); - template Vec2 operator*(const T& lhs, const Vec2& rhs) { if (!isProductValid(static_cast(lhs), rhs.x) || diff --git a/include/Mouse.hpp b/include/Mouse.hpp index a6f1fac..018d646 100644 --- a/include/Mouse.hpp +++ b/include/Mouse.hpp @@ -18,13 +18,11 @@ namespace mouse math::Vec2 getPos(); /** - * @brief Check if the argument mouse button is pressed. + * @brief Get all the mouse buttons that are pressed. * - * @param button The mouse button to check. - * - * @return If the argument mouse button is pressed. + * @return A bitfield of all the mouse buttons that are pressed. */ -bool isPressed(uint32_t button); +uint32_t getPressed(); } // namespace mouse } // namespace kn \ No newline at end of file diff --git a/include/Music.hpp b/include/Music.hpp index f587168..7895043 100644 --- a/include/Music.hpp +++ b/include/Music.hpp @@ -19,7 +19,7 @@ void unload(); /** * @brief Plays the currently loaded audio file. * - * @param loops The number of times to loop the music. -1 loops forever. + * @param loops The number of times to loop the music. ``-1`` loops forever. * @param fadeMs The number of milliseconds to fade in the music. */ void play(int loops = 0, int fadeMs = 0); @@ -54,7 +54,7 @@ void fadeOut(int fadeMs); /** * @brief Sets the volume of the music. * - * @param volume The volume to set the music to. 0.0f is silent, 1.0f is full volume. + * @param volume The volume to set the music to. ``0.0f`` is silent, ``1.0f`` is full volume. */ void setVolume(float volume); diff --git a/include/Overflow.hpp b/include/Overflow.hpp index aa79d49..7631d25 100644 --- a/include/Overflow.hpp +++ b/include/Overflow.hpp @@ -10,7 +10,7 @@ namespace kn::overflow * * @param first first value * @param second second value - * @return true if sum is valid, false otherwise + * @return ``true`` if sum is valid, ``false`` otherwise */ bool isSumValid(const double& first, const double& second); @@ -29,7 +29,7 @@ bool isSumValid(const int64_t& first, const int64_t& second); * * @param first first value * @param second second value - * @return true if product is valid, false otherwise + * @return ``true`` if product is valid, ``false`` otherwise */ bool isProductValid(const double& first, const double& second); @@ -48,7 +48,7 @@ bool isProductValid(const int64_t& first, const int64_t& second); * * @param value value to check * @param tolerance the accuracy to use, anything closer to 0 than this will be considered zero - * @return true if close to zero, false otherwise + * @return ``true`` if close to zero, ``false`` otherwise */ bool closeToZero(const double& value, double tolerance = 0.0001); diff --git a/include/Sound.hpp b/include/Sound.hpp index 148100f..5f9a483 100644 --- a/include/Sound.hpp +++ b/include/Sound.hpp @@ -26,7 +26,7 @@ class Sound final * @param playTime The number of milliseconds to play the sound for. * @param fadeMs The number of milliseconds to fade in. * - * @note If the loops parameter is set to -1, the sound will loop indefinitely. + * @note If the loops parameter is set to ``-1``, the sound will loop indefinitely. */ void play(int loops = 0, int playTime = -1, int fadeMs = 0) const; @@ -40,7 +40,7 @@ class Sound final /** * @brief Get the volume of the sound. * - * @return The volume of the sound. Between 0.0f and 1.0f. + * @return The volume of the sound. Between ``0.0f`` and ``1.0f``. */ [[nodiscard]] float getVolume() const; diff --git a/include/Texture.hpp b/include/Texture.hpp index e73a89f..59e71f9 100644 --- a/include/Texture.hpp +++ b/include/Texture.hpp @@ -84,7 +84,7 @@ class Texture final * * @param filePath Path to the image file. * - * @return true when successful, false on failure. + * @return ``true`` when successful, ``false`` on failure. */ [[maybe_unused]] bool loadFromFile(const std::string& filePath); diff --git a/include/Time.hpp b/include/Time.hpp index a5eea90..2b7a91c 100644 --- a/include/Time.hpp +++ b/include/Time.hpp @@ -6,8 +6,6 @@ namespace kn::time { /** * @brief A class to keep track of time. - * - * @warning This class is planned to become a singleton. */ class Clock final { diff --git a/include/_globals.hpp b/include/_globals.hpp index f8a7023..9738efe 100644 --- a/include/_globals.hpp +++ b/include/_globals.hpp @@ -1,6 +1,5 @@ #pragma once -#include "Math.hpp" #include namespace kn diff --git a/meson.build b/meson.build index 697cded..cf24b17 100644 --- a/meson.build +++ b/meson.build @@ -34,7 +34,7 @@ if get_option('build_example') executable( 'krakenapp', sources : example_src, - include_directories : [incs, include_directories('example')], + include_directories : [incs, include_directories('example/include')], dependencies : deps + [kraken_engine_dep], win_subsystem : 'console', link_with : libkraken, diff --git a/meson_options.txt b/meson_options.txt index 030e4d9..2e3e506 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,7 +1,7 @@ option( 'build_example', type : 'boolean', - value : false, + value : true, description : 'Build example demo. Off by default.', ) diff --git a/src/animation_controller.cpp b/src/animation_controller.cpp index e46ced6..6f3b8bf 100644 --- a/src/animation_controller.cpp +++ b/src/animation_controller.cpp @@ -68,6 +68,12 @@ const Frame& AnimationController::nextFrame(const double deltaTime) return currAnim.frames.at(static_cast(m_index)); } +void AnimationController::rewind() +{ + m_index = 0.0; + m_prevIndex = 0.0; +} + void AnimationController::pause() { m_paused = true; } void AnimationController::resume() @@ -94,4 +100,6 @@ bool AnimationController::isFinished() return false; } +const std::string& AnimationController::getCurrentAnim() const { return m_currAnim; } + } // namespace kn diff --git a/src/game_controller.cpp b/src/game_controller.cpp index 1843e95..5ad4e3b 100644 --- a/src/game_controller.cpp +++ b/src/game_controller.cpp @@ -11,13 +11,10 @@ static float _deadZone = 0.1f; math::Vec2 getLeftJoystick() { if (!_controller) - { - WARN("Game controller is not connected") return {}; - } - math::Vec2 controllerDir = {SDL_GameControllerGetAxis(_controller, SDL_CONTROLLER_AXIS_LEFTX), - SDL_GameControllerGetAxis(_controller, SDL_CONTROLLER_AXIS_LEFTY)}; + math::Vec2 controllerDir = {SDL_GameControllerGetAxis(_controller, C_AXIS_LEFTX), + SDL_GameControllerGetAxis(_controller, C_AXIS_LEFTY)}; controllerDir /= 32767.0; if (controllerDir.getLength() > _deadZone) return controllerDir; @@ -28,13 +25,10 @@ math::Vec2 getLeftJoystick() math::Vec2 getRightJoystick() { if (!_controller) - { - WARN("Game controller is not connected") return {}; - } - math::Vec2 controllerDir = {SDL_GameControllerGetAxis(_controller, SDL_CONTROLLER_AXIS_RIGHTX), - SDL_GameControllerGetAxis(_controller, SDL_CONTROLLER_AXIS_RIGHTY)}; + math::Vec2 controllerDir = {SDL_GameControllerGetAxis(_controller, C_AXIS_RIGHTX), + SDL_GameControllerGetAxis(_controller, C_AXIS_RIGHTY)}; controllerDir /= 32767.0; if (controllerDir.getLength() > _deadZone) return controllerDir; @@ -45,23 +39,25 @@ math::Vec2 getRightJoystick() double getLeftTrigger() { if (!_controller) - { - WARN("Game controller is not connected") return 0.0; - } - return SDL_GameControllerGetAxis(_controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) / 32768.0; + return SDL_GameControllerGetAxis(_controller, C_TRIGGERLEFT) / 32768.0; } double getRightTrigger() { if (!_controller) - { - WARN("Game controller is not connected") return 0.0; - } - return SDL_GameControllerGetAxis(_controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) / 32768.0; + return SDL_GameControllerGetAxis(_controller, C_TRIGGERRIGHT) / 32768.0; +} + +bool isPressed(const ControllerButton button) +{ + if (!_controller) + return false; + + return SDL_GameControllerGetButton(_controller, button); } void setControllerDeadZone(const float deadZone) { _deadZone = std::clamp(deadZone, 0.0f, 1.0f); } diff --git a/src/input.cpp b/src/input.cpp new file mode 100644 index 0000000..7f5961c --- /dev/null +++ b/src/input.cpp @@ -0,0 +1,124 @@ +#include "Input.hpp" + +#include +#include + +#include "ErrorLogger.hpp" +#include "GameController.hpp" +#include "Key.hpp" +#include "Math.hpp" +#include "Mouse.hpp" + +namespace kn +{ + +static std::unordered_map> _inputBindings; + +InputAction::InputAction(const Scancode key) : type(InputType::KEYBOARD), key(key) {} + +InputAction::InputAction(const ControllerAxis axis, const bool isPositive) + : type(InputType::CONTROLLER_AXIS), controllerAxis{axis, isPositive} +{ +} + +InputAction::InputAction(const ControllerButton controllerButton) + : type(InputType::CONTROLLER_BUTTON), controllerButton{controllerButton} +{ +} + +InputAction::InputAction(const int mouseButton) : type(InputType::MOUSE), mouseButton(mouseButton) +{ +} + +namespace input +{ + +void bind(const std::string& name, const std::vector& actions) +{ + if (name.empty()) + { + WARN("Input binding name cannot be empty") + return; + } + + _inputBindings[name] = actions; +} + +void unbind(const std::string& name) { _inputBindings.erase(name); } + +math::Vec2 getDirection(const std::string& left, const std::string& right, const std::string& up, + const std::string& down) +{ + math::Vec2 directionVec; + const auto* keysPressed = key::getPressed(); + const auto buttonsPressed = mouse::getPressed(); + const auto leftJoystick = controller::getLeftJoystick(); + const auto rightJoystick = controller::getRightJoystick(); + + static const auto processActions = + [&](const std::string& name, double& axisValue, const int direction) + { + if (const auto it = _inputBindings.find(name); it != _inputBindings.end()) + for (const InputAction& action : it->second) + { + if (action.type == InputType::KEYBOARD && keysPressed[action.key]) + axisValue += direction; + + if (action.type == InputType::MOUSE && buttonsPressed == action.mouseButton) + axisValue += direction; + + if (action.type == InputType::CONTROLLER_BUTTON && + controller::isPressed(action.controllerButton)) + axisValue += direction; + + if (action.type == InputType::CONTROLLER_AXIS) + { + if (action.controllerAxis.axis == C_AXIS_LEFTX && + (action.controllerAxis.isPositive && leftJoystick.x > 0.0 || + !action.controllerAxis.isPositive && leftJoystick.x < 0.0)) + axisValue += leftJoystick.x; + if (action.controllerAxis.axis == C_AXIS_LEFTY && + (action.controllerAxis.isPositive && leftJoystick.y > 0.0 || + !action.controllerAxis.isPositive && leftJoystick.y < 0.0)) + axisValue += leftJoystick.y; + if (action.controllerAxis.axis == C_AXIS_RIGHTX && + (action.controllerAxis.isPositive && rightJoystick.x > 0.0 || + !action.controllerAxis.isPositive && rightJoystick.x < 0.0)) + axisValue += rightJoystick.x; + if (action.controllerAxis.axis == C_AXIS_RIGHTY && + (action.controllerAxis.isPositive && rightJoystick.y > 0.0 || + !action.controllerAxis.isPositive && rightJoystick.y < 0.0)) + axisValue += rightJoystick.y; + } + } + }; + + processActions(left, directionVec.x, -1); // Left decreases X + processActions(right, directionVec.x, 1); // Right increases X + processActions(up, directionVec.y, -1); // Up decreases Y + processActions(down, directionVec.y, 1); // Down increases Y + + if (directionVec.getLength() > 1.0f) + directionVec.normalize(); + + return directionVec; +} + +bool isPressed(const std::string& name) +{ + const auto it = _inputBindings.find(name); + if (it == _inputBindings.end()) + return false; + + return std::any_of( + it->second.begin(), it->second.end(), + [](const InputAction& action) + { + return (action.type == InputType::KEYBOARD && key::getPressed()[action.key]) || + (action.type == InputType::MOUSE && mouse::getPressed() == action.mouseButton) || + (action.type == InputType::CONTROLLER_BUTTON && + controller::isPressed(action.controllerButton)); + }); +} +} // namespace input +} // namespace kn diff --git a/src/key.cpp b/src/key.cpp index 3055717..e32b4dc 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -1,9 +1,10 @@ #include "Key.hpp" +#include "Math.hpp" #include namespace kn::key { -bool isPressed(const int key) { return SDL_GetKeyboardState(nullptr)[key]; } +const uint8_t* getPressed() { return SDL_GetKeyboardState(nullptr); } } // namespace kn::key \ No newline at end of file diff --git a/src/math.cpp b/src/math.cpp index 7400661..25caf84 100644 --- a/src/math.cpp +++ b/src/math.cpp @@ -35,6 +35,8 @@ double Vec2::getLength() const return sqrt(first + second); } +double Vec2::getAngle() const { return toDegrees(atan2(y, x)); } + void Vec2::rotate(const double angle) { rotateRad(toRadians(angle)); } void Vec2::rotateRad(const double angle) @@ -241,12 +243,5 @@ double angleBetween(const Vec2& a, const Vec2& b) return (denominator == 0.0f) ? 0.0f : acos(numerator / denominator); } -double angleOfDifference(const Vec2& a, const Vec2& b) -{ - const Vec2 dVec = a - b; - - return toDegrees(atan2(dVec.y, dVec.x)); -} - } // namespace math } // namespace kn diff --git a/src/meson.build b/src/meson.build index 3d99cb6..4300ea3 100644 --- a/src/meson.build +++ b/src/meson.build @@ -3,6 +3,7 @@ sources = [ 'src/draw.cpp', 'src/font.cpp', 'src/game_controller.cpp', + 'src/input.cpp', 'src/key.cpp', 'src/math.cpp', 'src/mouse.cpp', diff --git a/src/mouse.cpp b/src/mouse.cpp index e5dff1d..7c9deba 100644 --- a/src/mouse.cpp +++ b/src/mouse.cpp @@ -12,5 +12,6 @@ math::Vec2 getPos() return pos / window::getScale() + camera; } -bool isPressed(const uint32_t button) { return SDL_GetMouseState(nullptr, nullptr) == button; } +uint32_t getPressed() { return SDL_GetMouseState(nullptr, nullptr); } + } // namespace kn::mouse diff --git a/src/window.cpp b/src/window.cpp index 2a480bd..e359643 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -129,6 +129,10 @@ int pollEvent(Event& event) _controller = nullptr; } break; + case KEYDOWN: + if (event.key.keysym.sym == SDLK_F11) + setFullscreen(!getFullscreen()); + break; default: break; }