moved from h4570/tyra
This commit is contained in:
+44
@@ -0,0 +1,44 @@
|
|||||||
|
.vscode/
|
||||||
|
|
||||||
|
*.bmp
|
||||||
|
*.obj
|
||||||
|
*.wav
|
||||||
|
*.md2
|
||||||
|
*.dff
|
||||||
|
*.irx
|
||||||
|
|
||||||
|
# ---
|
||||||
|
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
*.smod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
*.erl
|
||||||
|
*.elf
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
[![Contributors][contributors-shield]][contributors-url]
|
||||||
|
[![MIT License][license-shield]][license-url]
|
||||||
|
[![LinkedIn][linkedin-shield]][linkedin-url]
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/h4570/tyra">
|
||||||
|
<img src="http://allvectorlogo.com/img/2016/05/ps2-logo.png" alt="Logo" width="230" height="125">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<h3 align="center">Tyra (Work in progress)</h3>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
Tiny game engine for PS2 (PlayStation 2™) homebrew, written in C++98
|
||||||
|
<br />
|
||||||
|
<a href="https://www.youtube.com/"><strong>View Demo (soon) »</strong></a>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<a href="https://github.com/h4570/tyra/issues">Report Bug</a>
|
||||||
|
·
|
||||||
|
<a href="https://github.com/h4570/tyra/issues">Request Feature</a>
|
||||||
|
</p>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
* [About the Project](#about-the-project)
|
||||||
|
* [Samples](#samples)
|
||||||
|
* [Features](#features)
|
||||||
|
* [Built With](#built-with)
|
||||||
|
* [Getting Started](#getting-started)
|
||||||
|
* [Prerequisites](#prerequisites)
|
||||||
|
* [Installation](#installation)
|
||||||
|
* [Roadmap](#roadmap)
|
||||||
|
* [Contributing](#contributing)
|
||||||
|
* [License](#license)
|
||||||
|
* [Contact](#contact)
|
||||||
|
|
||||||
|
## About The Project
|
||||||
|
|
||||||
|
<img src="http://apgcglz.cluster028.hosting.ovh.net/tyra/1.0.0/tyra.gif" alt="sample" width="600" height="auto">
|
||||||
|
|
||||||
|
This repository contains a early version of game engine with simple demos for PS2 (PlayStation 2™) that I've developed using the freely available PS2DEV, unofficial SDK.
|
||||||
|
Developing for PS2 was and is a big challenge for me, it's pretty low-level and hard (for me :D). The architecture is completely different from an Intel x86 and there are lots of extra things that you need to take into account. There are some samples available to teach on, but overall community died several years ago :/
|
||||||
|
|
||||||
|
**Why PS2 game dev is so different?** Creating games for PS2 is completly different from dragging colored buttons from side to side through an application with nice GUI (ex. Unity).
|
||||||
|
Coding something for PS2 requires from you doing everything from scratch, even data transfer management through (/co)processors like:
|
||||||
|
* EE (Emotion Engine) - whole set of processors and subsystems that make up the PlayStation 2
|
||||||
|
* GS (Graphic synthesizer) - configurable rasterizer and texture mapper, geometry transformations are not done by it. Has only 2MB~ memory for textures, but very high transfer rate, so you can switch them in the blink
|
||||||
|
* VU0 - vector processor accessed by inline assembly code injected into C program
|
||||||
|
* VU1 - vector processor (similar vertex shader) accessed via DMAC
|
||||||
|
* IOP - I/O processor which enables access to peripheral devices, such the game controller
|
||||||
|
|
||||||
|
### Samples
|
||||||
|
* [Floors](https://github.com/h4570/tyra/tree/master/src/samples/floors)
|
||||||
|
* [Ari (WIP)](https://github.com/h4570/tyra/tree/master/src/samples/ari)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
* VU1 (PATH 1 rendering) with double buffering
|
||||||
|
* GIF (PATH 3 rendering) with double buffering
|
||||||
|
* Optimized calculations using VU0
|
||||||
|
* Frustum culling
|
||||||
|
* Backface culling
|
||||||
|
* Perspective projection (like OpenGL's)
|
||||||
|
* Audio support
|
||||||
|
* Animation support
|
||||||
|
* Third person view "lookAt" camera (like OpenGL's)
|
||||||
|
* Dualshock 2 pad support
|
||||||
|
* RGB 888 24bit texture support (with .bmp loader)
|
||||||
|
* 3D files loaders: ".obj", ".dff" (renderware) and ".md2"
|
||||||
|
* Multi threading management
|
||||||
|
* 3D object management
|
||||||
|
* Lighting support (now PATH3 only)
|
||||||
|
* Other: collision, gravity etc.
|
||||||
|
|
||||||
|
### Built With
|
||||||
|
|
||||||
|
* [PS2SDK](https://github.com/ps2dev/ps2sdk)
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
To get a local copy up and running follow these simple steps.
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
This is an example of how to list things you need to use the software and how to install them.
|
||||||
|
* PS2 DEV environment - [PS2DEV](https://github.com/ps2dev/ps2dev)
|
||||||
|
* At least #1a4587d PS2SDK - [PS2SDK](https://github.com/ps2dev/ps2sdk)
|
||||||
|
* PS2 Emulator. For example [PCSX2](https://pcsx2.net/)
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
1. Clone the repo
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/h4570/tyra.git
|
||||||
|
```
|
||||||
|
2. Get into src folder and compile it!
|
||||||
|
```sh
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extra info
|
||||||
|
* Textures can be saved using GIMP. Just replace red with green color, and when exporting select .bmp, 24bit: RGB888, without saving information about colors
|
||||||
|
* If you want to run .elf in PCSX2, be sure that you have version >=1.6 and **Host access** enabled in PCSX2 configuration file.
|
||||||
|
* If you want to use your own .obj file, please check "triangulate faces" in blender. PS2 is supporting only trinagle primitive type.
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
Here is a list of the things I'm working on:
|
||||||
|
|
||||||
|
* Fix PATH3 and PATH1 triangle clipping
|
||||||
|
* Add skybox with 6 textures to ari sample
|
||||||
|
* Ariana textures
|
||||||
|
* Bugfix: Player speed on different zoom
|
||||||
|
* Implement player rotation
|
||||||
|
* Bugfix: Backface culling bug on rotation
|
||||||
|
* Bugfix: Remove camera rotation reset flickering
|
||||||
|
* Bugfix: 2x Audio tick overflow
|
||||||
|
* Audio - change listeners logic
|
||||||
|
* Sound effects
|
||||||
|
* Code documentation
|
||||||
|
|
||||||
|
See the [open issues](https://github.com/h4570/tyra/issues) for a list of proposed features (and known issues).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
|
||||||
|
|
||||||
|
1. Fork the Project
|
||||||
|
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
|
||||||
|
3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
|
||||||
|
4. Push to the Branch (`git push origin feature/AmazingFeature`)
|
||||||
|
5. Open a Pull Request
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Distributed under the Apache License 2.0 License. See `LICENSE` for more information.
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
|
||||||
|
Sandro Sobczyński - hastoklai@gmail.com
|
||||||
|
|
||||||
|
Project Link: [https://github.com/h4570/tyra](https://github.com/h4570/tyra)
|
||||||
|
|
||||||
|
[contributors-shield]: https://img.shields.io/github/contributors/h4570/tyra.svg?style=flat-square
|
||||||
|
[contributors-url]: https://github.com/h4570/tyra/graphs/contributors
|
||||||
|
[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555
|
||||||
|
[linkedin-url]: https://linkedin.com/in/sandro-sobczyński-28820b15a/
|
||||||
|
[license-shield]: https://img.shields.io/github/license/h4570/tyra.svg?style=flat-square
|
||||||
|
[license-url]: https://github.com/h4570/tyra/blob/master/LICENSE
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "include/engine.hpp"
|
||||||
|
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sifrpc.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include "include/modules/vu1.hpp"
|
||||||
|
#include "include/utils/debug.hpp"
|
||||||
|
|
||||||
|
// VU1 micro program
|
||||||
|
extern u32 VU1Draw3D_CodeStart __attribute__((section(".vudata")));
|
||||||
|
extern u32 VU1Draw3D_CodeEnd __attribute__((section(".vudata")));
|
||||||
|
//
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
Engine::Engine()
|
||||||
|
{
|
||||||
|
SifInitRpc(0);
|
||||||
|
srand(time(NULL));
|
||||||
|
VU1::uploadProgram(0, &VU1Draw3D_CodeStart, &VU1Draw3D_CodeEnd);
|
||||||
|
audio.startThread();
|
||||||
|
isInitialized = 0;
|
||||||
|
isScreenInitialized = 0;
|
||||||
|
mainThreadId = GetThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
|
Engine::~Engine() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
void Engine::setScreen(ScreenSettings &t_settings)
|
||||||
|
{
|
||||||
|
screen = t_settings;
|
||||||
|
isScreenInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::setDefaultScreen()
|
||||||
|
{
|
||||||
|
screen.projectionScale = 4096.0F;
|
||||||
|
screen.nearPlaneDist = 2.0F;
|
||||||
|
screen.farPlaneDist = 2000.0F;
|
||||||
|
screen.fov = 60.0F;
|
||||||
|
screen.aspectRatio = 4.0F / 3.0F;
|
||||||
|
screen.width = 640.0F;
|
||||||
|
screen.height = 480.0F;
|
||||||
|
isScreenInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::init(Game *t_game, u32 t_gifPacketSize)
|
||||||
|
{
|
||||||
|
if (!isScreenInitialized)
|
||||||
|
PRINT_ERR("Cant init because screen was not set!");
|
||||||
|
else if (isInitialized)
|
||||||
|
PRINT_ERR("Already initialized!");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
game = t_game;
|
||||||
|
renderer = new Renderer(t_gifPacketSize, &screen);
|
||||||
|
isInitialized = true;
|
||||||
|
game->onInit();
|
||||||
|
gameLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Do not call this method. This is used in gameLoop() to maintain multithreading */
|
||||||
|
void Engine::wakeup(s32 t_alarmId, u16 t_time, void *t_common)
|
||||||
|
{
|
||||||
|
(void)t_alarmId;
|
||||||
|
(void)t_time;
|
||||||
|
iWakeupThread(*(int *)t_common);
|
||||||
|
ExitHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::gameLoop()
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
pad.update();
|
||||||
|
game->onUpdate();
|
||||||
|
if (fpsDelayer++ >= 4)
|
||||||
|
{
|
||||||
|
fps = timer.getFPS();
|
||||||
|
fpsDelayer = 0;
|
||||||
|
}
|
||||||
|
timer.primeTimer();
|
||||||
|
renderer->endFrame(fps);
|
||||||
|
/** -6~ FPS */
|
||||||
|
SetAlarm(fps > 49.0F ? 24 : 48, &Engine::wakeup, &mainThreadId);
|
||||||
|
SleepThread();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_ENGINE_
|
||||||
|
#define _TYRA_ENGINE_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include "game.hpp"
|
||||||
|
#include "models/screen_settings.hpp"
|
||||||
|
#include "models/math/matrix.hpp"
|
||||||
|
#include "modules/renderer.hpp"
|
||||||
|
#include "modules/timer.hpp"
|
||||||
|
#include "modules/pad.hpp"
|
||||||
|
#include "modules/audio.hpp"
|
||||||
|
|
||||||
|
class Engine
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
Engine();
|
||||||
|
~Engine();
|
||||||
|
|
||||||
|
void init(Game *t_game, u32 t_gifPacketSize);
|
||||||
|
void setDefaultScreen();
|
||||||
|
void setScreen(ScreenSettings &t_settings);
|
||||||
|
Renderer *renderer;
|
||||||
|
Audio audio;
|
||||||
|
ScreenSettings screen;
|
||||||
|
Pad pad;
|
||||||
|
float fps;
|
||||||
|
|
||||||
|
private:
|
||||||
|
u8 fpsDelayer;
|
||||||
|
Timer timer;
|
||||||
|
u8 isInitialized, isScreenInitialized;
|
||||||
|
void gameLoop();
|
||||||
|
Game *game;
|
||||||
|
s32 mainThreadId;
|
||||||
|
static void wakeup(s32 t_alarmId, u16 t_time, void *t_common);
|
||||||
|
|
||||||
|
// ThreadManager threadManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_GAME_
|
||||||
|
#define _TYRA_GAME_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
|
||||||
|
class Game
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~Game(){};
|
||||||
|
virtual void onInit() = 0;
|
||||||
|
virtual void onUpdate() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_BMP_LOADER_
|
||||||
|
#define _TYRA_BMP_LOADER_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include "../models/texture.hpp"
|
||||||
|
|
||||||
|
/** Class responsible for loading images in bmp format */
|
||||||
|
class BmpLoader
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
BmpLoader();
|
||||||
|
~BmpLoader();
|
||||||
|
|
||||||
|
void load(Texture &o_texture, char *t_subfolder, char *t_name, char *t_extension);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_DFF_LOADER_
|
||||||
|
#define _TYRA_DFF_LOADER_
|
||||||
|
|
||||||
|
#include "../models/dff_model.hpp"
|
||||||
|
#include "./dff_structure.hpp"
|
||||||
|
|
||||||
|
/** Class responsible for loading&parsing .obj 3D files */
|
||||||
|
class DffLoader
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
DffLoader();
|
||||||
|
~DffLoader();
|
||||||
|
|
||||||
|
void load(RwClump &o_clump, char *t_fileName, float t_scale);
|
||||||
|
void serialize(RwClump &t_clump, u8 *t_data, float t_scale);
|
||||||
|
|
||||||
|
static u8 readByteFromArrayLE(u8 *t_buffer, u32 &t_ptrPos);
|
||||||
|
static u16 readWordFromArrayLE(u8 *t_buffer, u32 &t_ptrPos);
|
||||||
|
static u32 readDwordFromArrayLE(u8 *t_buffer, u32 &t_ptrPos);
|
||||||
|
static float readFloatFromArrayLE(u8 *t_buffer, u32 &t_ptrPos);
|
||||||
|
static u8 *readData(u8 *t_buffer, u32 &t_ptrPos, u32 t_dataSize);
|
||||||
|
static char *readString(u8 *t_buffer, u32 &t_ptrPos, u32 t_dataSize = 0);
|
||||||
|
|
||||||
|
void readSectionHeader(RwSectionHeader &t_sh, u8 *t_buffer, u32 &t_ptrPos);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// ---
|
||||||
|
void readFrameListData(RwFrameListData &t_frd, u8 *t_buffer, u32 &t_ptrPos);
|
||||||
|
void readClumpData(RwClumpData &t_cd, u8 *t_buffer, u32 &t_ptrPos);
|
||||||
|
void readGeometryListData(RwGeometryListData &t_gld, u8 *t_buffer, u32 &t_ptrPos);
|
||||||
|
void readGeometryExtension(RwGeometryExtension &t_ge, u8 *t_buffer, u32 &t_ptrPos);
|
||||||
|
void readGeometryData(RwGeometryData &t_gd, u8 *t_buffer, u32 &t_ptrPos, float t_scale);
|
||||||
|
void readMaterialListData(RwMaterialListData &t_mld, u8 *t_buffer, u32 &t_ptrPos);
|
||||||
|
void readMaterialData(RwMaterialData &t_md, u8 *t_buffer, u32 &t_ptrPos);
|
||||||
|
void readTextureData(RwTextureData &t_td, u8 *t_buffer, u32 &t_ptrPos);
|
||||||
|
void readStringData(RwString &t_s, u8 *bt_uffer, u32 &t_ptrPos);
|
||||||
|
// ---
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,334 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_DFF_STRUCTURE_
|
||||||
|
#define _TYRA_DFF_STRUCTURE_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include "../models/math/vector3.hpp"
|
||||||
|
|
||||||
|
enum RwGeometryDataFlags
|
||||||
|
{
|
||||||
|
rwOBJECT_VERTEX_TRISTRIP = 0x01,
|
||||||
|
rwOBJECT_VERTEX_POS = 0x02,
|
||||||
|
rwOBJECT_VERTEX_TEXTURED = 0x04,
|
||||||
|
rwOBJECT_VERTEX_PRELIT = 0x08,
|
||||||
|
rwOBJECT_VERTEX_NORMALS = 0x10,
|
||||||
|
rwOBJECT_VERTEX_LIGHT = 0x20,
|
||||||
|
rwOBJECT_VERTEX_MODULATE_MATERIAL_COLOR = 0x40,
|
||||||
|
rwOBJECT_VERTEX_TEXTURED_2 = 0x80
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
u32 sectionType;
|
||||||
|
u32 sectionSize;
|
||||||
|
u32 versionNumber;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwFrameListChunk
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~RwFrameListChunk() { delete[] rotationalMatrix; }
|
||||||
|
float *rotationalMatrix; // [ROT_MAT_DIM]
|
||||||
|
float coordinatesOffsetX;
|
||||||
|
float coordinatesOffsetY;
|
||||||
|
float coordinatesOffsetZ;
|
||||||
|
u32 parentFrame; // 0xFFFFFFFF = NONE
|
||||||
|
u32 unk1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Section: Frame List
|
||||||
|
class RwFrameListData : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~RwFrameListData() { delete frameInformation; }
|
||||||
|
static const u32 ROT_MAT_DIM = 9;
|
||||||
|
u32 frameCount;
|
||||||
|
|
||||||
|
RwFrameListChunk *frameInformation; // [frameCount]
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwFrame : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~RwFrame() { delete[] frameName; }
|
||||||
|
u8 *frameName; // [sectionSize] - should be interpreted as string
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwFrameListExtension : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RwFrame frame;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwFrameList : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RwFrameListData data;
|
||||||
|
~RwFrameList() { delete[] extensions; }
|
||||||
|
RwFrameListExtension *extensions;
|
||||||
|
};
|
||||||
|
// ---
|
||||||
|
|
||||||
|
class RwGeometryDataHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
u16 flags;
|
||||||
|
u16 unk1;
|
||||||
|
u32 triangleCount;
|
||||||
|
u32 vertexCount;
|
||||||
|
u32 morphTargetCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwGeometryDataLightingHeader
|
||||||
|
{ // IF versionNumber = 4099 - according to not complete documentation
|
||||||
|
public:
|
||||||
|
float ambient;
|
||||||
|
float diffuse;
|
||||||
|
float specular;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwGeometryDataColorInformationChunk
|
||||||
|
{ // if rwOBJECT_VERTEX_PREILIT in flags
|
||||||
|
public:
|
||||||
|
u8 red;
|
||||||
|
u8 green;
|
||||||
|
u8 blue;
|
||||||
|
u8 alpha;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwGeometryDataTextureMappingInformationChunk
|
||||||
|
{ // if rwOBJECT_VERTEX_TEXTURED in flags
|
||||||
|
public:
|
||||||
|
float u;
|
||||||
|
float v;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwGeometryDataFaceInformation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
u16 vertex2; // this
|
||||||
|
u16 vertex1; // is
|
||||||
|
u16 flags; // weird
|
||||||
|
u16 vertex3; // order
|
||||||
|
};
|
||||||
|
|
||||||
|
// Section: Geometry
|
||||||
|
class RwGeometryData : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~RwGeometryData()
|
||||||
|
{
|
||||||
|
delete colorInformation;
|
||||||
|
delete textureMappingInformation;
|
||||||
|
delete faceInformation;
|
||||||
|
delete vertexInformation;
|
||||||
|
delete normalInformation;
|
||||||
|
}
|
||||||
|
RwGeometryDataHeader dataHeader;
|
||||||
|
|
||||||
|
RwGeometryDataLightingHeader lightingHeader;
|
||||||
|
|
||||||
|
RwGeometryDataColorInformationChunk *colorInformation; // [vertexCount]
|
||||||
|
|
||||||
|
RwGeometryDataTextureMappingInformationChunk *textureMappingInformation; // [vertexCount]
|
||||||
|
|
||||||
|
RwGeometryDataFaceInformation *faceInformation; // [triangleCount]
|
||||||
|
|
||||||
|
class RwGeometryDataNonameInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float boundingSphereX;
|
||||||
|
float boundingSphereY;
|
||||||
|
float boundingSphereZ;
|
||||||
|
float boundingSphereR;
|
||||||
|
u32 hasPosition;
|
||||||
|
u32 hasNormals;
|
||||||
|
} nonameInfo;
|
||||||
|
|
||||||
|
Vector3 *vertexInformation; // [vertexCount]
|
||||||
|
|
||||||
|
Vector3 *normalInformation; // [vertexCount]
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwMaterialData : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
u32 unk1;
|
||||||
|
u8 R;
|
||||||
|
u8 G;
|
||||||
|
u8 B;
|
||||||
|
u8 A;
|
||||||
|
u32 unk2;
|
||||||
|
u32 textureCount;
|
||||||
|
float unkPosX;
|
||||||
|
float unkPosY;
|
||||||
|
float unkPosZ;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwTextureData : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
u16 textureFilterModeFlags;
|
||||||
|
u16 unk;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwString : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~RwString() { delete[] text; }
|
||||||
|
char *text;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwTextureExtension : public RwSectionHeader
|
||||||
|
{
|
||||||
|
// May contain Sky Mipmap Val
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwTexture : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RwTextureData data;
|
||||||
|
RwString textureName;
|
||||||
|
RwString textureAlphaName;
|
||||||
|
RwTextureExtension extension;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwMaterialExtension : public RwSectionHeader
|
||||||
|
{
|
||||||
|
// meant to be void.. don't ask
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwMaterial : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~RwMaterial() { delete[] textures; }
|
||||||
|
RwMaterialData data;
|
||||||
|
RwTexture *textures;
|
||||||
|
RwMaterialExtension extension;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwMaterialListData : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~RwMaterialListData() { delete[] arrayOfUnks; }
|
||||||
|
u32 materialCount;
|
||||||
|
u32 *arrayOfUnks; // Filled with '-1's, [materialCount] - it wasn't mentioned in docs.
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwMaterialList : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~RwMaterialList() { delete[] materials; }
|
||||||
|
RwMaterialListData data;
|
||||||
|
RwMaterial *materials;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwGeometryListVertexInfoChunk
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
u32 vertex1;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwGeometryListInfoChunk
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~RwGeometryListInfoChunk() { delete vertexInformation; }
|
||||||
|
u32 faceIndex;
|
||||||
|
u32 materialIndex;
|
||||||
|
|
||||||
|
RwGeometryListVertexInfoChunk *vertexInformation; // [faceIndex]
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwMaterialSplit
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~RwMaterialSplit() { delete splitInformation; }
|
||||||
|
class Header
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
u32 triangleStrip;
|
||||||
|
u32 splitCount;
|
||||||
|
u32 faceCount;
|
||||||
|
} header;
|
||||||
|
|
||||||
|
RwGeometryListInfoChunk *splitInformation; // [splitCount]
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwGeometryExtension : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RwMaterialSplit materialSplit;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwGeometry : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RwGeometryData data;
|
||||||
|
RwMaterialList materialList;
|
||||||
|
RwGeometryExtension extension;
|
||||||
|
};
|
||||||
|
// ---
|
||||||
|
|
||||||
|
// Section: Geometry List
|
||||||
|
class RwGeometryListData : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
u32 geometryCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwGeometryList : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~RwGeometryList() { delete[] geometries; }
|
||||||
|
RwGeometryListData data;
|
||||||
|
RwGeometry *geometries;
|
||||||
|
};
|
||||||
|
// ---
|
||||||
|
|
||||||
|
// Section: Atomic
|
||||||
|
class RwAtomicData : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
u32 frameNumber;
|
||||||
|
u32 geometryNumber;
|
||||||
|
u32 unk1;
|
||||||
|
u32 unk2;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwAtomic : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RwAtomicData data;
|
||||||
|
};
|
||||||
|
// ---
|
||||||
|
|
||||||
|
// Section: Clump
|
||||||
|
class RwClumpData : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
u32 objectCount;
|
||||||
|
u32 unk1;
|
||||||
|
u32 unk2;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RwClump : public RwSectionHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RwClumpData data;
|
||||||
|
RwFrameList frameList;
|
||||||
|
RwGeometryList geometryList;
|
||||||
|
RwAtomic atomic; //multiple?? but how many
|
||||||
|
};
|
||||||
|
// ---
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_MD2_LOADER_
|
||||||
|
#define _TYRA_MD2_LOADER_
|
||||||
|
|
||||||
|
#include "../models/md2_model.hpp"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// magic number "IDP2" or 844121161
|
||||||
|
#define MD2_IDENT (('2' << 24) + ('P' << 16) + ('D' << 8) + 'I')
|
||||||
|
|
||||||
|
// model version
|
||||||
|
#define MD2_VERSION 8
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int ident; // magic number. must be equal to "IDP2"
|
||||||
|
int version; // md2 version. must be equal to 8
|
||||||
|
|
||||||
|
int skinwidth; // width of the texture
|
||||||
|
int skinheight; // height of the texture
|
||||||
|
int framesize; // size of one frame in bytes
|
||||||
|
|
||||||
|
int num_skins; // number of textures
|
||||||
|
int num_xyz; // number of vertices
|
||||||
|
int num_st; // number of texture coordinates
|
||||||
|
int num_tris; // number of triangles
|
||||||
|
int num_glcmds; // number of opengl commands
|
||||||
|
int num_frames; // total number of frames
|
||||||
|
|
||||||
|
int ofs_skins; // offset to skin names (64 bytes each)
|
||||||
|
int ofs_st; // offset to s-t texture coordinates
|
||||||
|
int ofs_tris; // offset to triangles
|
||||||
|
int ofs_frames; // offset to frame data
|
||||||
|
int ofs_glcmds; // offset to opengl commands
|
||||||
|
int ofs_end; // offset to end of file
|
||||||
|
|
||||||
|
} md2_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned char v[3]; // compressed vertex (x, y, z) coordinates
|
||||||
|
unsigned char lightnormalindex; // index to a normal vector for the lighting
|
||||||
|
|
||||||
|
} mvertex_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
float scale[3]; // scale values
|
||||||
|
float translate[3]; // translation vector
|
||||||
|
char name[16]; // frame name
|
||||||
|
mvertex_t verts[1]; // first vertex of this frame
|
||||||
|
|
||||||
|
} frame_t;
|
||||||
|
|
||||||
|
typedef float vec3_t[3];
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
short index_xyz[3]; // indexes to triangle's vertices
|
||||||
|
short index_st[3]; // indexes to vertices' texture coorinates
|
||||||
|
} triangle_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
short s;
|
||||||
|
short t;
|
||||||
|
} texCoord_t;
|
||||||
|
|
||||||
|
/** Class responsible for loading&parsing Quake's II ".md2" 3D files */
|
||||||
|
class MD2Loader
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
MD2Loader();
|
||||||
|
~MD2Loader();
|
||||||
|
|
||||||
|
void load(MD2Model *o_result, char *t_fileName, float t_scale);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_OBJ_LOADER_
|
||||||
|
#define _TYRA_OBJ_LOADER_
|
||||||
|
|
||||||
|
#include "../models/obj_model.hpp"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/** Class responsible for loading&parsing .obj 3D files */
|
||||||
|
class ObjLoader
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
ObjLoader();
|
||||||
|
~ObjLoader();
|
||||||
|
|
||||||
|
void load(ObjModel *o_result, char *t_fileName, float t_scale);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setObjDataQuantities(FILE *t_file, ObjModel *t_result);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_AUDIO_LISTENER_
|
||||||
|
#define _TYRA_AUDIO_LISTENER_
|
||||||
|
|
||||||
|
class AudioListener
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~AudioListener(){};
|
||||||
|
virtual void onAudioTick() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_DFF_MODEL_
|
||||||
|
#define _TYRA_DFF_MODEL_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <math3d.h>
|
||||||
|
#include "../loaders/dff_structure.hpp"
|
||||||
|
#include "./math/vector3.hpp"
|
||||||
|
|
||||||
|
/** Class which have common types for all 3D objects */
|
||||||
|
class DffModel
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
DffModel();
|
||||||
|
~DffModel();
|
||||||
|
|
||||||
|
u32 getDrawData(u32 splitIndex, VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, Vector3 &t_cameraPos, float t_scale, u8 t_shouldBeBackfaceCulled);
|
||||||
|
RwClump clump;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void fillNextFace(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, u8 geometry, u32 t_getI, u32 t_setI);
|
||||||
|
u8 isMemoryAllocated;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_LIGHT_BULB_
|
||||||
|
#define _TYRA_LIGHT_BULB_
|
||||||
|
|
||||||
|
#include "math/vector3.hpp"
|
||||||
|
#include <tamtypes.h>
|
||||||
|
|
||||||
|
struct LightBulb
|
||||||
|
{
|
||||||
|
Vector3 position;
|
||||||
|
u16 intensity;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_MATRIX_
|
||||||
|
#define _TYRA_MATRIX_
|
||||||
|
|
||||||
|
#include "vector3.hpp"
|
||||||
|
#include "../screen_settings.hpp"
|
||||||
|
|
||||||
|
/** https://en.wikipedia.org/wiki/Matrix_(mathematics) */
|
||||||
|
class Matrix
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
float data[16];
|
||||||
|
|
||||||
|
Matrix(float m11, float m12, float m13, float m14,
|
||||||
|
float m21, float m22, float m23, float m24,
|
||||||
|
float m31, float m32, float m33, float m34,
|
||||||
|
float m41, float m42, float m43, float m44);
|
||||||
|
Matrix(const Matrix &v);
|
||||||
|
Matrix operator*(Matrix &v);
|
||||||
|
Matrix();
|
||||||
|
~Matrix();
|
||||||
|
|
||||||
|
void lookAt(Vector3 &t_up, Vector3 &t_position, Vector3 &t_target);
|
||||||
|
void identity();
|
||||||
|
void makeZRotation(float t_radians);
|
||||||
|
void translate(float t_x, float t_y, float t_z);
|
||||||
|
void setPerspective(ScreenSettings &screen);
|
||||||
|
void print();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_PLANE_
|
||||||
|
#define _TYRA_PLANE_
|
||||||
|
|
||||||
|
#include "vector3.hpp"
|
||||||
|
|
||||||
|
/** https://en.wikipedia.org/wiki/Plane_(geometry) */
|
||||||
|
class Plane
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
Vector3 normal;
|
||||||
|
float distance;
|
||||||
|
|
||||||
|
Plane();
|
||||||
|
Plane(Vector3 &a, Vector3 &b, Vector3 &c);
|
||||||
|
~Plane();
|
||||||
|
|
||||||
|
void update(Vector3 &a, Vector3 &b, Vector3 &c);
|
||||||
|
inline float distanceTo(Vector3 &t_vec) { return this->distance + this->normal.innerProduct(t_vec); }
|
||||||
|
void print();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_POINT_
|
||||||
|
#define _TYRA_POINT_
|
||||||
|
|
||||||
|
/** https://en.wikipedia.org/wiki/Point_(geometry) */
|
||||||
|
class Point
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
};
|
||||||
|
float xy[2] __attribute__((__aligned__(16)));
|
||||||
|
};
|
||||||
|
|
||||||
|
Point(float x, float y);
|
||||||
|
Point();
|
||||||
|
~Point();
|
||||||
|
|
||||||
|
void set(float x, float y);
|
||||||
|
void print();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_VECTOR3_
|
||||||
|
#define _TYRA_VECTOR3_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
|
||||||
|
class Math; // Forward definition
|
||||||
|
|
||||||
|
/** https://en.wikipedia.org/wiki/Vector_(mathematics_and_physics) */
|
||||||
|
class Vector3
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
};
|
||||||
|
float xyz[3] __attribute__((__aligned__(16)));
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector3(float x, float y, float z);
|
||||||
|
Vector3(const Vector3 &v);
|
||||||
|
Vector3();
|
||||||
|
~Vector3();
|
||||||
|
|
||||||
|
Vector3 operator+(Vector3 v);
|
||||||
|
Vector3 operator-(const Vector3 &v);
|
||||||
|
Vector3 operator*(Vector3 &v);
|
||||||
|
Vector3 operator*(float t);
|
||||||
|
Vector3 operator/(float t);
|
||||||
|
Vector3 operator-(void);
|
||||||
|
|
||||||
|
static u8 shouldBeBackfaceCulled(const Vector3 *t_cameraPos, const Vector3 *v0, const Vector3 *v1, const Vector3 *v2);
|
||||||
|
u8 collidesSquare(Vector3 &t_min, Vector3 &t_max);
|
||||||
|
u8 isOnSquare(Vector3 &t_min, Vector3 &t_max);
|
||||||
|
float length();
|
||||||
|
void normalize();
|
||||||
|
void setByLerp(const Vector3 &v1, const Vector3 &v2, const float t_interp);
|
||||||
|
float innerProduct(Vector3 &v);
|
||||||
|
void set(Vector3 &v);
|
||||||
|
void set(float x, float y, float z);
|
||||||
|
void copy(Vector3 &v);
|
||||||
|
float distanceTo(Vector3 &v);
|
||||||
|
void print();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_MD2_MODEL_
|
||||||
|
#define _TYRA_MD2_MODEL_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <math3d.h>
|
||||||
|
#include "math/vector3.hpp"
|
||||||
|
#include "math/point.hpp"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 startFrame;
|
||||||
|
u32 endFrame;
|
||||||
|
float speed;
|
||||||
|
float interpolation;
|
||||||
|
u32 animType;
|
||||||
|
u32 currentFrame;
|
||||||
|
u32 nextFrame;
|
||||||
|
} MD2AnimState;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u16 verticeIndexes[3];
|
||||||
|
u16 coordIndexes[3];
|
||||||
|
} MD2Triangle;
|
||||||
|
|
||||||
|
/** Class which have common types for all 3D objects */
|
||||||
|
class MD2Model
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
u32 verticesPerFrameCount, framesCount, coordinatesCount, trianglesCount;
|
||||||
|
Vector3 *vertices __attribute__((aligned(16)));
|
||||||
|
Point *coordinates;
|
||||||
|
u32 *normalIndexes;
|
||||||
|
MD2Triangle *triangles;
|
||||||
|
MD2AnimState animState;
|
||||||
|
/** File name without extension */
|
||||||
|
char *filename;
|
||||||
|
MD2Model(char *t_md2File);
|
||||||
|
~MD2Model();
|
||||||
|
u32 getCurrentFrameData(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, Vector3 &t_cameraPos, float t_scale, u8 t_shouldBeBackfaceCulled);
|
||||||
|
void allocateMemory();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 calcVector;
|
||||||
|
Vector3 calc3Vectors[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_OBJECT3D_
|
||||||
|
#define _TYRA_OBJECT3D_
|
||||||
|
|
||||||
|
#include "math/vector3.hpp"
|
||||||
|
#include "math/plane.hpp"
|
||||||
|
#include "mesh_spec.hpp"
|
||||||
|
#include "obj_model.hpp"
|
||||||
|
#include "dff_model.hpp"
|
||||||
|
#include "md2_model.hpp"
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <draw_types.h>
|
||||||
|
|
||||||
|
/** Class which have common types for all 3D objects */
|
||||||
|
class Mesh
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
Vector3 position, rotation;
|
||||||
|
u8 shouldBeLighted, shouldBeBackfaceCulled, shouldBeFrustumCulled;
|
||||||
|
|
||||||
|
MeshSpec *spec;
|
||||||
|
MD2Model *md2;
|
||||||
|
ObjModel *obj;
|
||||||
|
DffModel *dff;
|
||||||
|
float scale;
|
||||||
|
color_t color;
|
||||||
|
Vector3 boxVertices[8];
|
||||||
|
|
||||||
|
Mesh();
|
||||||
|
~Mesh();
|
||||||
|
|
||||||
|
void loadObj(char *t_subfolder, char *t_objFile, Vector3 &t_initPos, float t_scale);
|
||||||
|
void setObj(Vector3 &t_initPos, ObjModel *t_objModel, MeshSpec *t_spec);
|
||||||
|
void loadDff(char *t_subfolder, char *t_dffFile, Vector3 &t_initPos, float t_scale);
|
||||||
|
void setDff(Vector3 &t_initPos, DffModel *t_dffModel, MeshSpec *t_spec);
|
||||||
|
void loadMD2(char *t_subfolder, char *t_md2File, Vector3 &t_initPos, float t_scale);
|
||||||
|
void getMinMax(Vector3 *t_min, Vector3 *t_max);
|
||||||
|
void playAnimation(u32 t_startFrame, u32 t_endFrame);
|
||||||
|
u32 getVertexCount();
|
||||||
|
void setAnimSpeed(float t_value);
|
||||||
|
u32 getDrawData(u32 splitIndex, VECTOR *t_vertices, VECTOR *t_normals, VECTOR *t_coordinates, VECTOR *t_colors, Vector3 &t_cameraPos);
|
||||||
|
u8 isInFrustum(Plane *t_frustumPlanes);
|
||||||
|
|
||||||
|
u8 isMd2Loaded, isObjLoaded, isDffLoaded, isSpecInitialized;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setDefaultWrapSettings(texwrap_t &t_wrapSettings);
|
||||||
|
u32 verticesCount;
|
||||||
|
Vector3 *vertices;
|
||||||
|
void loadTextures(char *t_subfolder, char *t_extension);
|
||||||
|
void computeBoundingBox();
|
||||||
|
void setVerticesReference(u32 t_verticesCount, Vector3 *t_verticesRef);
|
||||||
|
void createSpecIfNotCreated();
|
||||||
|
void setDefaultColor();
|
||||||
|
void getFarthestVertex(Vector3 *o_result, int t_offset);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_OBJECT3D_SPEC_
|
||||||
|
#define _TYRA_OBJECT3D_SPEC_
|
||||||
|
|
||||||
|
#include "math/vector3.hpp"
|
||||||
|
#include "./texture.hpp"
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <draw_buffers.h>
|
||||||
|
#include <draw_sampling.h>
|
||||||
|
|
||||||
|
/** Class which contain 3D object specification */
|
||||||
|
class MeshSpec
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
texbuffer_t textureBuffer;
|
||||||
|
clutbuffer_t clut;
|
||||||
|
lod_t lod;
|
||||||
|
|
||||||
|
MeshSpec();
|
||||||
|
~MeshSpec();
|
||||||
|
void allocateTextureBuffer(u16 t_width, u16 t_height);
|
||||||
|
void deallocateTextureBuffer();
|
||||||
|
void allocateMemory();
|
||||||
|
void setupLodAndClut();
|
||||||
|
Texture *textures;
|
||||||
|
|
||||||
|
private:
|
||||||
|
u8 isTextureVRAMAllocated;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_OBJ_MODEL_
|
||||||
|
#define _TYRA_OBJ_MODEL_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <math3d.h>
|
||||||
|
#include "math/vector3.hpp"
|
||||||
|
|
||||||
|
/** Class which have common types for all 3D objects */
|
||||||
|
class ObjModel
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
u32 verticesCount, coordinatesCount, normalsCount, facesCount;
|
||||||
|
Vector3 *vertices __attribute__((aligned(16))),
|
||||||
|
*coordinates __attribute__((aligned(16))),
|
||||||
|
*normals __attribute__((aligned(16)));
|
||||||
|
u32 *verticeFaces, *coordinateFaces, *normalFaces;
|
||||||
|
|
||||||
|
/** File name without extension */
|
||||||
|
char *filename;
|
||||||
|
|
||||||
|
ObjModel(char *t_objFile);
|
||||||
|
~ObjModel();
|
||||||
|
u32 getDrawData(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, Vector3 &t_cameraPos, float t_scale, u8 t_shouldBeBackfaceCulled);
|
||||||
|
void allocateMemory();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void fillNextFace(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, u32 t_getI, u32 t_setI);
|
||||||
|
u8 isMemoryAllocated;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_RENDER_DATA_
|
||||||
|
#define _TYRA_RENDER_DATA_
|
||||||
|
|
||||||
|
#include "light_bulb.hpp"
|
||||||
|
#include <draw_primitives.h>
|
||||||
|
#include "math/matrix.hpp"
|
||||||
|
#include "math/plane.hpp"
|
||||||
|
|
||||||
|
struct RenderData
|
||||||
|
{
|
||||||
|
LightBulb *bulbs;
|
||||||
|
u16 bulbsCount;
|
||||||
|
/** Camera (lookAt) */
|
||||||
|
Matrix *worldView;
|
||||||
|
/** Perspective projection */
|
||||||
|
Matrix *perspective;
|
||||||
|
Vector3 *cameraPosition;
|
||||||
|
Plane *frustumPlanes;
|
||||||
|
prim_t *prim;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_SCREEN_SETTINGS_
|
||||||
|
#define _TYRA_SCREEN_SETTINGS_
|
||||||
|
|
||||||
|
struct ScreenSettings
|
||||||
|
{
|
||||||
|
float fov;
|
||||||
|
float width;
|
||||||
|
float height;
|
||||||
|
float aspectRatio;
|
||||||
|
float nearPlaneDist;
|
||||||
|
float farPlaneDist;
|
||||||
|
/** change it to 4096.0F to check out frustum culling! 😎 */
|
||||||
|
float projectionScale;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_TEXTURE_
|
||||||
|
#define _TYRA_TEXTURE_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <draw_sampling.h>
|
||||||
|
|
||||||
|
struct Texture
|
||||||
|
{
|
||||||
|
u32 id;
|
||||||
|
unsigned char *data;
|
||||||
|
texwrap_t wrapSettings;
|
||||||
|
char *name;
|
||||||
|
u8 width, height;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_AUDIO_
|
||||||
|
#define _TYRA_AUDIO_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <audsrv.h>
|
||||||
|
#include <kernel.h>
|
||||||
|
#include "../models/audio_listener.hpp"
|
||||||
|
|
||||||
|
#define STACK_SIZE 8 * 1024
|
||||||
|
|
||||||
|
/** Class responsible for audio playing */
|
||||||
|
class Audio
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
Audio();
|
||||||
|
~Audio();
|
||||||
|
|
||||||
|
u8 isTrackDone;
|
||||||
|
ee_sema_t sema;
|
||||||
|
int fillbufferSema;
|
||||||
|
|
||||||
|
void init(u32 t_listenersAmount);
|
||||||
|
void play();
|
||||||
|
void stop();
|
||||||
|
void loadSong(char *t_filename);
|
||||||
|
void unloadSong();
|
||||||
|
void setVolume(u8 t_volume);
|
||||||
|
void addListener(AudioListener *t_listener);
|
||||||
|
void startThread();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void work();
|
||||||
|
static void audioThread();
|
||||||
|
u8 isInitialized, shouldPlay, songLoaded, isVolumeSet;
|
||||||
|
|
||||||
|
ee_thread_t audioThreadAttr;
|
||||||
|
u8 audioThreadStack[STACK_SIZE] ALIGNED(16);
|
||||||
|
int audioThreadId;
|
||||||
|
|
||||||
|
AudioListener **listeners;
|
||||||
|
u32 listenersAmount;
|
||||||
|
u32 addedListeners;
|
||||||
|
void initSema();
|
||||||
|
void loadModules();
|
||||||
|
void initAUDSRV();
|
||||||
|
|
||||||
|
int ret, played;
|
||||||
|
char chunk[2048];
|
||||||
|
FILE *wav;
|
||||||
|
audsrv_fmt_t format;
|
||||||
|
static int fillbuffer(void *arg);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_CAMERA_BASE_
|
||||||
|
#define _TYRA_CAMERA_BASE_
|
||||||
|
|
||||||
|
#include "../models/math/plane.hpp"
|
||||||
|
#include "../models/math/matrix.hpp"
|
||||||
|
#include "../models/math/vector3.hpp"
|
||||||
|
#include "../models/screen_settings.hpp"
|
||||||
|
|
||||||
|
/** Class responsible for frustum culling */
|
||||||
|
class CameraBase
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
CameraBase(ScreenSettings *t_screen, Vector3 *t_position, Vector3 *t_up, Vector3 *t_unitCirclePosition);
|
||||||
|
virtual ~CameraBase(){};
|
||||||
|
|
||||||
|
void setScreen();
|
||||||
|
void updatePlanes(Vector3 t_target);
|
||||||
|
Plane planes[6];
|
||||||
|
Matrix worldView;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ScreenSettings *screen;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 *position2, *up2, *unitCirclePosition2;
|
||||||
|
float farPlaneDist, nearPlaneDist, nearHeight, nearWidth, farHeight, farWidth;
|
||||||
|
Vector3 ftl, ftr, fbl, fbr, ntl, ntr, nbl, nbr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_GIF_SENDER_
|
||||||
|
#define _TYRA_GIF_SENDER_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <draw_buffers.h>
|
||||||
|
#include <draw_types.h>
|
||||||
|
#include <draw_primitives.h>
|
||||||
|
#include <math3d.h>
|
||||||
|
#include <packet.h>
|
||||||
|
#include "../models/mesh.hpp"
|
||||||
|
#include "../models/math/matrix.hpp"
|
||||||
|
#include "../models/screen_settings.hpp"
|
||||||
|
#include "../models/light_bulb.hpp"
|
||||||
|
#include "../models/render_data.hpp"
|
||||||
|
|
||||||
|
/** Class responsible for sending data packets via GIF (PATH3) */
|
||||||
|
class GifSender
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
GifSender(u32 t_packetSize, ScreenSettings *t_screen);
|
||||||
|
~GifSender();
|
||||||
|
|
||||||
|
void initPacket(u8 context);
|
||||||
|
void addObjects(RenderData *t_renderData, Mesh **t_objects3D, u32 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||||
|
void addClear(zbuffer_t *t_zBuffer);
|
||||||
|
void sendPacket();
|
||||||
|
void sendClear(zbuffer_t *t_zBuffer);
|
||||||
|
static void sendTexture(Texture &texture, texbuffer_t *t_texBuffer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
xyz_t *xyz;
|
||||||
|
color_t *rgbaq;
|
||||||
|
texel_t *st;
|
||||||
|
u8 isAnyObjectAdded;
|
||||||
|
ScreenSettings *screen;
|
||||||
|
u64 *dw;
|
||||||
|
qword_t *q, *dmatag;
|
||||||
|
packet_t *packets[2];
|
||||||
|
packet_t *currentPacket;
|
||||||
|
u8 packetsCount;
|
||||||
|
int packetSize;
|
||||||
|
float halfScreenW, halfScreenH;
|
||||||
|
MATRIX localWorld, localScreen, localLight;
|
||||||
|
|
||||||
|
u32 calc3DObject(Matrix t_perspective, Mesh &t_mesh, RenderData *t_renderData, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||||
|
void convertCalcs(u32 t_vertCount, VECTOR *t_vertices, VECTOR *t_colors, VECTOR *t_sts, u8 t_alpha);
|
||||||
|
void addCurrentCalcs(u32 &t_vertexCount);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_LIGHT_
|
||||||
|
#define _TYRA_LIGHT_
|
||||||
|
|
||||||
|
#include <math3d.h>
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include "../models/math/vector3.hpp"
|
||||||
|
#include "../models/light_bulb.hpp"
|
||||||
|
|
||||||
|
class Light
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
Light();
|
||||||
|
~Light();
|
||||||
|
|
||||||
|
static u16 getLightsCount(u32 t_bulbsCount);
|
||||||
|
static void calculateLight(VECTOR *t_lightDirections, VECTOR *t_lightColors, int *t_lightTypes, LightBulb *t_bulbs, u32 t_bulbsCount, Vector3 t_objPosition);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_PAD_
|
||||||
|
#define _TYRA_PAD_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <libpad.h>
|
||||||
|
|
||||||
|
/** Class responsible for player pad */
|
||||||
|
class Pad
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
u8 isCrossClicked, isSquareClicked, isTriangleClicked, isCircleClicked;
|
||||||
|
u8 isDpadUpPressed, isDpadDownPressed, isDpadLeftPressed, isDpadRightPressed;
|
||||||
|
u8 lJoyH, lJoyV, rJoyH, rJoyV;
|
||||||
|
|
||||||
|
Pad();
|
||||||
|
~Pad();
|
||||||
|
void update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
char padBuf[256] __attribute__((aligned(64)));
|
||||||
|
char actAlign[6];
|
||||||
|
int actuators, ret, port, slot;
|
||||||
|
padButtonStatus buttons;
|
||||||
|
u32 padData, oldPad, newPad;
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
void loadModules();
|
||||||
|
int waitPadReady();
|
||||||
|
int initPad();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_RENDERER_
|
||||||
|
#define _TYRA_RENDERER_
|
||||||
|
|
||||||
|
#include <draw_buffers.h>
|
||||||
|
#include <draw_primitives.h>
|
||||||
|
#include <packet.h>
|
||||||
|
#include "gif_sender.hpp"
|
||||||
|
#include "vif_sender.hpp"
|
||||||
|
#include "../models/math/plane.hpp"
|
||||||
|
#include "../models/screen_settings.hpp"
|
||||||
|
#include "../models/render_data.hpp"
|
||||||
|
|
||||||
|
/** Class responsible for intializing draw env, textures and buffers */
|
||||||
|
class Renderer
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
Renderer(u32 t_packetSize, ScreenSettings *t_screen);
|
||||||
|
~Renderer();
|
||||||
|
|
||||||
|
framebuffer_t frameBuffers[2];
|
||||||
|
u8 context;
|
||||||
|
zbuffer_t zBuffer;
|
||||||
|
prim_t prim;
|
||||||
|
|
||||||
|
/** PATH3 Many + lighting */
|
||||||
|
void drawByPath3(Mesh **t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||||
|
/** PATH3 Single + lighting */
|
||||||
|
void drawByPath3(Mesh *t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||||
|
/** PATH3 Many */
|
||||||
|
void drawByPath3(Mesh **t_meshes, u16 t_amount);
|
||||||
|
/** PATH3 Single */
|
||||||
|
void drawByPath3(Mesh *t_mesh);
|
||||||
|
|
||||||
|
/** PATH1 Many + lighting */
|
||||||
|
void draw(Mesh **t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||||
|
/** PATH1 Single + lighting */
|
||||||
|
void draw(Mesh *t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||||
|
/** PATH1 Many */
|
||||||
|
void draw(Mesh **t_meshes, u16 t_amount);
|
||||||
|
/** PATH1 Single */
|
||||||
|
void draw(Mesh *t_mesh);
|
||||||
|
|
||||||
|
void setCameraDefinitions(Matrix *t_worldView, Vector3 *t_cameraPos, Plane *t_planes);
|
||||||
|
|
||||||
|
void endFrame(float fps);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void changeTexture(Mesh *t_mesh, u8 t_textureIndex);
|
||||||
|
void flipBuffers();
|
||||||
|
void beginFrameIfNeeded();
|
||||||
|
u8 isFrameEmpty;
|
||||||
|
Matrix perspective;
|
||||||
|
RenderData renderData;
|
||||||
|
|
||||||
|
u32 lastTextureId;
|
||||||
|
GifSender *gifSender;
|
||||||
|
VifSender *vifSender;
|
||||||
|
packet_t *flipPacket;
|
||||||
|
void allocateBuffers(float t_screenW, float t_screenH);
|
||||||
|
void initDrawingEnv(float t_screenW, float t_screenH);
|
||||||
|
void setPrim();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_TIMER_
|
||||||
|
#define _TYRA_TIMER_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
|
||||||
|
/** Class responsible for fps counting */
|
||||||
|
class Timer
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
Timer();
|
||||||
|
~Timer();
|
||||||
|
|
||||||
|
u32 getTimeDelta();
|
||||||
|
void primeTimer();
|
||||||
|
float getFPS();
|
||||||
|
|
||||||
|
private:
|
||||||
|
u32 lastTime, time, change;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_VIF_SENDER_
|
||||||
|
#define _TYRA_VIF_SENDER_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include "../models/render_data.hpp"
|
||||||
|
#include "../models/light_bulb.hpp"
|
||||||
|
#include "../models/mesh.hpp"
|
||||||
|
#include "../models/math/matrix.hpp"
|
||||||
|
#include "../models/math/vector3.hpp"
|
||||||
|
#include "vu1.hpp"
|
||||||
|
|
||||||
|
/** Class responsible for sending 3D objects via VIF (PATH 1) */
|
||||||
|
class VifSender
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
VifSender();
|
||||||
|
~VifSender();
|
||||||
|
|
||||||
|
// TODO refactor
|
||||||
|
void drawMesh(RenderData *t_renderData, Matrix t_perspective, u32 vertCount2, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, VECTOR *colors, Mesh *t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void drawVertices(Mesh *t_mesh, u32 t_start, u32 t_end, VECTOR *t_vertices, VECTOR *t_colors, VECTOR *t_coordinates, prim_t *t_prim);
|
||||||
|
|
||||||
|
MATRIX localWorld, localScreen;
|
||||||
|
VECTOR position, rotation;
|
||||||
|
u32 vertCount;
|
||||||
|
VU1 vu1;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_VU1_
|
||||||
|
#define _TYRA_VU1_
|
||||||
|
|
||||||
|
#include "../models/math/matrix.hpp"
|
||||||
|
#include <draw_buffers.h>
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <draw_primitives.h>
|
||||||
|
#include <packet.h>
|
||||||
|
#include <math3d.h>
|
||||||
|
|
||||||
|
const u32 VIF_BUFFER_SIZE = 48 * 1024;
|
||||||
|
|
||||||
|
typedef struct VU1BuildList
|
||||||
|
{
|
||||||
|
u8 isBuilding;
|
||||||
|
void *offset;
|
||||||
|
void *kickBuffer;
|
||||||
|
u32 dmaSize;
|
||||||
|
u32 dmaSizeAll;
|
||||||
|
u32 dmaDestination;
|
||||||
|
} VU1BuildList;
|
||||||
|
|
||||||
|
/** Class responsible for managing VU1 micro programs */
|
||||||
|
class VU1
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
VU1();
|
||||||
|
~VU1();
|
||||||
|
|
||||||
|
static void uploadProgram(int t_dest, u32 *t_start, u32 *t_end);
|
||||||
|
void createList();
|
||||||
|
void sendSingleRefList(int t_destAddress, void *t_data, int t_quadSize);
|
||||||
|
void addListBeginning();
|
||||||
|
void continueList();
|
||||||
|
void addReferenceList(u32 t_offset, void *t_data, u32 t_size, u8 t_useTops);
|
||||||
|
void addFloat(float v);
|
||||||
|
void add32(u32 v);
|
||||||
|
void add64(u64 v);
|
||||||
|
void add128(u64 v1, u64 v2);
|
||||||
|
void addListEnding();
|
||||||
|
void addStartProgram();
|
||||||
|
void addContinueProgram();
|
||||||
|
void sendList();
|
||||||
|
void addDoubleBufferSetting();
|
||||||
|
void addFlush();
|
||||||
|
|
||||||
|
private:
|
||||||
|
u8 isDoubleBufferSet;
|
||||||
|
void checkDataAlignment(void *data);
|
||||||
|
VU1BuildList buildList;
|
||||||
|
char dmaBuffer1[VIF_BUFFER_SIZE] __attribute__((aligned(16)));
|
||||||
|
char dmaBuffer2[VIF_BUFFER_SIZE] __attribute__((aligned(16)));
|
||||||
|
void *currentBuffer;
|
||||||
|
u32 switchBuffer;
|
||||||
|
static u32 countProgramSize(u32 *t_start, u32 *t_end);
|
||||||
|
void checkList();
|
||||||
|
inline s32 AddUnpack(int format, int addr, int num, int usetops = 0, int nosign = 1, int masking = 0)
|
||||||
|
{
|
||||||
|
return (s32)((0x60 << 24) + (format << 24) + (masking << 28) + (usetops << 15) +
|
||||||
|
(nosign << 14) + (num << 16) + addr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DMA_REF_TAG(ADDR, COUNT) ((((unsigned long)ADDR) << 32) | (0x3 << 28) | COUNT)
|
||||||
|
#define DMA_CNT_TAG(COUNT) (((unsigned long)(0x1) << 28) | COUNT)
|
||||||
|
#define DMA_END_TAG(COUNT) (((unsigned long)(0x7) << 28) | COUNT)
|
||||||
|
#define VIF_NOP 0x00
|
||||||
|
#define VIF_STCYL 0x01
|
||||||
|
#define VIF_OFFSET 0x02
|
||||||
|
#define VIF_BASE 0x03
|
||||||
|
#define VIF_FLUSH 0x11
|
||||||
|
#define VIF_MSCAL 0x14
|
||||||
|
#define VIF_MSCNT 0x17
|
||||||
|
#define VIF_MPG 0x4A
|
||||||
|
#define V4_32 0xC
|
||||||
|
#define VIF_UNPACK 0x60
|
||||||
|
#define U128(n) ((u128)(n))
|
||||||
|
#define VIF_UNPACK_V4_32 (VIF_UNPACK | V4_32)
|
||||||
|
#define VIF_CODE(CMD, NUM, IMMEDIATE) ((((unsigned int)(CMD)) << 24) | \
|
||||||
|
(((unsigned int)(NUM)) << 16) | \
|
||||||
|
((unsigned int)(IMMEDIATE)))
|
||||||
|
#define GS_PRIM(PRIM, IIP, TME, FGE, ABE, AA1, FST, CTXT, FIX) U128((FIX << 10) | (CTXT << 9) | (FST << 8) | (AA1 << 7) | (ABE << 6) | (FGE << 5) | (TME << 4) | (IIP << 3) | (PRIM))
|
||||||
|
#define GS_GIFTAG(NLOOP, EOP, PRE, PRIM, FLG, NREG) (((u64)(NREG) << 60) | ((u64)(FLG) << 58) | ((u64)(PRIM) << 47) | ((u64)(PRE) << 46) | (EOP << 15) | (NLOOP << 0))
|
||||||
|
#define VU1_DMA_CHAN_TIMEOUT -1
|
||||||
|
#define GS_GIFTAG_PACKED 0
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 1997-2001 Id Software, Inc.
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_ANORMS_
|
||||||
|
#define _TYRA_ANORMS_
|
||||||
|
|
||||||
|
const float ANORMS[162][3] = {
|
||||||
|
{-0.525731f, 0.000000f, 0.850651f},
|
||||||
|
{-0.442863f, 0.238856f, 0.864188f},
|
||||||
|
{-0.295242f, 0.000000f, 0.955423f},
|
||||||
|
{-0.309017f, 0.500000f, 0.809017f},
|
||||||
|
{-0.162460f, 0.262866f, 0.951056f},
|
||||||
|
{0.000000f, 0.000000f, 1.000000f},
|
||||||
|
{0.000000f, 0.850651f, 0.525731f},
|
||||||
|
{-0.147621f, 0.716567f, 0.681718f},
|
||||||
|
{0.147621f, 0.716567f, 0.681718f},
|
||||||
|
{0.000000f, 0.525731f, 0.850651f},
|
||||||
|
{0.309017f, 0.500000f, 0.809017f},
|
||||||
|
{0.525731f, 0.000000f, 0.850651f},
|
||||||
|
{0.295242f, 0.000000f, 0.955423f},
|
||||||
|
{0.442863f, 0.238856f, 0.864188f},
|
||||||
|
{0.162460f, 0.262866f, 0.951056f},
|
||||||
|
{-0.681718f, 0.147621f, 0.716567f},
|
||||||
|
{-0.809017f, 0.309017f, 0.500000f},
|
||||||
|
{-0.587785f, 0.425325f, 0.688191f},
|
||||||
|
{-0.850651f, 0.525731f, 0.000000f},
|
||||||
|
{-0.864188f, 0.442863f, 0.238856f},
|
||||||
|
{-0.716567f, 0.681718f, 0.147621f},
|
||||||
|
{-0.688191f, 0.587785f, 0.425325f},
|
||||||
|
{-0.500000f, 0.809017f, 0.309017f},
|
||||||
|
{-0.238856f, 0.864188f, 0.442863f},
|
||||||
|
{-0.425325f, 0.688191f, 0.587785f},
|
||||||
|
{-0.716567f, 0.681718f, -0.147621f},
|
||||||
|
{-0.500000f, 0.809017f, -0.309017f},
|
||||||
|
{-0.525731f, 0.850651f, 0.000000f},
|
||||||
|
{0.000000f, 0.850651f, -0.525731f},
|
||||||
|
{-0.238856f, 0.864188f, -0.442863f},
|
||||||
|
{0.000000f, 0.955423f, -0.295242f},
|
||||||
|
{-0.262866f, 0.951056f, -0.162460f},
|
||||||
|
{0.000000f, 1.000000f, 0.000000f},
|
||||||
|
{0.000000f, 0.955423f, 0.295242f},
|
||||||
|
{-0.262866f, 0.951056f, 0.162460f},
|
||||||
|
{0.238856f, 0.864188f, 0.442863f},
|
||||||
|
{0.262866f, 0.951056f, 0.162460f},
|
||||||
|
{0.500000f, 0.809017f, 0.309017f},
|
||||||
|
{0.238856f, 0.864188f, -0.442863f},
|
||||||
|
{0.262866f, 0.951056f, -0.162460f},
|
||||||
|
{0.500000f, 0.809017f, -0.309017f},
|
||||||
|
{0.850651f, 0.525731f, 0.000000f},
|
||||||
|
{0.716567f, 0.681718f, 0.147621f},
|
||||||
|
{0.716567f, 0.681718f, -0.147621f},
|
||||||
|
{0.525731f, 0.850651f, 0.000000f},
|
||||||
|
{0.425325f, 0.688191f, 0.587785f},
|
||||||
|
{0.864188f, 0.442863f, 0.238856f},
|
||||||
|
{0.688191f, 0.587785f, 0.425325f},
|
||||||
|
{0.809017f, 0.309017f, 0.500000f},
|
||||||
|
{0.681718f, 0.147621f, 0.716567f},
|
||||||
|
{0.587785f, 0.425325f, 0.688191f},
|
||||||
|
{0.955423f, 0.295242f, 0.000000f},
|
||||||
|
{1.000000f, 0.000000f, 0.000000f},
|
||||||
|
{0.951056f, 0.162460f, 0.262866f},
|
||||||
|
{0.850651f, -0.525731f, 0.000000f},
|
||||||
|
{0.955423f, -0.295242f, 0.000000f},
|
||||||
|
{0.864188f, -0.442863f, 0.238856f},
|
||||||
|
{0.951056f, -0.162460f, 0.262866f},
|
||||||
|
{0.809017f, -0.309017f, 0.500000f},
|
||||||
|
{0.681718f, -0.147621f, 0.716567f},
|
||||||
|
{0.850651f, 0.000000f, 0.525731f},
|
||||||
|
{0.864188f, 0.442863f, -0.238856f},
|
||||||
|
{0.809017f, 0.309017f, -0.500000f},
|
||||||
|
{0.951056f, 0.162460f, -0.262866f},
|
||||||
|
{0.525731f, 0.000000f, -0.850651f},
|
||||||
|
{0.681718f, 0.147621f, -0.716567f},
|
||||||
|
{0.681718f, -0.147621f, -0.716567f},
|
||||||
|
{0.850651f, 0.000000f, -0.525731f},
|
||||||
|
{0.809017f, -0.309017f, -0.500000f},
|
||||||
|
{0.864188f, -0.442863f, -0.238856f},
|
||||||
|
{0.951056f, -0.162460f, -0.262866f},
|
||||||
|
{0.147621f, 0.716567f, -0.681718f},
|
||||||
|
{0.309017f, 0.500000f, -0.809017f},
|
||||||
|
{0.425325f, 0.688191f, -0.587785f},
|
||||||
|
{0.442863f, 0.238856f, -0.864188f},
|
||||||
|
{0.587785f, 0.425325f, -0.688191f},
|
||||||
|
{0.688191f, 0.587785f, -0.425325f},
|
||||||
|
{-0.147621f, 0.716567f, -0.681718f},
|
||||||
|
{-0.309017f, 0.500000f, -0.809017f},
|
||||||
|
{0.000000f, 0.525731f, -0.850651f},
|
||||||
|
{-0.525731f, 0.000000f, -0.850651f},
|
||||||
|
{-0.442863f, 0.238856f, -0.864188f},
|
||||||
|
{-0.295242f, 0.000000f, -0.955423f},
|
||||||
|
{-0.162460f, 0.262866f, -0.951056f},
|
||||||
|
{0.000000f, 0.000000f, -1.000000f},
|
||||||
|
{0.295242f, 0.000000f, -0.955423f},
|
||||||
|
{0.162460f, 0.262866f, -0.951056f},
|
||||||
|
{-0.442863f, -0.238856f, -0.864188f},
|
||||||
|
{-0.309017f, -0.500000f, -0.809017f},
|
||||||
|
{-0.162460f, -0.262866f, -0.951056f},
|
||||||
|
{0.000000f, -0.850651f, -0.525731f},
|
||||||
|
{-0.147621f, -0.716567f, -0.681718f},
|
||||||
|
{0.147621f, -0.716567f, -0.681718f},
|
||||||
|
{0.000000f, -0.525731f, -0.850651f},
|
||||||
|
{0.309017f, -0.500000f, -0.809017f},
|
||||||
|
{0.442863f, -0.238856f, -0.864188f},
|
||||||
|
{0.162460f, -0.262866f, -0.951056f},
|
||||||
|
{0.238856f, -0.864188f, -0.442863f},
|
||||||
|
{0.500000f, -0.809017f, -0.309017f},
|
||||||
|
{0.425325f, -0.688191f, -0.587785f},
|
||||||
|
{0.716567f, -0.681718f, -0.147621f},
|
||||||
|
{0.688191f, -0.587785f, -0.425325f},
|
||||||
|
{0.587785f, -0.425325f, -0.688191f},
|
||||||
|
{0.000000f, -0.955423f, -0.295242f},
|
||||||
|
{0.000000f, -1.000000f, 0.000000f},
|
||||||
|
{0.262866f, -0.951056f, -0.162460f},
|
||||||
|
{0.000000f, -0.850651f, 0.525731f},
|
||||||
|
{0.000000f, -0.955423f, 0.295242f},
|
||||||
|
{0.238856f, -0.864188f, 0.442863f},
|
||||||
|
{0.262866f, -0.951056f, 0.162460f},
|
||||||
|
{0.500000f, -0.809017f, 0.309017f},
|
||||||
|
{0.716567f, -0.681718f, 0.147621f},
|
||||||
|
{0.525731f, -0.850651f, 0.000000f},
|
||||||
|
{-0.238856f, -0.864188f, -0.442863f},
|
||||||
|
{-0.500000f, -0.809017f, -0.309017f},
|
||||||
|
{-0.262866f, -0.951056f, -0.162460f},
|
||||||
|
{-0.850651f, -0.525731f, 0.000000f},
|
||||||
|
{-0.716567f, -0.681718f, -0.147621f},
|
||||||
|
{-0.716567f, -0.681718f, 0.147621f},
|
||||||
|
{-0.525731f, -0.850651f, 0.000000f},
|
||||||
|
{-0.500000f, -0.809017f, 0.309017f},
|
||||||
|
{-0.238856f, -0.864188f, 0.442863f},
|
||||||
|
{-0.262866f, -0.951056f, 0.162460f},
|
||||||
|
{-0.864188f, -0.442863f, 0.238856f},
|
||||||
|
{-0.809017f, -0.309017f, 0.500000f},
|
||||||
|
{-0.688191f, -0.587785f, 0.425325f},
|
||||||
|
{-0.681718f, -0.147621f, 0.716567f},
|
||||||
|
{-0.442863f, -0.238856f, 0.864188f},
|
||||||
|
{-0.587785f, -0.425325f, 0.688191f},
|
||||||
|
{-0.309017f, -0.500000f, 0.809017f},
|
||||||
|
{-0.147621f, -0.716567f, 0.681718f},
|
||||||
|
{-0.425325f, -0.688191f, 0.587785f},
|
||||||
|
{-0.162460f, -0.262866f, 0.951056f},
|
||||||
|
{0.442863f, -0.238856f, 0.864188f},
|
||||||
|
{0.162460f, -0.262866f, 0.951056f},
|
||||||
|
{0.309017f, -0.500000f, 0.809017f},
|
||||||
|
{0.147621f, -0.716567f, 0.681718f},
|
||||||
|
{0.000000f, -0.525731f, 0.850651f},
|
||||||
|
{0.425325f, -0.688191f, 0.587785f},
|
||||||
|
{0.587785f, -0.425325f, 0.688191f},
|
||||||
|
{0.688191f, -0.587785f, 0.425325f},
|
||||||
|
{-0.955423f, 0.295242f, 0.000000f},
|
||||||
|
{-0.951056f, 0.162460f, 0.262866f},
|
||||||
|
{-1.000000f, 0.000000f, 0.000000f},
|
||||||
|
{-0.850651f, 0.000000f, 0.525731f},
|
||||||
|
{-0.955423f, -0.295242f, 0.000000f},
|
||||||
|
{-0.951056f, -0.162460f, 0.262866f},
|
||||||
|
{-0.864188f, 0.442863f, -0.238856f},
|
||||||
|
{-0.951056f, 0.162460f, -0.262866f},
|
||||||
|
{-0.809017f, 0.309017f, -0.500000f},
|
||||||
|
{-0.864188f, -0.442863f, -0.238856f},
|
||||||
|
{-0.951056f, -0.162460f, -0.262866f},
|
||||||
|
{-0.809017f, -0.309017f, -0.500000f},
|
||||||
|
{-0.681718f, 0.147621f, -0.716567f},
|
||||||
|
{-0.681718f, -0.147621f, -0.716567f},
|
||||||
|
{-0.850651f, 0.000000f, -0.525731f},
|
||||||
|
{-0.688191f, 0.587785f, -0.425325f},
|
||||||
|
{-0.587785f, 0.425325f, -0.688191f},
|
||||||
|
{-0.425325f, 0.688191f, -0.587785f},
|
||||||
|
{-0.425325f, -0.688191f, -0.587785f},
|
||||||
|
{-0.587785f, -0.425325f, -0.688191f},
|
||||||
|
{-0.688191f, -0.587785f, -0.425325f}};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_DEBUG_
|
||||||
|
#define _TYRA_DEBUG_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <math3d.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define PRINT_LOG(TEXT) printf("LOG: " TEXT " (" __FILE__ ")\n")
|
||||||
|
#define PRINT_ERR(TEXT) printf("---\n--- ---\n--- --- --- ERR: " TEXT " (" __FILE__ ")\n--- ---\n---\n")
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_MATH_
|
||||||
|
#define _TYRA_MATH_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <math3d.h>
|
||||||
|
#include "../models/math/vector3.hpp"
|
||||||
|
|
||||||
|
class Vector3; // Forward definition
|
||||||
|
|
||||||
|
void manyVec3ToNative(VECTOR *t_result, Vector3 *t_vec, int t_amount, float t_fourthVal);
|
||||||
|
void vec3ToNative(VECTOR t_result, Vector3 &t_vec, float t_fourthVal);
|
||||||
|
|
||||||
|
class Math
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
const static float HALF_ANG2RAD = 3.14159265358979323846 / 360.0;
|
||||||
|
const static float PI = 3.1415926535897932384626433832795F;
|
||||||
|
const static float HALF_PI = 1.5707963267948966192313216916398F;
|
||||||
|
static float cos(float x);
|
||||||
|
static inline float sin(float x) { return cos(x - HALF_PI); };
|
||||||
|
static float sqrt(float x);
|
||||||
|
static float invSqrt(float x);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Math();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_STRING_
|
||||||
|
#define _TYRA_STRING_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
|
||||||
|
class String
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
static char *createCopy(char *source);
|
||||||
|
static u32 getLength(char *a);
|
||||||
|
static char *createConcatenated(char *a, char *b);
|
||||||
|
static char *createWithoutExtension(char *source);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/loaders/bmp_loader.hpp"
|
||||||
|
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
#include "../include/utils/string.hpp"
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
BmpLoader::BmpLoader() {}
|
||||||
|
|
||||||
|
BmpLoader::~BmpLoader() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param t_name Without extension. Example "skyfall2"
|
||||||
|
* @param t_extension With dot and extension. Example ".BMP"
|
||||||
|
*/
|
||||||
|
void BmpLoader::load(Texture &o_texture, char *t_subfolder, char *t_name, char *t_extension)
|
||||||
|
{
|
||||||
|
char *t_path_part = String::createConcatenated(t_subfolder, t_name);
|
||||||
|
char *t_path = String::createConcatenated(t_path_part, t_extension);
|
||||||
|
delete[] t_path_part;
|
||||||
|
|
||||||
|
FILE *file = fopen(t_path, "rb");
|
||||||
|
|
||||||
|
if (file == NULL)
|
||||||
|
PRINT_ERR("Failed to load .bmp file!");
|
||||||
|
|
||||||
|
unsigned char header[54];
|
||||||
|
fread(header, sizeof(unsigned char), 54, file);
|
||||||
|
|
||||||
|
u32 width = *(u32 *)&header[18];
|
||||||
|
u32 height = *(u32 *)&header[22];
|
||||||
|
o_texture.id = rand() % 100000;
|
||||||
|
o_texture.width = width;
|
||||||
|
o_texture.height = height;
|
||||||
|
o_texture.data = new unsigned char[width * height * 3];
|
||||||
|
printf("BMPLoader - width: %d | height: %d\n", width, height);
|
||||||
|
|
||||||
|
u64 rowPadded = (width * 3 + 3) & (~3);
|
||||||
|
|
||||||
|
unsigned char *data = new unsigned char[rowPadded];
|
||||||
|
unsigned char tmp;
|
||||||
|
|
||||||
|
u32 x = 0;
|
||||||
|
for (u32 i = 0; i < height; i++)
|
||||||
|
{
|
||||||
|
fread(data, sizeof(unsigned char), rowPadded, file);
|
||||||
|
for (u32 j = 0; j < width * 3; j += 3)
|
||||||
|
{
|
||||||
|
// Convert (B, G, R) to (R, G, B)
|
||||||
|
tmp = data[j];
|
||||||
|
data[j] = data[j + 2];
|
||||||
|
data[j + 2] = tmp;
|
||||||
|
|
||||||
|
o_texture.data[x] = data[j];
|
||||||
|
o_texture.data[x + 1] = data[j + 1];
|
||||||
|
o_texture.data[x + 2] = data[j + 2];
|
||||||
|
x += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete[] t_path;
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
@@ -0,0 +1,346 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTICE: Based on
|
||||||
|
* https://github.com/mrqo/rw_parse/blob/master/rw_utils/rw_utils.cpp
|
||||||
|
* rw_utils.cpp Written by Marek Iwaniuk (c).
|
||||||
|
* Dff structure documentation http://www.chronetal.co.uk/gta/index.php?page=dff
|
||||||
|
* Created on 02/04/2017 (MM/DD/YYYY)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/loaders/dff_loader.hpp"
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
#include "../include/utils/math.hpp"
|
||||||
|
#include "../include/utils/string.hpp"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
DffLoader::DffLoader() {}
|
||||||
|
|
||||||
|
DffLoader::~DffLoader() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
void DffLoader::load(RwClump &o_clump, char *t_filename, float t_scale)
|
||||||
|
{
|
||||||
|
PRINT_LOG("Loading dff file");
|
||||||
|
FILE *file = fopen(t_filename, "rb");
|
||||||
|
if (file == NULL)
|
||||||
|
PRINT_ERR("Failed to load .obj file!");
|
||||||
|
fseek(file, 0L, SEEK_END);
|
||||||
|
long fileSize = ftell(file);
|
||||||
|
u8 *data = new u8[fileSize];
|
||||||
|
rewind(file);
|
||||||
|
fread(data, sizeof(u8), fileSize, file);
|
||||||
|
fclose(file);
|
||||||
|
serialize(o_clump, data, t_scale);
|
||||||
|
delete[] data;
|
||||||
|
PRINT_LOG("Dff file loaded!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DffLoader::serialize(RwClump &t_clump, u8 *t_data, float t_scale)
|
||||||
|
{
|
||||||
|
u32 ptrPos = 0;
|
||||||
|
readSectionHeader(t_clump, t_data, ptrPos);
|
||||||
|
readSectionHeader(t_clump.data, t_data, ptrPos);
|
||||||
|
readClumpData(t_clump.data, t_data, ptrPos);
|
||||||
|
readSectionHeader(t_clump.frameList, t_data, ptrPos);
|
||||||
|
readSectionHeader(t_clump.frameList.data, t_data, ptrPos);
|
||||||
|
readFrameListData(t_clump.frameList.data, t_data, ptrPos);
|
||||||
|
|
||||||
|
t_clump.frameList.extensions = new RwFrameListExtension[t_clump.frameList.data.frameCount];
|
||||||
|
for (u32 i = 0; i < t_clump.frameList.data.frameCount; i++)
|
||||||
|
{
|
||||||
|
readSectionHeader(t_clump.frameList.extensions[i], t_data, ptrPos);
|
||||||
|
ptrPos += t_clump.frameList.extensions[i].sectionSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
readSectionHeader(t_clump.geometryList, t_data, ptrPos);
|
||||||
|
readSectionHeader(t_clump.geometryList.data, t_data, ptrPos);
|
||||||
|
readGeometryListData(t_clump.geometryList.data, t_data, ptrPos);
|
||||||
|
|
||||||
|
t_clump.geometryList.geometries = new RwGeometry[t_clump.geometryList.data.geometryCount];
|
||||||
|
printf("Geometries:%d\n", t_clump.geometryList.data.geometryCount);
|
||||||
|
for (u32 i = 0; i < t_clump.geometryList.data.geometryCount; i++)
|
||||||
|
{
|
||||||
|
readSectionHeader(t_clump.geometryList.geometries[i], t_data, ptrPos);
|
||||||
|
readSectionHeader(t_clump.geometryList.geometries[i].data, t_data, ptrPos);
|
||||||
|
readGeometryData(t_clump.geometryList.geometries[i].data, t_data, ptrPos, t_scale);
|
||||||
|
|
||||||
|
readSectionHeader(t_clump.geometryList.geometries[i].materialList, t_data, ptrPos);
|
||||||
|
readSectionHeader(t_clump.geometryList.geometries[i].materialList.data, t_data, ptrPos);
|
||||||
|
readMaterialListData(t_clump.geometryList.geometries[i].materialList.data, t_data, ptrPos);
|
||||||
|
|
||||||
|
u32 materialCount = t_clump.geometryList.geometries[i].materialList.data.materialCount;
|
||||||
|
printf("Materials:%d\n", materialCount);
|
||||||
|
|
||||||
|
t_clump.geometryList.geometries[i].materialList.materials = new RwMaterial[materialCount];
|
||||||
|
for (u32 j = 0; j < materialCount; j++)
|
||||||
|
{
|
||||||
|
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j], t_data, ptrPos);
|
||||||
|
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].data, t_data, ptrPos);
|
||||||
|
readMaterialData(t_clump.geometryList.geometries[i].materialList.materials[j].data, t_data, ptrPos);
|
||||||
|
|
||||||
|
u32 textureCount = t_clump.geometryList.geometries[i].materialList.materials[j].data.textureCount;
|
||||||
|
t_clump.geometryList.geometries[i].materialList.materials[j].textures = new RwTexture[textureCount];
|
||||||
|
for (u32 k = 0; k < textureCount; k++)
|
||||||
|
{
|
||||||
|
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k], t_data, ptrPos);
|
||||||
|
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].data, t_data, ptrPos);
|
||||||
|
readTextureData(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].data, t_data, ptrPos);
|
||||||
|
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].textureName, t_data, ptrPos);
|
||||||
|
readStringData(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].textureName, t_data, ptrPos);
|
||||||
|
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].textureAlphaName, t_data, ptrPos);
|
||||||
|
readStringData(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].textureAlphaName, t_data, ptrPos);
|
||||||
|
|
||||||
|
// The content of extension is Sky Mipmap Val
|
||||||
|
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].extension, t_data, ptrPos);
|
||||||
|
ptrPos += t_clump.geometryList.geometries[i].materialList.materials[j].textures[k].extension.sectionSize;
|
||||||
|
}
|
||||||
|
// Probably always void extension
|
||||||
|
readSectionHeader(t_clump.geometryList.geometries[i].materialList.materials[j].extension, t_data, ptrPos);
|
||||||
|
ptrPos += t_clump.geometryList.geometries[i].materialList.materials[j].extension.sectionSize;
|
||||||
|
}
|
||||||
|
// For Bin Mesh aka Material split
|
||||||
|
readSectionHeader(t_clump.geometryList.geometries[i].extension, t_data, ptrPos);
|
||||||
|
readGeometryExtension(t_clump.geometryList.geometries[i].extension, t_data, ptrPos);
|
||||||
|
ptrPos += t_clump.geometryList.geometries[i].extension.sectionSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
readSectionHeader(t_clump.atomic, t_data, ptrPos);
|
||||||
|
readSectionHeader(t_clump.atomic.data, t_data, ptrPos);
|
||||||
|
ptrPos += t_clump.atomic.data.sectionSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DffLoader::readSectionHeader(RwSectionHeader &t_sh, u8 *t_buffer, u32 &t_ptrPos)
|
||||||
|
{
|
||||||
|
t_sh.sectionType = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_sh.sectionSize = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_sh.versionNumber = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
void DffLoader::readFrameListData(RwFrameListData &t_frd, u8 *t_buffer, u32 &t_ptrPos)
|
||||||
|
{
|
||||||
|
t_frd.frameCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
printf("Frame count:%d\n", t_frd.frameCount);
|
||||||
|
t_frd.frameInformation = new RwFrameListChunk[t_frd.frameCount];
|
||||||
|
|
||||||
|
for (u32 i = 0; i < t_frd.frameCount; i++)
|
||||||
|
{
|
||||||
|
t_frd.frameInformation[i].rotationalMatrix = new float[t_frd.ROT_MAT_DIM];
|
||||||
|
for (u32 j = 0; j < t_frd.ROT_MAT_DIM; j++)
|
||||||
|
t_frd.frameInformation[i].rotationalMatrix[j] = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
|
||||||
|
t_frd.frameInformation[i].coordinatesOffsetX = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_frd.frameInformation[i].coordinatesOffsetY = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_frd.frameInformation[i].coordinatesOffsetZ = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_frd.frameInformation[i]
|
||||||
|
.parentFrame = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_frd.frameInformation[i].unk1 = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DffLoader::readClumpData(RwClumpData &t_cd, u8 *t_buffer, u32 &t_ptrPos)
|
||||||
|
{
|
||||||
|
t_cd.objectCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_cd.unk1 = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_cd.unk2 = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DffLoader::readGeometryListData(RwGeometryListData &t_gld, u8 *t_buffer, u32 &t_ptrPos)
|
||||||
|
{
|
||||||
|
t_gld.geometryCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DffLoader::readGeometryExtension(RwGeometryExtension &t_ge, u8 *t_buffer, u32 &t_ptrPos)
|
||||||
|
{
|
||||||
|
for (u8 i = 0; i < 3; i++)
|
||||||
|
t_ptrPos += sizeof(u32);
|
||||||
|
|
||||||
|
t_ge.materialSplit.header.triangleStrip = readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_ge.materialSplit.header.splitCount = readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_ge.materialSplit.header.faceCount = readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
|
||||||
|
t_ge.materialSplit.splitInformation = new RwGeometryListInfoChunk[t_ge.materialSplit.header.splitCount];
|
||||||
|
for (u32 i = 0; i < t_ge.materialSplit.header.splitCount; i++)
|
||||||
|
{
|
||||||
|
t_ge.materialSplit.splitInformation[i].faceIndex = readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_ge.materialSplit.splitInformation[i].materialIndex = readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
|
||||||
|
t_ge.materialSplit.splitInformation[i].vertexInformation = new RwGeometryListVertexInfoChunk[t_ge.materialSplit.splitInformation[i].faceIndex];
|
||||||
|
for (u32 j = 0; j < t_ge.materialSplit.splitInformation[i].faceIndex; j++)
|
||||||
|
t_ge.materialSplit.splitInformation[i].vertexInformation[j].vertex1 = readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DffLoader::readGeometryData(RwGeometryData &t_gd, u8 *t_buffer, u32 &t_ptrPos, float t_scale)
|
||||||
|
{
|
||||||
|
t_gd.dataHeader.flags = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.dataHeader.unk1 = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.dataHeader.triangleCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.dataHeader.vertexCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.dataHeader.morphTargetCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
|
||||||
|
if (false)
|
||||||
|
{ // version equals 4099 according to old documentation, disabled as for now
|
||||||
|
t_gd.lightingHeader.ambient = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.lightingHeader.diffuse = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.lightingHeader.specular = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t_gd.dataHeader.flags & rwOBJECT_VERTEX_PRELIT)
|
||||||
|
{
|
||||||
|
t_gd.colorInformation = new RwGeometryDataColorInformationChunk[t_gd.dataHeader.vertexCount];
|
||||||
|
for (u32 i = 0; i < t_gd.dataHeader.vertexCount; i++)
|
||||||
|
{
|
||||||
|
t_gd.colorInformation[i].red = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.colorInformation[i].green = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.colorInformation[i].blue = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.colorInformation[i].alpha = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t_gd.dataHeader.flags & rwOBJECT_VERTEX_TEXTURED)
|
||||||
|
{
|
||||||
|
t_gd.textureMappingInformation = new RwGeometryDataTextureMappingInformationChunk[t_gd.dataHeader.vertexCount];
|
||||||
|
for (u32 i = 0; i < t_gd.dataHeader.vertexCount; i++)
|
||||||
|
{
|
||||||
|
t_gd.textureMappingInformation[i].u = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.textureMappingInformation[i].v = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t_gd.faceInformation = new RwGeometryDataFaceInformation[t_gd.dataHeader.triangleCount];
|
||||||
|
for (u32 i = 0; i < t_gd.dataHeader.triangleCount; i++)
|
||||||
|
{
|
||||||
|
t_gd.faceInformation[i].vertex2 = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.faceInformation[i].vertex1 = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.faceInformation[i].flags = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.faceInformation[i].vertex3 = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_gd.nonameInfo.boundingSphereX = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.nonameInfo.boundingSphereY = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.nonameInfo.boundingSphereZ = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.nonameInfo.boundingSphereR = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.nonameInfo.hasPosition = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.nonameInfo.hasNormals = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
|
||||||
|
t_gd.vertexInformation = new Vector3[t_gd.dataHeader.vertexCount];
|
||||||
|
for (u32 i = 0; i < t_gd.dataHeader.vertexCount; i++)
|
||||||
|
{
|
||||||
|
t_gd.vertexInformation[i].x = readFloatFromArrayLE(t_buffer, t_ptrPos) * t_scale;
|
||||||
|
t_gd.vertexInformation[i].y = readFloatFromArrayLE(t_buffer, t_ptrPos) * t_scale;
|
||||||
|
t_gd.vertexInformation[i].z = readFloatFromArrayLE(t_buffer, t_ptrPos) * t_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t_gd.dataHeader.flags & rwOBJECT_VERTEX_NORMALS)
|
||||||
|
{
|
||||||
|
t_gd.normalInformation = new Vector3[t_gd.dataHeader.vertexCount];
|
||||||
|
for (u32 i = 0; i < t_gd.dataHeader.vertexCount; i++)
|
||||||
|
{
|
||||||
|
t_gd.normalInformation[i].x = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.normalInformation[i].y = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_gd.normalInformation[i].z = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DffLoader::readMaterialListData(RwMaterialListData &t_mld, u8 *t_buffer, u32 &t_ptrPos)
|
||||||
|
{
|
||||||
|
t_mld.materialCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_mld.arrayOfUnks = new u32[t_mld.materialCount];
|
||||||
|
for (u32 i = 0; i < t_mld.materialCount; i++)
|
||||||
|
{
|
||||||
|
t_mld.arrayOfUnks[i] = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DffLoader::readMaterialData(RwMaterialData &t_md, u8 *t_buffer, u32 &t_ptrPos)
|
||||||
|
{
|
||||||
|
t_md.unk1 = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_md.R = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_md.G = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_md.B = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_md.A = readByteFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_md.unk2 = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_md.textureCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_md.unkPosX = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_md.unkPosY = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_md.unkPosZ = readFloatFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DffLoader::readTextureData(RwTextureData &t_td, u8 *t_buffer, u32 &t_ptrPos)
|
||||||
|
{
|
||||||
|
t_td.textureFilterModeFlags = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
t_td.unk = readWordFromArrayLE(t_buffer, t_ptrPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DffLoader::readStringData(RwString &t_s, u8 *t_buffer, u32 &t_ptrPos)
|
||||||
|
{
|
||||||
|
t_s.text = readString(t_buffer, t_ptrPos, t_s.sectionSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
u8 DffLoader::readByteFromArrayLE(u8 *t_buffer, u32 &t_ptrPos)
|
||||||
|
{
|
||||||
|
return t_buffer[t_ptrPos++];
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 DffLoader::readWordFromArrayLE(u8 *t_buffer, u32 &t_ptrPos)
|
||||||
|
{
|
||||||
|
u16 res = (t_buffer[t_ptrPos + 1] << 8) + (t_buffer[t_ptrPos]);
|
||||||
|
t_ptrPos += sizeof(u16);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 DffLoader::readDwordFromArrayLE(u8 *t_buffer, u32 &t_ptrPos)
|
||||||
|
{
|
||||||
|
u32 res = (t_buffer[t_ptrPos + 3] << 24) + (t_buffer[t_ptrPos + 2] << 16) + (t_buffer[t_ptrPos + 1] << 8) + (t_buffer[t_ptrPos]);
|
||||||
|
t_ptrPos += sizeof(u32);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DffLoader::readFloatFromArrayLE(u8 *t_buffer, u32 &t_ptrPos)
|
||||||
|
{
|
||||||
|
float res;
|
||||||
|
memcpy(&res, t_buffer + t_ptrPos, sizeof(float));
|
||||||
|
t_ptrPos += sizeof(float);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *DffLoader::readData(u8 *t_buffer, u32 &t_ptrPos, u32 t_dataSize)
|
||||||
|
{
|
||||||
|
u8 *arr = new u8[t_dataSize];
|
||||||
|
for (u32 i = 0; i < t_dataSize; ++i)
|
||||||
|
arr[i] = t_buffer[i + t_ptrPos];
|
||||||
|
t_ptrPos += t_dataSize;
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *DffLoader::readString(u8 *t_buffer, u32 &t_ptrPos, u32 t_dataSize)
|
||||||
|
{
|
||||||
|
u32 strLength = String::getLength((char *)&t_buffer[t_ptrPos]);
|
||||||
|
char *result = new char[strLength + 1];
|
||||||
|
for (u32 i = 0; i < strLength; i++)
|
||||||
|
result[i] = (char)t_buffer[t_ptrPos + i];
|
||||||
|
result[strLength] = '\0';
|
||||||
|
t_ptrPos += t_dataSize;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/loaders/md2_loader.hpp"
|
||||||
|
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
#include "../include/models/math/vector3.hpp"
|
||||||
|
#include "../include/models/math/point.hpp"
|
||||||
|
#include <string.h>
|
||||||
|
#include <iosfwd>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
MD2Loader::MD2Loader() {}
|
||||||
|
|
||||||
|
MD2Loader::~MD2Loader() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Load, parse .obj file and load data into given MeshSpec */
|
||||||
|
void MD2Loader::load(MD2Model *o_result, char *t_filename, float t_scale)
|
||||||
|
{
|
||||||
|
PRINT_LOG("Loading new MD2 file");
|
||||||
|
md2_t header; // md2 header
|
||||||
|
char *buffer; // buffer storing frame data
|
||||||
|
|
||||||
|
FILE *file = fopen(t_filename, "rb");
|
||||||
|
|
||||||
|
if (file == NULL)
|
||||||
|
PRINT_ERR("Failed to load .md2 file!");
|
||||||
|
|
||||||
|
fread((char *)&header, sizeof(md2_t), 1, file);
|
||||||
|
|
||||||
|
if ((header.ident != MD2_IDENT) && (header.version != MD2_VERSION))
|
||||||
|
PRINT_ERR("This MD2 file was not in correct format!");
|
||||||
|
|
||||||
|
o_result->framesCount = header.num_frames;
|
||||||
|
o_result->verticesPerFrameCount = header.num_xyz;
|
||||||
|
o_result->coordinatesCount = header.num_st;
|
||||||
|
o_result->trianglesCount = header.num_tris;
|
||||||
|
|
||||||
|
printf("MD2 - Frames: %d\n", header.num_frames);
|
||||||
|
printf("MD2 - Vert: %d\n", header.num_xyz);
|
||||||
|
printf("MD2 - Tris: %d\n", header.num_tris);
|
||||||
|
printf("MD2 - STs: %d\n", header.num_st);
|
||||||
|
printf("MD2 - Skin W:%d H: %d\n", header.skinwidth, header.skinheight);
|
||||||
|
|
||||||
|
o_result->allocateMemory();
|
||||||
|
|
||||||
|
buffer = new char[o_result->framesCount * header.framesize];
|
||||||
|
fseek(file, header.ofs_frames, SEEK_SET);
|
||||||
|
fread((char *)buffer, o_result->framesCount * header.framesize, 1, file);
|
||||||
|
|
||||||
|
frame_t *frame; // temporary vars
|
||||||
|
Vector3 *ptrVerts;
|
||||||
|
u32 *ptrNormals;
|
||||||
|
// vertex array initialization
|
||||||
|
for (u32 j = 0; j < o_result->framesCount; j++)
|
||||||
|
{
|
||||||
|
frame = (frame_t *)&buffer[header.framesize * j];
|
||||||
|
ptrVerts = &o_result->vertices[o_result->verticesPerFrameCount * j];
|
||||||
|
ptrNormals = &o_result->normalIndexes[o_result->verticesPerFrameCount * j];
|
||||||
|
|
||||||
|
for (u32 i = 0; i < o_result->verticesPerFrameCount; i++)
|
||||||
|
{
|
||||||
|
ptrVerts[i].x = ((frame->verts[i].v[0] * frame->scale[0]) + frame->translate[0]) * t_scale;
|
||||||
|
ptrVerts[i].y = ((frame->verts[i].v[1] * frame->scale[1]) + frame->translate[1]) * t_scale;
|
||||||
|
ptrVerts[i].z = ((frame->verts[i].v[2] * frame->scale[2]) + frame->translate[2]) * t_scale;
|
||||||
|
|
||||||
|
ptrNormals[i] = frame->verts[i].lightnormalindex;
|
||||||
|
}
|
||||||
|
if (j == o_result->framesCount - 1)
|
||||||
|
printf("Last frame, last vert: X:%f Y:%f Z:%f\n",
|
||||||
|
ptrVerts[o_result->verticesPerFrameCount - 1].x,
|
||||||
|
ptrVerts[o_result->verticesPerFrameCount - 1].y,
|
||||||
|
ptrVerts[o_result->verticesPerFrameCount - 1].z);
|
||||||
|
}
|
||||||
|
delete[] buffer;
|
||||||
|
|
||||||
|
buffer = new char[o_result->coordinatesCount * sizeof(texCoord_t)];
|
||||||
|
fseek(file, header.ofs_st, SEEK_SET);
|
||||||
|
fread((char *)buffer, o_result->coordinatesCount * sizeof(texCoord_t), 1, file);
|
||||||
|
|
||||||
|
texCoord_t *texCoord;
|
||||||
|
for (u32 i = 0; i < o_result->coordinatesCount; i++)
|
||||||
|
{
|
||||||
|
texCoord = (texCoord_t *)&buffer[sizeof(texCoord_t) * i];
|
||||||
|
o_result->coordinates[i].x = (float)texCoord->s / header.skinwidth;
|
||||||
|
o_result->coordinates[i].y = (float)texCoord->t / header.skinheight;
|
||||||
|
}
|
||||||
|
delete[] buffer;
|
||||||
|
|
||||||
|
printf("Last tex coord(%d): S:%f T:%f\n",
|
||||||
|
o_result->coordinatesCount,
|
||||||
|
o_result->coordinates[o_result->coordinatesCount - 1].x,
|
||||||
|
o_result->coordinates[o_result->coordinatesCount - 1].y);
|
||||||
|
|
||||||
|
buffer = new char[o_result->trianglesCount * sizeof(triangle_t)];
|
||||||
|
fseek(file, header.ofs_tris, SEEK_SET);
|
||||||
|
fread((char *)buffer, o_result->trianglesCount * sizeof(triangle_t), 1, file);
|
||||||
|
|
||||||
|
triangle_t *triangle; // temporary var
|
||||||
|
// vertex array initialization
|
||||||
|
for (u32 i = 0; i < o_result->trianglesCount; i++)
|
||||||
|
{
|
||||||
|
triangle = (triangle_t *)&buffer[sizeof(triangle_t) * i];
|
||||||
|
for (u8 j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
o_result->triangles[i].verticeIndexes[j] = triangle->index_xyz[j];
|
||||||
|
o_result->triangles[i].coordIndexes[j] = triangle->index_st[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete[] buffer;
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
PRINT_LOG("MD2 file loaded!");
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/loaders/obj_loader.hpp"
|
||||||
|
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
ObjLoader::ObjLoader() {}
|
||||||
|
|
||||||
|
ObjLoader::~ObjLoader() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Load, parse .obj file and load data into given MeshSpec */
|
||||||
|
void ObjLoader::load(ObjModel *o_result, char *t_filename, float t_scale)
|
||||||
|
{
|
||||||
|
FILE *file = fopen(t_filename, "rb");
|
||||||
|
if (file == NULL)
|
||||||
|
PRINT_ERR("Failed to load .obj file!");
|
||||||
|
setObjDataQuantities(file, o_result);
|
||||||
|
o_result->allocateMemory();
|
||||||
|
u32 verticesI = 0, cordsI = 0, normalsI = 0, i = 0, vertexIndex[3], coordIndex[3], normalIndex[3];
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
char lineHeader[128]; // read the first word of the line
|
||||||
|
int res = fscanf(file, "%s", lineHeader);
|
||||||
|
if (res != EOF)
|
||||||
|
{
|
||||||
|
if (strcmp(lineHeader, "v") == 0)
|
||||||
|
{
|
||||||
|
Vector3 vector = Vector3();
|
||||||
|
fscanf(file, "%f %f %f\n", &vector.x, &vector.y, &vector.z);
|
||||||
|
o_result->vertices[verticesI++] = vector * t_scale;
|
||||||
|
}
|
||||||
|
else if (strcmp(lineHeader, "vt") == 0)
|
||||||
|
{
|
||||||
|
Vector3 vector = Vector3();
|
||||||
|
fscanf(file, "%f %f\n", &vector.x, &vector.y);
|
||||||
|
o_result->coordinates[cordsI++] = vector;
|
||||||
|
}
|
||||||
|
else if (strcmp(lineHeader, "vn") == 0)
|
||||||
|
{
|
||||||
|
Vector3 vector = Vector3();
|
||||||
|
fscanf(file, "%f %f %f\n", &vector.x, &vector.y, &vector.z);
|
||||||
|
o_result->normals[normalsI++] = vector;
|
||||||
|
}
|
||||||
|
else if (strcmp(lineHeader, "f") == 0)
|
||||||
|
{
|
||||||
|
int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n",
|
||||||
|
&vertexIndex[0], &coordIndex[0], &normalIndex[0],
|
||||||
|
&vertexIndex[1], &coordIndex[1], &normalIndex[1],
|
||||||
|
&vertexIndex[2], &coordIndex[2], &normalIndex[2]);
|
||||||
|
if (matches != 9)
|
||||||
|
PRINT_ERR(".obj can't be read by this simple parser. Try exporting with other options");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
o_result->verticeFaces[i] = vertexIndex[0] - 1;
|
||||||
|
o_result->verticeFaces[i + 1] = vertexIndex[1] - 1;
|
||||||
|
o_result->verticeFaces[i + 2] = vertexIndex[2] - 1;
|
||||||
|
|
||||||
|
o_result->coordinateFaces[i] = coordIndex[0] - 1;
|
||||||
|
o_result->coordinateFaces[i + 1] = coordIndex[1] - 1;
|
||||||
|
o_result->coordinateFaces[i + 2] = coordIndex[2] - 1;
|
||||||
|
|
||||||
|
o_result->normalFaces[i] = normalIndex[0] - 1;
|
||||||
|
o_result->normalFaces[i + 1] = normalIndex[1] - 1;
|
||||||
|
o_result->normalFaces[i + 2] = normalIndex[2] - 1;
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Calculate how many vertices(v), coordinates(vt), normals(vn) and faces(f) have .obj file
|
||||||
|
* When done, file read offset is resetted to the begginning of file
|
||||||
|
*/
|
||||||
|
void ObjLoader::setObjDataQuantities(FILE *t_file, ObjModel *o_result)
|
||||||
|
{
|
||||||
|
o_result->verticesCount = 0;
|
||||||
|
o_result->coordinatesCount = 0;
|
||||||
|
o_result->normalsCount = 0;
|
||||||
|
o_result->facesCount = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
char lineHeader[128];
|
||||||
|
int res = fscanf(t_file, "%s", lineHeader);
|
||||||
|
if (res != EOF)
|
||||||
|
{
|
||||||
|
if (strcmp(lineHeader, "v") == 0)
|
||||||
|
o_result->verticesCount += 1;
|
||||||
|
else if (strcmp(lineHeader, "vt") == 0)
|
||||||
|
o_result->coordinatesCount += 1;
|
||||||
|
else if (strcmp(lineHeader, "vn") == 0)
|
||||||
|
o_result->normalsCount += 1;
|
||||||
|
else if (strcmp(lineHeader, "f") == 0)
|
||||||
|
o_result->facesCount += 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fseek(t_file, 0, SEEK_SET);
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/models/dff_model.hpp"
|
||||||
|
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
DffModel::DffModel() {}
|
||||||
|
|
||||||
|
DffModel::~DffModel() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
u32 DffModel::getDrawData(u32 splitIndex, VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, Vector3 &t_cameraPos, float t_scale, u8 t_shouldBeBackfaceCulled)
|
||||||
|
{
|
||||||
|
u32 result = 0;
|
||||||
|
for (u32 i = 0; i < clump.geometryList.geometries[0].extension.materialSplit.splitInformation[splitIndex].faceIndex; i++)
|
||||||
|
fillNextFace(o_vertices, o_normals, o_coordinates, o_colors, 0,
|
||||||
|
clump.geometryList.geometries[0].extension.materialSplit.splitInformation[splitIndex].vertexInformation[i].vertex1,
|
||||||
|
result++);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DffModel::fillNextFace(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, u8 geometry, u32 t_getI, u32 t_setI)
|
||||||
|
{
|
||||||
|
o_vertices[t_setI][0] = clump.geometryList.geometries[geometry].data.vertexInformation[t_getI].x;
|
||||||
|
o_vertices[t_setI][1] = clump.geometryList.geometries[geometry].data.vertexInformation[t_getI].y;
|
||||||
|
o_vertices[t_setI][2] = clump.geometryList.geometries[geometry].data.vertexInformation[t_getI].z;
|
||||||
|
o_vertices[t_setI][3] = 1.0F;
|
||||||
|
|
||||||
|
o_normals[t_setI][0] = clump.geometryList.geometries[geometry].data.normalInformation[t_getI].x;
|
||||||
|
o_normals[t_setI][1] = clump.geometryList.geometries[geometry].data.normalInformation[t_getI].y;
|
||||||
|
o_normals[t_setI][2] = clump.geometryList.geometries[geometry].data.normalInformation[t_getI].z;
|
||||||
|
o_normals[t_setI][3] = 1.0F;
|
||||||
|
|
||||||
|
o_coordinates[t_setI][0] = clump.geometryList.geometries[geometry].data.textureMappingInformation[t_getI].u;
|
||||||
|
o_coordinates[t_setI][1] = 1.0F - clump.geometryList.geometries[geometry].data.textureMappingInformation[t_getI].v;
|
||||||
|
o_coordinates[t_setI][2] = 1.0F;
|
||||||
|
o_coordinates[t_setI][3] = 1.0F;
|
||||||
|
|
||||||
|
o_colors[t_setI][0] = 1.0F;
|
||||||
|
o_colors[t_setI][1] = 1.0F;
|
||||||
|
o_colors[t_setI][2] = 1.0F;
|
||||||
|
o_colors[t_setI][3] = 1.0F;
|
||||||
|
}
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../include/models/math/matrix.hpp"
|
||||||
|
|
||||||
|
#include "../../include/utils/math.hpp"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Create by specifying all points */
|
||||||
|
Matrix::Matrix(float m11, float m12, float m13, float m14,
|
||||||
|
float m21, float m22, float m23, float m24,
|
||||||
|
float m31, float m32, float m33, float m34,
|
||||||
|
float m41, float m42, float m43, float m44)
|
||||||
|
{
|
||||||
|
data[0] = m11;
|
||||||
|
data[1] = m12;
|
||||||
|
data[2] = m13;
|
||||||
|
data[3] = m14;
|
||||||
|
|
||||||
|
data[4] = m21;
|
||||||
|
data[5] = m22;
|
||||||
|
data[6] = m23;
|
||||||
|
data[7] = m24;
|
||||||
|
|
||||||
|
data[8] = m31;
|
||||||
|
data[9] = m32;
|
||||||
|
data[10] = m33;
|
||||||
|
data[11] = m34;
|
||||||
|
|
||||||
|
data[12] = m41;
|
||||||
|
data[13] = m42;
|
||||||
|
data[14] = m43;
|
||||||
|
data[15] = m44;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create with another matrix values */
|
||||||
|
Matrix::Matrix(const Matrix &v)
|
||||||
|
{
|
||||||
|
data[0] = v.data[0];
|
||||||
|
data[1] = v.data[1];
|
||||||
|
data[2] = v.data[2];
|
||||||
|
data[3] = v.data[3];
|
||||||
|
|
||||||
|
data[4] = v.data[4];
|
||||||
|
data[5] = v.data[5];
|
||||||
|
data[6] = v.data[6];
|
||||||
|
data[7] = v.data[7];
|
||||||
|
|
||||||
|
data[8] = v.data[8];
|
||||||
|
data[9] = v.data[9];
|
||||||
|
data[10] = v.data[10];
|
||||||
|
data[11] = v.data[11];
|
||||||
|
|
||||||
|
data[12] = v.data[12];
|
||||||
|
data[13] = v.data[13];
|
||||||
|
data[14] = v.data[14];
|
||||||
|
data[15] = v.data[15];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix::identity()
|
||||||
|
{
|
||||||
|
asm volatile(
|
||||||
|
"vsub.xyzw vf4, vf0, vf0 \n\t"
|
||||||
|
"vadd.w vf4, vf4, vf0 \n\t"
|
||||||
|
"vmr32.xyzw vf5, vf4 \n\t"
|
||||||
|
"vmr32.xyzw vf6, vf5 \n\t"
|
||||||
|
"vmr32.xyzw vf7, vf6 \n\t"
|
||||||
|
"sqc2 vf4, 0x30(%0) \n\t"
|
||||||
|
"sqc2 vf5, 0x20(%0) \n\t"
|
||||||
|
"sqc2 vf6, 0x10(%0) \n\t"
|
||||||
|
"sqc2 vf7, 0x0(%0) \n\t"
|
||||||
|
:
|
||||||
|
: "r"(this->data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix::translate(float x, float y, float z)
|
||||||
|
{
|
||||||
|
this->identity();
|
||||||
|
this->data[(3 << 2) + 0] = x; // 3,0
|
||||||
|
this->data[(3 << 2) + 1] = y; // 3,1
|
||||||
|
this->data[(3 << 2) + 2] = z; // 3,2
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix::makeZRotation(float t_radians)
|
||||||
|
{
|
||||||
|
this->identity();
|
||||||
|
float c = Math::cos(t_radians);
|
||||||
|
float s = Math::sin(t_radians);
|
||||||
|
this->data[0] = c; // 0,0
|
||||||
|
this->data[1] = s; // 0,1
|
||||||
|
this->data[4] = -s; // 1,0
|
||||||
|
this->data[5] = c; // 1,1
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix Matrix::operator*(Matrix &t)
|
||||||
|
{
|
||||||
|
Matrix result;
|
||||||
|
asm volatile(
|
||||||
|
"lqc2 vf1, 0x00(%1) \n\t"
|
||||||
|
"lqc2 vf2, 0x10(%1) \n\t"
|
||||||
|
"lqc2 vf3, 0x20(%1) \n\t"
|
||||||
|
"lqc2 vf4, 0x30(%1) \n\t"
|
||||||
|
"lqc2 vf5, 0x00(%2) \n\t"
|
||||||
|
"lqc2 vf6, 0x10(%2) \n\t"
|
||||||
|
"lqc2 vf7, 0x20(%2) \n\t"
|
||||||
|
"lqc2 vf8, 0x30(%2) \n\t"
|
||||||
|
"vmulax.xyzw ACC, vf5, vf1 \n\t"
|
||||||
|
"vmadday.xyzw ACC, vf6, vf1 \n\t"
|
||||||
|
"vmaddaz.xyzw ACC, vf7, vf1 \n\t"
|
||||||
|
"vmaddw.xyzw vf1, vf8, vf1 \n\t"
|
||||||
|
"vmulax.xyzw ACC, vf5, vf2 \n\t"
|
||||||
|
"vmadday.xyzw ACC, vf6, vf2 \n\t"
|
||||||
|
"vmaddaz.xyzw ACC, vf7, vf2 \n\t"
|
||||||
|
"vmaddw.xyzw vf2, vf8, vf2 \n\t"
|
||||||
|
"vmulax.xyzw ACC, vf5, vf3 \n\t"
|
||||||
|
"vmadday.xyzw ACC, vf6, vf3 \n\t"
|
||||||
|
"vmaddaz.xyzw ACC, vf7, vf3 \n\t"
|
||||||
|
"vmaddw.xyzw vf3, vf8, vf3 \n\t"
|
||||||
|
"vmulax.xyzw ACC, vf5, vf4 \n\t"
|
||||||
|
"vmadday.xyzw ACC, vf6, vf4 \n\t"
|
||||||
|
"vmaddaz.xyzw ACC, vf7, vf4 \n\t"
|
||||||
|
"vmaddw.xyzw vf4, vf8, vf4 \n\t"
|
||||||
|
"sqc2 vf1, 0x00(%0) \n\t"
|
||||||
|
"sqc2 vf2, 0x10(%0) \n\t"
|
||||||
|
"sqc2 vf3, 0x20(%0) \n\t"
|
||||||
|
"sqc2 vf4, 0x30(%0) \n\t"
|
||||||
|
:
|
||||||
|
: "r"(result.data), "r"(this->data), "r"(t.data)
|
||||||
|
: "memory");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create empty matrix */
|
||||||
|
Matrix::Matrix()
|
||||||
|
{
|
||||||
|
data[0] = 0.0F;
|
||||||
|
data[1] = 0.0F;
|
||||||
|
data[2] = 0.0F;
|
||||||
|
data[3] = 0.0F;
|
||||||
|
|
||||||
|
data[4] = 0.0F;
|
||||||
|
data[5] = 0.0F;
|
||||||
|
data[6] = 0.0F;
|
||||||
|
data[7] = 0.0F;
|
||||||
|
|
||||||
|
data[8] = 0.0F;
|
||||||
|
data[9] = 0.0F;
|
||||||
|
data[10] = 0.0F;
|
||||||
|
data[11] = 0.0F;
|
||||||
|
|
||||||
|
data[12] = 0.0F;
|
||||||
|
data[13] = 0.0F;
|
||||||
|
data[14] = 0.0F;
|
||||||
|
data[15] = 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix::~Matrix() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Set up a perspective projection matrix
|
||||||
|
*
|
||||||
|
* Clone of gluPerspective()
|
||||||
|
* https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml
|
||||||
|
* @param fov (FOV in radians)/2
|
||||||
|
* @param aspect Aspect ratio
|
||||||
|
* @param scrW Half of screen width
|
||||||
|
* @param scrH Half of screen height
|
||||||
|
* @param zNear Distance to near plane
|
||||||
|
* @param zFar Distance to far plane
|
||||||
|
* @param projScale Projection scale
|
||||||
|
*/
|
||||||
|
void Matrix::setPerspective(ScreenSettings &t_screen)
|
||||||
|
{
|
||||||
|
float fovYdiv2 = Math::HALF_ANG2RAD * t_screen.fov;
|
||||||
|
float cotFOV = 1.0F / (Math::sin(fovYdiv2) / Math::cos(fovYdiv2));
|
||||||
|
float w = cotFOV * (t_screen.width / 4096.0F) / t_screen.aspectRatio;
|
||||||
|
float h = cotFOV * (t_screen.height / 4096.0F);
|
||||||
|
|
||||||
|
this->data[0] = w;
|
||||||
|
this->data[1] = 0.0F;
|
||||||
|
this->data[2] = 0.0F;
|
||||||
|
this->data[3] = 0.0F;
|
||||||
|
|
||||||
|
this->data[4] = 0.0F;
|
||||||
|
this->data[5] = -h;
|
||||||
|
this->data[6] = 0.0F;
|
||||||
|
this->data[7] = 0.0F;
|
||||||
|
|
||||||
|
this->data[8] = 0.0F;
|
||||||
|
this->data[9] = 0.0F;
|
||||||
|
this->data[10] =
|
||||||
|
(t_screen.farPlaneDist + t_screen.nearPlaneDist) /
|
||||||
|
(t_screen.farPlaneDist - t_screen.nearPlaneDist);
|
||||||
|
this->data[11] = -1.0F;
|
||||||
|
|
||||||
|
this->data[12] = 0.0F;
|
||||||
|
this->data[13] = 0.0F;
|
||||||
|
this->data[14] =
|
||||||
|
(2.0F * t_screen.farPlaneDist * t_screen.nearPlaneDist) /
|
||||||
|
(t_screen.farPlaneDist - t_screen.nearPlaneDist);
|
||||||
|
this->data[15] = 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a view matrix that transforms coordinates in
|
||||||
|
* such a way that the user looks at a target vector
|
||||||
|
* direction from a position vector.
|
||||||
|
*
|
||||||
|
* Clone of OpenGL lookAt function
|
||||||
|
* https://learnopengl.com/Getting-started/Camera
|
||||||
|
*/
|
||||||
|
void Matrix::lookAt(Vector3 &t_up, Vector3 &t_position, Vector3 &t_target)
|
||||||
|
{
|
||||||
|
Vector3 camForward, camUp, camRight;
|
||||||
|
|
||||||
|
camForward = t_position - t_target;
|
||||||
|
camForward.normalize();
|
||||||
|
camRight = t_up * camForward;
|
||||||
|
camRight.normalize();
|
||||||
|
camUp = camForward * camRight;
|
||||||
|
|
||||||
|
data[0] = camRight.x;
|
||||||
|
data[4] = camRight.y;
|
||||||
|
data[8] = camRight.z;
|
||||||
|
data[12] = -camRight.innerProduct(t_position);
|
||||||
|
|
||||||
|
data[1] = camUp.x;
|
||||||
|
data[5] = camUp.y;
|
||||||
|
data[9] = camUp.z;
|
||||||
|
data[13] = -camUp.innerProduct(t_position);
|
||||||
|
|
||||||
|
data[2] = camForward.x;
|
||||||
|
data[6] = camForward.y;
|
||||||
|
data[10] = camForward.z;
|
||||||
|
data[14] = -camForward.innerProduct(t_position);
|
||||||
|
|
||||||
|
data[3] = 0;
|
||||||
|
data[7] = 0;
|
||||||
|
data[11] = 0;
|
||||||
|
data[15] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matrix::print()
|
||||||
|
{
|
||||||
|
printf("MATRIX(\n%f, %f, %f, %f\n%f, %f, %f, %f\n%f, %f, %f, %f\n%f, %f, %f, %f\n)\n",
|
||||||
|
data[0], data[1], data[2], data[3],
|
||||||
|
data[4], data[5], data[6], data[7],
|
||||||
|
data[8], data[9], data[10], data[11],
|
||||||
|
data[12], data[13], data[14], data[15]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../include/models/math/plane.hpp"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Create empty plane */
|
||||||
|
Plane::Plane() { this->distance = 0; }
|
||||||
|
|
||||||
|
/** Create by specyfying 3 points.
|
||||||
|
* This function assumes that the points
|
||||||
|
* are given in counter clockwise order
|
||||||
|
*/
|
||||||
|
Plane::Plane(Vector3 &a, Vector3 &b, Vector3 &c) { this->update(a, b, c); }
|
||||||
|
|
||||||
|
Plane::~Plane() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Set plane by specyfying 3 points.
|
||||||
|
* This function assumes that the points
|
||||||
|
* are given in counter clockwise order
|
||||||
|
*/
|
||||||
|
void Plane::update(Vector3 &a, Vector3 &b, Vector3 &c)
|
||||||
|
{
|
||||||
|
Vector3 aux1 = a - b;
|
||||||
|
Vector3 aux2 = c - b;
|
||||||
|
this->normal = aux2 * aux1;
|
||||||
|
this->normal.normalize();
|
||||||
|
this->distance = -this->normal.innerProduct(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane::print()
|
||||||
|
{
|
||||||
|
printf("Plane(Vector3(%f, %f, %f), %f)\n", this->normal.x, this->normal.y, this->normal.z, this->distance);
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../include/models/math/point.hpp"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Create by specifying values */
|
||||||
|
Point::Point(float x, float y)
|
||||||
|
{
|
||||||
|
this->x = x;
|
||||||
|
this->y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create empty point */
|
||||||
|
Point::Point()
|
||||||
|
{
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point::~Point() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
void Point::set(float x, float y)
|
||||||
|
{
|
||||||
|
this->x = x;
|
||||||
|
this->y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Point::print()
|
||||||
|
{
|
||||||
|
printf("Point(%f, %f)\n", x, y);
|
||||||
|
}
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../include/models/math/vector3.hpp"
|
||||||
|
|
||||||
|
#include "../../include/utils/math.hpp"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Create by specifying 3 points */
|
||||||
|
Vector3::Vector3(float x, float y, float z)
|
||||||
|
{
|
||||||
|
this->x = x;
|
||||||
|
this->y = y;
|
||||||
|
this->z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create with another vector values */
|
||||||
|
Vector3::Vector3(const Vector3 &another)
|
||||||
|
{
|
||||||
|
x = another.x;
|
||||||
|
y = another.y;
|
||||||
|
z = another.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vector3::setByLerp(const Vector3 &v1, const Vector3 &v2, const float t_interp)
|
||||||
|
{
|
||||||
|
asm volatile(
|
||||||
|
"lqc2 vf4, 0x0(%1) \n\t" // vf4 = v1
|
||||||
|
"lqc2 vf5, 0x0(%2) \n\t" // vf5 = v2
|
||||||
|
"mfc1 $8, %3 \n\t" // vf6 = t
|
||||||
|
"qmtc2 $8, vf6 \n\t" // lerp:
|
||||||
|
"vsub.xyz vf7, vf5, vf4 \n\t" // vf7 = v2 - v1
|
||||||
|
"vmulx.xyz vf8, vf7, vf6 \n\t" // vf8 = vf7 * t
|
||||||
|
"vadd.xyz vf9, vf8, vf4 \n\t" // vf9 = vf8 + vf4
|
||||||
|
"sqc2 vf9, 0x0(%0) \n\t" // v0 = vf9
|
||||||
|
:
|
||||||
|
: "r"(&this->xyz), "r"(&v1.xyz), "r"(&v2.xyz), "f"(t_interp)
|
||||||
|
: "$8");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create empty vector */
|
||||||
|
Vector3::Vector3()
|
||||||
|
{
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
z = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3::~Vector3() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
Vector3 Vector3::operator+(Vector3 v)
|
||||||
|
{
|
||||||
|
Vector3 result;
|
||||||
|
asm volatile( // VU0 Macro program
|
||||||
|
"lqc2 vf4, 0x0(%1) \n\t"
|
||||||
|
"lqc2 vf5, 0x0(%2) \n\t"
|
||||||
|
"vadd.xyz vf6, vf4, vf5 \n\t"
|
||||||
|
"sqc2 vf6, 0x0(%0) \n\t"
|
||||||
|
:
|
||||||
|
: "r"(result.xyz), "r"(this->xyz), "r"(v.xyz));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 Vector3::operator-(const Vector3 &v)
|
||||||
|
{
|
||||||
|
Vector3 result;
|
||||||
|
asm volatile( // VU0 Macro program
|
||||||
|
"lqc2 vf4, 0x0(%1) \n\t"
|
||||||
|
"lqc2 vf5, 0x0(%2) \n\t"
|
||||||
|
"vsub.xyz vf6, vf4, vf5 \n\t"
|
||||||
|
"sqc2 vf6, 0x0(%0) \n\t"
|
||||||
|
:
|
||||||
|
: "r"(result.xyz), "r"(this->xyz), "r"(v.xyz));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 Vector3::operator-(void)
|
||||||
|
{
|
||||||
|
Vector3 result;
|
||||||
|
result.x = -x;
|
||||||
|
result.y = -y;
|
||||||
|
result.z = -z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Also called "cross product" */
|
||||||
|
Vector3 Vector3::operator*(Vector3 &v)
|
||||||
|
{
|
||||||
|
Vector3 res;
|
||||||
|
asm volatile( // VU0 Macro program
|
||||||
|
"lqc2 vf4, 0x0(%1) \n\t" // vf4 = this
|
||||||
|
"lqc2 vf5, 0x0(%2) \n\t" // vf5 = v
|
||||||
|
|
||||||
|
"vmulz.y vf6, vf4, vf5 \n\t" // vf6.y = vf4.y * vf5.z
|
||||||
|
"vmuly.z vf6, vf4, vf5 \n\t"
|
||||||
|
"vsubz.y vf6, vf6, vf6 \n\t" // vf6.y = vf4.y - vf4.z
|
||||||
|
"vaddy.x vf8, vf0, vf6 \n\t" // res.x = vf4.y * vf5.z - vf4.z * vf5.y
|
||||||
|
|
||||||
|
"vmulx.z vf6, vf4, vf5 \n\t"
|
||||||
|
"vmulz.x vf6, vf4, vf5 \n\t"
|
||||||
|
"vsubx.z vf6, vf6, vf6 \n\t"
|
||||||
|
"vaddz.y vf8, vf0, vf6 \n\t" // res.y = vf4.z * vf5.x - vf4.x * vf5.z
|
||||||
|
|
||||||
|
"vmuly.x vf6, vf4, vf5 \n\t"
|
||||||
|
"vmulx.y vf6, vf4, vf5 \n\t"
|
||||||
|
"vsuby.x vf6, vf6, vf6 \n\t"
|
||||||
|
"vaddx.z vf8, vf0, vf6 \n\t" // res.z = vf4.x * vf5.y - vf4.y * vf5.x
|
||||||
|
"sqc2 vf8, 0x0(%0) \n\t"
|
||||||
|
:
|
||||||
|
: "r"(res.xyz), "r"(this->xyz), "r"(v.xyz));
|
||||||
|
// result.x = y * v.z - z * v.y;
|
||||||
|
// result.y = z * v.x - x * v.z;
|
||||||
|
// result.z = x * v.y - y * v.x;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 Vector3::operator*(float t)
|
||||||
|
{
|
||||||
|
Vector3 result;
|
||||||
|
asm volatile(
|
||||||
|
"lqc2 vf4, 0x0(%1) \n\t"
|
||||||
|
"mfc1 $8, %2 \n\t"
|
||||||
|
"qmtc2 $8, vf5 \n\t"
|
||||||
|
"vmulx.xyz vf6, vf4, vf5 \n\t"
|
||||||
|
"sqc2 vf6, 0x0(%0) \n\t"
|
||||||
|
:
|
||||||
|
: "r"(result.xyz), "r"(this->xyz), "f"(t)
|
||||||
|
: "$8");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 Vector3::operator/(float t)
|
||||||
|
{
|
||||||
|
Vector3 result;
|
||||||
|
result.x = x / t;
|
||||||
|
result.y = y / t;
|
||||||
|
result.z = z / t;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 Vector3::shouldBeBackfaceCulled(const Vector3 *t_cameraPos, const Vector3 *v0, const Vector3 *v1, const Vector3 *v2)
|
||||||
|
{
|
||||||
|
register float dot;
|
||||||
|
asm volatile(
|
||||||
|
"lqc2 vf4, 0x0(%1) \n\t" // vf4 = cameraPos
|
||||||
|
"lqc2 vf5, 0x0(%2) \n\t" // vf5 = v0
|
||||||
|
"lqc2 vf6, 0x0(%3) \n\t" // vf6 = v1
|
||||||
|
"lqc2 vf7, 0x0(%4) \n\t" // vf7 = v2
|
||||||
|
"vsub.xyz vf8, vf7, vf5 \n\t" // vf8 = vf7(v2) - vf5(v0)
|
||||||
|
"vsub.xyz vf9, vf6, vf5 \n\t" // vf9 = vf6(v1) - vf5(v0)
|
||||||
|
"vopmula.xyz ACC, vf8, vf9 \n\t" // vf6 = cross(vf8, vf9)
|
||||||
|
"vopmsub.xyz vf6, vf9, vf8 \n\t"
|
||||||
|
"vsub.w vf6, vf6, vf6 \n\t"
|
||||||
|
"vsub.xyz vf7, vf5, vf4 \n\t" // vf7 = vf5(v0) - vf4(cameraPos)
|
||||||
|
"vmul.xyz vf5, vf7, vf6 \n\t" // vf5 = dot(vf7, vf6)
|
||||||
|
"vaddy.x vf5, vf5, vf5 \n\t"
|
||||||
|
"vaddz.x vf5, vf5, vf5 \n\t"
|
||||||
|
"qmfc2 $2, vf5 \n\t" // store result on `dot` variable
|
||||||
|
"mtc1 $2, %0 \n\t"
|
||||||
|
: "=f"(dot)
|
||||||
|
: "r"(t_cameraPos->xyz), "r"(v0->xyz), "r"(v1->xyz), "r"(v2->xyz)
|
||||||
|
: "$2");
|
||||||
|
return dot <= 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks intersection with given square */
|
||||||
|
u8 Vector3::collidesSquare(Vector3 &t_min, Vector3 &t_max)
|
||||||
|
{
|
||||||
|
return ((this->x <= t_max.x && this->x >= t_min.x) && (this->y < t_max.y && this->y >= t_min.y) && (this->z <= t_max.z && this->z >= t_min.z)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks is this vector is on given square */
|
||||||
|
u8 Vector3::isOnSquare(Vector3 &t_min, Vector3 &t_max)
|
||||||
|
{
|
||||||
|
return ((this->x <= t_max.x && this->x >= t_min.x) && (this->y >= t_max.y) && (this->z <= t_max.z && this->z >= t_min.z)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Vector3::length()
|
||||||
|
{
|
||||||
|
register float result;
|
||||||
|
asm volatile( // VU0 Macro program
|
||||||
|
"lqc2 vf4, 0x0(%1) \n\t"
|
||||||
|
"vmul.xyz vf5, vf4, vf4 \n\t"
|
||||||
|
"vaddy.x vf5, vf5, vf5 \n\t"
|
||||||
|
"vaddz.x vf5, vf5, vf5 \n\t"
|
||||||
|
"vsqrt Q , vf5x \n\t"
|
||||||
|
"vaddq.x vf8, vf0, Q \n\t"
|
||||||
|
"qmfc2 $2, vf8 \n\t"
|
||||||
|
"mtc1 $2, %0 \n\t"
|
||||||
|
: "=f"(result)
|
||||||
|
: "r"(this->xyz)
|
||||||
|
: "$2");
|
||||||
|
return result;
|
||||||
|
// return Math::sqrt(x * x + y * y + z * z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vector3::normalize()
|
||||||
|
{
|
||||||
|
asm volatile( // VU0 Macro program
|
||||||
|
"lqc2 vf4, 0x0(%0) \n\t"
|
||||||
|
"vmul.xyz vf5, vf4, vf4 \n\t"
|
||||||
|
"vaddy.x vf5, vf5, vf5 \n\t"
|
||||||
|
"vaddz.x vf5, vf5, vf5 \n\t"
|
||||||
|
"vrsqrt Q, vf0w, vf5x \n\t"
|
||||||
|
"vsub.xyz vf6, vf0, vf0 \n\t"
|
||||||
|
"vaddw.xyz vf6, vf6, vf4 \n\t"
|
||||||
|
"vwaitq \n\t"
|
||||||
|
"vmulq.xyz vf6, vf4, Q \n\t"
|
||||||
|
"sqc2 vf6, 0x0(%0) \n\t"
|
||||||
|
:
|
||||||
|
: "r"(this->xyz));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Also called dot3 */
|
||||||
|
float Vector3::innerProduct(Vector3 &v)
|
||||||
|
{
|
||||||
|
register float result;
|
||||||
|
asm volatile( // VU0 Macro program
|
||||||
|
"lqc2 vf4, 0x0(%1) \n\t"
|
||||||
|
"lqc2 vf5, 0x0(%2) \n\t"
|
||||||
|
"vmul.xyz vf6, vf4, vf5 \n\t"
|
||||||
|
"vaddy.x vf6, vf6, vf6 \n\t"
|
||||||
|
"vaddz.x vf6, vf6, vf6 \n\t"
|
||||||
|
"qmfc2 $2, vf6 \n\t"
|
||||||
|
"mtc1 $2, %0 \n\t"
|
||||||
|
: "=f"(result)
|
||||||
|
: "r"(this->xyz), "r"(v.xyz)
|
||||||
|
: "$2");
|
||||||
|
return result;
|
||||||
|
// return (x * v.x + y * v.y + z * v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vector3::set(float x, float y, float z)
|
||||||
|
{
|
||||||
|
this->x = x;
|
||||||
|
this->y = y;
|
||||||
|
this->z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vector3::set(Vector3 &v)
|
||||||
|
{
|
||||||
|
this->x = v.x;
|
||||||
|
this->y = v.y;
|
||||||
|
this->z = v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vector3::copy(Vector3 &v)
|
||||||
|
{
|
||||||
|
asm volatile( // VU0 Macro program
|
||||||
|
"lq $6, 0x0(%1) \n\t"
|
||||||
|
"sq $6, 0x0(%0) \n\t"
|
||||||
|
:
|
||||||
|
: "r"(v.xyz), "r"(this->xyz)
|
||||||
|
: "$6");
|
||||||
|
}
|
||||||
|
|
||||||
|
float Vector3::distanceTo(Vector3 &v)
|
||||||
|
{
|
||||||
|
register float result;
|
||||||
|
asm volatile( // VU0 Macro program
|
||||||
|
"lqc2 vf4, 0x0(%1) \n\t"
|
||||||
|
"lqc2 vf5, 0x0(%2) \n\t"
|
||||||
|
"vsub.xyz vf6, vf4, vf5 \n\t"
|
||||||
|
"vmul.xyz vf7, vf6, vf6 \n\t"
|
||||||
|
"vaddy.x vf7, vf7, vf7 \n\t"
|
||||||
|
"vaddz.x vf7, vf7, vf7 \n\t"
|
||||||
|
"vsqrt Q , vf7x \n\t"
|
||||||
|
"vaddq.x vf8, vf0, Q \n\t"
|
||||||
|
"qmfc2 $2, vf8 \n\t"
|
||||||
|
"mtc1 $2, %0 \n\t"
|
||||||
|
: "=f"(result)
|
||||||
|
: "r"(this->xyz), "r"(v.xyz)
|
||||||
|
: "$2");
|
||||||
|
return result;
|
||||||
|
// return Math::sqrt((this->x - another.x) * (this->x - another.x) +
|
||||||
|
// (this->y - another.y) * (this->y - another.y) +
|
||||||
|
// (this->z - another.z) * (this->z - another.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vector3::print()
|
||||||
|
{
|
||||||
|
printf("Vector3(%f, %f, %f)\n", x, y, z);
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/models/md2_model.hpp"
|
||||||
|
|
||||||
|
#include "../include/utils/anorms.hpp"
|
||||||
|
#include "../include/utils/string.hpp"
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
MD2Model::MD2Model(char *t_md2File)
|
||||||
|
{
|
||||||
|
filename = String::createWithoutExtension(t_md2File);
|
||||||
|
|
||||||
|
verticesPerFrameCount = 0;
|
||||||
|
coordinatesCount = 0;
|
||||||
|
trianglesCount = 0;
|
||||||
|
framesCount = 0;
|
||||||
|
|
||||||
|
animState.startFrame = 0;
|
||||||
|
animState.endFrame = 0;
|
||||||
|
animState.interpolation = 0.0F;
|
||||||
|
animState.animType = 0;
|
||||||
|
animState.currentFrame = 0;
|
||||||
|
animState.nextFrame = 0;
|
||||||
|
animState.speed = 0.1F;
|
||||||
|
|
||||||
|
vertices = 0;
|
||||||
|
coordinates = 0;
|
||||||
|
normalIndexes = 0;
|
||||||
|
triangles = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MD2Model::~MD2Model()
|
||||||
|
{
|
||||||
|
delete[] vertices;
|
||||||
|
delete[] normalIndexes;
|
||||||
|
delete[] coordinates;
|
||||||
|
delete[] triangles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
u32 MD2Model::getCurrentFrameData(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, Vector3 &t_cameraPos, float t_scale, u8 t_shouldBeBackfaceCulled)
|
||||||
|
{
|
||||||
|
u32 i = 0;
|
||||||
|
animState.interpolation += animState.speed;
|
||||||
|
if (animState.interpolation >= 1.0F)
|
||||||
|
{
|
||||||
|
animState.interpolation = 0.0F;
|
||||||
|
animState.currentFrame = animState.nextFrame;
|
||||||
|
if (++animState.nextFrame > animState.endFrame)
|
||||||
|
animState.nextFrame = animState.startFrame;
|
||||||
|
}
|
||||||
|
for (u32 iTri = 0; iTri < trianglesCount; iTri++)
|
||||||
|
{
|
||||||
|
for (u32 iVert = 0; iVert < 3; iVert++)
|
||||||
|
{
|
||||||
|
const u32 CURR_VERTICE =
|
||||||
|
triangles[iTri].verticeIndexes[iVert] +
|
||||||
|
(verticesPerFrameCount * animState.currentFrame);
|
||||||
|
|
||||||
|
if (animState.startFrame == animState.endFrame)
|
||||||
|
{
|
||||||
|
calc3Vectors[iVert].x = vertices[CURR_VERTICE].x * t_scale;
|
||||||
|
calc3Vectors[iVert].y = vertices[CURR_VERTICE].y * t_scale;
|
||||||
|
calc3Vectors[iVert].z = vertices[CURR_VERTICE].z * t_scale;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const u32 NEXT_VERTICE =
|
||||||
|
triangles[iTri].verticeIndexes[iVert] +
|
||||||
|
(verticesPerFrameCount * animState.nextFrame);
|
||||||
|
calcVector.setByLerp(vertices[CURR_VERTICE], vertices[NEXT_VERTICE], animState.interpolation);
|
||||||
|
calc3Vectors[iVert].x = calcVector.x * t_scale;
|
||||||
|
calc3Vectors[iVert].y = calcVector.y * t_scale;
|
||||||
|
calc3Vectors[iVert].z = calcVector.z * t_scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!t_shouldBeBackfaceCulled || Vector3::shouldBeBackfaceCulled(&t_cameraPos, &calc3Vectors[2], &calc3Vectors[1], &calc3Vectors[0]) == 0)
|
||||||
|
for (u32 iVert = 0; iVert < 3; iVert++)
|
||||||
|
{
|
||||||
|
const u32 CURR_VERTICE =
|
||||||
|
triangles[iTri].verticeIndexes[iVert] +
|
||||||
|
(verticesPerFrameCount * animState.currentFrame);
|
||||||
|
|
||||||
|
const u32 CURR_COORD = triangles[iTri].coordIndexes[iVert];
|
||||||
|
|
||||||
|
o_vertices[i][0] = calc3Vectors[iVert].x;
|
||||||
|
o_vertices[i][1] = calc3Vectors[iVert].y;
|
||||||
|
o_vertices[i][2] = calc3Vectors[iVert].z;
|
||||||
|
o_vertices[i][3] = 1.0F;
|
||||||
|
|
||||||
|
o_normals[i][0] = ANORMS[normalIndexes[CURR_VERTICE]][0];
|
||||||
|
o_normals[i][1] = ANORMS[normalIndexes[CURR_VERTICE]][1];
|
||||||
|
o_normals[i][2] = ANORMS[normalIndexes[CURR_VERTICE]][2];
|
||||||
|
o_normals[i][3] = 1.0F;
|
||||||
|
|
||||||
|
o_coordinates[i][0] = coordinates[CURR_COORD].x;
|
||||||
|
o_coordinates[i][1] = 1.0F - coordinates[CURR_COORD].y;
|
||||||
|
o_coordinates[i][2] = 1.0F;
|
||||||
|
o_coordinates[i][3] = 1.0F;
|
||||||
|
|
||||||
|
o_colors[i][0] = 1.0F;
|
||||||
|
o_colors[i][1] = 1.0F;
|
||||||
|
o_colors[i][2] = 1.0F;
|
||||||
|
o_colors[i][3] = 1.0F;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MD2Model::allocateMemory()
|
||||||
|
{
|
||||||
|
vertices = new Vector3[verticesPerFrameCount * framesCount];
|
||||||
|
normalIndexes = new u32[verticesPerFrameCount * framesCount];
|
||||||
|
coordinates = new Point[coordinatesCount];
|
||||||
|
triangles = new MD2Triangle[trianglesCount];
|
||||||
|
}
|
||||||
@@ -0,0 +1,339 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/models/mesh.hpp"
|
||||||
|
|
||||||
|
#include "../include/loaders/obj_loader.hpp"
|
||||||
|
#include "../include/loaders/md2_loader.hpp"
|
||||||
|
#include "../include/loaders/dff_loader.hpp"
|
||||||
|
#include "../include/loaders/bmp_loader.hpp"
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
#include "../include/utils/string.hpp"
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
Mesh::Mesh()
|
||||||
|
{
|
||||||
|
shouldBeFrustumCulled = true;
|
||||||
|
shouldBeBackfaceCulled = false;
|
||||||
|
shouldBeLighted = false;
|
||||||
|
isMd2Loaded = false;
|
||||||
|
isObjLoaded = false;
|
||||||
|
isDffLoaded = false;
|
||||||
|
isSpecInitialized = false;
|
||||||
|
scale = 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mesh::~Mesh()
|
||||||
|
{
|
||||||
|
if (isMd2Loaded)
|
||||||
|
delete md2;
|
||||||
|
if (isObjLoaded)
|
||||||
|
delete obj;
|
||||||
|
if (isDffLoaded)
|
||||||
|
delete dff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
void Mesh::loadDff(char *t_subfolder, char *t_dffFile, Vector3 &t_initPos, float t_scale)
|
||||||
|
{
|
||||||
|
createSpecIfNotCreated();
|
||||||
|
DffLoader loader = DffLoader();
|
||||||
|
dff = new DffModel();
|
||||||
|
char *dffPath = String::createConcatenated(t_subfolder, t_dffFile);
|
||||||
|
loader.load(dff->clump, dffPath, t_scale);
|
||||||
|
delete[] dffPath;
|
||||||
|
position = t_initPos;
|
||||||
|
setVerticesReference(
|
||||||
|
dff->clump.geometryList.geometries[0].data.dataHeader.vertexCount,
|
||||||
|
dff->clump.geometryList.geometries[0].data.vertexInformation);
|
||||||
|
setDefaultColor();
|
||||||
|
isDffLoaded = true;
|
||||||
|
loadTextures(t_subfolder, ".bmp");
|
||||||
|
spec->allocateTextureBuffer(spec->textures[0].width, spec->textures[0].height); // wtf?
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::setDff(Vector3 &t_initPos, DffModel *t_dffModel, MeshSpec *t_spec)
|
||||||
|
{
|
||||||
|
position = t_initPos;
|
||||||
|
spec = t_spec;
|
||||||
|
isSpecInitialized = 1;
|
||||||
|
dff = t_dffModel;
|
||||||
|
setVerticesReference(
|
||||||
|
dff->clump.geometryList.geometries[0].data.dataHeader.vertexCount,
|
||||||
|
dff->clump.geometryList.geometries[0].data.vertexInformation);
|
||||||
|
setDefaultColor();
|
||||||
|
isDffLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::loadObj(char *t_subfolder, char *t_objFile, Vector3 &t_initPos, float t_scale)
|
||||||
|
{
|
||||||
|
createSpecIfNotCreated();
|
||||||
|
ObjLoader loader = ObjLoader();
|
||||||
|
obj = new ObjModel(t_objFile);
|
||||||
|
char *objPath = String::createConcatenated(t_subfolder, t_objFile);
|
||||||
|
loader.load(obj, objPath, t_scale);
|
||||||
|
delete[] objPath;
|
||||||
|
position = t_initPos;
|
||||||
|
setVerticesReference(obj->facesCount, obj->vertices);
|
||||||
|
setDefaultColor();
|
||||||
|
isObjLoaded = true;
|
||||||
|
loadTextures(t_subfolder, ".bmp");
|
||||||
|
spec->allocateTextureBuffer(spec->textures[0].width, spec->textures[0].height); // wtf?
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::setObj(Vector3 &t_initPos, ObjModel *t_objModel, MeshSpec *t_spec)
|
||||||
|
{
|
||||||
|
position = t_initPos;
|
||||||
|
spec = t_spec;
|
||||||
|
isSpecInitialized = true;
|
||||||
|
obj = t_objModel;
|
||||||
|
setVerticesReference(obj->facesCount, obj->vertices);
|
||||||
|
setDefaultColor();
|
||||||
|
isObjLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::createSpecIfNotCreated()
|
||||||
|
{
|
||||||
|
if (!isSpecInitialized)
|
||||||
|
{
|
||||||
|
isSpecInitialized = true;
|
||||||
|
spec = new MeshSpec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::setAnimSpeed(float t_value)
|
||||||
|
{
|
||||||
|
if (isMd2Loaded == 1)
|
||||||
|
md2->animState.speed = t_value;
|
||||||
|
else
|
||||||
|
PRINT_ERR("Animation speed set is not possible, because no md2 3D model was loaded!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::setVerticesReference(u32 t_verticesCount, Vector3 *t_verticesRef)
|
||||||
|
{
|
||||||
|
verticesCount = t_verticesCount;
|
||||||
|
vertices = t_verticesRef;
|
||||||
|
computeBoundingBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 Mesh::getVertexCount()
|
||||||
|
{
|
||||||
|
if (isMd2Loaded)
|
||||||
|
return md2->trianglesCount * 3;
|
||||||
|
else if (isObjLoaded)
|
||||||
|
return obj->facesCount;
|
||||||
|
else if (isDffLoaded)
|
||||||
|
return dff->clump.geometryList.geometries[0].data.dataHeader.triangleCount * 3;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PRINT_ERR("Can't get vertex count, because no 3D model was loaded!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::setDefaultWrapSettings(texwrap_t &t_wrapSettings)
|
||||||
|
{
|
||||||
|
t_wrapSettings.horizontal = WRAP_REPEAT;
|
||||||
|
t_wrapSettings.vertical = WRAP_REPEAT;
|
||||||
|
t_wrapSettings.maxu = 0;
|
||||||
|
t_wrapSettings.maxv = 0;
|
||||||
|
t_wrapSettings.minu = 0;
|
||||||
|
t_wrapSettings.minv = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::loadTextures(char *t_subfolder, char *t_extension)
|
||||||
|
{
|
||||||
|
BmpLoader bmpLoader = BmpLoader();
|
||||||
|
if (isMd2Loaded || isObjLoaded)
|
||||||
|
{
|
||||||
|
spec->textures = new Texture[1];
|
||||||
|
if (isMd2Loaded)
|
||||||
|
bmpLoader.load(spec->textures[0], t_subfolder, md2->filename, t_extension);
|
||||||
|
if (isObjLoaded)
|
||||||
|
bmpLoader.load(spec->textures[0], t_subfolder, obj->filename, t_extension);
|
||||||
|
setDefaultWrapSettings(spec->textures[0].wrapSettings);
|
||||||
|
}
|
||||||
|
else if (isDffLoaded)
|
||||||
|
{
|
||||||
|
spec->textures = new Texture[dff->clump.geometryList.geometries[0].materialList.data.materialCount];
|
||||||
|
for (u8 i = 0; i < dff->clump.geometryList.geometries[0].materialList.data.materialCount; i++)
|
||||||
|
for (u8 j = 0; j < dff->clump.geometryList.geometries[0].materialList.materials[i].data.textureCount; j++)
|
||||||
|
{
|
||||||
|
bmpLoader.load(spec->textures[i], t_subfolder, dff->clump.geometryList.geometries[0].materialList.materials[i].textures[j].textureName.text, t_extension);
|
||||||
|
setDefaultWrapSettings(spec->textures[i].wrapSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PRINT_ERR("Can't load textures, because no 3D model was loaded!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO refactor
|
||||||
|
u32 Mesh::getDrawData(u32 splitIndex, VECTOR *t_vertices, VECTOR *t_normals, VECTOR *t_coordinates, VECTOR *t_colors, Vector3 &t_cameraPos)
|
||||||
|
{
|
||||||
|
if (isMd2Loaded)
|
||||||
|
return md2->getCurrentFrameData(t_vertices, t_normals, t_coordinates, t_colors, t_cameraPos, scale, shouldBeBackfaceCulled);
|
||||||
|
else if (isObjLoaded)
|
||||||
|
return obj->getDrawData(t_vertices, t_normals, t_coordinates, t_colors, t_cameraPos, scale, shouldBeBackfaceCulled);
|
||||||
|
else if (isDffLoaded)
|
||||||
|
return dff->getDrawData(splitIndex, t_vertices, t_normals, t_coordinates, t_colors, t_cameraPos, scale, shouldBeBackfaceCulled);
|
||||||
|
PRINT_ERR("Can't get draw data, because no 3D model was loaded!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set object position and specification */
|
||||||
|
void Mesh::loadMD2(char *t_subfolder, char *t_md2File, Vector3 &t_initPos, float t_scale)
|
||||||
|
{
|
||||||
|
createSpecIfNotCreated();
|
||||||
|
md2 = new MD2Model(t_md2File);
|
||||||
|
MD2Loader loader = MD2Loader();
|
||||||
|
position = t_initPos;
|
||||||
|
char *md2Path = String::createConcatenated(t_subfolder, t_md2File);
|
||||||
|
loader.load(md2, md2Path, t_scale);
|
||||||
|
delete[] md2Path;
|
||||||
|
setVerticesReference(md2->verticesPerFrameCount * md2->framesCount, md2->vertices);
|
||||||
|
setDefaultColor();
|
||||||
|
isMd2Loaded = true;
|
||||||
|
loadTextures(t_subfolder, ".bmp");
|
||||||
|
spec->allocateTextureBuffer(spec->textures[0].width, spec->textures[0].height); // wtf?
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set's default object color + no transparency */
|
||||||
|
void Mesh::setDefaultColor()
|
||||||
|
{
|
||||||
|
color.r = 0x80;
|
||||||
|
color.g = 0x80;
|
||||||
|
color.b = 0x80;
|
||||||
|
color.a = 0x80;
|
||||||
|
color.q = 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Calculates minimum and maximum X, Y, Z of this 3D objects vertices + current position */
|
||||||
|
void Mesh::getMinMax(Vector3 *t_min, Vector3 *t_max)
|
||||||
|
{
|
||||||
|
Vector3 calc = Vector3();
|
||||||
|
u8 isInitialized = 0;
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
getFarthestVertex(&calc, i);
|
||||||
|
if (isInitialized == 0)
|
||||||
|
{
|
||||||
|
isInitialized = 1;
|
||||||
|
t_min->set(calc);
|
||||||
|
t_max->set(calc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t_min->x > calc.x)
|
||||||
|
t_min->x = calc.x;
|
||||||
|
if (calc.x > t_max->x)
|
||||||
|
t_max->x = calc.x;
|
||||||
|
|
||||||
|
if (t_min->y > calc.y)
|
||||||
|
t_min->y = calc.y;
|
||||||
|
if (calc.y > t_max->y)
|
||||||
|
t_max->y = calc.y;
|
||||||
|
|
||||||
|
if (t_min->z > calc.z)
|
||||||
|
t_min->z = calc.z;
|
||||||
|
if (calc.z > t_max->z)
|
||||||
|
t_max->z = calc.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::playAnimation(u32 t_startFrame, u32 t_endFrame)
|
||||||
|
{
|
||||||
|
if (isMd2Loaded == 1)
|
||||||
|
{
|
||||||
|
md2->animState.startFrame = t_startFrame;
|
||||||
|
md2->animState.endFrame = t_endFrame;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PRINT_ERR("Animation is only supported in MD2 format!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns next farthest vertex of 3D object
|
||||||
|
* @param offset Max 8 (because, box have 8 corners)
|
||||||
|
*/
|
||||||
|
void Mesh::getFarthestVertex(Vector3 *o_result, int t_offset)
|
||||||
|
{
|
||||||
|
o_result->x = boxVertices[t_offset].x + position.x;
|
||||||
|
o_result->y = boxVertices[t_offset].y + position.y;
|
||||||
|
o_result->z = boxVertices[t_offset].z + position.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Check if box is visible in view frustum */
|
||||||
|
u8 Mesh::isInFrustum(Plane *t_frustumPlanes)
|
||||||
|
{
|
||||||
|
Vector3 boxCalcTemp;
|
||||||
|
int boxResult = 1, boxIn = 0, boxOut = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
boxOut = 0;
|
||||||
|
boxIn = 0;
|
||||||
|
// for each corner of the box do ...
|
||||||
|
// get out of the cycle as soon as a box as corners
|
||||||
|
// both inside and out of the frustum
|
||||||
|
for (int y = 0; y < 8 && (boxIn == 0 || boxOut == 0); y++)
|
||||||
|
{
|
||||||
|
getFarthestVertex(&boxCalcTemp, y);
|
||||||
|
if (t_frustumPlanes[i].distanceTo(boxCalcTemp) < 0)
|
||||||
|
boxOut++;
|
||||||
|
else
|
||||||
|
boxIn++;
|
||||||
|
}
|
||||||
|
//if all corners are out
|
||||||
|
if (boxIn == 0)
|
||||||
|
return 0;
|
||||||
|
else if (boxOut)
|
||||||
|
boxResult = 1;
|
||||||
|
}
|
||||||
|
return boxResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compute 8 farthest corners for intersection check */
|
||||||
|
void Mesh::computeBoundingBox()
|
||||||
|
{
|
||||||
|
float lowX, lowY, lowZ, hiX, hiY, hiZ;
|
||||||
|
lowX = hiX = vertices[0].x;
|
||||||
|
lowY = hiY = vertices[0].y;
|
||||||
|
lowZ = hiZ = vertices[0].z;
|
||||||
|
for (u32 i = 0; i < verticesCount; i++)
|
||||||
|
{
|
||||||
|
if (lowX > vertices[i].x)
|
||||||
|
lowX = vertices[i].x;
|
||||||
|
if (hiX < vertices[i].x)
|
||||||
|
hiX = vertices[i].x;
|
||||||
|
|
||||||
|
if (lowY > vertices[i].y)
|
||||||
|
lowY = vertices[i].y;
|
||||||
|
if (hiY < vertices[i].y)
|
||||||
|
hiY = vertices[i].y;
|
||||||
|
|
||||||
|
if (lowZ > vertices[i].z)
|
||||||
|
lowZ = vertices[i].z;
|
||||||
|
if (hiZ < vertices[i].z)
|
||||||
|
hiZ = vertices[i].z;
|
||||||
|
}
|
||||||
|
boxVertices[0].set(lowX, lowY, lowZ);
|
||||||
|
boxVertices[1].set(lowX, lowY, hiZ);
|
||||||
|
boxVertices[2].set(lowX, hiY, lowZ);
|
||||||
|
boxVertices[3].set(lowX, hiY, hiZ);
|
||||||
|
|
||||||
|
boxVertices[4].set(hiX, lowY, lowZ);
|
||||||
|
boxVertices[5].set(hiX, lowY, hiZ);
|
||||||
|
boxVertices[6].set(hiX, hiY, lowZ);
|
||||||
|
boxVertices[7].set(hiX, hiY, hiZ);
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/models/mesh_spec.hpp"
|
||||||
|
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
#include "../include/utils/math.hpp"
|
||||||
|
#include <graph_vram.h>
|
||||||
|
#include <gs_psm.h>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
MeshSpec::MeshSpec()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Creating object 3D spec");
|
||||||
|
this->setupLodAndClut();
|
||||||
|
PRINT_LOG("Object 3D spec created!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Release memory if object was initialized */
|
||||||
|
MeshSpec::~MeshSpec()
|
||||||
|
{
|
||||||
|
if (this->isTextureVRAMAllocated == true)
|
||||||
|
graph_vram_free(this->textureBuffer.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Configure and allocate vRAM for texture buffer */
|
||||||
|
void MeshSpec::allocateTextureBuffer(u16 t_width, u16 t_height)
|
||||||
|
{
|
||||||
|
this->textureBuffer.width = t_width;
|
||||||
|
this->textureBuffer.psm = GS_PSM_24;
|
||||||
|
this->textureBuffer.address = graph_vram_allocate(t_width, t_height, GS_PSM_24, GRAPH_ALIGN_BLOCK);
|
||||||
|
if (this->textureBuffer.address <= 1)
|
||||||
|
PRINT_ERR("Texture buffer allocation error. No memory!");
|
||||||
|
this->textureBuffer.info.width = draw_log2(t_width);
|
||||||
|
this->textureBuffer.info.height = draw_log2(t_height);
|
||||||
|
this->textureBuffer.info.components = TEXTURE_COMPONENTS_RGB;
|
||||||
|
this->textureBuffer.info.function = TEXTURE_FUNCTION_MODULATE;
|
||||||
|
this->isTextureVRAMAllocated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Configure and allocate vRAM for texture buffer */
|
||||||
|
void MeshSpec::deallocateTextureBuffer()
|
||||||
|
{
|
||||||
|
if (this->isTextureVRAMAllocated)
|
||||||
|
{
|
||||||
|
graph_vram_free(textureBuffer.address);
|
||||||
|
this->isTextureVRAMAllocated = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets texture level of details settings and CLUT settings */
|
||||||
|
void MeshSpec::setupLodAndClut()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Setting LOD, CLUT");
|
||||||
|
this->lod.calculation = LOD_USE_K;
|
||||||
|
this->lod.max_level = 0;
|
||||||
|
this->lod.mag_filter = LOD_MAG_NEAREST;
|
||||||
|
this->lod.min_filter = LOD_MIN_NEAREST;
|
||||||
|
this->lod.l = 0;
|
||||||
|
this->lod.k = 0.0F;
|
||||||
|
|
||||||
|
this->clut.storage_mode = CLUT_STORAGE_MODE1;
|
||||||
|
this->clut.start = 0;
|
||||||
|
this->clut.psm = 0;
|
||||||
|
this->clut.load_method = CLUT_NO_LOAD;
|
||||||
|
this->clut.address = 0;
|
||||||
|
PRINT_LOG("LOD, CLUT set!");
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/models/obj_model.hpp"
|
||||||
|
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
#include "../include/utils/string.hpp"
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
ObjModel::ObjModel(char *t_objFile)
|
||||||
|
{
|
||||||
|
filename = String::createWithoutExtension(t_objFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjModel::~ObjModel()
|
||||||
|
{
|
||||||
|
if (isMemoryAllocated == true)
|
||||||
|
{
|
||||||
|
delete[] vertices;
|
||||||
|
delete[] coordinates;
|
||||||
|
delete[] normals;
|
||||||
|
|
||||||
|
delete[] verticeFaces;
|
||||||
|
delete[] coordinateFaces;
|
||||||
|
delete[] normalFaces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
u32 ObjModel::getDrawData(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, Vector3 &t_cameraPos, float t_scale, u8 t_shouldBeBackfaceCulled)
|
||||||
|
{
|
||||||
|
u32 addedFaces = 0;
|
||||||
|
for (u32 i = 0; i < facesCount; i += 3)
|
||||||
|
if (!t_shouldBeBackfaceCulled || Vector3::shouldBeBackfaceCulled(
|
||||||
|
&t_cameraPos,
|
||||||
|
&vertices[verticeFaces[i]],
|
||||||
|
&vertices[verticeFaces[i + 1]],
|
||||||
|
&vertices[verticeFaces[i + 2]]) == 0)
|
||||||
|
{
|
||||||
|
fillNextFace(o_vertices, o_normals, o_coordinates, o_colors, i, addedFaces++);
|
||||||
|
fillNextFace(o_vertices, o_normals, o_coordinates, o_colors, i + 1, addedFaces++);
|
||||||
|
fillNextFace(o_vertices, o_normals, o_coordinates, o_colors, i + 2, addedFaces++);
|
||||||
|
}
|
||||||
|
|
||||||
|
return addedFaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Allocate memory for vertices,coords etc.
|
||||||
|
* Called by ObjLoader
|
||||||
|
*/
|
||||||
|
void ObjModel::allocateMemory()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Allocating 3D object specification memory");
|
||||||
|
vertices = new Vector3[verticesCount];
|
||||||
|
coordinates = new Vector3[coordinatesCount];
|
||||||
|
normals = new Vector3[normalsCount];
|
||||||
|
|
||||||
|
verticeFaces = new u32[facesCount];
|
||||||
|
coordinateFaces = new u32[facesCount];
|
||||||
|
normalFaces = new u32[facesCount];
|
||||||
|
isMemoryAllocated = true;
|
||||||
|
PRINT_LOG("3D object specification memory allocated!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjModel::fillNextFace(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, u32 t_getI, u32 t_setI)
|
||||||
|
{
|
||||||
|
o_vertices[t_setI][0] = vertices[verticeFaces[t_getI]].x;
|
||||||
|
o_vertices[t_setI][1] = vertices[verticeFaces[t_getI]].y;
|
||||||
|
o_vertices[t_setI][2] = vertices[verticeFaces[t_getI]].z;
|
||||||
|
o_vertices[t_setI][3] = 1.0F;
|
||||||
|
|
||||||
|
o_normals[t_setI][0] = normals[normalFaces[t_getI]].x;
|
||||||
|
o_normals[t_setI][1] = normals[normalFaces[t_getI]].y;
|
||||||
|
o_normals[t_setI][2] = normals[normalFaces[t_getI]].z;
|
||||||
|
o_normals[t_setI][3] = 1.0F;
|
||||||
|
|
||||||
|
o_coordinates[t_setI][0] = coordinates[coordinateFaces[t_getI]].x;
|
||||||
|
o_coordinates[t_setI][1] = coordinates[coordinateFaces[t_getI]].y;
|
||||||
|
o_coordinates[t_setI][2] = 1.0F;
|
||||||
|
o_coordinates[t_setI][3] = 1.0F;
|
||||||
|
|
||||||
|
o_colors[t_setI][0] = 1.0F;
|
||||||
|
o_colors[t_setI][1] = 1.0F;
|
||||||
|
o_colors[t_setI][2] = 1.0F;
|
||||||
|
o_colors[t_setI][3] = 1.0F;
|
||||||
|
}
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/modules/audio.hpp"
|
||||||
|
|
||||||
|
#include <loadfile.h>
|
||||||
|
#include "../include/utils/string.hpp"
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
|
||||||
|
#define SONG_NAME "MOV-CIRC.WAV"
|
||||||
|
const int AUDSRV_BUFFER_SIZE = 1024 * 4;
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
Audio *audioRef;
|
||||||
|
|
||||||
|
Audio::Audio()
|
||||||
|
{
|
||||||
|
addedListeners = 0;
|
||||||
|
isInitialized = 0;
|
||||||
|
songLoaded = 0;
|
||||||
|
isVolumeSet = 0;
|
||||||
|
shouldPlay = 0;
|
||||||
|
audioRef = this;
|
||||||
|
initSema();
|
||||||
|
loadModules();
|
||||||
|
initAUDSRV();
|
||||||
|
}
|
||||||
|
|
||||||
|
Audio::~Audio() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Initialize audio module
|
||||||
|
*
|
||||||
|
* - Initialize threading semaphore
|
||||||
|
* - Load modules
|
||||||
|
* - Initialize AUDSRV
|
||||||
|
* - Load background song
|
||||||
|
*/
|
||||||
|
void Audio::init(u32 t_listenersAmount)
|
||||||
|
{
|
||||||
|
PRINT_LOG("Initialize audio module started");
|
||||||
|
listenersAmount = t_listenersAmount;
|
||||||
|
listeners = new AudioListener *[t_listenersAmount];
|
||||||
|
isInitialized = true;
|
||||||
|
PRINT_LOG("Audio module initialized!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::addListener(AudioListener *t_listener)
|
||||||
|
{
|
||||||
|
listeners[addedListeners++] = t_listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initialize threading semaphore */
|
||||||
|
void Audio::initSema()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Creating semaphore started");
|
||||||
|
sema.init_count = 0;
|
||||||
|
sema.max_count = 1;
|
||||||
|
sema.option = 0;
|
||||||
|
fillbufferSema = CreateSema(&sema);
|
||||||
|
PRINT_LOG("Semaphore created");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Load LIBSD and AUDSRV */
|
||||||
|
void Audio::loadModules()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Modules loading started (LIBSD, AUDSRV)");
|
||||||
|
ret = SifLoadModule("rom0:LIBSD", 0, NULL);
|
||||||
|
ret = SifLoadModule("host:AUDSRV.IRX", 0, NULL);
|
||||||
|
PRINT_LOG("Modules loaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initialize AUDSRV and install fillbuffer callback */
|
||||||
|
void Audio::initAUDSRV()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Initialize AUDSRV started");
|
||||||
|
ret = audsrv_init();
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
PRINT_ERR("Failed to initialize AUDSRV!");
|
||||||
|
printf("AUDSRV returned error string: %s", audsrv_get_error_string());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = audsrv_on_fillbuf(AUDSRV_BUFFER_SIZE, Audio::fillbuffer, (void *)fillbufferSema);
|
||||||
|
PRINT_LOG("AUDSRV initialized!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set audio format, volume and load song */
|
||||||
|
void Audio::loadSong(char *t_filename)
|
||||||
|
{
|
||||||
|
if (!isInitialized)
|
||||||
|
{
|
||||||
|
PRINT_ERR("Please initialize audio class first!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PRINT_LOG("Song loading started");
|
||||||
|
format.bits = 16;
|
||||||
|
format.freq = 22050;
|
||||||
|
format.channels = 2;
|
||||||
|
char *fullFilename = String::createConcatenated("host:", t_filename);
|
||||||
|
int err = audsrv_set_format(&format);
|
||||||
|
if (err == 0)
|
||||||
|
{
|
||||||
|
PRINT_LOG("Audio format set");
|
||||||
|
if (!isVolumeSet)
|
||||||
|
setVolume(MAX_VOLUME);
|
||||||
|
PRINT_LOG("Opening song file: " SONG_NAME);
|
||||||
|
wav = fopen(fullFilename, "rb");
|
||||||
|
delete[] fullFilename;
|
||||||
|
if (wav == NULL)
|
||||||
|
{
|
||||||
|
PRINT_ERR("Failed to open wav file!");
|
||||||
|
audsrv_quit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fseek(wav, 0x30, SEEK_SET);
|
||||||
|
played = 0;
|
||||||
|
songLoaded = 1;
|
||||||
|
PRINT_LOG("Song loaded!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PRINT_ERR("Failed to set audio format!");
|
||||||
|
printf("AUDSRV returned error string: %s", audsrv_get_error_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::setVolume(u8 t_volume)
|
||||||
|
{
|
||||||
|
audsrv_set_volume(t_volume);
|
||||||
|
isVolumeSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create and start audio thread. */
|
||||||
|
void Audio::startThread()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Creating audio thread");
|
||||||
|
extern void *_gp;
|
||||||
|
audioThreadAttr.func = (void *)Audio::audioThread;
|
||||||
|
audioThreadAttr.stack = audioThreadStack;
|
||||||
|
audioThreadAttr.stack_size = STACK_SIZE;
|
||||||
|
audioThreadAttr.gp_reg = (void *)&_gp;
|
||||||
|
audioThreadAttr.initial_priority = 0x17;
|
||||||
|
if ((audioThreadId = CreateThread(&audioThreadAttr)) < 0)
|
||||||
|
PRINT_ERR("Create audio thread failed!");
|
||||||
|
PRINT_LOG("Audio thread created");
|
||||||
|
StartThread(audioThreadId, NULL);
|
||||||
|
PRINT_LOG("Audio thread started");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Do not call this function.
|
||||||
|
* This is a audio thread, runned by AudioThread::start()
|
||||||
|
*/
|
||||||
|
void Audio::audioThread()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (audioRef->shouldPlay)
|
||||||
|
audioRef->work();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::play()
|
||||||
|
{
|
||||||
|
if (!isInitialized)
|
||||||
|
{
|
||||||
|
PRINT_ERR("Please initialize audio class first!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
shouldPlay = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::stop()
|
||||||
|
{
|
||||||
|
if (!isInitialized)
|
||||||
|
{
|
||||||
|
PRINT_ERR("Please initialize audio class first!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
shouldPlay = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Play song and run it again on finish */
|
||||||
|
void Audio::work()
|
||||||
|
{
|
||||||
|
if (!isTrackDone)
|
||||||
|
{
|
||||||
|
ret = fread(chunk, 1, sizeof(chunk), wav);
|
||||||
|
if (ret > 0)
|
||||||
|
{
|
||||||
|
WaitSema(fillbufferSema);
|
||||||
|
audsrv_play_audio(chunk, ret);
|
||||||
|
}
|
||||||
|
if (ret < (int)sizeof(chunk))
|
||||||
|
{
|
||||||
|
isTrackDone = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
played++;
|
||||||
|
if ((played + 20) % 41 == 0 && addedListeners)
|
||||||
|
for (u32 i = 0; i < addedListeners; i++)
|
||||||
|
listeners[i]->onAudioTick();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PRINT_LOG("Song " SONG_NAME " finished. Running again...");
|
||||||
|
played = 0;
|
||||||
|
fseek(wav, 0x30, SEEK_SET);
|
||||||
|
isTrackDone = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Unload audio module by closing file stream and stopping AUDSRV */
|
||||||
|
void Audio::unloadSong()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Unloading audio module started");
|
||||||
|
fclose(wav);
|
||||||
|
PRINT_LOG("Song file stream closed");
|
||||||
|
audsrv_quit();
|
||||||
|
PRINT_LOG("AUDSRV stopped");
|
||||||
|
PRINT_LOG("Audio module unloaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Do not call this function.
|
||||||
|
* This is a static callback function
|
||||||
|
* for AUDSRV fillbuffer (semaphore)
|
||||||
|
*/
|
||||||
|
int Audio::fillbuffer(void *arg)
|
||||||
|
{
|
||||||
|
iSignalSema((int)arg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/modules/camera_base.hpp"
|
||||||
|
|
||||||
|
#include <fastmath.h>
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
#include "../include/utils/math.hpp"
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Initializes vars and calculate width/height of near and far plane
|
||||||
|
* @param fov (FOV in radians)/2
|
||||||
|
* @param ratio Aspect ratio
|
||||||
|
*/
|
||||||
|
CameraBase::CameraBase(ScreenSettings *t_screen, Vector3 *t_position, Vector3 *t_up, Vector3 *t_unitCirclePosition)
|
||||||
|
: screen(t_screen)
|
||||||
|
{
|
||||||
|
PRINT_LOG("Initializing frustum");
|
||||||
|
farPlaneDist = screen->farPlaneDist;
|
||||||
|
nearPlaneDist = screen->nearPlaneDist;
|
||||||
|
float tang = tanf(screen->fov * Math::HALF_ANG2RAD);
|
||||||
|
nearHeight = tang * nearPlaneDist;
|
||||||
|
nearWidth = nearHeight * screen->aspectRatio;
|
||||||
|
farHeight = tang * farPlaneDist;
|
||||||
|
farWidth = farHeight * screen->aspectRatio;
|
||||||
|
position2 = t_position;
|
||||||
|
up2 = t_up;
|
||||||
|
unitCirclePosition2 = t_unitCirclePosition;
|
||||||
|
PRINT_LOG("CameraBase initialized!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Calculates and updates frustum planes
|
||||||
|
* http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-extracting-the-planes/
|
||||||
|
*/
|
||||||
|
void CameraBase::updatePlanes(Vector3 t_target)
|
||||||
|
{
|
||||||
|
Vector3 nearCenter, farCenter, X, Y, Z;
|
||||||
|
// compute the Z axis of camera
|
||||||
|
Z = *position2 - t_target;
|
||||||
|
Z.normalize();
|
||||||
|
// X axis of camera of given "up" vector and Z axis
|
||||||
|
X = *up2 * Z;
|
||||||
|
X.normalize();
|
||||||
|
// the real "up" vector is the cross product of Z and X
|
||||||
|
Y = Z * X;
|
||||||
|
// compute the center of the near and far planes
|
||||||
|
nearCenter = *position2 - Z * nearPlaneDist;
|
||||||
|
farCenter = *position2 - Z * farPlaneDist;
|
||||||
|
// compute the 8 corners of the frustum
|
||||||
|
ntl = nearCenter + Y * nearHeight - X * nearWidth;
|
||||||
|
ntr = nearCenter + Y * nearHeight + X * nearWidth;
|
||||||
|
nbl = nearCenter - Y * nearHeight - X * nearWidth;
|
||||||
|
nbr = nearCenter - Y * nearHeight + X * nearWidth;
|
||||||
|
|
||||||
|
ftl = farCenter + Y * farHeight - X * farWidth;
|
||||||
|
fbr = farCenter - Y * farHeight + X * farWidth;
|
||||||
|
ftr = farCenter + Y * farHeight + X * farWidth;
|
||||||
|
fbl = farCenter - Y * farHeight - X * farWidth;
|
||||||
|
|
||||||
|
planes[0].update(ntr, ntl, ftl); // Top
|
||||||
|
planes[1].update(nbl, nbr, fbr); // BOTTOM
|
||||||
|
planes[2].update(ntl, nbl, fbl); // LEFT
|
||||||
|
planes[3].update(nbr, ntr, fbr); // RIGHT
|
||||||
|
planes[4].update(ntl, ntr, nbr); // NEAR
|
||||||
|
planes[5].update(ftr, ftl, fbl); // FAR
|
||||||
|
}
|
||||||
@@ -0,0 +1,273 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/modules/gif_sender.hpp"
|
||||||
|
|
||||||
|
#include "../include/utils/math.hpp"
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
#include "../include/modules/light.hpp"
|
||||||
|
#include <dma.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <dma_tags.h>
|
||||||
|
#include <gs_psm.h>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Initializes vars and creates data transfer packets
|
||||||
|
* @param packetSize Size of data packet, should be increased when more data will be rendered
|
||||||
|
*/
|
||||||
|
GifSender::GifSender(u32 t_packetSize, ScreenSettings *t_screen) : screen(t_screen)
|
||||||
|
{
|
||||||
|
PRINT_LOG("Initializing GifSender");
|
||||||
|
packetSize = t_packetSize;
|
||||||
|
packets[0] = packet_init(t_packetSize, PACKET_NORMAL);
|
||||||
|
packets[1] = packet_init(t_packetSize, PACKET_NORMAL);
|
||||||
|
PRINT_LOG("GifSender initialized!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Releases packets memory */
|
||||||
|
GifSender::~GifSender()
|
||||||
|
{
|
||||||
|
packet_free(packets[0]);
|
||||||
|
packet_free(packets[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
#include <gif_tags.h>
|
||||||
|
#include <gs_gp.h>
|
||||||
|
|
||||||
|
/** Send texture via GIF */
|
||||||
|
void GifSender::sendTexture(Texture &texture, texbuffer_t *t_texBuffer)
|
||||||
|
{
|
||||||
|
const u16 packetSize = 40;
|
||||||
|
packet_t *packet = packet_init(packetSize, PACKET_NORMAL);
|
||||||
|
qword_t *q = packet->data;
|
||||||
|
q = draw_texture_transfer(q, texture.data, texture.width, texture.height, GS_PSM_24, t_texBuffer->address, t_texBuffer->width);
|
||||||
|
DMATAG_CNT(q, 2, 0, 0, 0);
|
||||||
|
q++;
|
||||||
|
q = draw_texture_wrapping(q, 0, &texture.wrapSettings);
|
||||||
|
q = draw_texture_flush(q);
|
||||||
|
dma_channel_send_chain(DMA_CHANNEL_GIF, packet->data, q - packet->data, 0, 0);
|
||||||
|
dma_wait_fast();
|
||||||
|
packet_free(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSender::sendClear(zbuffer_t *t_zBuffer)
|
||||||
|
{
|
||||||
|
packet_t *packet = packet_init(100, PACKET_NORMAL);
|
||||||
|
qword_t *q = packet->data;
|
||||||
|
q++;
|
||||||
|
q = draw_disable_tests(q, 0, t_zBuffer);
|
||||||
|
q = draw_clear(q, 0,
|
||||||
|
2048.0F - (screen->width / 2), 2048.0F - (screen->height / 2),
|
||||||
|
screen->width, screen->height,
|
||||||
|
0x10, 0x10, 0x10);
|
||||||
|
q = draw_enable_tests(q, 0, t_zBuffer);
|
||||||
|
q = draw_finish(q);
|
||||||
|
DMATAG_END(packet->data, q - packet->data - 1, 0, 0, 0);
|
||||||
|
dma_channel_send_chain(DMA_CHANNEL_GIF, packet->data, q - packet->data, 0, 0);
|
||||||
|
dma_wait_fast();
|
||||||
|
packet_free(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Used in game loop.
|
||||||
|
* Switches current packet to next one
|
||||||
|
*/
|
||||||
|
void GifSender::initPacket(u8 t_context)
|
||||||
|
{
|
||||||
|
currentPacket = packets[t_context];
|
||||||
|
if (currentPacket->qwords > (u32)packetSize || currentPacket->qwords < 0)
|
||||||
|
PRINT_ERR("GifSender packet size error. Please consider to change packet size!\n");
|
||||||
|
q = currentPacket->data;
|
||||||
|
dmatag = q;
|
||||||
|
q++;
|
||||||
|
isAnyObjectAdded = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sends packet to GIF. */
|
||||||
|
void GifSender::sendPacket()
|
||||||
|
{
|
||||||
|
if (isAnyObjectAdded)
|
||||||
|
{
|
||||||
|
dmatag = q;
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
q = draw_finish(q);
|
||||||
|
DMATAG_END(dmatag, q - dmatag - 1, 0, 0, 0);
|
||||||
|
dma_wait_fast();
|
||||||
|
dma_channel_send_chain(DMA_CHANNEL_GIF, currentPacket->data, q - currentPacket->data, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds clear screen to current packet */
|
||||||
|
void GifSender::addClear(zbuffer_t *t_zBuffer)
|
||||||
|
{
|
||||||
|
q = draw_disable_tests(q, 0, t_zBuffer);
|
||||||
|
q = draw_clear(q, 0,
|
||||||
|
2048.0F - (screen->width / 2), 2048.0F - (screen->height / 2),
|
||||||
|
screen->width, screen->height,
|
||||||
|
0x10, 0x10, 0x10);
|
||||||
|
q = draw_enable_tests(q, 0, t_zBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds 3D objects to current packet
|
||||||
|
* @param worldView Matrix
|
||||||
|
* @param perspective Matrix with .setPerpsective() used [clone of gluPerspective]
|
||||||
|
* @param objects3D Array of 3D objects pointers
|
||||||
|
* @param amount Amount of 3D objects
|
||||||
|
*/
|
||||||
|
void GifSender::addObjects(RenderData *t_renderData, Mesh **t_objects3D, u32 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||||
|
{
|
||||||
|
if (!isAnyObjectAdded)
|
||||||
|
{
|
||||||
|
isAnyObjectAdded = true;
|
||||||
|
DMATAG_CNT(dmatag, q - dmatag - 1, 0, 0, 0); // init tag (before first 3d obj)
|
||||||
|
}
|
||||||
|
qword_t *tempDMATag;
|
||||||
|
tempDMATag = q;
|
||||||
|
q++;
|
||||||
|
|
||||||
|
q = draw_texture_sampling(q, 0, &t_objects3D[0]->spec->lod);
|
||||||
|
q = draw_texturebuffer(q, 0, &t_objects3D[0]->spec->textureBuffer, &t_objects3D[0]->spec->clut);
|
||||||
|
dw = (u64 *)draw_prim_start(q, 0, t_renderData->prim, &t_objects3D[0]->color);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < t_amount; i++)
|
||||||
|
if (t_objects3D[i]->shouldBeFrustumCulled == 0 || t_objects3D[i]->isInFrustum(t_renderData->frustumPlanes))
|
||||||
|
{
|
||||||
|
u32 vertexCount = calc3DObject(*t_renderData->perspective, *t_objects3D[i], t_renderData, t_bulbs, t_bulbsCount);
|
||||||
|
addCurrentCalcs(vertexCount);
|
||||||
|
delete[] xyz;
|
||||||
|
delete[] rgbaq;
|
||||||
|
delete[] st;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((u32)dw % 16) // if we are in the middle of qw, switch packet
|
||||||
|
*dw++ = 0;
|
||||||
|
|
||||||
|
q = draw_prim_end((qword_t *)dw, 3, DRAW_STQ_REGLIST);
|
||||||
|
|
||||||
|
DMATAG_CNT(tempDMATag, q - tempDMATag - 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Calculates 3D object data into xyz, rgbq, st
|
||||||
|
* After it addCurrentSTQ() can be done
|
||||||
|
* @param worldView Matrix
|
||||||
|
* @param perspective Matrix with .setPerpsective() used [clone of gluPerspective]
|
||||||
|
* @param mesh 3D object
|
||||||
|
* @returns Vertex count
|
||||||
|
*/
|
||||||
|
u32 GifSender::calc3DObject(Matrix t_perspective, Mesh &t_mesh, RenderData *t_renderData, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||||
|
{
|
||||||
|
u32 vertexCount = t_mesh.getVertexCount();
|
||||||
|
|
||||||
|
VECTOR *vertices = new VECTOR[vertexCount];
|
||||||
|
VECTOR *normals = new VECTOR[vertexCount];
|
||||||
|
VECTOR *coordinates = new VECTOR[vertexCount];
|
||||||
|
VECTOR *colors = new VECTOR[vertexCount];
|
||||||
|
vertexCount = t_mesh.getDrawData(0, vertices, normals, coordinates, colors, *t_renderData->cameraPosition);
|
||||||
|
|
||||||
|
xyz = new xyz_t[vertexCount];
|
||||||
|
rgbaq = new color_t[vertexCount];
|
||||||
|
st = new texel_t[vertexCount];
|
||||||
|
|
||||||
|
VECTOR position, rotation;
|
||||||
|
|
||||||
|
vec3ToNative(position, t_mesh.position, 1.0F);
|
||||||
|
vec3ToNative(rotation, t_mesh.rotation, 1.0F);
|
||||||
|
|
||||||
|
create_local_world(localWorld, position, rotation);
|
||||||
|
|
||||||
|
const u8 SHOULD_BE_LIGHTED = t_bulbs != NULL && t_mesh.shouldBeLighted;
|
||||||
|
|
||||||
|
if (SHOULD_BE_LIGHTED)
|
||||||
|
create_local_light(localLight, rotation);
|
||||||
|
|
||||||
|
// I cant put perspective from renderData here. PS2SDK bug?
|
||||||
|
create_local_screen(localScreen, localWorld, t_renderData->worldView->data, t_perspective.data);
|
||||||
|
|
||||||
|
if (SHOULD_BE_LIGHTED)
|
||||||
|
{
|
||||||
|
const u16 lightsCount = Light::getLightsCount(t_bulbsCount);
|
||||||
|
VECTOR *lightDirections = new VECTOR[lightsCount];
|
||||||
|
VECTOR *lightColors = new VECTOR[lightsCount];
|
||||||
|
int *lightTypes = new int[lightsCount];
|
||||||
|
|
||||||
|
VECTOR *lights = new VECTOR[vertexCount];
|
||||||
|
calculate_normals(normals, vertexCount, normals, localLight);
|
||||||
|
|
||||||
|
Light::calculateLight(lightDirections, lightColors, lightTypes, t_bulbs, t_bulbsCount, t_mesh.position);
|
||||||
|
|
||||||
|
calculate_lights(lights, vertexCount, normals, lightDirections, lightColors, lightTypes, lightsCount);
|
||||||
|
|
||||||
|
calculate_colours(colors, vertexCount, colors, lights);
|
||||||
|
|
||||||
|
delete[] lightDirections;
|
||||||
|
delete[] lightColors;
|
||||||
|
delete[] lightTypes;
|
||||||
|
delete[] lights;
|
||||||
|
}
|
||||||
|
|
||||||
|
calculate_vertices(vertices, vertexCount, vertices, localScreen);
|
||||||
|
|
||||||
|
convertCalcs(vertexCount, vertices, colors, coordinates, t_mesh.color.a);
|
||||||
|
|
||||||
|
delete[] vertices;
|
||||||
|
delete[] normals;
|
||||||
|
delete[] coordinates;
|
||||||
|
delete[] colors;
|
||||||
|
|
||||||
|
return vertexCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSender::convertCalcs(u32 t_vertexCount, VECTOR *t_vertices, VECTOR *t_colors, VECTOR *t_sts, u8 t_alpha)
|
||||||
|
{
|
||||||
|
// TODO get this via screensettings
|
||||||
|
const s32 centerX = ftoi4(2048);
|
||||||
|
const s32 centerY = ftoi4(2048);
|
||||||
|
const u32 maxZ = ftoi4(((float)0xFFFFFF) / 32.0F);
|
||||||
|
float q = 1.00F;
|
||||||
|
for (u32 i = 0; i < t_vertexCount; i++)
|
||||||
|
{
|
||||||
|
xyz[i].x = (u16)((t_vertices[i][0] + 1.0F) * centerX);
|
||||||
|
xyz[i].y = (u16)((t_vertices[i][1] + 1.0F) * centerY);
|
||||||
|
xyz[i].z = (u32)((t_vertices[i][2] + 1.0F) * maxZ);
|
||||||
|
|
||||||
|
if (t_vertices[i][3])
|
||||||
|
q = 1 / t_vertices[i][3];
|
||||||
|
|
||||||
|
st[i].s = t_sts[i][0] * q;
|
||||||
|
st[i].t = t_sts[i][1] * q;
|
||||||
|
|
||||||
|
rgbaq[i].r = (u8)(t_colors[i][0] * 128.0F);
|
||||||
|
rgbaq[i].g = (u8)(t_colors[i][1] * 128.0F);
|
||||||
|
rgbaq[i].b = (u8)(t_colors[i][2] * 128.0F);
|
||||||
|
rgbaq[i].a = t_alpha;
|
||||||
|
rgbaq[i].q = q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update q's double words. It may look strange, but this workaround
|
||||||
|
* use's a 64-bit pointer to simplify adding data to the packet.
|
||||||
|
*/
|
||||||
|
void GifSender::addCurrentCalcs(u32 &t_vertexCount)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < t_vertexCount; i++)
|
||||||
|
{
|
||||||
|
*dw++ = rgbaq[i].rgbaq;
|
||||||
|
*dw++ = st[i].uv;
|
||||||
|
*dw++ = xyz[i].xyz;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/modules/light.hpp"
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
Light::Light() {}
|
||||||
|
|
||||||
|
Light::~Light() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
const u8 ADDITIONAL_LIGHTS = 1; // Ambient
|
||||||
|
|
||||||
|
u16 Light::getLightsCount(u32 t_bulbsCount) { return t_bulbsCount + ADDITIONAL_LIGHTS; }
|
||||||
|
|
||||||
|
/** Calculates lighting. Used in gifSender in object 3D calculations */
|
||||||
|
void Light::calculateLight(VECTOR *t_lightDirections, VECTOR *t_lightColors, int *t_lightTypes, LightBulb *t_bulbs, u32 t_bulbsCount, Vector3 t_objPosition)
|
||||||
|
{
|
||||||
|
// --- Ambient light
|
||||||
|
|
||||||
|
t_lightTypes[0] = LIGHT_AMBIENT;
|
||||||
|
|
||||||
|
t_lightDirections[0][0] = 0.0F;
|
||||||
|
t_lightDirections[0][1] = 0.0F;
|
||||||
|
t_lightDirections[0][2] = 0.0F;
|
||||||
|
t_lightDirections[0][3] = 1.0F;
|
||||||
|
|
||||||
|
t_lightColors[0][0] = 0.0F;
|
||||||
|
t_lightColors[0][1] = 0.0F;
|
||||||
|
t_lightColors[0][2] = 0.0F;
|
||||||
|
t_lightColors[0][3] = 1.0F;
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
for (u8 i = 0; i < t_bulbsCount; i++)
|
||||||
|
{
|
||||||
|
t_lightTypes[i + 1] = LIGHT_DIRECTIONAL;
|
||||||
|
|
||||||
|
Vector3 newLight = Vector3(t_objPosition.x - t_bulbs[i].position.x,
|
||||||
|
t_objPosition.y - t_bulbs[i].position.y,
|
||||||
|
t_objPosition.z - t_bulbs[i].position.z);
|
||||||
|
|
||||||
|
newLight.normalize();
|
||||||
|
newLight = newLight *
|
||||||
|
(.1F +
|
||||||
|
(t_bulbs[i].intensity / t_bulbs[i].position.distanceTo(t_objPosition)));
|
||||||
|
|
||||||
|
t_lightDirections[i + 1][0] = newLight.x;
|
||||||
|
t_lightDirections[i + 1][1] = newLight.y;
|
||||||
|
t_lightDirections[i + 1][2] = newLight.z;
|
||||||
|
t_lightDirections[i + 1][3] = 1.0F;
|
||||||
|
|
||||||
|
t_lightColors[i + 1][0] = 0.8F;
|
||||||
|
t_lightColors[i + 1][1] = 0.8F;
|
||||||
|
t_lightColors[i + 1][2] = 0.8F;
|
||||||
|
t_lightColors[i + 1][3] = 1.0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/modules/pad.hpp"
|
||||||
|
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <loadfile.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Init vars, load modules, opens pad port and initializes pad */
|
||||||
|
Pad::Pad()
|
||||||
|
{
|
||||||
|
this->oldPad = 0;
|
||||||
|
this->loadModules();
|
||||||
|
padInit(0);
|
||||||
|
this->port = 0; // 0 -> Connector 1, 1 -> Connector 2
|
||||||
|
this->slot = 0; // Always zero if not using multitap
|
||||||
|
if ((this->ret = padPortOpen(this->port, this->slot, padBuf)) == 0)
|
||||||
|
{
|
||||||
|
PRINT_ERR("padPortOpen failed!");
|
||||||
|
printf("padPortOpen returned: %d\n", this->ret);
|
||||||
|
SleepThread();
|
||||||
|
}
|
||||||
|
if (!this->initPad())
|
||||||
|
{
|
||||||
|
PRINT_ERR("initPad failed!");
|
||||||
|
SleepThread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pad::~Pad() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Load SIO2MAN and PADMAN modules */
|
||||||
|
void Pad::loadModules()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Loading pad modules");
|
||||||
|
this->ret = SifLoadModule("rom0:SIO2MAN", 0, NULL);
|
||||||
|
if (this->ret < 0)
|
||||||
|
{
|
||||||
|
PRINT_ERR("SifLoadModule (SIO2MAN) failed!");
|
||||||
|
printf("SifLoadModule returned: %d\n", this->ret);
|
||||||
|
SleepThread();
|
||||||
|
}
|
||||||
|
this->ret = SifLoadModule("rom0:PADMAN", 0, NULL);
|
||||||
|
if (this->ret < 0)
|
||||||
|
{
|
||||||
|
PRINT_ERR("SifLoadModule (PADMAN) failed!");
|
||||||
|
printf("SifLoadModule returned: %d\n", this->ret);
|
||||||
|
SleepThread();
|
||||||
|
}
|
||||||
|
PRINT_LOG("Pad modules loaded!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Wait when pad will be ready (stable and ready) */
|
||||||
|
int Pad::waitPadReady()
|
||||||
|
{
|
||||||
|
int state;
|
||||||
|
int lastState;
|
||||||
|
char stateString[16];
|
||||||
|
state = padGetState(this->port, this->slot);
|
||||||
|
lastState = -1;
|
||||||
|
while ((state != PAD_STATE_STABLE) && (state != PAD_STATE_FINDCTP1))
|
||||||
|
{
|
||||||
|
if (state != lastState)
|
||||||
|
{
|
||||||
|
padStateInt2String(state, stateString);
|
||||||
|
PRINT_LOG("Pad state changed");
|
||||||
|
printf("Curent pad(%d,%d) status: %s\n", this->port, this->slot, stateString);
|
||||||
|
}
|
||||||
|
lastState = state;
|
||||||
|
state = padGetState(this->port, this->slot);
|
||||||
|
}
|
||||||
|
// Were the pad ever 'out of sync'?
|
||||||
|
if (lastState != -1)
|
||||||
|
PRINT_LOG("Pad is ready!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initializes and checks type of pad */
|
||||||
|
int Pad::initPad()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Initializing pad");
|
||||||
|
this->waitPadReady();
|
||||||
|
// How many different modes can this device operate in?
|
||||||
|
// i.e. get # entrys in the modetable
|
||||||
|
int modes = padInfoMode(this->port, this->slot, PAD_MODETABLE, -1);
|
||||||
|
if (modes == 0)
|
||||||
|
{
|
||||||
|
PRINT_ERR("Connected device is not a dual shock controller!"); // (it has no actuator engines)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// Verify that the controller has a DUAL SHOCK mode
|
||||||
|
int i = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (padInfoMode(this->port, this->slot, PAD_MODETABLE, i) == PAD_TYPE_DUALSHOCK)
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
} while (i < modes);
|
||||||
|
|
||||||
|
if (i >= modes)
|
||||||
|
{
|
||||||
|
PRINT_ERR("Connected device is not a dual shock controller!");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If ExId != 0x0 => This controller has actuator engines
|
||||||
|
// This check should always pass if the Dual Shock test above passed
|
||||||
|
this->ret = padInfoMode(this->port, this->slot, PAD_MODECUREXID, 0);
|
||||||
|
if (this->ret == 0)
|
||||||
|
{
|
||||||
|
PRINT_ERR("Connected device is not a dual shock controller!");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_LOG("Enabling dual shock functions.");
|
||||||
|
|
||||||
|
// When using MMODE_LOCK, user cant change mode with Select button
|
||||||
|
padSetMainMode(this->port, this->slot, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK);
|
||||||
|
|
||||||
|
this->waitPadReady();
|
||||||
|
printf("Pad has pressure sensitive buttons? %d\n", padInfoPressMode(this->port, this->slot));
|
||||||
|
this->waitPadReady();
|
||||||
|
padEnterPressMode(this->port, this->slot); // Set pressure sensitive mode
|
||||||
|
this->waitPadReady();
|
||||||
|
this->actuators = padInfoAct(this->port, this->slot, -1, 0);
|
||||||
|
printf("# of actuators: %d\n", this->actuators);
|
||||||
|
if (actuators != 0)
|
||||||
|
{
|
||||||
|
this->actAlign[0] = 0; // Enable small engine
|
||||||
|
this->actAlign[1] = 1; // Enable big engine
|
||||||
|
this->actAlign[2] = 0xff;
|
||||||
|
this->actAlign[3] = 0xff;
|
||||||
|
this->actAlign[4] = 0xff;
|
||||||
|
this->actAlign[5] = 0xff;
|
||||||
|
this->waitPadReady();
|
||||||
|
printf("padSetActAlign: %d\n", padSetActAlign(this->port, this->slot, actAlign));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
printf("Did not find any actuators.\n");
|
||||||
|
this->waitPadReady();
|
||||||
|
PRINT_LOG("Pad initialized!");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Updates state of joys/buttons */
|
||||||
|
void Pad::update()
|
||||||
|
{
|
||||||
|
int x = 0;
|
||||||
|
this->ret = padGetState(this->port, this->slot);
|
||||||
|
while ((this->ret != PAD_STATE_STABLE) && (this->ret != PAD_STATE_FINDCTP1))
|
||||||
|
{
|
||||||
|
if (this->ret == PAD_STATE_DISCONN)
|
||||||
|
printf("Pad(%d, %d) is disconnected\n", this->port, this->slot);
|
||||||
|
this->ret = padGetState(this->port, this->slot);
|
||||||
|
}
|
||||||
|
if (x == 1)
|
||||||
|
printf("Pad: OK!\n");
|
||||||
|
|
||||||
|
this->ret = padRead(this->port, this->slot, &this->buttons); // this->port, this->slot, this->buttons
|
||||||
|
|
||||||
|
if (this->ret != 0)
|
||||||
|
{
|
||||||
|
this->padData = 0xffff ^ this->buttons.btns;
|
||||||
|
|
||||||
|
this->newPad = this->padData & ~this->oldPad;
|
||||||
|
this->oldPad = this->padData;
|
||||||
|
this->reset();
|
||||||
|
this->rJoyH = this->buttons.rjoy_h;
|
||||||
|
this->rJoyV = this->buttons.rjoy_v;
|
||||||
|
this->lJoyH = this->buttons.ljoy_h;
|
||||||
|
this->lJoyV = this->buttons.ljoy_v;
|
||||||
|
|
||||||
|
if (this->newPad & PAD_CROSS)
|
||||||
|
this->isCrossClicked = 1;
|
||||||
|
if (this->newPad & PAD_SQUARE)
|
||||||
|
this->isSquareClicked = 1;
|
||||||
|
if (this->newPad & PAD_TRIANGLE)
|
||||||
|
this->isTriangleClicked = 1;
|
||||||
|
if (this->newPad & PAD_CIRCLE)
|
||||||
|
this->isCircleClicked = 1;
|
||||||
|
|
||||||
|
if (this->buttons.up_p > 0)
|
||||||
|
this->isDpadUpPressed = 1;
|
||||||
|
if (this->buttons.down_p > 0)
|
||||||
|
this->isDpadDownPressed = 1;
|
||||||
|
if (this->buttons.left_p)
|
||||||
|
this->isDpadLeftPressed = 1;
|
||||||
|
if (this->buttons.right_p)
|
||||||
|
this->isDpadRightPressed = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Resets state of joys/buttons */
|
||||||
|
void Pad::reset()
|
||||||
|
{
|
||||||
|
this->isCrossClicked = 0;
|
||||||
|
this->isSquareClicked = 0;
|
||||||
|
this->isTriangleClicked = 0;
|
||||||
|
this->isCircleClicked = 0;
|
||||||
|
this->isDpadUpPressed = 0;
|
||||||
|
this->isDpadDownPressed = 0;
|
||||||
|
this->isDpadLeftPressed = 0;
|
||||||
|
this->isDpadRightPressed = 0;
|
||||||
|
this->lJoyH = 0;
|
||||||
|
this->lJoyV = 0;
|
||||||
|
this->rJoyH = 0;
|
||||||
|
this->rJoyV = 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/modules/renderer.hpp"
|
||||||
|
|
||||||
|
#include <dma.h>
|
||||||
|
#include <graph.h>
|
||||||
|
#include <packet.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include <gs_psm.h>
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
#include "../include/utils/math.hpp"
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Initialize DMA<->GIF channel
|
||||||
|
* Allocate buffers
|
||||||
|
* Initialize screen
|
||||||
|
* Initialize drawing environment
|
||||||
|
* Load/setup textures
|
||||||
|
* @param screenW Half of screen width
|
||||||
|
* @param screenH Half of screen height
|
||||||
|
*/
|
||||||
|
Renderer::Renderer(u32 t_packetSize, ScreenSettings *t_screen)
|
||||||
|
{
|
||||||
|
PRINT_LOG("Initializing renderer");
|
||||||
|
dma_channel_initialize(DMA_CHANNEL_GIF, NULL, 0); // Initialize DMA to enable data transfer
|
||||||
|
dma_channel_fast_waits(DMA_CHANNEL_GIF);
|
||||||
|
context = 0;
|
||||||
|
lastTextureId = 0;
|
||||||
|
isFrameEmpty = false;
|
||||||
|
flipPacket = packet_init(3, PACKET_UCAB); // Uncached accelerated
|
||||||
|
allocateBuffers(t_screen->width, t_screen->height);
|
||||||
|
initDrawingEnv(t_screen->width, t_screen->height);
|
||||||
|
setPrim();
|
||||||
|
gifSender = new GifSender(t_packetSize, t_screen);
|
||||||
|
vifSender = new VifSender();
|
||||||
|
perspective.setPerspective(*t_screen);
|
||||||
|
renderData.perspective = &perspective;
|
||||||
|
PRINT_LOG("Renderer initialized!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Renderer::~Renderer() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Initializes drawing environment (1st app packet) */
|
||||||
|
void Renderer::initDrawingEnv(float t_screenW, float t_screenH)
|
||||||
|
{
|
||||||
|
PRINT_LOG("Initializing drawing environment");
|
||||||
|
packet_t *packet = packet_init(20, PACKET_NORMAL);
|
||||||
|
u16 halfW = (u16)t_screenW / 2;
|
||||||
|
u16 halfH = (u16)t_screenH / 2;
|
||||||
|
qword_t *q = packet->data; // Generic qword pointer.
|
||||||
|
q = draw_setup_environment(q, 0, frameBuffers, &(zBuffer));
|
||||||
|
q = draw_primitive_xyoffset(q, 0, (2048 - halfW), (2048 - halfH));
|
||||||
|
q = draw_finish(q);
|
||||||
|
// Now send the packet, no need to wait since it's the first.
|
||||||
|
dma_channel_send_normal(DMA_CHANNEL_GIF, packet->data, q - packet->data, 0, 0);
|
||||||
|
dma_wait_fast();
|
||||||
|
packet_free(packet);
|
||||||
|
PRINT_LOG("Drawing environment initialized!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets drawing prim for all 3D objects */
|
||||||
|
void Renderer::setPrim()
|
||||||
|
{
|
||||||
|
prim.type = PRIM_TRIANGLE;
|
||||||
|
prim.shading = PRIM_SHADE_FLAT;
|
||||||
|
prim.mapping = DRAW_ENABLE;
|
||||||
|
prim.fogging = DRAW_DISABLE;
|
||||||
|
prim.blending = DRAW_ENABLE;
|
||||||
|
prim.antialiasing = DRAW_DISABLE;
|
||||||
|
prim.mapping_type = PRIM_MAP_ST;
|
||||||
|
prim.colorfix = PRIM_UNFIXED;
|
||||||
|
renderData.prim = &prim;
|
||||||
|
PRINT_LOG("Prim set!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::changeTexture(Mesh *t_mesh, u8 t_textureIndex)
|
||||||
|
{
|
||||||
|
if (t_mesh->spec->textures[t_textureIndex].id != lastTextureId)
|
||||||
|
{
|
||||||
|
lastTextureId = t_mesh->spec->textures[t_textureIndex].id;
|
||||||
|
t_mesh->spec->deallocateTextureBuffer();
|
||||||
|
t_mesh->spec->allocateTextureBuffer(t_mesh->spec->textures[t_textureIndex].width, t_mesh->spec->textures[t_textureIndex].height);
|
||||||
|
GifSender::sendTexture(t_mesh->spec->textures[t_textureIndex], &t_mesh->spec->textureBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Defines and allocates framebuffers and zbuffer */
|
||||||
|
void Renderer::allocateBuffers(float t_screenW, float t_screenH)
|
||||||
|
{
|
||||||
|
frameBuffers[0].width = (u16)t_screenW;
|
||||||
|
frameBuffers[0].height = (u16)t_screenH;
|
||||||
|
frameBuffers[0].mask = 0;
|
||||||
|
frameBuffers[0].psm = GS_PSM_32;
|
||||||
|
frameBuffers[0].address = graph_vram_allocate((u16)t_screenW, (u16)t_screenH, frameBuffers[0].psm, GRAPH_ALIGN_PAGE);
|
||||||
|
|
||||||
|
frameBuffers[1].width = (u16)t_screenW;
|
||||||
|
frameBuffers[1].height = (u16)t_screenH;
|
||||||
|
frameBuffers[1].mask = 0;
|
||||||
|
frameBuffers[1].psm = GS_PSM_32;
|
||||||
|
frameBuffers[1].address = graph_vram_allocate((u16)t_screenW, (u16)t_screenH, frameBuffers[1].psm, GRAPH_ALIGN_PAGE);
|
||||||
|
|
||||||
|
zBuffer.enable = DRAW_ENABLE;
|
||||||
|
zBuffer.mask = 0;
|
||||||
|
zBuffer.method = ZTEST_METHOD_GREATER_EQUAL;
|
||||||
|
zBuffer.zsm = GS_ZBUF_32;
|
||||||
|
zBuffer.address = graph_vram_allocate((u16)t_screenW, (u16)t_screenH, zBuffer.zsm, GRAPH_ALIGN_PAGE);
|
||||||
|
PRINT_LOG("Framebuffers, zBuffer set and allocated!");
|
||||||
|
|
||||||
|
// Initialize the screen and tie the first framebuffer to the read circuits.
|
||||||
|
graph_initialize(frameBuffers[1].address, frameBuffers[1].width, frameBuffers[1].height, frameBuffers[1].psm, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// --- Draw: PATH3
|
||||||
|
|
||||||
|
/** PATH3 Many + lighting */
|
||||||
|
void Renderer::drawByPath3(Mesh **t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||||
|
{
|
||||||
|
beginFrameIfNeeded();
|
||||||
|
gifSender->initPacket(context);
|
||||||
|
// TODO
|
||||||
|
changeTexture(t_meshes[0], 0);
|
||||||
|
gifSender->addObjects(&renderData, t_meshes, t_amount, t_bulbs, t_bulbsCount);
|
||||||
|
gifSender->sendPacket();
|
||||||
|
draw_wait_finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** PATH3 Single + lighting */
|
||||||
|
void Renderer::drawByPath3(Mesh *t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||||
|
{
|
||||||
|
beginFrameIfNeeded();
|
||||||
|
gifSender->initPacket(context);
|
||||||
|
// TODO
|
||||||
|
changeTexture(t_mesh, 0);
|
||||||
|
gifSender->addObjects(&renderData, &t_mesh, 1, t_bulbs, t_bulbsCount);
|
||||||
|
gifSender->sendPacket();
|
||||||
|
draw_wait_finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** PATH3 Many */
|
||||||
|
void Renderer::drawByPath3(Mesh **t_meshes, u16 t_amount) { drawByPath3(t_meshes, t_amount, NULL, 0); }
|
||||||
|
|
||||||
|
/** PATH3 Single */
|
||||||
|
void Renderer::drawByPath3(Mesh *t_mesh) { drawByPath3(t_mesh, NULL, 0); }
|
||||||
|
|
||||||
|
/// --- Draw: PATH1
|
||||||
|
|
||||||
|
/** PATH1 Many + lighting */
|
||||||
|
void Renderer::draw(Mesh **t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
beginFrameIfNeeded();
|
||||||
|
for (u16 i = 0; i < t_amount; i++)
|
||||||
|
draw(t_meshes[i], t_bulbs, t_bulbsCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** PATH1 Single + lighting */
|
||||||
|
void Renderer::draw(Mesh *t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||||
|
{
|
||||||
|
beginFrameIfNeeded();
|
||||||
|
// TODO VU1 send single list here
|
||||||
|
if (!t_mesh->isObjLoaded && !t_mesh->isDffLoaded && !t_mesh->isMd2Loaded)
|
||||||
|
return;
|
||||||
|
u32 vertCount = t_mesh->getVertexCount();
|
||||||
|
VECTOR *vertices = new VECTOR[vertCount];
|
||||||
|
VECTOR *normals = new VECTOR[vertCount];
|
||||||
|
VECTOR *coordinates = new VECTOR[vertCount];
|
||||||
|
VECTOR *colors = new VECTOR[vertCount];
|
||||||
|
if (t_mesh->isObjLoaded || t_mesh->isMd2Loaded)
|
||||||
|
{
|
||||||
|
changeTexture(t_mesh, 0);
|
||||||
|
vertCount = t_mesh->getDrawData(0, vertices, normals, coordinates, colors, *renderData.cameraPosition);
|
||||||
|
vifSender->drawMesh(&renderData, perspective, vertCount, vertices, normals, coordinates, colors, t_mesh, t_bulbs, t_bulbsCount);
|
||||||
|
}
|
||||||
|
else if (t_mesh->isDffLoaded)
|
||||||
|
for (u32 i = 0; i < t_mesh->dff->clump.geometryList.geometries[0].extension.materialSplit.header.splitCount; i++)
|
||||||
|
{
|
||||||
|
const u32 currentTexI = t_mesh->dff->clump.geometryList.geometries[0].extension.materialSplit.splitInformation[i].materialIndex;
|
||||||
|
changeTexture(t_mesh, currentTexI);
|
||||||
|
vertCount = t_mesh->getDrawData(i, vertices, normals, coordinates, colors, *renderData.cameraPosition);
|
||||||
|
vifSender->drawMesh(&renderData, perspective, vertCount, vertices, normals, coordinates, colors, t_mesh, t_bulbs, t_bulbsCount);
|
||||||
|
}
|
||||||
|
delete[] vertices;
|
||||||
|
delete[] normals;
|
||||||
|
delete[] coordinates;
|
||||||
|
delete[] colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** PATH1 Many */
|
||||||
|
void Renderer::draw(Mesh **t_objects3D, u16 t_amount) { draw(t_objects3D, t_amount, NULL, 0); }
|
||||||
|
|
||||||
|
/** PATH1 Single */
|
||||||
|
void Renderer::draw(Mesh *t_mesh) { draw(t_mesh, NULL, 0); }
|
||||||
|
|
||||||
|
/// ---
|
||||||
|
|
||||||
|
void Renderer::setCameraDefinitions(Matrix *t_worldView, Vector3 *t_cameraPos, Plane *t_planes)
|
||||||
|
{
|
||||||
|
renderData.worldView = t_worldView;
|
||||||
|
renderData.cameraPosition = t_cameraPos;
|
||||||
|
renderData.frustumPlanes = t_planes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::beginFrameIfNeeded()
|
||||||
|
{
|
||||||
|
if (isFrameEmpty)
|
||||||
|
{
|
||||||
|
isFrameEmpty = false;
|
||||||
|
gifSender->sendClear(&zBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::endFrame(float fps)
|
||||||
|
{
|
||||||
|
if (!isFrameEmpty)
|
||||||
|
{
|
||||||
|
if (fps > 49.0F)
|
||||||
|
graph_wait_vsync();
|
||||||
|
flipBuffers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** We need to flip buffers outside of the chain, for some reason,
|
||||||
|
* so we use a separate small packet
|
||||||
|
* Do not use this method. This is called via packetManager
|
||||||
|
*/
|
||||||
|
void Renderer::flipBuffers()
|
||||||
|
{
|
||||||
|
graph_set_framebuffer_filtered(
|
||||||
|
frameBuffers[context].address,
|
||||||
|
frameBuffers[context].width,
|
||||||
|
frameBuffers[context].psm,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
context ^= 1;
|
||||||
|
isFrameEmpty = 1;
|
||||||
|
qword_t *q = flipPacket->data;
|
||||||
|
q = draw_framebuffer(q, 0, &frameBuffers[context]);
|
||||||
|
q = draw_finish(q);
|
||||||
|
dma_wait_fast();
|
||||||
|
dma_channel_send_normal_ucab(DMA_CHANNEL_GIF, flipPacket->data, q - flipPacket->data, 0);
|
||||||
|
draw_wait_finish();
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/modules/timer.hpp"
|
||||||
|
|
||||||
|
#include <timer.h>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
Timer::Timer()
|
||||||
|
{
|
||||||
|
this->lastTime = *T3_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer::~Timer() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
u32 Timer::getTimeDelta()
|
||||||
|
{
|
||||||
|
this->time = *T3_COUNT;
|
||||||
|
|
||||||
|
if (this->time < this->lastTime) // The counter has wrapped
|
||||||
|
this->change = this->time + (65536 - this->lastTime);
|
||||||
|
else
|
||||||
|
this->change = this->time - this->lastTime;
|
||||||
|
|
||||||
|
this->lastTime = this->time;
|
||||||
|
return this->change;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Timer::primeTimer()
|
||||||
|
{
|
||||||
|
lastTime = *T3_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Timer::getFPS()
|
||||||
|
{
|
||||||
|
u32 timeDelta = this->getTimeDelta();
|
||||||
|
|
||||||
|
if (timeDelta == 0)
|
||||||
|
return -1.0F;
|
||||||
|
|
||||||
|
return 15625.0F / (float)timeDelta; // PAL
|
||||||
|
}
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/modules/vif_sender.hpp"
|
||||||
|
|
||||||
|
#include <gs_gp.h>
|
||||||
|
#include <dma.h>
|
||||||
|
#include <gif_tags.h>
|
||||||
|
#include "../include/utils/math.hpp"
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
|
||||||
|
// Similiar set is in PS2SDK, but for VU1 we have to switch ST with RGBAQ, because VU1 must know Q before sending RGBAQ
|
||||||
|
#define DRAW_R_STQ_REGLIST ((u64)GIF_REG_ST) << 0 | ((u64)GIF_REG_RGBAQ) << 4 | ((u64)GIF_REG_XYZ2) << 8
|
||||||
|
const u32 VU1_PACKAGE_VERTS_PER_BUFF = 96; // Remember to modify buffer size in vu1 also
|
||||||
|
const u32 VU1_PACKAGES_PER_PACKET = 6;
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
VifSender::VifSender()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Initializing VifSender");
|
||||||
|
PRINT_LOG("VifSender initialized!");
|
||||||
|
}
|
||||||
|
|
||||||
|
VifSender::~VifSender() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
void VifSender::drawMesh(RenderData *t_renderData, Matrix t_perspective, u32 vertCount2, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, VECTOR *colors, Mesh *t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||||
|
{
|
||||||
|
if (t_mesh->shouldBeFrustumCulled == 1 && !t_mesh->isInFrustum(t_renderData->frustumPlanes))
|
||||||
|
return;
|
||||||
|
|
||||||
|
vec3ToNative(position, t_mesh->position, 1.0F);
|
||||||
|
vec3ToNative(rotation, t_mesh->rotation, 1.0F);
|
||||||
|
create_local_world(localWorld, position, rotation);
|
||||||
|
create_local_screen(localScreen, localWorld, t_renderData->worldView->data, t_perspective.data);
|
||||||
|
|
||||||
|
// TODO Send it once man xd
|
||||||
|
vu1.sendSingleRefList(0, &localScreen, 4);
|
||||||
|
|
||||||
|
// we have to split 3D object into small parts, because of small memory of VU1
|
||||||
|
for (u32 i = 0; i < vertCount2;)
|
||||||
|
{
|
||||||
|
vu1.createList();
|
||||||
|
for (u8 j = 0; j < VU1_PACKAGES_PER_PACKET; j++) // how many "packages" per one packet
|
||||||
|
{
|
||||||
|
if (i != 0) // we have to go back to avoid the visual artifacts
|
||||||
|
i -= 3;
|
||||||
|
|
||||||
|
const u32 endI = i + (VU1_PACKAGE_VERTS_PER_BUFF - 1) > vertCount2 ? vertCount2 : i + (VU1_PACKAGE_VERTS_PER_BUFF - 1);
|
||||||
|
drawVertices(t_mesh, i, endI, vertices, colors, coordinates, t_renderData->prim);
|
||||||
|
if (endI == vertCount2) // if there are no more vertices to draw, break
|
||||||
|
{
|
||||||
|
i = vertCount2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i += (VU1_PACKAGE_VERTS_PER_BUFF - 1);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
vu1.sendList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Draw using PATH1 */
|
||||||
|
void VifSender::drawVertices(Mesh *t_mesh, u32 t_start, u32 t_end, VECTOR *t_vertices, VECTOR *t_colors, VECTOR *t_coordinates, prim_t *t_prim)
|
||||||
|
{
|
||||||
|
const u32 vertCount = t_end - t_start;
|
||||||
|
vu1.addListBeginning();
|
||||||
|
|
||||||
|
// TODO get this via screensettings
|
||||||
|
vu1.addFloat(2048.0F); // scale
|
||||||
|
vu1.addFloat(2048.0F); // scale
|
||||||
|
vu1.addFloat(((float)0xFFFFFF) / 32.0F); // scale
|
||||||
|
vu1.add32(vertCount); // vertex count
|
||||||
|
|
||||||
|
vu1.add128(GIF_SET_TAG(1, 0, 0, 0, GIF_FLG_PACKED, 1), GIF_REG_AD); // 1x set tag
|
||||||
|
|
||||||
|
vu1.add128( // tex -> lod
|
||||||
|
GS_SET_TEX1(
|
||||||
|
t_mesh->spec->lod.calculation,
|
||||||
|
t_mesh->spec->lod.max_level,
|
||||||
|
t_mesh->spec->lod.mag_filter,
|
||||||
|
t_mesh->spec->lod.min_filter,
|
||||||
|
t_mesh->spec->lod.mipmap_select,
|
||||||
|
t_mesh->spec->lod.l,
|
||||||
|
(int)(t_mesh->spec->lod.k * 16.0F)),
|
||||||
|
GS_REG_TEX1);
|
||||||
|
|
||||||
|
vu1.add128( // tex -> buff + clut
|
||||||
|
GS_SET_TEX0(
|
||||||
|
t_mesh->spec->textureBuffer.address >> 6,
|
||||||
|
t_mesh->spec->textureBuffer.width >> 6,
|
||||||
|
t_mesh->spec->textureBuffer.psm,
|
||||||
|
t_mesh->spec->textureBuffer.info.width,
|
||||||
|
t_mesh->spec->textureBuffer.info.height,
|
||||||
|
t_mesh->spec->textureBuffer.info.components,
|
||||||
|
t_mesh->spec->textureBuffer.info.function,
|
||||||
|
t_mesh->spec->clut.address >> 6,
|
||||||
|
t_mesh->spec->clut.psm,
|
||||||
|
t_mesh->spec->clut.storage_mode,
|
||||||
|
t_mesh->spec->clut.start,
|
||||||
|
t_mesh->spec->clut.load_method),
|
||||||
|
GS_REG_TEX0);
|
||||||
|
|
||||||
|
vu1.add128(
|
||||||
|
GS_GIFTAG(
|
||||||
|
vertCount, // amount of loops
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
GS_PRIM(
|
||||||
|
t_prim->type,
|
||||||
|
t_prim->shading,
|
||||||
|
t_prim->mapping,
|
||||||
|
t_prim->fogging,
|
||||||
|
t_prim->blending,
|
||||||
|
t_prim->antialiasing,
|
||||||
|
t_prim->mapping_type,
|
||||||
|
0, // context
|
||||||
|
t_prim->colorfix),
|
||||||
|
GS_GIFTAG_PACKED,
|
||||||
|
3), // STQ + RGBA + XYZ
|
||||||
|
DRAW_R_STQ_REGLIST);
|
||||||
|
|
||||||
|
for (u8 j = 0; j < 4; j++)
|
||||||
|
vu1.add32(128);
|
||||||
|
|
||||||
|
//// Clipping tests start
|
||||||
|
|
||||||
|
// const float minZ = 1;
|
||||||
|
// const float maxZ = 65535;
|
||||||
|
// const int iGuardDimXY = 2048;
|
||||||
|
|
||||||
|
// vu1.addFloat(1.0F); // TODO clipping maybe there is problem?
|
||||||
|
// vu1.addFloat(1.0F);
|
||||||
|
// vu1.addFloat(1.0F);
|
||||||
|
// vu1.addFloat(1.0F);
|
||||||
|
// float xClip = (float)2048.0f/(drawContext.GetFBWidth() * 0.5f * 2.0f);
|
||||||
|
// packet += Math::Max( xClip, 1.0f );
|
||||||
|
// float yClip = (float)2048.0f/(drawContext.GetFBHeight() * 0.5f * 2.0f);
|
||||||
|
// packet += Math::Max( yClip, 1.0f );
|
||||||
|
// float depthClip = 2048.0f / depthClipToGs;
|
||||||
|
// // FIXME: maybe these 2048's should be 2047.5s...
|
||||||
|
// depthClip *= 1.003f; // round up a bit for fp error (????)
|
||||||
|
// packet += depthClip;
|
||||||
|
// // enable/disable clipping
|
||||||
|
// packet += (drawContext.GetDoClipping()) ? 1 : 0;
|
||||||
|
|
||||||
|
u32 depthBits = 24; // or 28(fog) or 16
|
||||||
|
float depthClipToGs = (float)((1 << depthBits) - 1) / 2.0f;
|
||||||
|
vu1.addFloat(2048.0f / (640.0F * 0.5f * 2.0f));
|
||||||
|
vu1.addFloat(2048.0f / (480.0F * 0.5f * 2.0f));
|
||||||
|
vu1.addFloat((2048.0f / depthClipToGs) * 1.003F);
|
||||||
|
// vu1.addFloat(2048.0F); // scale
|
||||||
|
// vu1.addFloat(2048.0F); // scale
|
||||||
|
// vu1.addFloat(((float)0xFFFFFF) / 32.0F); // scale
|
||||||
|
vu1.addFloat(0.0F);
|
||||||
|
// vu1.addFloat(0.5f * iGuardDimXY);
|
||||||
|
// vu1.addFloat(-0.5f * iGuardDimXY);
|
||||||
|
// vu1.addFloat(1.0F);
|
||||||
|
// vu1.addFloat(500.0F); // far
|
||||||
|
|
||||||
|
//// Clipping tests end
|
||||||
|
|
||||||
|
vu1.addListEnding();
|
||||||
|
vu1.addReferenceList(0, t_vertices + t_start, 2 * vertCount, 1);
|
||||||
|
vu1.addReferenceList(0, t_coordinates + t_start, 2 * vertCount, 1);
|
||||||
|
vu1.addStartProgram();
|
||||||
|
}
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/modules/vu1.hpp"
|
||||||
|
|
||||||
|
#include "../include/utils/debug.hpp"
|
||||||
|
#include <dma.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <kernel.h>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
VU1::VU1()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Initializing VU1");
|
||||||
|
currentBuffer = 0;
|
||||||
|
switchBuffer = 0;
|
||||||
|
PRINT_LOG("VU1 initialized!");
|
||||||
|
}
|
||||||
|
|
||||||
|
VU1::~VU1() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// -
|
||||||
|
|
||||||
|
/** Create dynamic list */
|
||||||
|
void VU1::createList()
|
||||||
|
{
|
||||||
|
switchBuffer = !switchBuffer;
|
||||||
|
memset((char *)&buildList, 0, sizeof(buildList));
|
||||||
|
|
||||||
|
if (switchBuffer)
|
||||||
|
currentBuffer = (char *)&dmaBuffer1;
|
||||||
|
else
|
||||||
|
currentBuffer = (char *)&dmaBuffer2;
|
||||||
|
buildList.kickBuffer = currentBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add reference list and send via VIF1
|
||||||
|
* Not using TOPS register
|
||||||
|
* Similar to addReferenceList()
|
||||||
|
*/
|
||||||
|
void VU1::sendSingleRefList(int t_destAddress, void *t_data, int t_quadSize)
|
||||||
|
{
|
||||||
|
checkDataAlignment(t_data);
|
||||||
|
|
||||||
|
u8 tempBuffer[32] __attribute__((aligned(16)));
|
||||||
|
void *chain = (u64 *)&tempBuffer; // uncached
|
||||||
|
|
||||||
|
*((u64 *)chain)++ = DMA_REF_TAG((u32)t_data, t_quadSize);
|
||||||
|
*((u32 *)chain)++ = VIF_CODE(VIF_STCYL, 0, 0x0101);
|
||||||
|
*((u32 *)chain)++ = VIF_CODE(VIF_UNPACK_V4_32, t_quadSize, t_destAddress);
|
||||||
|
|
||||||
|
*((u64 *)chain)++ = DMA_END_TAG(0);
|
||||||
|
*((u32 *)chain)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||||
|
*((u32 *)chain)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||||
|
|
||||||
|
FlushCache(0);
|
||||||
|
dma_channel_send_chain(DMA_CHANNEL_VIF1, tempBuffer, 0, DMA_FLAG_TRANSFERTAG, 0);
|
||||||
|
dma_channel_wait(DMA_CHANNEL_VIF1, VU1_DMA_CHAN_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add list beginning, set's double buffer if not set */
|
||||||
|
void VU1::addListBeginning()
|
||||||
|
{
|
||||||
|
if (buildList.isBuilding == 1)
|
||||||
|
PRINT_ERR("Please end current list list before adding new one!");
|
||||||
|
|
||||||
|
if (isDoubleBufferSet == 0)
|
||||||
|
addDoubleBufferSetting();
|
||||||
|
else
|
||||||
|
addFlush();
|
||||||
|
|
||||||
|
buildList.dmaSizeAll += buildList.dmaSize;
|
||||||
|
buildList.dmaSize = 0;
|
||||||
|
buildList.offset = currentBuffer;
|
||||||
|
*((u64 *)currentBuffer)++ = DMA_CNT_TAG(0); // placeholder
|
||||||
|
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_STCYL, 0, 0x0101); // placeholder
|
||||||
|
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_UNPACK_V4_32, 0, 0); // placeholder
|
||||||
|
buildList.isBuilding = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add list ending and fix unpack size */
|
||||||
|
void VU1::addListEnding()
|
||||||
|
{
|
||||||
|
if (buildList.isBuilding == 0)
|
||||||
|
{
|
||||||
|
PRINT_ERR("Please add list beginning first. Nothing to end!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((buildList.dmaSize & 0xF))
|
||||||
|
{
|
||||||
|
*((u32 *)currentBuffer)++ = 0;
|
||||||
|
buildList.dmaSize += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
*((u64 *)buildList.offset)++ = DMA_CNT_TAG(buildList.dmaSize >> 4);
|
||||||
|
*((u32 *)buildList.offset)++ = VIF_CODE(VIF_STCYL, 0, 0x0101);
|
||||||
|
*((u32 *)buildList.offset)++ = AddUnpack(V4_32, 0, buildList.dmaSize >> 4, 1);
|
||||||
|
|
||||||
|
buildList.isBuilding = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add list which will load data from given pointer
|
||||||
|
* A lot faster than standard list.
|
||||||
|
* @param offset offset before data in quadwords
|
||||||
|
* @param data data pointer
|
||||||
|
* @param size in quadwords
|
||||||
|
* @param useTops when true, data will be loaded at the beginning of buffer (BASE+OFFSET)
|
||||||
|
*/
|
||||||
|
void VU1::addReferenceList(u32 t_offset, void *t_data, u32 t_size, u8 t_useTops)
|
||||||
|
{
|
||||||
|
checkDataAlignment(t_data);
|
||||||
|
if (buildList.isBuilding == 1)
|
||||||
|
PRINT_ERR("Please end current list list before adding new one!");
|
||||||
|
*((u64 *)currentBuffer)++ = DMA_REF_TAG((u32)t_data, t_size);
|
||||||
|
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_STCYL, 0, 0x0101);
|
||||||
|
*((u32 *)currentBuffer)++ =
|
||||||
|
AddUnpack(V4_32, t_useTops == 1 ? buildList.dmaSize / 16 : t_offset / 16, t_size, t_useTops);
|
||||||
|
buildList.dmaSize += t_size * 8;
|
||||||
|
buildList.dmaSizeAll += buildList.dmaSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Start VU1 program */
|
||||||
|
void VU1::addStartProgram()
|
||||||
|
{
|
||||||
|
*((u64 *)currentBuffer)++ = DMA_CNT_TAG(8 >> 4);
|
||||||
|
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_MSCAL, 0, 0);
|
||||||
|
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_FLUSH, 0, 0);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Continue VU1 program from "--cont" line */
|
||||||
|
void VU1::addContinueProgram()
|
||||||
|
{
|
||||||
|
*((u64 *)currentBuffer)++ = DMA_CNT_TAG(8 >> 4);
|
||||||
|
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_MSCAL, 0, 0);
|
||||||
|
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_FLUSH, 0, 0);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add end tag and send packet via VIF1 */
|
||||||
|
void VU1::sendList()
|
||||||
|
{
|
||||||
|
*((u64 *)currentBuffer)++ = DMA_END_TAG(0);
|
||||||
|
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||||
|
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||||
|
dma_channel_wait(DMA_CHANNEL_VIF1, VU1_DMA_CHAN_TIMEOUT);
|
||||||
|
dma_channel_send_chain(DMA_CHANNEL_VIF1, buildList.kickBuffer, (u32 *)currentBuffer - (u32 *)buildList.kickBuffer, DMA_FLAG_TRANSFERTAG, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VU1::addDoubleBufferSetting()
|
||||||
|
{
|
||||||
|
*((u64 *)currentBuffer)++ = DMA_CNT_TAG(8 >> 4);
|
||||||
|
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_BASE, 0, 8);
|
||||||
|
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_OFFSET, 0, 496);
|
||||||
|
isDoubleBufferSet = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VU1::addFlush()
|
||||||
|
{
|
||||||
|
*((u64 *)currentBuffer)++ = DMA_CNT_TAG(8 >> 4);
|
||||||
|
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||||
|
*((u32 *)currentBuffer)++ = VIF_CODE(VIF_FLUSH, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VU1::checkDataAlignment(void *t_data)
|
||||||
|
{
|
||||||
|
if (((u32)t_data & 0xF))
|
||||||
|
PRINT_ERR("data is not 16 byte aligned!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// List adding
|
||||||
|
// ----
|
||||||
|
|
||||||
|
void VU1::add128(u64 v1, u64 v2)
|
||||||
|
{
|
||||||
|
checkList();
|
||||||
|
*((u64 *)currentBuffer)++ = v1;
|
||||||
|
*((u64 *)currentBuffer)++ = v2;
|
||||||
|
buildList.dmaSize += 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VU1::add64(u64 v)
|
||||||
|
{
|
||||||
|
checkList();
|
||||||
|
*((u64 *)currentBuffer)++ = v;
|
||||||
|
buildList.dmaSize += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VU1::add32(u32 v)
|
||||||
|
{
|
||||||
|
checkList();
|
||||||
|
*((u32 *)currentBuffer)++ = v;
|
||||||
|
buildList.dmaSize += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VU1::addFloat(float v)
|
||||||
|
{
|
||||||
|
checkList();
|
||||||
|
*((float *)currentBuffer)++ = v;
|
||||||
|
buildList.dmaSize += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VU1::checkList()
|
||||||
|
{
|
||||||
|
if (buildList.isBuilding == 0)
|
||||||
|
PRINT_ERR("Please add list beginning before adding data!");
|
||||||
|
if (buildList.dmaSizeAll > VIF_BUFFER_SIZE)
|
||||||
|
PRINT_ERR("Buffer size exceed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Static
|
||||||
|
// ----
|
||||||
|
|
||||||
|
u8 IS_DMA_VIF1_INITIALIZED = 0;
|
||||||
|
/** TODO */
|
||||||
|
void VU1::uploadProgram(int t_dest, u32 *t_start, u32 *t_end)
|
||||||
|
{
|
||||||
|
if (!IS_DMA_VIF1_INITIALIZED)
|
||||||
|
{
|
||||||
|
IS_DMA_VIF1_INITIALIZED = 1;
|
||||||
|
dma_channel_initialize(DMA_CHANNEL_VIF1, NULL, 0);
|
||||||
|
dma_channel_fast_waits(DMA_CHANNEL_VIF1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
u8 tempBuffer[512] __attribute__((aligned(16)));
|
||||||
|
void *chain = (u64 *)&tempBuffer; // uncached
|
||||||
|
|
||||||
|
// get the size of the code as we can only send 256 instructions in each MPGtag
|
||||||
|
count = VU1::countProgramSize(t_start, t_end);
|
||||||
|
while (count > 0)
|
||||||
|
{
|
||||||
|
u32 currentCount = count > 256 ? 256 : count;
|
||||||
|
|
||||||
|
*((u64 *)chain)++ = DMA_REF_TAG((u32)t_start, currentCount / 2);
|
||||||
|
*((u32 *)chain)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||||
|
*((u32 *)chain)++ = VIF_CODE(VIF_MPG, currentCount & 0xFF, t_dest);
|
||||||
|
|
||||||
|
t_start += currentCount * 2;
|
||||||
|
count -= currentCount;
|
||||||
|
t_dest += currentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
*((u64 *)chain)++ = DMA_END_TAG(0);
|
||||||
|
*((u32 *)chain)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||||
|
*((u32 *)chain)++ = VIF_CODE(VIF_NOP, 0, 0);
|
||||||
|
|
||||||
|
// Send it to vif1
|
||||||
|
FlushCache(0);
|
||||||
|
dma_channel_send_chain(DMA_CHANNEL_VIF1, tempBuffer, 0, DMA_FLAG_TRANSFERTAG, 0);
|
||||||
|
dma_channel_wait(DMA_CHANNEL_VIF1, VU1_DMA_CHAN_TIMEOUT); // synchronize immediately.
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 VU1::countProgramSize(u32 *t_start, u32 *t_end)
|
||||||
|
{
|
||||||
|
u32 size = (t_end - t_start) / 2;
|
||||||
|
if (size & 1)
|
||||||
|
size++;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/utils/math.hpp"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <fastmath.h>
|
||||||
|
|
||||||
|
float Math::cos(float x)
|
||||||
|
{
|
||||||
|
float r;
|
||||||
|
asm volatile(
|
||||||
|
"lui $9, 0x3f00 \n\t"
|
||||||
|
".set noreorder \n\t"
|
||||||
|
".align 3 \n\t"
|
||||||
|
"abs.s %0, %1 \n\t"
|
||||||
|
"lui $8, 0xbe22 \n\t"
|
||||||
|
"mtc1 $9, $f1 \n\t"
|
||||||
|
"ori $8, $8, 0xf983 \n\t"
|
||||||
|
"mtc1 $8, $f8 \n\t"
|
||||||
|
"lui $9, 0x4b00 \n\t"
|
||||||
|
"mtc1 $9, $f3 \n\t"
|
||||||
|
"lui $8, 0x3f80 \n\t"
|
||||||
|
"mtc1 $8, $f2 \n\t"
|
||||||
|
"mula.s %0, $f8 \n\t"
|
||||||
|
"msuba.s $f3, $f2 \n\t"
|
||||||
|
"madda.s $f3, $f2 \n\t"
|
||||||
|
"lui $8, 0x40c9 \n\t"
|
||||||
|
"msuba.s %0, $f8 \n\t"
|
||||||
|
"ori $8, 0x0fdb \n\t"
|
||||||
|
"msub.s %0, $f1, $f2 \n\t"
|
||||||
|
"lui $9, 0xc225 \n\t"
|
||||||
|
"abs.s %0, %0 \n\t"
|
||||||
|
"lui $10, 0x3e80 \n\t"
|
||||||
|
"mtc1 $10, $f7 \n\t"
|
||||||
|
"ori $9, 0x5de1 \n\t"
|
||||||
|
"sub.s %0, %0, $f7 \n\t"
|
||||||
|
"lui $10, 0x42a3 \n\t"
|
||||||
|
"mtc1 $8, $f3 \n\t"
|
||||||
|
"ori $10, 0x3458 \n\t"
|
||||||
|
"mtc1 $9, $f4 \n\t"
|
||||||
|
"lui $8, 0xc299 \n\t"
|
||||||
|
"mtc1 $10, $f5 \n\t"
|
||||||
|
"ori $8, 0x2663 \n\t"
|
||||||
|
"mul.s $f8, %0, %0 \n\t"
|
||||||
|
"lui $9, 0x421e \n\t"
|
||||||
|
"mtc1 $8, $f6 \n\t"
|
||||||
|
"ori $9, 0xd7bb \n\t"
|
||||||
|
"mtc1 $9, $f7 \n\t"
|
||||||
|
"nop \n\t"
|
||||||
|
"mul.s $f1, %0, $f8 \n\t"
|
||||||
|
"mul.s $f9, $f8, $f8 \n\t"
|
||||||
|
"mula.s $f3, %0 \n\t"
|
||||||
|
"mul.s $f2, $f1, $f8 \n\t"
|
||||||
|
"madda.s $f4, $f1 \n\t"
|
||||||
|
"mul.s $f1, $f1, $f9 \n\t"
|
||||||
|
"mul.s %0, $f2, $f9 \n\t"
|
||||||
|
"madda.s $f5, $f2 \n\t"
|
||||||
|
"madda.s $f6, $f1 \n\t"
|
||||||
|
"madd.s %0, $f7, %0 \n\t"
|
||||||
|
".set reorder \n\t"
|
||||||
|
: "=&f"(r)
|
||||||
|
: "f"(x)
|
||||||
|
: "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$8", "$9", "$10");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Math::sqrt(float x)
|
||||||
|
{
|
||||||
|
float r;
|
||||||
|
__asm__ volatile(
|
||||||
|
"sqrt.s %0, %1 \n\t"
|
||||||
|
: "=&f"(r)
|
||||||
|
: "f"(x));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Math::invSqrt(float x) { return 1.0F / sqrt(x); }
|
||||||
|
|
||||||
|
/** Converts Vector3 to PS2SDK's Vector4 */
|
||||||
|
void vec3ToNative(VECTOR o_result, Vector3 &t_vec, float t_fourthVal)
|
||||||
|
{
|
||||||
|
o_result[0] = t_vec.x;
|
||||||
|
o_result[1] = t_vec.y;
|
||||||
|
o_result[2] = t_vec.z;
|
||||||
|
o_result[3] = t_fourthVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Converts array of Vector3 to array of PS2SDK's Vector4 */
|
||||||
|
void manyVec3ToNative(VECTOR *o_result, Vector3 *t_vec, int t_amount, float t_fourthVal)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < t_amount; i++)
|
||||||
|
vec3ToNative(o_result[i], t_vec[i], t_fourthVal);
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/utils/string.hpp"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
char *String::createWithoutExtension(char *source)
|
||||||
|
{
|
||||||
|
u32 length = 0;
|
||||||
|
for (;; length++)
|
||||||
|
if (source[length] == '.')
|
||||||
|
break;
|
||||||
|
char *res = new char[length + 1];
|
||||||
|
for (u32 i = 0; i < length; i++)
|
||||||
|
res[i] = source[i];
|
||||||
|
res[length] = '\0';
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *String::createCopy(char *source)
|
||||||
|
{
|
||||||
|
u32 srcLength = getLength(source);
|
||||||
|
char *res = new char[srcLength + 1];
|
||||||
|
for (u32 i = 0; i < srcLength; i++)
|
||||||
|
res[i] = source[i];
|
||||||
|
res[srcLength] = '\0';
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 String::getLength(char *a)
|
||||||
|
{
|
||||||
|
if (a == NULL)
|
||||||
|
return 0;
|
||||||
|
for (u32 i = 0;; i++)
|
||||||
|
if (a[i] == '\0')
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *String::createConcatenated(char *a, char *b)
|
||||||
|
{
|
||||||
|
u32 aLength = getLength(a);
|
||||||
|
u32 bLength = getLength(b);
|
||||||
|
char *res = new char[aLength + bLength + 1]; // + '\0'
|
||||||
|
for (u32 i = 0; i < aLength; i++)
|
||||||
|
res[i] = a[i];
|
||||||
|
for (u32 i = 0; i < bLength; i++)
|
||||||
|
res[aLength + i] = b[i];
|
||||||
|
res[aLength + bLength] = '\0';
|
||||||
|
return res;
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
; ______ ____ ___
|
||||||
|
; | \/ ____| |___|
|
||||||
|
; | | | \ | |
|
||||||
|
;---------------------------
|
||||||
|
; Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
; Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
;
|
||||||
|
;---------------------------------------------------------------
|
||||||
|
; draw3D.vcl |
|
||||||
|
;---------------------------------------------------------------
|
||||||
|
; A VU1 microprogram to draw 3D object using XYZ2, RGBAQ and ST|
|
||||||
|
; This program uses double buffering (xtop) |
|
||||||
|
; |
|
||||||
|
; Many thanks to: |
|
||||||
|
; - Dr Henry Fortuna |
|
||||||
|
; - Jesper Svennevid, Daniel Collin |
|
||||||
|
; - Guilherme Lampert |
|
||||||
|
;---------------------------------------------------------------
|
||||||
|
|
||||||
|
; TODO
|
||||||
|
; - Fix vertex clipping (is clipping visible triangles :/)
|
||||||
|
; - Move lerp() from EE to VU1 (performance)
|
||||||
|
; - Add dynamic lighting (feature)
|
||||||
|
; - Add --cont + MSCNT instead of alltime MSCAL (performance)
|
||||||
|
|
||||||
|
.syntax new
|
||||||
|
.name VU1Draw3D
|
||||||
|
.vu
|
||||||
|
.init_vf_all
|
||||||
|
.init_vi_all
|
||||||
|
|
||||||
|
--enter
|
||||||
|
--endenter
|
||||||
|
|
||||||
|
;//////////// --- Load data 1 --- /////////////
|
||||||
|
; Updated once per frame
|
||||||
|
lq matrixRow0, 0(vi00) ; load view-projection matrix
|
||||||
|
lq matrixRow1, 1(vi00)
|
||||||
|
lq matrixRow2, 2(vi00)
|
||||||
|
lq matrixRow3, 3(vi00)
|
||||||
|
;/////////////////////////////////////////////
|
||||||
|
|
||||||
|
fcset 0x000000 ; VCL won't let us use CLIP without first zeroing
|
||||||
|
; the clip flags
|
||||||
|
|
||||||
|
;//////////// --- Load data 2 --- /////////////
|
||||||
|
; Updated dynamically
|
||||||
|
xtop iBase
|
||||||
|
|
||||||
|
lq.xyz scale, 0(iBase) ; load program params
|
||||||
|
; float : X, Y, Z - scale vector that we will use to scale the verts after projecting them.
|
||||||
|
; float : W - vert count.
|
||||||
|
lq gifSetTag, 1(iBase) ; GIF tag - set
|
||||||
|
lq texGifTag1, 2(iBase) ; GIF tag - texture LOD
|
||||||
|
lq texGifTag2, 3(iBase) ; GIF tag - texture buffer & CLUT
|
||||||
|
lq primTag, 4(iBase) ; GIF tag - tell GS how many data we will send
|
||||||
|
lq rgba, 5(iBase) ; RGBA
|
||||||
|
;lq clipScale, 6(iBase) ; TODO clipping tests
|
||||||
|
; u32 : R, G, B, A (0-128)
|
||||||
|
iaddiu vertexData, iBase, 7 ; pointer to vertex data
|
||||||
|
ilw.w vertCount, 0(iBase) ; load vert count from scale vector
|
||||||
|
iadd stqData, vertexData, vertCount ; pointer to stq
|
||||||
|
iadd kickAddress, stqData, vertCount ; pointer for XGKICK
|
||||||
|
iadd destAddress, stqData, vertCount ; helper pointer for data inserting
|
||||||
|
;////////////////////////////////////////////
|
||||||
|
|
||||||
|
;/////////// --- Store tags --- /////////////
|
||||||
|
sqi gifSetTag, (destAddress++) ;
|
||||||
|
sqi texGifTag1, (destAddress++) ; texture LOD tag
|
||||||
|
sqi gifSetTag, (destAddress++) ;
|
||||||
|
sqi texGifTag2, (destAddress++) ; texture buffer & CLUT tag
|
||||||
|
sqi primTag, (destAddress++) ; prim + tell gs how many data will be
|
||||||
|
;////////////////////////////////////////////
|
||||||
|
|
||||||
|
;/////////////// --- Loop --- ///////////////
|
||||||
|
iadd vertexCounter, iBase, vertCount ; loop vertCount times
|
||||||
|
vertexLoop:
|
||||||
|
|
||||||
|
;////////// --- Load loop data --- //////////
|
||||||
|
lq vertex, 0(vertexData) ; load xyz
|
||||||
|
; float : X, Y, Z
|
||||||
|
; any32 : _ = 0
|
||||||
|
lq stq, 0(stqData) ; load stq
|
||||||
|
; float : S, T
|
||||||
|
; any32 : Q = 1 ; 1, because we will mul this by 1/vert[w] and this
|
||||||
|
; will be our q for texture perspective correction
|
||||||
|
; any32 : _ = 0
|
||||||
|
;////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
;////////////// --- Vertex --- //////////////
|
||||||
|
mul acc, matrixRow0, vertex[x] ; transform each vertex by the matrix
|
||||||
|
madd acc, matrixRow1, vertex[y]
|
||||||
|
madd acc, matrixRow2, vertex[z]
|
||||||
|
madd vertex, matrixRow3, vertex[w]
|
||||||
|
|
||||||
|
;add.z acc, vf0, clipScale[w] ; TODO clipping maybe this?
|
||||||
|
;madd.z clipVec, clipScale, vertex
|
||||||
|
;mul.xy clipVec, clipScale, vertex
|
||||||
|
;mul.w clipVec, vf0, vertex[z]
|
||||||
|
|
||||||
|
;mul.xyz clipVec, vertex, clipScale ; TODO clipping maybe this?
|
||||||
|
|
||||||
|
clipw.xyz vertex, vertex ; Dr. Fortuna: This instruction checks if the vertex is outside
|
||||||
|
; the viewing frustum. If it is, then the appropriate
|
||||||
|
; clipping flags are set
|
||||||
|
fcand VI01, 0x3FFFF ; Bitwise AND the clipping flags with 0x3FFFF, this makes
|
||||||
|
; sure that we get the clipping judgement for the last three
|
||||||
|
; verts (i.e. that make up the triangle we are about to draw)
|
||||||
|
iaddiu iADC, VI01, 0x7FFF ; Add 0x7FFF. If any of the clipping flags were set this will
|
||||||
|
; cause the triangle not to be drawn (any values above 0x8000
|
||||||
|
; that are stored in the w component of XYZ2 will set the ADC
|
||||||
|
; bit, which tells the GS not to perform a drawing kick on this
|
||||||
|
; triangle.
|
||||||
|
|
||||||
|
;ilw.w iNoDraw, UVStart(Counter) ; Load the iNoDraw flag. If true we should set the ADC bit so the vert isn't drawn
|
||||||
|
;iadd iADC, iADC, iNoDraw ; TODO clipping maybe this?
|
||||||
|
|
||||||
|
isw.w iADC, 2(destAddress)
|
||||||
|
|
||||||
|
div q, vf00[w], vertex[w] ; perspective divide (1/vert[w]):
|
||||||
|
mul.xyz vertex, vertex, q
|
||||||
|
mula.xyz acc, scale, vf00[w] ; scale to GS screen space
|
||||||
|
madd.xyz vertex, vertex, scale ; multiply and add the scales -> vert = vert * scale + scale
|
||||||
|
ftoi4.xyz vertex, vertex ; convert vertex to 12:4 fixed point format
|
||||||
|
;////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
;//////////////// --- ST --- ////////////////
|
||||||
|
mulq modStq, stq, q
|
||||||
|
;////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
;//////////// --- Store data --- ////////////
|
||||||
|
sq modStq, 0(destAddress) ; STQ
|
||||||
|
sq rgba, 1(destAddress) ; RGBA ; q is grabbed from stq
|
||||||
|
sq.xyz vertex, 2(destAddress) ; XYZ2
|
||||||
|
;////////////////////////////////////////////
|
||||||
|
|
||||||
|
iaddiu vertexData, vertexData, 1
|
||||||
|
iaddiu stqData, stqData, 1
|
||||||
|
iaddiu destAddress, destAddress, 3
|
||||||
|
|
||||||
|
iaddi vertexCounter, vertexCounter, -1 ; decrement the loop counter
|
||||||
|
ibne vertexCounter, iBase, vertexLoop ; and repeat if needed
|
||||||
|
|
||||||
|
;////////////////////////////////////////////
|
||||||
|
|
||||||
|
--barrier
|
||||||
|
|
||||||
|
xgkick kickAddress ; dispatch to the GS rasterizer.
|
||||||
|
|
||||||
|
--exit
|
||||||
|
--endexit
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
;-------------------------
|
||||||
|
;-------------------------
|
||||||
|
;-----VCL CODE------------
|
||||||
|
;-------------------------
|
||||||
|
;-------------------------
|
||||||
|
; =================================================
|
||||||
|
; flowMon::Emit() vcl 1.4beta7 produced this code:
|
||||||
|
.vu
|
||||||
|
.align 4
|
||||||
|
.global VU1Draw3D_CodeStart
|
||||||
|
.global VU1Draw3D_CodeEnd
|
||||||
|
VU1Draw3D_CodeStart:
|
||||||
|
__v_draw3D_vcl_4:
|
||||||
|
; _LNOPT_w=[ normal2 ] 23 [23 0] 23 [__v_draw3D_vcl_4]
|
||||||
|
NOP lq VF01,0(VI00)
|
||||||
|
NOP xtop VI02
|
||||||
|
NOP lq VF02,1(VI00)
|
||||||
|
NOP lq VF06,1(VI02)
|
||||||
|
NOP lq VF09,2(VI02)
|
||||||
|
NOP lq VF08,3(VI02)
|
||||||
|
NOP lq VF07,4(VI02)
|
||||||
|
NOP lq VF03,2(VI00)
|
||||||
|
NOP iaddiu VI03,VI02,0x00000007
|
||||||
|
NOP ilw.w VI07,0(VI02)
|
||||||
|
NOP lq VF04,3(VI00)
|
||||||
|
NOP fcset 0
|
||||||
|
NOP lq.xyz VF05,0(VI02)
|
||||||
|
NOP iadd VI04,VI03,VI07
|
||||||
|
NOP iadd VI06,VI04,VI07
|
||||||
|
NOP sqi VF06,(VI06++)
|
||||||
|
NOP sqi VF09,(VI06++)
|
||||||
|
NOP sqi VF06,(VI06++)
|
||||||
|
NOP sqi VF08,(VI06++)
|
||||||
|
NOP lq VF06,5(VI02)
|
||||||
|
NOP iadd VI05,VI04,VI07
|
||||||
|
NOP sqi VF07,(VI06++)
|
||||||
|
NOP iadd VI07,VI02,VI07
|
||||||
|
vertexLoop:
|
||||||
|
; _LNOPT_w=[ normal2 ] 21 [31 14] 31 [vertexLoop]
|
||||||
|
NOP lq VF07,0(VI03)
|
||||||
|
mulax ACC,VF01,VF07x sq VF06,1(VI06) ; STALL_LATENCY ?3
|
||||||
|
madday ACC,VF02,VF07y lq VF08,0(VI04)
|
||||||
|
maddaz ACC,VF03,VF07z iaddiu VI06,VI06,0x00000003
|
||||||
|
maddw VF07,VF04,VF07w NOP
|
||||||
|
clipw.xyz VF07xyz,VF07w div Q,VF00w,VF07w ; STALL_LATENCY ?3
|
||||||
|
NOP NOP
|
||||||
|
NOP NOP
|
||||||
|
NOP NOP
|
||||||
|
NOP NOP
|
||||||
|
NOP NOP
|
||||||
|
NOP NOP
|
||||||
|
mulq.xyz VF07,VF07,Q fcand VI01,262143
|
||||||
|
mulaw.xyz ACC,VF05,VF00w iaddiu VI03,VI03,0x00000001
|
||||||
|
madd.xyz VF07,VF07,VF05 iaddiu VI04,VI04,0x00000001 ; STALL_LATENCY ?2
|
||||||
|
mulq VF08,VF08,Q isubiu VI07,VI07,1
|
||||||
|
ftoi4.xyz VF07,VF07 iaddiu VI01,VI01,0x00007fff ; STALL_LATENCY ?2
|
||||||
|
NOP isw.w VI01,-1(VI06)
|
||||||
|
NOP sq VF08,-3(VI06)
|
||||||
|
NOP ibne VI07,VI02,vertexLoop
|
||||||
|
NOP sq.xyz VF07,-1(VI06)
|
||||||
|
; _LNOPT_w=[ normal2 ] 3 [1 0] 3 [__v_draw3D_vcl_7]
|
||||||
|
NOP xgkick VI05
|
||||||
|
NOP[E] NOP
|
||||||
|
NOP NOP
|
||||||
|
.align 4
|
||||||
|
VU1Draw3D_CodeEnd:
|
||||||
|
; iCount=47
|
||||||
|
; register stats:
|
||||||
|
; 8 VU User integer
|
||||||
|
; 10 VU User floating point
|
||||||
|
;-------------------------
|
||||||
|
;-------------------------
|
||||||
|
;-------------------------
|
||||||
|
;-------------------------
|
||||||
|
;-------------------------
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
EE_BIN = ari.elf
|
||||||
|
|
||||||
|
EE_OBJS = \
|
||||||
|
../../engine/models/math/matrix.o \
|
||||||
|
../../engine/models/math/plane.o \
|
||||||
|
../../engine/models/math/point.o \
|
||||||
|
../../engine/models/math/vector3.o \
|
||||||
|
../../engine/models/dff_model.o \
|
||||||
|
../../engine/models/md2_model.o \
|
||||||
|
../../engine/models/mesh.o \
|
||||||
|
../../engine/models/mesh_spec.o \
|
||||||
|
../../engine/models/obj_model.o \
|
||||||
|
../../engine/modules/audio.o \
|
||||||
|
../../engine/modules/camera_base.o \
|
||||||
|
../../engine/modules/gif_sender.o \
|
||||||
|
../../engine/modules/light.o \
|
||||||
|
../../engine/modules/pad.o \
|
||||||
|
../../engine/modules/renderer.o \
|
||||||
|
../../engine/modules/timer.o \
|
||||||
|
../../engine/modules/vif_sender.o \
|
||||||
|
../../engine/modules/vu1.o \
|
||||||
|
../../engine/utils/math.o \
|
||||||
|
../../engine/utils/string.o \
|
||||||
|
../../engine/loaders/bmp_loader.o \
|
||||||
|
../../engine/loaders/dff_loader.o \
|
||||||
|
../../engine/loaders/md2_loader.o \
|
||||||
|
../../engine/loaders/obj_loader.o \
|
||||||
|
../../engine/vu1_progs/draw3D.o \
|
||||||
|
../../engine/engine.o \
|
||||||
|
camera.o \
|
||||||
|
objects/player.o \
|
||||||
|
ari.o \
|
||||||
|
main.o
|
||||||
|
|
||||||
|
EE_LIBS = -ldraw -lgraph -lmath3d -lpacket -ldma -lpad -laudsrv -lc -lstdc++
|
||||||
|
EE_INCS := -I./../../engine/include $(EE_INCS)
|
||||||
|
EE_DVP = dvp-as
|
||||||
|
EE_VCL = vcl
|
||||||
|
|
||||||
|
all: $(EE_BIN)
|
||||||
|
$(EE_STRIP) --strip-all $(EE_BIN)
|
||||||
|
mv $(EE_BIN) bin/$(EE_BIN)
|
||||||
|
rm $(EE_OBJS)
|
||||||
|
|
||||||
|
# https://github.com/microsoft/wsl/issues/2468#issuecomment-374904520
|
||||||
|
#%.vsm: %.vcl # sudo service binfmt-support start
|
||||||
|
# $(EE_VCL) $< >> $@
|
||||||
|
|
||||||
|
%.o: %.vsm
|
||||||
|
$(EE_DVP) $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(EE_BIN) $(EE_OBJS)
|
||||||
|
|
||||||
|
include $(PS2SDK)/samples/Makefile.pref
|
||||||
|
include $(PS2SDK)/samples/Makefile.eeglobal
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
## Ari sample
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
Testing demo. In future there will be Ariana Grande demo.
|
||||||
|
|
||||||
|
### Assets
|
||||||
|
[Download](http://apgcglz.cluster028.hosting.ovh.net/tyra/1.0.0/samples/ari/assets.zip)
|
||||||
|
|
||||||
|
### Screenshot
|
||||||
|
|
||||||
|
[![Ari screenshot][ari-screenshot]](#)
|
||||||
|
|
||||||
|
[ari-screenshot]: http://apgcglz.cluster028.hosting.ovh.net/tyra/1.0.0/samples/ari/ari.gif
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
// SANDRO TODO
|
||||||
|
// Ogarnac czemu tekstura sie zle wczytuje
|
||||||
|
// Ogarnac wiele tekstur do skyboxa (wczytywane z .mtl i .obj)
|
||||||
|
// texture loading for obj and md2
|
||||||
|
// animation for dff
|
||||||
|
// TODO obj destructor
|
||||||
|
// TODO md2 destructor
|
||||||
|
// TODO dff destructor
|
||||||
|
|
||||||
|
#include "ari.hpp"
|
||||||
|
|
||||||
|
#include "utils/math.hpp"
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
Ari::Ari() {}
|
||||||
|
|
||||||
|
Ari::~Ari() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
// TEST START
|
||||||
|
const u8 WATER_TILES_COUNT = 64;
|
||||||
|
Mesh *island, *islandAddons, *skybox;
|
||||||
|
Mesh **waterFloors;
|
||||||
|
Point *spirals;
|
||||||
|
|
||||||
|
void calcSpiral(int X, int Y)
|
||||||
|
{
|
||||||
|
int x, y, dx;
|
||||||
|
x = y = dx = 0;
|
||||||
|
int dy = -1;
|
||||||
|
int t = X > Y ? X : Y;
|
||||||
|
int maxI = t * t;
|
||||||
|
for (int i = 0; i < maxI; i++)
|
||||||
|
{
|
||||||
|
if ((-X / 2 <= x) && (x <= X / 2) && (-Y / 2 <= y) && (y <= Y / 2))
|
||||||
|
{
|
||||||
|
spirals[i].x = x;
|
||||||
|
spirals[i].y = y;
|
||||||
|
}
|
||||||
|
if ((x == y) || ((x < 0) && (x == -y)) || ((x > 0) && (x == 1 - y)))
|
||||||
|
{
|
||||||
|
t = dx;
|
||||||
|
dx = -dy;
|
||||||
|
dy = t;
|
||||||
|
}
|
||||||
|
x += dx;
|
||||||
|
y += dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TEST END
|
||||||
|
|
||||||
|
void Ari::onInit()
|
||||||
|
{
|
||||||
|
player = new Player();
|
||||||
|
camera = new Camera(&engine.screen);
|
||||||
|
engine.renderer->setCameraDefinitions(&camera->worldView, &camera->unitCirclePosition, camera->planes);
|
||||||
|
engine.audio.init(0);
|
||||||
|
engine.audio.setVolume(40);
|
||||||
|
engine.audio.loadSong("MOV-CIRC.WAV");
|
||||||
|
engine.audio.play();
|
||||||
|
|
||||||
|
Vector3 islandPos = Vector3(0.0F, 10.0F, 0.0F);
|
||||||
|
island = new Mesh();
|
||||||
|
island->rotation.x = -1.6F;
|
||||||
|
island->loadDff("sunnyisl/", "sunnyisl.dff", islandPos, 0.1F);
|
||||||
|
island->shouldBeFrustumCulled = false;
|
||||||
|
island->shouldBeBackfaceCulled = true;
|
||||||
|
|
||||||
|
islandAddons = new Mesh();
|
||||||
|
islandAddons->rotation.x = -1.6F;
|
||||||
|
islandAddons->loadDff("sunnyisl/", "sunnyisl3.dff", islandPos, 0.1F);
|
||||||
|
islandAddons->shouldBeFrustumCulled = false;
|
||||||
|
|
||||||
|
skybox = new Mesh();
|
||||||
|
Vector3 skyboxPos = Vector3(0.0F, 0.0F, 0.0F);
|
||||||
|
skybox->loadObj("skybox/", "skybox.obj", skyboxPos, 100.0F);
|
||||||
|
skybox->shouldBeFrustumCulled = true;
|
||||||
|
|
||||||
|
waterFloors = new Mesh *[WATER_TILES_COUNT];
|
||||||
|
spirals = new Point[WATER_TILES_COUNT];
|
||||||
|
Vector3 initPos = Vector3(0.0F, 8.0F, 0.0F);
|
||||||
|
waterFloors[0] = new Mesh();
|
||||||
|
waterFloors[0]->loadObj("water/", "water.obj", initPos, 5.0F);
|
||||||
|
waterFloors[0]->shouldBeFrustumCulled = true;
|
||||||
|
for (u8 i = 0; i < WATER_TILES_COUNT; i++)
|
||||||
|
{
|
||||||
|
spirals[i].x = 1.0F;
|
||||||
|
spirals[i].y = 2.0F;
|
||||||
|
}
|
||||||
|
u32 spiralOffset = (u32)Math::sqrt(WATER_TILES_COUNT);
|
||||||
|
calcSpiral(spiralOffset, spiralOffset);
|
||||||
|
for (u8 i = 1; i < WATER_TILES_COUNT; i++)
|
||||||
|
{
|
||||||
|
waterFloors[i] = new Mesh();
|
||||||
|
Vector3 nextPos = Vector3(10.0F * spirals[i].x, 8.0F, 10.0F * spirals[i].y);
|
||||||
|
waterFloors[i]->setObj(nextPos, waterFloors[0]->obj, waterFloors[0]->spec);
|
||||||
|
waterFloors[i]->shouldBeFrustumCulled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 currentTexI = 0;
|
||||||
|
|
||||||
|
void Ari::initBulb()
|
||||||
|
{
|
||||||
|
bulb.intensity = 15;
|
||||||
|
bulb.position.set(5.0F, 10.0F, 10.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ari::onUpdate()
|
||||||
|
{
|
||||||
|
if (engine.pad.isCrossClicked)
|
||||||
|
printf("FPS:%f\n", engine.fps);
|
||||||
|
camera->update(engine.pad, player->mesh);
|
||||||
|
engine.renderer->draw(skybox);
|
||||||
|
engine.renderer->draw(island);
|
||||||
|
engine.renderer->draw(islandAddons);
|
||||||
|
engine.renderer->draw(&player->mesh);
|
||||||
|
for (u8 i = 0; i < WATER_TILES_COUNT; i++)
|
||||||
|
engine.renderer->draw(waterFloors[i]); // TODO
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ARI_
|
||||||
|
#define _ARI_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <game.hpp>
|
||||||
|
#include <engine.hpp>
|
||||||
|
#include "objects/player.hpp"
|
||||||
|
#include <models/light_bulb.hpp>
|
||||||
|
#include "./camera.hpp"
|
||||||
|
|
||||||
|
class Ari : public Game
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
Ari();
|
||||||
|
~Ari();
|
||||||
|
|
||||||
|
void onInit();
|
||||||
|
void onUpdate();
|
||||||
|
|
||||||
|
Engine engine;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initBulb();
|
||||||
|
LightBulb bulb;
|
||||||
|
Player *player;
|
||||||
|
Camera *camera;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "camera.hpp"
|
||||||
|
|
||||||
|
#include <utils/math.hpp>
|
||||||
|
#include <utils/debug.hpp>
|
||||||
|
|
||||||
|
const float CAMERA_Y = 15.0F;
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
Camera::Camera(ScreenSettings *t_screen) : CameraBase(t_screen, &position, &up, &unitCirclePosition)
|
||||||
|
{
|
||||||
|
PRINT_LOG("Initializing camera");
|
||||||
|
verticalLevel = 80.0F;
|
||||||
|
up.x = 0.0F;
|
||||||
|
up.y = 1.0F;
|
||||||
|
up.z = 0.0F;
|
||||||
|
PRINT_LOG("Camera initialized!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Camera::~Camera() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
void Camera::update(Pad &t_pad, Mesh &t_mesh)
|
||||||
|
{
|
||||||
|
rotate(t_pad);
|
||||||
|
followBy(t_mesh);
|
||||||
|
updatePlanes(t_mesh.position); // TODO move it out
|
||||||
|
Vector3 newPos = Vector3(t_mesh.position.x, t_mesh.position.y + 10.0F, t_mesh.position.z);
|
||||||
|
worldView.lookAt(up, position, newPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set camera rotation by pad right joy and update unit circle
|
||||||
|
* https://en.wikipedia.org/wiki/Unit_circle
|
||||||
|
* https://www.desmos.com/calculator/3e7iypw4ow
|
||||||
|
*/
|
||||||
|
void Camera::rotate(Pad &t_pad)
|
||||||
|
{
|
||||||
|
if (t_pad.rJoyH <= 50)
|
||||||
|
horizontalLevel -= 0.08;
|
||||||
|
else if (t_pad.rJoyH >= 200)
|
||||||
|
horizontalLevel += 0.04;
|
||||||
|
if (t_pad.rJoyV <= 50 && verticalLevel > 25.0F)
|
||||||
|
verticalLevel -= 0.9F;
|
||||||
|
else if (t_pad.rJoyV >= 200 && verticalLevel < 80.0F)
|
||||||
|
verticalLevel += 0.9F;
|
||||||
|
unitCirclePosition.x = (Math::sin(horizontalLevel) * verticalLevel);
|
||||||
|
unitCirclePosition.y = CAMERA_Y;
|
||||||
|
unitCirclePosition.z = (Math::cos(horizontalLevel) * verticalLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Rotate camera around 3D object */
|
||||||
|
void Camera::followBy(Mesh &t_mesh)
|
||||||
|
{
|
||||||
|
position.x = unitCirclePosition.x + t_mesh.position.x;
|
||||||
|
position.y = unitCirclePosition.y + t_mesh.position.y;
|
||||||
|
position.z = unitCirclePosition.z + t_mesh.position.z;
|
||||||
|
|
||||||
|
if (position.x > (-0.04F * verticalLevel) &&
|
||||||
|
position.x < 0.0F &&
|
||||||
|
position.z > (0.998F * verticalLevel))
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
// position.x = 0.0F;
|
||||||
|
// position.y = 0.0F;
|
||||||
|
// position.z = 0.0F;
|
||||||
|
// horizontalLevel = 0.0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CAMERA_
|
||||||
|
#define _CAMERA_
|
||||||
|
|
||||||
|
#include <modules/pad.hpp>
|
||||||
|
#include <models/mesh.hpp>
|
||||||
|
#include <models/math/vector3.hpp>
|
||||||
|
#include <models/screen_settings.hpp>
|
||||||
|
#include <modules/camera_base.hpp>
|
||||||
|
#include <tamtypes.h>
|
||||||
|
|
||||||
|
/** 3D camera which follow by 3D object. Can be rotated via pad */
|
||||||
|
class Camera : public CameraBase
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
Vector3 up, position, unitCirclePosition;
|
||||||
|
float horizontalLevel, verticalLevel;
|
||||||
|
|
||||||
|
Camera(ScreenSettings *t_screen);
|
||||||
|
~Camera();
|
||||||
|
|
||||||
|
void update(Pad &t_pad, Mesh &t_mesh);
|
||||||
|
void rotate(Pad &t_pad);
|
||||||
|
void followBy(Mesh &t_mesh);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Vector3 *getPosition() { return &position; };
|
||||||
|
Vector3 *getUp() { return &up; };
|
||||||
|
ScreenSettings screen;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ari.hpp"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Ari game = Ari();
|
||||||
|
game.engine.setDefaultScreen();
|
||||||
|
game.engine.init(&game, 40000);
|
||||||
|
SleepThread();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "player.hpp"
|
||||||
|
|
||||||
|
#include <loaders/obj_loader.hpp>
|
||||||
|
#include <loaders/bmp_loader.hpp>
|
||||||
|
#include <modules/gif_sender.hpp>
|
||||||
|
#include <utils/debug.hpp>
|
||||||
|
#include <utils/math.hpp>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
Player::Player()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Creating player object");
|
||||||
|
this->gravity = 0.1F;
|
||||||
|
this->lift = -1.0F;
|
||||||
|
Vector3 initPos = Vector3(0.0F, 8.0F, 0.0F);
|
||||||
|
this->mesh.loadMD2("ari/", "ari.md2", initPos, 0.0001F);
|
||||||
|
this->mesh.shouldBeBackfaceCulled = true;
|
||||||
|
this->mesh.shouldBeFrustumCulled = false;
|
||||||
|
// this->mesh.shouldBeLighted = true;
|
||||||
|
this->mesh.setAnimSpeed(0.05F);
|
||||||
|
this->mesh.playAnimation(0, 1);
|
||||||
|
PRINT_LOG("Player object created!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Player::~Player()
|
||||||
|
{
|
||||||
|
delete[] this->spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PLAYER_
|
||||||
|
#define _PLAYER_
|
||||||
|
|
||||||
|
#include "../camera.hpp"
|
||||||
|
#include <modules/pad.hpp>
|
||||||
|
#include <models/mesh_spec.hpp>
|
||||||
|
#include <tamtypes.h>
|
||||||
|
|
||||||
|
/** Player 3D object class */
|
||||||
|
class Player
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
float gravity, velocity, lift;
|
||||||
|
u8 isOnFloor, isCollideFloor, indexOfCurrentFloor;
|
||||||
|
Mesh mesh;
|
||||||
|
MeshSpec *spec;
|
||||||
|
Player();
|
||||||
|
~Player();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 playerNextPosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
EE_BIN = floors.elf
|
||||||
|
|
||||||
|
EE_OBJS = \
|
||||||
|
../../engine/models/math/matrix.o \
|
||||||
|
../../engine/models/math/plane.o \
|
||||||
|
../../engine/models/math/point.o \
|
||||||
|
../../engine/models/math/vector3.o \
|
||||||
|
../../engine/models/dff_model.o \
|
||||||
|
../../engine/models/md2_model.o \
|
||||||
|
../../engine/models/mesh.o \
|
||||||
|
../../engine/models/mesh_spec.o \
|
||||||
|
../../engine/models/obj_model.o \
|
||||||
|
../../engine/modules/audio.o \
|
||||||
|
../../engine/modules/camera_base.o \
|
||||||
|
../../engine/modules/gif_sender.o \
|
||||||
|
../../engine/modules/light.o \
|
||||||
|
../../engine/modules/pad.o \
|
||||||
|
../../engine/modules/renderer.o \
|
||||||
|
../../engine/modules/timer.o \
|
||||||
|
../../engine/modules/vif_sender.o \
|
||||||
|
../../engine/modules/vu1.o \
|
||||||
|
../../engine/utils/math.o \
|
||||||
|
../../engine/utils/string.o \
|
||||||
|
../../engine/loaders/bmp_loader.o \
|
||||||
|
../../engine/loaders/dff_loader.o \
|
||||||
|
../../engine/loaders/md2_loader.o \
|
||||||
|
../../engine/loaders/obj_loader.o \
|
||||||
|
../../engine/vu1_progs/draw3D.o \
|
||||||
|
../../engine/engine.o \
|
||||||
|
managers/light_manager.o \
|
||||||
|
managers/floor_manager.o \
|
||||||
|
camera.o \
|
||||||
|
objects/floor.o \
|
||||||
|
objects/player.o \
|
||||||
|
utils.o \
|
||||||
|
floors.o \
|
||||||
|
main.o
|
||||||
|
|
||||||
|
EE_LIBS = -ldraw -lgraph -lmath3d -lpacket -ldma -lpad -laudsrv -lc -lstdc++
|
||||||
|
EE_INCS := -I./../../engine/include $(EE_INCS)
|
||||||
|
EE_DVP = dvp-as
|
||||||
|
EE_VCL = openvcl
|
||||||
|
|
||||||
|
all: $(EE_BIN)
|
||||||
|
$(EE_STRIP) --strip-all $(EE_BIN)
|
||||||
|
mv $(EE_BIN) bin/$(EE_BIN)
|
||||||
|
rm $(EE_OBJS)
|
||||||
|
|
||||||
|
%.vsm: %.vcl
|
||||||
|
$(EE_VCL) $< >> $@
|
||||||
|
|
||||||
|
%.o: %.vsm
|
||||||
|
$(EE_DVP) $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(EE_BIN) $(EE_OBJS)
|
||||||
|
|
||||||
|
include $(PS2SDK)/samples/Makefile.pref
|
||||||
|
include $(PS2SDK)/samples/Makefile.eeglobal
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
## Floors sample
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
Simple demo which shows lighting using PATH3, and player movement and animation.
|
||||||
|
|
||||||
|
### Assets
|
||||||
|
[Download](http://apgcglz.cluster028.hosting.ovh.net/tyra/1.0.0/samples/floors/assets.zip)
|
||||||
|
|
||||||
|
### Screenshot
|
||||||
|
|
||||||
|
[![Floors screenshot][floors-screenshot]](#)
|
||||||
|
|
||||||
|
[floors-screenshot]: http://apgcglz.cluster028.hosting.ovh.net/tyra/1.0.0/samples/floors/floors.gif
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "camera.hpp"
|
||||||
|
|
||||||
|
#include <utils/debug.hpp>
|
||||||
|
#include <fastmath.h>
|
||||||
|
|
||||||
|
const float CAMERA_Y = 30.0F;
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
Camera::Camera(ScreenSettings *t_screen) : CameraBase(t_screen, &position, &up, &unitCirclePosition)
|
||||||
|
{
|
||||||
|
PRINT_LOG("Initializing camera");
|
||||||
|
verticalLevel = 80.0F;
|
||||||
|
up.x = 0.0F;
|
||||||
|
up.y = 1.0F;
|
||||||
|
up.z = 0.0F;
|
||||||
|
PRINT_LOG("Camera initialized!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Camera::~Camera() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
void Camera::update(Pad &t_pad, Mesh &t_mesh)
|
||||||
|
{
|
||||||
|
rotate(t_pad);
|
||||||
|
followBy(t_mesh);
|
||||||
|
updatePlanes(t_mesh.position);
|
||||||
|
worldView.lookAt(up, position, t_mesh.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set camera rotation by pad right joy and update unit circle
|
||||||
|
* https://en.wikipedia.org/wiki/Unit_circle
|
||||||
|
* https://www.desmos.com/calculator/3e7iypw4ow
|
||||||
|
*/
|
||||||
|
void Camera::rotate(Pad &t_pad)
|
||||||
|
{
|
||||||
|
if (t_pad.rJoyH <= 50)
|
||||||
|
horizontalLevel -= 0.08;
|
||||||
|
else if (t_pad.rJoyH >= 200)
|
||||||
|
horizontalLevel += 0.04;
|
||||||
|
if (t_pad.rJoyV <= 50 && verticalLevel > 25.0F)
|
||||||
|
verticalLevel -= 0.9F;
|
||||||
|
else if (t_pad.rJoyV >= 200 && verticalLevel < 80.0F)
|
||||||
|
verticalLevel += 0.9F;
|
||||||
|
unitCirclePosition.x = (sin(horizontalLevel) * verticalLevel);
|
||||||
|
unitCirclePosition.y = CAMERA_Y;
|
||||||
|
unitCirclePosition.z = (cos(horizontalLevel) * verticalLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Rotate camera around 3D object */
|
||||||
|
void Camera::followBy(Mesh &t_mesh)
|
||||||
|
{
|
||||||
|
position.x = unitCirclePosition.x + t_mesh.position.x;
|
||||||
|
position.y = unitCirclePosition.y + t_mesh.position.y;
|
||||||
|
position.z = unitCirclePosition.z + t_mesh.position.z;
|
||||||
|
|
||||||
|
if (position.x > (-0.04F * verticalLevel) &&
|
||||||
|
position.x < 0.0F &&
|
||||||
|
position.z > (0.998F * verticalLevel))
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
// position.x = 0.0F;
|
||||||
|
// position.y = 0.0F;
|
||||||
|
// position.z = 0.0F;
|
||||||
|
// horizontalLevel = 0.0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CAMERA_
|
||||||
|
#define _CAMERA_
|
||||||
|
|
||||||
|
#include <modules/pad.hpp>
|
||||||
|
#include <models/mesh.hpp>
|
||||||
|
#include <models/math/vector3.hpp>
|
||||||
|
#include <models/screen_settings.hpp>
|
||||||
|
#include <modules/camera_base.hpp>
|
||||||
|
#include <tamtypes.h>
|
||||||
|
|
||||||
|
/** 3D camera which follow by 3D object. Can be rotated via pad */
|
||||||
|
class Camera : public CameraBase
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
Vector3 up, position, unitCirclePosition;
|
||||||
|
float horizontalLevel, verticalLevel;
|
||||||
|
|
||||||
|
Camera(ScreenSettings *t_screen);
|
||||||
|
~Camera();
|
||||||
|
|
||||||
|
void update(Pad &t_pad, Mesh &t_mesh);
|
||||||
|
void rotate(Pad &t_pad);
|
||||||
|
void followBy(Mesh &t_mesh);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Vector3 *getPosition() { return &position; };
|
||||||
|
Vector3 *getUp() { return &up; };
|
||||||
|
ScreenSettings screen;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "floors.hpp"
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
Floors::Floors() {}
|
||||||
|
|
||||||
|
Floors::~Floors() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
void Floors::onInit()
|
||||||
|
{
|
||||||
|
player = new Player();
|
||||||
|
camera = new Camera(&engine.screen);
|
||||||
|
engine.renderer->setCameraDefinitions(&camera->worldView, &camera->unitCirclePosition, camera->planes);
|
||||||
|
floorManager = new FloorManager(64); // Temp change it also in floor_manager.hpp
|
||||||
|
engine.audio.init(2);
|
||||||
|
engine.audio.addListener(floorManager);
|
||||||
|
engine.audio.addListener(&lightManager);
|
||||||
|
engine.audio.loadSong("NF-CHILL.WAV");
|
||||||
|
engine.audio.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Floors::onUpdate()
|
||||||
|
{
|
||||||
|
if (engine.pad.isCrossClicked)
|
||||||
|
printf("FPS:%f\n", engine.fps);
|
||||||
|
lightManager.update();
|
||||||
|
camera->update(engine.pad, player->mesh);
|
||||||
|
floorManager->update(*player);
|
||||||
|
player->update(engine.pad, *camera, *floorManager);
|
||||||
|
engine.renderer->draw(&player->mesh);
|
||||||
|
engine.renderer->drawByPath3(floorManager->meshes, floorManager->floorAmount, lightManager.bulbs, lightManager.bulbsCount);
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FLOORS_
|
||||||
|
#define _FLOORS_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
#include <game.hpp>
|
||||||
|
#include <engine.hpp>
|
||||||
|
#include "managers/floor_manager.hpp"
|
||||||
|
#include "managers/light_manager.hpp"
|
||||||
|
#include "objects/player.hpp"
|
||||||
|
#include "./camera.hpp"
|
||||||
|
|
||||||
|
class Floors : public Game
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
Floors();
|
||||||
|
~Floors();
|
||||||
|
|
||||||
|
void onInit();
|
||||||
|
void onUpdate();
|
||||||
|
|
||||||
|
Engine engine;
|
||||||
|
|
||||||
|
private:
|
||||||
|
LightManager lightManager;
|
||||||
|
FloorManager *floorManager;
|
||||||
|
Player *player;
|
||||||
|
Camera *camera;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "floors.hpp"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Floors game = Floors();
|
||||||
|
game.engine.setDefaultScreen();
|
||||||
|
game.engine.init(&game, 40000);
|
||||||
|
SleepThread();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "floor_manager.hpp"
|
||||||
|
|
||||||
|
#include <utils/math.hpp>
|
||||||
|
#include <utils/debug.hpp>
|
||||||
|
#include <loaders/obj_loader.hpp>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Calculate square spiral offsets and initialize floors
|
||||||
|
* @param floorAmount must be a number from square root table
|
||||||
|
*/
|
||||||
|
FloorManager::FloorManager(int t_floorAmount)
|
||||||
|
{
|
||||||
|
floorAmount = t_floorAmount;
|
||||||
|
spirals = new Point[t_floorAmount];
|
||||||
|
int floorSpiralMaxOffset = (int)Math::sqrt(t_floorAmount);
|
||||||
|
calcSpiral(floorSpiralMaxOffset, floorSpiralMaxOffset);
|
||||||
|
initFloors();
|
||||||
|
audioOffset = audioMode = audioTick = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FloorManager::~FloorManager()
|
||||||
|
{
|
||||||
|
delete[] spirals;
|
||||||
|
delete[] spec;
|
||||||
|
delete[] obj;
|
||||||
|
delete[] meshes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Calculates square spiral offsets by specyfying max X and Y, fills "spirals" variable
|
||||||
|
* @param X Max X offset off spiral
|
||||||
|
* @param Y Max Y offset off spiral
|
||||||
|
*/
|
||||||
|
void FloorManager::calcSpiral(int X, int Y)
|
||||||
|
{
|
||||||
|
PRINT_LOG("Calculating square spiral for floors");
|
||||||
|
int x, y, dx;
|
||||||
|
x = y = dx = 0;
|
||||||
|
int dy = -1;
|
||||||
|
int t = X > Y ? X : Y;
|
||||||
|
int maxI = t * t;
|
||||||
|
for (int i = 0; i < maxI; i++)
|
||||||
|
{
|
||||||
|
if ((-X / 2 <= x) && (x <= X / 2) && (-Y / 2 <= y) && (y <= Y / 2))
|
||||||
|
{
|
||||||
|
spirals[i].x = x;
|
||||||
|
spirals[i].y = y;
|
||||||
|
}
|
||||||
|
if ((x == y) || ((x < 0) && (x == -y)) || ((x > 0) && (x == 1 - y)))
|
||||||
|
{
|
||||||
|
t = dx;
|
||||||
|
dx = -dy;
|
||||||
|
dy = t;
|
||||||
|
}
|
||||||
|
x += dx;
|
||||||
|
y += dy;
|
||||||
|
}
|
||||||
|
PRINT_LOG("Square spiral calculated!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initialize all floors by:
|
||||||
|
* - Setting position (with spirals offset)
|
||||||
|
* - Anim timer position
|
||||||
|
*/
|
||||||
|
void FloorManager::initFloors()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Initializing floors");
|
||||||
|
meshes = new Mesh *[floorAmount];
|
||||||
|
|
||||||
|
Vector3 initPos = Vector3(0.0F, 0.0F, 0.0F);
|
||||||
|
meshes[0] = new Mesh();
|
||||||
|
meshes[0]->loadObj("floor/", "floor.obj", initPos, 2.0F);
|
||||||
|
meshes[0]->shouldBeFrustumCulled = true;
|
||||||
|
obj = meshes[0]->obj;
|
||||||
|
spec = meshes[0]->spec;
|
||||||
|
for (u8 i = 0; i < floorAmount; i++)
|
||||||
|
{
|
||||||
|
floors[i].init(obj, spec, spirals[i], i);
|
||||||
|
meshes[i] = &floors[i].mesh;
|
||||||
|
}
|
||||||
|
PRINT_LOG("Floors initialized!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Main floor loop.
|
||||||
|
* - Checks if floor should be rendered (isVisible, frustum culling)
|
||||||
|
* - Maintain floor animation
|
||||||
|
* - Fix player position after floor position change
|
||||||
|
*/
|
||||||
|
void FloorManager::update(Player &t_player)
|
||||||
|
{
|
||||||
|
for (u8 i = 0; i < floorAmount; i++)
|
||||||
|
{
|
||||||
|
floors[i].animate(t_player);
|
||||||
|
|
||||||
|
if (floors[i].isByAudioTriggered == true)
|
||||||
|
floors[i].mesh.color.a = 0x20;
|
||||||
|
else
|
||||||
|
floors[i].mesh.color.a = 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Called by audio thread */
|
||||||
|
void FloorManager::onAudioTick()
|
||||||
|
{
|
||||||
|
if (audioTick++ > 16)
|
||||||
|
{
|
||||||
|
if (audioMode == 0)
|
||||||
|
{
|
||||||
|
for (u8 i = 0; i < floorAmount; i++)
|
||||||
|
{
|
||||||
|
if ((i + audioOffset) % 2 == 0)
|
||||||
|
floors[i].isByAudioTriggered = true;
|
||||||
|
else
|
||||||
|
floors[i].isByAudioTriggered = false;
|
||||||
|
}
|
||||||
|
if (++audioOffset > 3)
|
||||||
|
{
|
||||||
|
audioOffset = 0;
|
||||||
|
audioMode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (audioMode == 1)
|
||||||
|
{
|
||||||
|
for (u8 i = 0; i < floorAmount; i++)
|
||||||
|
{
|
||||||
|
if (i < floorAmount / (audioOffset + 1))
|
||||||
|
floors[i].isByAudioTriggered = true;
|
||||||
|
else
|
||||||
|
floors[i].isByAudioTriggered = false;
|
||||||
|
}
|
||||||
|
if (++audioOffset > 3)
|
||||||
|
{
|
||||||
|
audioOffset = 0;
|
||||||
|
audioMode = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (audioMode == 2)
|
||||||
|
{
|
||||||
|
for (u8 i = 0; i < floorAmount; i++)
|
||||||
|
{
|
||||||
|
if ((i + audioOffset) % 4 == 0)
|
||||||
|
floors[i].isByAudioTriggered = true;
|
||||||
|
else
|
||||||
|
floors[i].isByAudioTriggered = false;
|
||||||
|
}
|
||||||
|
if (++audioOffset > 3)
|
||||||
|
{
|
||||||
|
audioOffset = 0;
|
||||||
|
audioMode = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (audioMode == 3)
|
||||||
|
{
|
||||||
|
for (u8 i = 0; i < floorAmount; i++)
|
||||||
|
{
|
||||||
|
if (i + 1 > floorAmount / (audioOffset + 1))
|
||||||
|
floors[i].isByAudioTriggered = true;
|
||||||
|
else
|
||||||
|
floors[i].isByAudioTriggered = false;
|
||||||
|
}
|
||||||
|
if (++audioOffset > 3)
|
||||||
|
{
|
||||||
|
audioOffset = 0;
|
||||||
|
audioMode = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FLOOR_MANAGER_
|
||||||
|
#define _FLOOR_MANAGER_
|
||||||
|
|
||||||
|
class Player; // Forward definition
|
||||||
|
|
||||||
|
#include <models/math/point.hpp>
|
||||||
|
#include <models/obj_model.hpp>
|
||||||
|
#include <models/mesh_spec.hpp>
|
||||||
|
#include <modules/camera_base.hpp>
|
||||||
|
#include <models/audio_listener.hpp>
|
||||||
|
|
||||||
|
#include "../objects/floor.hpp"
|
||||||
|
|
||||||
|
/** Class which is maintaining floors objects */
|
||||||
|
class FloorManager : public AudioListener
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
FloorManager(int t_floorAmount);
|
||||||
|
~FloorManager();
|
||||||
|
Floor floors[64]; // Temp change it also in floors.cpp
|
||||||
|
int floorAmount;
|
||||||
|
void update(Player &t_player);
|
||||||
|
Mesh **meshes;
|
||||||
|
void onAudioTick();
|
||||||
|
MeshSpec *spec;
|
||||||
|
|
||||||
|
private:
|
||||||
|
u8 audioOffset, audioMode;
|
||||||
|
u32 audioTick;
|
||||||
|
ObjModel *obj;
|
||||||
|
Point *spirals;
|
||||||
|
void calcSpiral(int X, int Y);
|
||||||
|
void initFloors();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "light_manager.hpp"
|
||||||
|
#include <utils/debug.hpp>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
LightManager::LightManager()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Creating light manager!");
|
||||||
|
bulbsCount = 2;
|
||||||
|
|
||||||
|
bulbs = new LightBulb[2];
|
||||||
|
bulb1Dir = 0;
|
||||||
|
bulbs[0].intensity = 1;
|
||||||
|
bulbs[0].position.set(30.00F, 30.00F, -30.00F);
|
||||||
|
|
||||||
|
bulb2Dir = 1;
|
||||||
|
bulbs[1].intensity = 1;
|
||||||
|
bulbs[1].position.set(-30.00F, 30.00F, 30.00F);
|
||||||
|
|
||||||
|
audioOffset = audioTick = 0;
|
||||||
|
|
||||||
|
PRINT_LOG("Light manager created!");
|
||||||
|
}
|
||||||
|
|
||||||
|
LightManager::~LightManager()
|
||||||
|
{
|
||||||
|
delete[] bulbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Light bulb moving test */
|
||||||
|
void LightManager::update()
|
||||||
|
{
|
||||||
|
updateBulb1();
|
||||||
|
updateBulb2();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightManager::updateBulb1()
|
||||||
|
{
|
||||||
|
if (bulb1Dir == 1)
|
||||||
|
{
|
||||||
|
if (areLightsInverted)
|
||||||
|
{
|
||||||
|
bulbs[0].position.x += 0.6F;
|
||||||
|
bulbs[0].position.z -= 0.6F;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bulbs[0].position.x += 0.6F;
|
||||||
|
bulbs[0].position.z += 0.6F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (areLightsInverted)
|
||||||
|
{
|
||||||
|
bulbs[0].position.x -= 0.6F;
|
||||||
|
bulbs[0].position.z += 0.6F;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bulbs[0].position.x -= 0.6F;
|
||||||
|
bulbs[0].position.z -= 0.6F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightManager::updateBulb2()
|
||||||
|
{
|
||||||
|
if (bulb2Dir == 1)
|
||||||
|
{
|
||||||
|
if (areLightsInverted)
|
||||||
|
{
|
||||||
|
bulbs[1].position.x -= 0.6F;
|
||||||
|
bulbs[1].position.z += 0.6F;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bulbs[1].position.x += 0.6F;
|
||||||
|
bulbs[1].position.z += 0.6F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (areLightsInverted)
|
||||||
|
{
|
||||||
|
bulbs[1].position.x += 0.6F;
|
||||||
|
bulbs[1].position.z -= 0.6F;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bulbs[1].position.x -= 0.6F;
|
||||||
|
bulbs[1].position.z -= 0.6F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Called by audio thread */
|
||||||
|
void LightManager::onAudioTick()
|
||||||
|
{
|
||||||
|
bulb1Dir = bulb1Dir == 1 ? 0 : 1;
|
||||||
|
bulb2Dir = bulb2Dir == 1 ? 0 : 1;
|
||||||
|
if (audioTick++ > 17)
|
||||||
|
{
|
||||||
|
if (++audioOffset > 3)
|
||||||
|
{
|
||||||
|
audioOffset = 0;
|
||||||
|
if (areLightsInverted)
|
||||||
|
{
|
||||||
|
areLightsInverted = false;
|
||||||
|
bulbs[0].position.x = 20.0F;
|
||||||
|
bulbs[0].position.z = -20.0F;
|
||||||
|
|
||||||
|
bulbs[1].position.x = -20.0F;
|
||||||
|
bulbs[1].position.z = 20.0F;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
areLightsInverted = true;
|
||||||
|
bulbs[0].position.x = 20.0F;
|
||||||
|
bulbs[0].position.z = 20.0F;
|
||||||
|
|
||||||
|
bulbs[1].position.x = -20.0F;
|
||||||
|
bulbs[1].position.z = -20.0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bulbs[0].intensity += 6;
|
||||||
|
bulbs[1].intensity += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIGHT_MANAGER_
|
||||||
|
#define _LIGHT_MANAGER_
|
||||||
|
|
||||||
|
#include <models/light_bulb.hpp>
|
||||||
|
#include <models/audio_listener.hpp>
|
||||||
|
|
||||||
|
/** Class which is maintaining floors objects */
|
||||||
|
class LightManager : public AudioListener
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
LightManager();
|
||||||
|
~LightManager();
|
||||||
|
|
||||||
|
LightBulb *bulbs;
|
||||||
|
u8 bulbsCount;
|
||||||
|
void update();
|
||||||
|
void onAudioTick();
|
||||||
|
|
||||||
|
private:
|
||||||
|
u8 bulb1Dir, bulb2Dir;
|
||||||
|
void updateBulb1();
|
||||||
|
void updateBulb2();
|
||||||
|
u8 audioOffset, areLightsInverted;
|
||||||
|
u32 audioTick;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "floor.hpp"
|
||||||
|
|
||||||
|
#include "../utils.hpp"
|
||||||
|
#include "./player.hpp"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
const int FLOOR_ANIMATION_LENGTH = 100;
|
||||||
|
const float FLOOR_ANIMATION_Y_MIN = 0.0F;
|
||||||
|
const float FLOOR_ANIMATION_Y_MAX = 10.0F;
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
Floor::Floor() {}
|
||||||
|
|
||||||
|
Floor::~Floor() {}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Init floor position and animation timer position
|
||||||
|
* @param spec pointer to 3D object specification
|
||||||
|
* @param spiral Spiral position
|
||||||
|
* @param initOffset Number of floor (index)
|
||||||
|
*/
|
||||||
|
void Floor::init(ObjModel *obj, MeshSpec *spec, Point &spiral, u8 &initOffset)
|
||||||
|
{
|
||||||
|
Vector3 initPos = Vector3(0.00F, -10.00F, 0.00F);
|
||||||
|
this->mesh.setObj(initPos, obj, spec);
|
||||||
|
this->initOffset = initOffset;
|
||||||
|
this->animTimer = rand() % FLOOR_ANIMATION_LENGTH;
|
||||||
|
this->mesh.shouldBeLighted = true;
|
||||||
|
this->mesh.shouldBeFrustumCulled = true;
|
||||||
|
this->animDirection = 0;
|
||||||
|
this->mesh.position.x = spiral.x * 40.0F;
|
||||||
|
this->mesh.position.z = spiral.y * 40.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Check and update animation direction and position
|
||||||
|
* Runs Player::onBeforePlayerFloorMove() method
|
||||||
|
*/
|
||||||
|
void Floor::animate(Player &player)
|
||||||
|
{
|
||||||
|
if (this->animDirection == 0)
|
||||||
|
this->animTimer++;
|
||||||
|
else
|
||||||
|
this->animTimer--;
|
||||||
|
|
||||||
|
if (this->animDirection == 0 && this->animTimer >= FLOOR_ANIMATION_LENGTH)
|
||||||
|
this->animDirection = 1;
|
||||||
|
else if (this->animDirection == 1 && this->animTimer <= 0)
|
||||||
|
this->animDirection = 0;
|
||||||
|
float newY = Utils::expoEaseInOut(this->animTimer, FLOOR_ANIMATION_Y_MIN, FLOOR_ANIMATION_Y_MAX, FLOOR_ANIMATION_LENGTH);
|
||||||
|
float yDiff = newY - this->mesh.position.y;
|
||||||
|
if (this->initOffset == player.indexOfCurrentFloor)
|
||||||
|
player.onBeforePlayerFloorMove(this, yDiff);
|
||||||
|
this->mesh.position.y = newY;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FLOOR_
|
||||||
|
#define _FLOOR_
|
||||||
|
|
||||||
|
class Player; // Forward definition
|
||||||
|
|
||||||
|
#include <models/mesh.hpp>
|
||||||
|
#include <models/obj_model.hpp>
|
||||||
|
#include <models/math/point.hpp>
|
||||||
|
#include <tamtypes.h>
|
||||||
|
|
||||||
|
/** Floor 3D object class */
|
||||||
|
class Floor
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
u16 animTimer;
|
||||||
|
u8 animDirection, initOffset, isByAudioTriggered;
|
||||||
|
Mesh mesh;
|
||||||
|
|
||||||
|
Floor();
|
||||||
|
~Floor();
|
||||||
|
|
||||||
|
void init(ObjModel *obj, MeshSpec *spec, Point &spiral, u8 &initOffset);
|
||||||
|
void animate(Player &player);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "player.hpp"
|
||||||
|
|
||||||
|
#include <loaders/obj_loader.hpp>
|
||||||
|
#include <loaders/bmp_loader.hpp>
|
||||||
|
#include <modules/gif_sender.hpp>
|
||||||
|
#include <utils/debug.hpp>
|
||||||
|
#include <utils/math.hpp>
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Constructors/Destructors
|
||||||
|
// ----
|
||||||
|
|
||||||
|
Player::Player()
|
||||||
|
{
|
||||||
|
PRINT_LOG("Creating player object");
|
||||||
|
this->gravity = 0.1F;
|
||||||
|
this->lift = -1.0F;
|
||||||
|
|
||||||
|
Vector3 initPos = Vector3(0.00F, 20.00F, 0.00F);
|
||||||
|
this->mesh.loadMD2("warrior/", "warrior.md2", initPos, 0.2F);
|
||||||
|
this->mesh.rotation.x = -1.6F;
|
||||||
|
this->mesh.shouldBeBackfaceCulled = false;
|
||||||
|
this->mesh.shouldBeFrustumCulled = false;
|
||||||
|
|
||||||
|
this->mesh.setAnimSpeed(0.2F);
|
||||||
|
this->mesh.playAnimation(0, 24);
|
||||||
|
PRINT_LOG("Player object created!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Player::~Player()
|
||||||
|
{
|
||||||
|
delete[] this->spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// Methods
|
||||||
|
// ----
|
||||||
|
|
||||||
|
/** Update player position and control gravity */
|
||||||
|
void Player::update(Pad &pad, Camera &camera, FloorManager &floorManager)
|
||||||
|
{
|
||||||
|
this->updatePosition(pad, camera, floorManager);
|
||||||
|
this->updateGravity(pad, floorManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Move player when pad move buttons are pressed and is not blocked by any floor side */
|
||||||
|
void Player::updatePosition(Pad &pad, Camera &camera, FloorManager &floorManager)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (pad.isDpadUpPressed == 1)
|
||||||
|
{
|
||||||
|
this->playerNextPosition.x = this->mesh.position.x + 0.01F * -camera.unitCirclePosition.x;
|
||||||
|
this->playerNextPosition.z = this->mesh.position.z + 0.01F * -camera.unitCirclePosition.z;
|
||||||
|
}
|
||||||
|
if (pad.isDpadDownPressed == 1)
|
||||||
|
{
|
||||||
|
this->playerNextPosition.x = this->mesh.position.x + 0.01F * camera.unitCirclePosition.x;
|
||||||
|
this->playerNextPosition.z = this->mesh.position.z + 0.01F * camera.unitCirclePosition.z;
|
||||||
|
}
|
||||||
|
if (pad.isDpadLeftPressed == 1)
|
||||||
|
{
|
||||||
|
this->playerNextPosition.x = this->mesh.position.x + 0.01F * -camera.unitCirclePosition.z;
|
||||||
|
this->playerNextPosition.z = this->mesh.position.z + 0.01F * camera.unitCirclePosition.x;
|
||||||
|
}
|
||||||
|
if (pad.isDpadRightPressed == 1)
|
||||||
|
{
|
||||||
|
this->playerNextPosition.x = this->mesh.position.x + 0.01F * camera.unitCirclePosition.z;
|
||||||
|
this->playerNextPosition.z = this->mesh.position.z + 0.01F * -camera.unitCirclePosition.x;
|
||||||
|
}
|
||||||
|
this->playerNextPosition.y = this->mesh.position.y;
|
||||||
|
this->isCollideFloor = 0;
|
||||||
|
Vector3 min = Vector3();
|
||||||
|
Vector3 max = Vector3();
|
||||||
|
for (int i = 0; i < floorManager.floorAmount; i++)
|
||||||
|
{
|
||||||
|
floorManager.floors[i].mesh.getMinMax(&min, &max);
|
||||||
|
this->isCollideFloor = this->playerNextPosition.collidesSquare(min, max);
|
||||||
|
if (this->isCollideFloor == 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (this->isCollideFloor == 0)
|
||||||
|
{
|
||||||
|
this->mesh.position.x = this->playerNextPosition.x;
|
||||||
|
this->mesh.position.z = this->playerNextPosition.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Do not call this.
|
||||||
|
* This is called by Floor::animate() on player's floor move in Y direction
|
||||||
|
*/
|
||||||
|
void Player::onBeforePlayerFloorMove(Floor *floor, float &newY)
|
||||||
|
{
|
||||||
|
if (floor->animDirection == 0 && newY > 0.0F)
|
||||||
|
this->mesh.position.y += newY * 1.05F;
|
||||||
|
else if ((floor->animDirection == 1 && -newY < 0.0F))
|
||||||
|
this->mesh.position.y -= -newY * 1.05F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update player position by gravity and update index of current floor */
|
||||||
|
void Player::updateGravity(Pad &pad, FloorManager &floorManager)
|
||||||
|
{
|
||||||
|
Vector3 min = Vector3();
|
||||||
|
Vector3 max = Vector3();
|
||||||
|
|
||||||
|
if (pad.isCrossClicked == 1)
|
||||||
|
this->velocity = this->lift;
|
||||||
|
|
||||||
|
this->isOnFloor = 0;
|
||||||
|
for (int i = 0; i < floorManager.floorAmount; i++)
|
||||||
|
{
|
||||||
|
floorManager.floors[i].mesh.getMinMax(&min, &max);
|
||||||
|
this->isOnFloor = this->mesh.position.isOnSquare(min, max);
|
||||||
|
if (this->isOnFloor == 1)
|
||||||
|
{
|
||||||
|
this->indexOfCurrentFloor = floorManager.floors[i].initOffset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->velocity += this->gravity;
|
||||||
|
this->mesh.position.y -= this->velocity;
|
||||||
|
|
||||||
|
if (this->mesh.position.y >= 60.0F)
|
||||||
|
{
|
||||||
|
this->mesh.position.y = 60.0F;
|
||||||
|
this->velocity = 0;
|
||||||
|
}
|
||||||
|
else if ((this->mesh.position.y) < max.y && this->isOnFloor)
|
||||||
|
{
|
||||||
|
this->mesh.position.y = max.y;
|
||||||
|
this->velocity = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PLAYER_
|
||||||
|
#define _PLAYER_
|
||||||
|
|
||||||
|
#include "../managers/floor_manager.hpp"
|
||||||
|
#include "../camera.hpp"
|
||||||
|
#include <modules/pad.hpp>
|
||||||
|
#include <models/mesh_spec.hpp>
|
||||||
|
#include <tamtypes.h>
|
||||||
|
|
||||||
|
/** Player 3D object class */
|
||||||
|
class Player
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
float gravity, velocity, lift;
|
||||||
|
u8 isOnFloor, isCollideFloor, indexOfCurrentFloor;
|
||||||
|
Mesh mesh;
|
||||||
|
MeshSpec *spec;
|
||||||
|
Player();
|
||||||
|
~Player();
|
||||||
|
|
||||||
|
void update(Pad &pad, Camera &camera, FloorManager &floorManager);
|
||||||
|
void onBeforePlayerFloorMove(Floor *floor, float &newY);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 playerNextPosition;
|
||||||
|
void updatePosition(Pad &pad, Camera &camera, FloorManager &floorManager);
|
||||||
|
void updateGravity(Pad &pad, FloorManager &floorManager);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "./utils.hpp"
|
||||||
|
|
||||||
|
#include <fastmath.h>
|
||||||
|
|
||||||
|
/** Exponential ease-in-out animation
|
||||||
|
* @param t Time
|
||||||
|
* @param b Start value
|
||||||
|
* @param c Change
|
||||||
|
* @param d Duration
|
||||||
|
* @returns Current animation position
|
||||||
|
*/
|
||||||
|
float Utils::expoEaseInOut(float t, float b, float c, float d)
|
||||||
|
{
|
||||||
|
if (t == 0)
|
||||||
|
return b;
|
||||||
|
|
||||||
|
if (t == d)
|
||||||
|
return b + c;
|
||||||
|
|
||||||
|
if ((t /= d / 2) < 1)
|
||||||
|
return c / 2 * powf(2, 10 * (t - 1)) + b;
|
||||||
|
|
||||||
|
return c / 2 * (-powf(2, -10 * --t) + 2) + b;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
# ______ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licenced under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TYRA_UTILS_
|
||||||
|
#define _TYRA_UTILS_
|
||||||
|
|
||||||
|
#include <tamtypes.h>
|
||||||
|
|
||||||
|
class Utils
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
static float expoEaseInOut(float t, float b, float c, float d);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user